package handlers_test import ( "database/sql" "net/http" "net/http/httptest" "regexp" "testing" "time" "github.com/DATA-DOG/go-sqlmock" "github.com/rede5/gohorsejobs/backend/internal/api/handlers" "github.com/rede5/gohorsejobs/backend/internal/services" ) // createTestAdminHandlers creates handlers with mocks and optional DB func createTestAdminHandlers(t *testing.T, db *sql.DB) *handlers.AdminHandlers { t.Helper() var adminSvc *services.AdminService var jobSvc *services.JobService var auditSvc *services.AuditService if db != nil { adminSvc = services.NewAdminService(db) jobSvc = services.NewJobService(db) auditSvc = services.NewAuditService(db) } return handlers.NewAdminHandlers( adminSvc, auditSvc, jobSvc, nil, // Cloudflare service not needed for basic tests yet ) } func TestNewAdminHandlers(t *testing.T) { h := handlers.NewAdminHandlers(nil, nil, nil, nil) if h == nil { t.Error("NewAdminHandlers should not return nil") } } func TestAdminHandlers_ListCompanies(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() handlers := createTestAdminHandlers(t, db) // Mock Count Query mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM companies`)). WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1)) // Mock List Query mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, name, slug, type, document, city_id, email, website, verified, active, created_at FROM companies`)). WillReturnRows(sqlmock.NewRows([]string{"id", "name", "slug", "type", "document", "city_id", "email", "website", "verified", "active", "created_at"}). AddRow(1, "Acme Corp", "acme-corp", "company", "1234567890", 1, "contact@acme.com", "https://acme.com", true, true, time.Now())) req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/companies", nil) rec := httptest.NewRecorder() handlers.ListCompanies(rec, req) if rec.Code != http.StatusOK { t.Errorf("Expected status %d, got %d. Body: %s", http.StatusOK, rec.Code, rec.Body.String()) } } func TestAdminHandlers_DuplicateJob(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() handlers := createTestAdminHandlers(t, db) // 1. Mock GetJobByID (for duplication source) // Updated query based on actual implementation rows := sqlmock.NewRows([]string{"company_id", "created_by", "title", "description", "salary_min", "salary_max", "salary_type", "employment_type", "work_mode", "working_hours", "location", "region_id", "city_id", "requirements", "benefits", "visa_support", "language_level"}). AddRow(1, 1, "Original Job", "Desc", 1000, 2000, "monthly", "full-time", "remote", "8h", "Remote", 1, 1, "[]", "[]", false, "native") mock.ExpectQuery(regexp.QuoteMeta(`SELECT company_id, created_by, title, description, salary_min, salary_max, salary_type, employment_type, work_mode, working_hours, location, region_id, city_id, requirements, benefits, visa_support, language_level FROM jobs WHERE id = $1`)). WithArgs(100). WillReturnRows(rows) // 2. Mock INSERT // Note: The implementation might be returning more or fewer columns, blindly matching logic usually safer but here we try to match. // Implementation typically inserts and returns ID. mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO jobs`)). WithArgs(1, 1, "Copy of Original Job", "Desc", 1000.0, 2000.0, "monthly", sqlmock.AnyArg(), "full-time", "remote", "8h", "Remote", 1, 1, "[]", "[]", false, "native", "draft"). WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(101)) // Request req := httptest.NewRequest(http.MethodPost, "/api/v1/admin/jobs/100/duplicate", nil) req.SetPathValue("id", "100") rec := httptest.NewRecorder() handlers.DuplicateJob(rec, req) if rec.Code != http.StatusCreated { t.Errorf("Expected status %d, got %d. Body: %s", http.StatusCreated, rec.Code, rec.Body.String()) } }