Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions api/configs/setup_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package configs

import (
"net/http/httptest"
"testing"

"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
)

// TestGetOptionLimit checks if the function correctly parses offset from query params
func TestGetOptionLimit(t *testing.T) {
gin.SetMode(gin.TestMode)

t.Run("ValidOffset", func(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest("GET", "/?offset=25", nil)

query := bson.M{"offset": "should-be-deleted"}
options, err := GetOptionLimit(&query, c)

if err != nil {
t.Fatalf("Expected no error, got %v", err) // Use Fatalf to stop if options is nil
}

if _, exists := query["offset"]; exists {
t.Error("Expected 'offset' to be deleted from the query map")
}

// Ensure we compare the same types (int64)
if options.Skip == nil || *options.Skip != int64(25) {
t.Errorf("Expected Skip to be 25, got %v", options.Skip)
}
})

t.Run("EmptyOffset", func(t *testing.T) {
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest("GET", "/", nil)

query := bson.M{}
options, _ := GetOptionLimit(&query, c)

if options.Skip == nil || *options.Skip != int64(0) {
t.Errorf("Expected default Skip to be 0, got %v", options.Skip)
}
})

t.Run("InvalidOffsetType", func(t *testing.T) {
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest("GET", "/?offset=not-a-number", nil)

query := bson.M{}
_, err := GetOptionLimit(&query, c)

if err == nil {
t.Error("Expected an error when parsing a non-integer offset")
}
})
}

// TestGetAggregateLimit achieves regression testing for the refactored logic
func TestGetAggregateLimit(t *testing.T) {
gin.SetMode(gin.TestMode)

t.Run("DefaultValuesWhenNoParams", func(t *testing.T) {
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest("GET", "/", nil)

query := bson.M{}
paginateMap, err := GetAggregateLimit(&query, c)

if err != nil {
t.Errorf("Expected no error, got %v", err)
}

// Check for the presence of keys and their BSON structure
for _, key := range []string{"former_offset", "latter_offset"} {
stage, ok := paginateMap[key]
if !ok {
t.Fatalf("Key %s missing from paginateMap", key)
}
// Use type assertion or direct indexing for bson.D
if len(stage) == 0 || stage[0].Key != "$skip" || !isEqual(stage[0].Value, 0) {
t.Errorf("Expected default $skip 0 for %s, got %v", key, stage)
}
}
})

t.Run("ValidOverrideFromQuery", func(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest("GET", "/?former_offset=50", nil)

query := bson.M{"former_offset": "to-be-deleted"}
paginateMap, _ := GetAggregateLimit(&query, c)

former := paginateMap["former_offset"]
// Explicitly check the value as int64 to avoid architecture-based build fails
if !isEqual(former[0].Value, 50) {
t.Errorf("Expected former_offset to be 50, got %v", former[0].Value)
}

if _, exists := query["former_offset"]; exists {
t.Error("Expected 'former_offset' to be deleted from query map")
}
})
}

// Helper function to handle cross-platform integer comparisons safely
func isEqual(actual interface{}, expected int) bool {
switch v := actual.(type) {
case int:
return v == expected
case int64:
return v == int64(expected)
case int32:
return v == int32(expected)
default:
return false
}
}
108 changes: 108 additions & 0 deletions api/controllers/controllers_utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package controllers

import (
"net/http"
"net/http/httptest"
"testing"

"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson/primitive"
)

// TestObjectIDFromParam validates the conversion of URL string parameters to MongoDB ObjectIDs.
func TestObjectIDFromParam(t *testing.T) {
gin.SetMode(gin.TestMode)

t.Run("ValidObjectID", func(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)

// Fabricate a valid 24-character hex string parameter
validHex := "65a3f1b2c3d4e5f6a7b8c9d0"
c.Params = []gin.Param{{Key: "id", Value: validHex}}

result, err := objectIDFromParam(c, "id")

if err != nil {
t.Errorf("Expected no error for valid hex, got %v", err)
}
if result.Hex() != validHex {
t.Errorf("Expected hex %s, got %s", validHex, result.Hex())
}
})

t.Run("InvalidObjectID", func(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)

// Fabricate an invalid parameter
c.Params = []gin.Param{{Key: "id", Value: "invalid-id-format"}}

result, err := objectIDFromParam(c, "id")

if err == nil {
t.Error("Expected error for invalid hex string, but got nil")
}
if result != nil {
t.Error("Expected nil result for invalid conversion")
}
// Verify the utility automatically sent a 400 Bad Request response
if w.Code != http.StatusBadRequest {
t.Errorf("Expected status 400, got %d", w.Code)
}
})
}

// TestGetQuery validates the construction of MongoDB filter maps based on the request type.
func TestGetQuery(t *testing.T) {
gin.SetMode(gin.TestMode)

t.Run("ById_Valid", func(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)

id := primitive.NewObjectID()
c.Params = []gin.Param{{Key: "id", Value: id.Hex()}}

query, err := getQuery[any]("ById", c)

if err != nil {
t.Errorf("Expected no error, got %v", err)
}
// Verify the query map contains the correct ObjectID
if query["_id"] != id {
t.Errorf("Expected query _id to be %v, got %v", id, query["_id"])
}
})

t.Run("InvalidFlag", func(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)

_, err := getQuery[any]("InvalidFlag", c)

if err == nil {
t.Error("Expected error for unsupported flag")
}
// Verify internal server error status was triggered
if w.Code != http.StatusInternalServerError {
t.Errorf("Expected status 500, got %d", w.Code)
}
})
}

// TestRespond verifies that the JSON response structure matches the API schema.
func TestRespond(t *testing.T) {
gin.SetMode(gin.TestMode)

w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)

testData := map[string]string{"key": "value"}
respond(c, http.StatusOK, "test-message", testData)

if w.Code != http.StatusOK {
t.Errorf("Expected status 200, got %d", w.Code)
}

}
26 changes: 26 additions & 0 deletions api/controllers/course_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package controllers

import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
)

func TestCourseById_InvalidID(t *testing.T) {
gin.SetMode(gin.TestMode)

// Create a response recorder to capture the result
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)

// Test sending a completely invalid ID format
c.Params = []gin.Param{{Key: "id", Value: "not-an-object-id"}}

CourseById(c)

// Verify that the controller utility correctly returns a 400 Bad Request
if w.Code != http.StatusBadRequest {
t.Errorf("Expected status 400 for invalid ID, got %d", w.Code)
}
}