package handlers import ( "net/http" "testing" "github.com/gin-gonic/gin" ) // newTestContext, parseResponse, and gin.SetMode are defined in iace_handler_test.go // ============================================================================ // Module Endpoint Tests // ============================================================================ func TestGetModule_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/modules/not-a-uuid", nil, nil, gin.Params{{Key: "id", Value: "not-a-uuid"}}) h.GetModule(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestGetModule_EmptyID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/modules/", nil, nil, gin.Params{{Key: "id", Value: ""}}) h.GetModule(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestCreateModule_EmptyBody_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/modules", nil, nil, nil) h.CreateModule(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestCreateModule_MissingTitle_Returns400(t *testing.T) { h := &TrainingHandlers{} body := map[string]interface{}{"module_code": "T01", "regulation_area": "dsgvo", "frequency_type": "annual"} w, c := newTestContext("POST", "/modules", body, nil, nil) h.CreateModule(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestCreateModule_MissingModuleCode_Returns400(t *testing.T) { h := &TrainingHandlers{} body := map[string]interface{}{"title": "Test", "regulation_area": "dsgvo", "frequency_type": "annual"} w, c := newTestContext("POST", "/modules", body, nil, nil) h.CreateModule(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestCreateModule_MissingRegulationArea_Returns400(t *testing.T) { h := &TrainingHandlers{} body := map[string]interface{}{"module_code": "T01", "title": "Test", "frequency_type": "annual"} w, c := newTestContext("POST", "/modules", body, nil, nil) h.CreateModule(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestUpdateModule_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("PUT", "/modules/bad", map[string]interface{}{"title": "x"}, nil, gin.Params{{Key: "id", Value: "bad"}}) h.UpdateModule(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestDeleteModule_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("DELETE", "/modules/bad", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.DeleteModule(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestDeleteModule_EmptyID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("DELETE", "/modules/", nil, nil, gin.Params{{Key: "id", Value: ""}}) h.DeleteModule(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } // ============================================================================ // Matrix Endpoint Tests // ============================================================================ func TestSetMatrixEntry_EmptyBody_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/matrix", nil, nil, nil) h.SetMatrixEntry(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestSetMatrixEntry_MissingRoleCode_Returns400(t *testing.T) { h := &TrainingHandlers{} body := map[string]interface{}{"module_id": "00000000-0000-0000-0000-000000000001"} w, c := newTestContext("POST", "/matrix", body, nil, nil) h.SetMatrixEntry(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestDeleteMatrixEntry_InvalidModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("DELETE", "/matrix/R1/bad", nil, nil, gin.Params{ {Key: "role", Value: "R1"}, {Key: "moduleId", Value: "bad"}, }) h.DeleteMatrixEntry(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } // ============================================================================ // Assignment Endpoint Tests // ============================================================================ func TestGetAssignment_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/assignments/bad", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.GetAssignment(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestStartAssignment_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/assignments/bad/start", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.StartAssignment(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestUpdateAssignmentProgress_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/assignments/bad/progress", map[string]interface{}{"progress": 50}, nil, gin.Params{{Key: "id", Value: "bad"}}) h.UpdateAssignmentProgress(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestUpdateAssignmentProgress_EmptyBody_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/assignments/00000000-0000-0000-0000-000000000001/progress", nil, nil, gin.Params{{Key: "id", Value: "00000000-0000-0000-0000-000000000001"}}) h.UpdateAssignmentProgress(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestCompleteAssignment_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/assignments/bad/complete", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.CompleteAssignment(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestComputeAssignments_EmptyBody_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/assignments/compute", nil, nil, nil) h.ComputeAssignments(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestComputeAssignments_MissingUserID_Returns400(t *testing.T) { h := &TrainingHandlers{} body := map[string]interface{}{"user_name": "Test", "user_email": "test@test.de", "roles": []string{"R1"}} w, c := newTestContext("POST", "/assignments/compute", body, nil, nil) h.ComputeAssignments(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } // ============================================================================ // Quiz Endpoint Tests // ============================================================================ func TestGetQuiz_InvalidModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/quiz/bad", nil, nil, gin.Params{{Key: "moduleId", Value: "bad"}}) h.GetQuiz(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestSubmitQuiz_InvalidModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/quiz/bad/submit", map[string]interface{}{}, nil, gin.Params{{Key: "moduleId", Value: "bad"}}) h.SubmitQuiz(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestSubmitQuiz_EmptyBody_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/quiz/00000000-0000-0000-0000-000000000001/submit", nil, nil, gin.Params{{Key: "moduleId", Value: "00000000-0000-0000-0000-000000000001"}}) h.SubmitQuiz(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestGetQuizAttempts_InvalidAssignmentID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/quiz/attempts/bad", nil, nil, gin.Params{{Key: "assignmentId", Value: "bad"}}) h.GetQuizAttempts(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } // ============================================================================ // Content Endpoint Tests // ============================================================================ func TestGetContent_InvalidModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/content/bad", nil, nil, gin.Params{{Key: "moduleId", Value: "bad"}}) h.GetContent(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestPublishContent_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/content/bad/publish", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.PublishContent(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestGenerateContent_EmptyBody_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/content/generate", nil, nil, nil) h.GenerateContent(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestGenerateQuiz_EmptyBody_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/content/generate-quiz", nil, nil, nil) h.GenerateQuiz(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } // ============================================================================ // Media Endpoint Tests // ============================================================================ func TestGetModuleMedia_InvalidModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/media/module/bad", nil, nil, gin.Params{{Key: "moduleId", Value: "bad"}}) h.GetModuleMedia(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestGetMediaURL_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/media/bad/url", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.GetMediaURL(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestPublishMedia_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/media/bad/publish", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.PublishMedia(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestStreamMedia_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/media/bad/stream", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.StreamMedia(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestGenerateAudio_InvalidModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/content/bad/generate-audio", nil, nil, gin.Params{{Key: "moduleId", Value: "bad"}}) h.GenerateAudio(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestGenerateVideo_InvalidModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/content/bad/generate-video", nil, nil, gin.Params{{Key: "moduleId", Value: "bad"}}) h.GenerateVideo(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestPreviewVideoScript_InvalidModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/content/bad/preview-script", nil, nil, gin.Params{{Key: "moduleId", Value: "bad"}}) h.PreviewVideoScript(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } // ============================================================================ // Certificate Endpoint Tests // ============================================================================ func TestGenerateCertificate_InvalidAssignmentID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/certificates/generate/bad", nil, nil, gin.Params{{Key: "assignmentId", Value: "bad"}}) h.GenerateCertificate(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestDownloadCertificatePDF_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/certificates/bad/pdf", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.DownloadCertificatePDF(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestVerifyCertificate_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/certificates/bad/verify", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.VerifyCertificate(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestListCertificates_NilStore_Panics(t *testing.T) { // This tests that a nil store doesn't silently succeed defer func() { if r := recover(); r == nil { t.Error("Expected panic with nil store") } }() h := &TrainingHandlers{} _, c := newTestContext("GET", "/certificates", nil, nil, nil) h.ListCertificates(c) } // ============================================================================ // Interactive Video Endpoint Tests (User Journey: Admin generates video) // ============================================================================ func TestGenerateInteractiveVideo_InvalidModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/content/bad/generate-interactive", nil, nil, gin.Params{{Key: "moduleId", Value: "bad"}}) h.GenerateInteractiveVideo(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } resp := parseResponse(w) if resp["error"] == nil { t.Error("Response should contain 'error' key") } } func TestGenerateInteractiveVideo_EmptyModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/content//generate-interactive", nil, nil, gin.Params{{Key: "moduleId", Value: ""}}) h.GenerateInteractiveVideo(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestGetInteractiveManifest_InvalidModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/content/bad/interactive-manifest", nil, nil, gin.Params{{Key: "moduleId", Value: "bad"}}) h.GetInteractiveManifest(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } resp := parseResponse(w) if resp["error"] == nil { t.Error("Response should contain 'error' key") } } func TestGetInteractiveManifest_EmptyModuleID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/content//interactive-manifest", nil, nil, gin.Params{{Key: "moduleId", Value: ""}}) h.GetInteractiveManifest(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } // ============================================================================ // Checkpoint Quiz Endpoint Tests (User Journey: Learner takes quiz) // ============================================================================ func TestSubmitCheckpointQuiz_InvalidCheckpointID_Returns400(t *testing.T) { h := &TrainingHandlers{} body := map[string]interface{}{ "assignment_id": "00000000-0000-0000-0000-000000000001", "answers": []int{0, 1, 2}, } w, c := newTestContext("POST", "/checkpoints/bad/submit", body, nil, gin.Params{{Key: "checkpointId", Value: "bad"}}) h.SubmitCheckpointQuiz(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } resp := parseResponse(w) if resp["error"] == nil { t.Error("Response should contain 'error' key") } } func TestSubmitCheckpointQuiz_EmptyCheckpointID_Returns400(t *testing.T) { h := &TrainingHandlers{} body := map[string]interface{}{ "assignment_id": "00000000-0000-0000-0000-000000000001", "answers": []int{0}, } w, c := newTestContext("POST", "/checkpoints//submit", body, nil, gin.Params{{Key: "checkpointId", Value: ""}}) h.SubmitCheckpointQuiz(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestSubmitCheckpointQuiz_EmptyBody_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/checkpoints/00000000-0000-0000-0000-000000000001/submit", nil, nil, gin.Params{{Key: "checkpointId", Value: "00000000-0000-0000-0000-000000000001"}}) h.SubmitCheckpointQuiz(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestSubmitCheckpointQuiz_InvalidAssignmentID_Returns400(t *testing.T) { h := &TrainingHandlers{} body := map[string]interface{}{ "assignment_id": "not-a-uuid", "answers": []int{0}, } w, c := newTestContext("POST", "/checkpoints/00000000-0000-0000-0000-000000000001/submit", body, nil, gin.Params{{Key: "checkpointId", Value: "00000000-0000-0000-0000-000000000001"}}) h.SubmitCheckpointQuiz(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestSubmitCheckpointQuiz_ValidIDs_NilStore_Panics(t *testing.T) { // When both IDs are valid, handler reaches store → panic with nil store defer func() { if r := recover(); r == nil { t.Error("Expected panic with nil store") } }() h := &TrainingHandlers{} body := map[string]interface{}{ "assignment_id": "00000000-0000-0000-0000-000000000001", "answers": []int{0}, } _, c := newTestContext("POST", "/checkpoints/00000000-0000-0000-0000-000000000001/submit", body, nil, gin.Params{{Key: "checkpointId", Value: "00000000-0000-0000-0000-000000000001"}}) h.SubmitCheckpointQuiz(c) } // ============================================================================ // Checkpoint Progress Endpoint Tests (User Journey: Learner views progress) // ============================================================================ func TestGetCheckpointProgress_InvalidAssignmentID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/checkpoints/progress/bad", nil, nil, gin.Params{{Key: "assignmentId", Value: "bad"}}) h.GetCheckpointProgress(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } resp := parseResponse(w) if resp["error"] == nil { t.Error("Response should contain 'error' key") } } func TestGetCheckpointProgress_EmptyAssignmentID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/checkpoints/progress/", nil, nil, gin.Params{{Key: "assignmentId", Value: ""}}) h.GetCheckpointProgress(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } // ============================================================================ // Interactive Video Error Format Tests (table-driven) // ============================================================================ func TestInteractiveEndpoints_InvalidID_ResponseContainsErrorKey(t *testing.T) { tests := []struct { name string method string handler func(h *TrainingHandlers, c *gin.Context) params gin.Params }{ {"GenerateInteractiveVideo", "POST", func(h *TrainingHandlers, c *gin.Context) { h.GenerateInteractiveVideo(c) }, gin.Params{{Key: "moduleId", Value: "x"}}}, {"GetInteractiveManifest", "GET", func(h *TrainingHandlers, c *gin.Context) { h.GetInteractiveManifest(c) }, gin.Params{{Key: "moduleId", Value: "x"}}}, {"SubmitCheckpointQuiz", "POST", func(h *TrainingHandlers, c *gin.Context) { h.SubmitCheckpointQuiz(c) }, gin.Params{{Key: "checkpointId", Value: "x"}}}, {"GetCheckpointProgress", "GET", func(h *TrainingHandlers, c *gin.Context) { h.GetCheckpointProgress(c) }, gin.Params{{Key: "assignmentId", Value: "x"}}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext(tt.method, "/test", nil, nil, tt.params) tt.handler(h, c) if w.Code != http.StatusBadRequest { t.Errorf("%s: Expected 400, got %d", tt.name, w.Code) } resp := parseResponse(w) if resp["error"] == nil { t.Errorf("%s: response should contain 'error' key", tt.name) } }) } } // ============================================================================ // Block Endpoint Tests // ============================================================================ func TestGetBlockConfig_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/blocks/bad", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.GetBlockConfig(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestCreateBlockConfig_EmptyBody_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/blocks", nil, nil, nil) h.CreateBlockConfig(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestCreateBlockConfig_MissingName_Returns400(t *testing.T) { h := &TrainingHandlers{} body := map[string]interface{}{"regulation_area": "dsgvo", "module_code_prefix": "BLK"} w, c := newTestContext("POST", "/blocks", body, nil, nil) h.CreateBlockConfig(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestUpdateBlockConfig_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("PUT", "/blocks/bad", map[string]interface{}{"name": "x"}, nil, gin.Params{{Key: "id", Value: "bad"}}) h.UpdateBlockConfig(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestDeleteBlockConfig_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("DELETE", "/blocks/bad", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.DeleteBlockConfig(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestPreviewBlock_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/blocks/bad/preview", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.PreviewBlock(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestGenerateBlock_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("POST", "/blocks/bad/generate", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.GenerateBlock(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } func TestGetBlockControls_InvalidID_Returns400(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext("GET", "/blocks/bad/controls", nil, nil, gin.Params{{Key: "id", Value: "bad"}}) h.GetBlockControls(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d", w.Code) } } // ============================================================================ // Response Error Format Tests // ============================================================================ func TestInvalidID_ResponseContainsErrorKey(t *testing.T) { tests := []struct { name string method string handler func(h *TrainingHandlers, c *gin.Context) params gin.Params }{ {"GetModule", "GET", func(h *TrainingHandlers, c *gin.Context) { h.GetModule(c) }, gin.Params{{Key: "id", Value: "x"}}}, {"DeleteModule", "DELETE", func(h *TrainingHandlers, c *gin.Context) { h.DeleteModule(c) }, gin.Params{{Key: "id", Value: "x"}}}, {"StreamMedia", "GET", func(h *TrainingHandlers, c *gin.Context) { h.StreamMedia(c) }, gin.Params{{Key: "id", Value: "x"}}}, {"GenerateCertificate", "POST", func(h *TrainingHandlers, c *gin.Context) { h.GenerateCertificate(c) }, gin.Params{{Key: "assignmentId", Value: "x"}}}, {"DownloadCertificatePDF", "GET", func(h *TrainingHandlers, c *gin.Context) { h.DownloadCertificatePDF(c) }, gin.Params{{Key: "id", Value: "x"}}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := &TrainingHandlers{} w, c := newTestContext(tt.method, "/test", nil, nil, tt.params) tt.handler(h, c) resp := parseResponse(w) if resp["error"] == nil { t.Errorf("%s: response should contain 'error' key", tt.name) } }) } }