=== RUN   TestValidateJWT
--- PASS: TestValidateJWT (0.00s)
=== RUN   TestConfigureSwagger
--- PASS: TestConfigureSwagger (0.00s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/cmd/api	(cached)
=== RUN   TestVerifyUserPassword
--- PASS: TestVerifyUserPassword (0.61s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/cmd/debug_user	(cached)
?   	github.com/rede5/gohorsejobs/backend/cmd/fixhash	[no test files]
=== RUN   TestGenerateHash
--- PASS: TestGenerateHash (0.23s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/cmd/genhash	(cached)
?   	github.com/rede5/gohorsejobs/backend/cmd/inspect_schema	[no test files]
?   	github.com/rede5/gohorsejobs/backend/cmd/manual_migrate	[no test files]
?   	github.com/rede5/gohorsejobs/backend/docs	[no test files]
=== RUN   TestNewAdminHandlers
--- PASS: TestNewAdminHandlers (0.00s)
=== RUN   TestAdminHandlers_ListCompanies
--- PASS: TestAdminHandlers_ListCompanies (0.00s)
=== RUN   TestAdminHandlers_DuplicateJob
--- PASS: TestAdminHandlers_DuplicateJob (0.00s)
=== RUN   TestAdminHandlers_ListAccessRoles
--- PASS: TestAdminHandlers_ListAccessRoles (0.00s)
=== RUN   TestAdminHandlers_ListTags
--- PASS: TestAdminHandlers_ListTags (0.00s)
=== RUN   TestRegisterCandidateHandler_Success
    core_handlers_test.go:74: Integration test requires full DI setup
--- SKIP: TestRegisterCandidateHandler_Success (0.00s)
=== RUN   TestRegisterCandidateHandler_InvalidPayload
--- PASS: TestRegisterCandidateHandler_InvalidPayload (0.00s)
=== RUN   TestRegisterCandidateHandler_MissingFields
=== RUN   TestRegisterCandidateHandler_MissingFields/Missing_Email
=== RUN   TestRegisterCandidateHandler_MissingFields/Missing_Password
=== RUN   TestRegisterCandidateHandler_MissingFields/Missing_Name
=== RUN   TestRegisterCandidateHandler_MissingFields/All_Empty
--- PASS: TestRegisterCandidateHandler_MissingFields (0.00s)
    --- PASS: TestRegisterCandidateHandler_MissingFields/Missing_Email (0.00s)
    --- PASS: TestRegisterCandidateHandler_MissingFields/Missing_Password (0.00s)
    --- PASS: TestRegisterCandidateHandler_MissingFields/Missing_Name (0.00s)
    --- PASS: TestRegisterCandidateHandler_MissingFields/All_Empty (0.00s)
=== RUN   TestLoginHandler_InvalidPayload
--- PASS: TestLoginHandler_InvalidPayload (0.00s)
=== RUN   TestLoginHandler_Success
[LOGIN DEBUG] Searching for user: john@example.com
[LOGIN DEBUG] User found: ID=u1, Status=active, HashPrefix=hashed_123
[LOGIN DEBUG] Password verification PASSED
[LOGIN DEBUG] Status check PASSED
--- PASS: TestLoginHandler_Success (0.00s)
=== RUN   TestCoreHandlers_ListNotifications
--- PASS: TestCoreHandlers_ListNotifications (0.00s)
=== RUN   TestCoreHandlers_Tickets
=== RUN   TestCoreHandlers_Tickets/CreateTicket
=== RUN   TestCoreHandlers_Tickets/ListTickets
--- PASS: TestCoreHandlers_Tickets (0.00s)
    --- PASS: TestCoreHandlers_Tickets/CreateTicket (0.00s)
    --- PASS: TestCoreHandlers_Tickets/ListTickets (0.00s)
=== RUN   TestNewLocationHandlers
--- PASS: TestNewLocationHandlers (0.00s)
=== RUN   TestListStatesByCountry_MissingID
--- PASS: TestListStatesByCountry_MissingID (0.00s)
=== RUN   TestListCitiesByState_MissingID
--- PASS: TestListCitiesByState_MissingID (0.00s)
=== RUN   TestSearchLocations_ShortQuery
--- PASS: TestSearchLocations_ShortQuery (0.00s)
=== RUN   TestSearchLocations_MissingCountryID
--- PASS: TestSearchLocations_MissingCountryID (0.00s)
=== RUN   TestSearchLocations_InvalidCountryID
--- PASS: TestSearchLocations_InvalidCountryID (0.00s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/internal/api/handlers	0.036s
=== RUN   TestHeaderAuthGuard_ValidTokenFromHeader

[TEST] === TestHeaderAuthGuard_ValidTokenFromHeader ===
[AUTH DEBUG] === HeaderAuthGuard START ===
[AUTH DEBUG] Method: GET, Path: /protected
[AUTH DEBUG] Authorization Header: 'Bearer valid-jwt-token'
[AUTH DEBUG] Token from Header (first 20 chars): 'valid-jwt-token...'
[AUTH DEBUG] Validating token...
[TEST LOG] ValidateToken called with token: 'valid-jwt-token...'
[AUTH DEBUG] Token VALID! Claims: sub=user-123, tenant=tenant-456, roles=[admin user]
[AUTH DEBUG] === HeaderAuthGuard SUCCESS ===
[TEST LOG] Handler reached - checking context values
[TEST LOG] Context: userID=user-123, tenantID=tenant-456, roles=[admin user]
[TEST LOG] Response status: 200 (expected: 200)
--- PASS: TestHeaderAuthGuard_ValidTokenFromHeader (0.00s)
=== RUN   TestHeaderAuthGuard_ValidTokenFromCookie

[TEST] === TestHeaderAuthGuard_ValidTokenFromCookie ===
[AUTH DEBUG] === HeaderAuthGuard START ===
[AUTH DEBUG] Method: GET, Path: /protected
[AUTH DEBUG] Authorization Header: ''
[AUTH DEBUG] Token from Cookie (first 20 chars): 'cookie-jwt-token...'
[AUTH DEBUG] Validating token...
[TEST LOG] ValidateToken called with token: 'cookie-jwt-token...'
[AUTH DEBUG] Token VALID! Claims: sub=user-cookie-123, tenant=tenant-cookie-456, roles=[candidate]
[AUTH DEBUG] === HeaderAuthGuard SUCCESS ===
[TEST LOG] Handler reached via cookie auth
[TEST LOG] Context userID: user-cookie-123
[TEST LOG] Response status: 200 (expected: 200)
--- PASS: TestHeaderAuthGuard_ValidTokenFromCookie (0.00s)
=== RUN   TestHeaderAuthGuard_MissingToken

[TEST] === TestHeaderAuthGuard_MissingToken ===
[AUTH DEBUG] === HeaderAuthGuard START ===
[AUTH DEBUG] Method: GET, Path: /protected
[AUTH DEBUG] Authorization Header: ''
[AUTH DEBUG] No jwt cookie found: http: named cookie not present
[AUTH DEBUG] No token found - returning 401
[TEST LOG] Response status: 401 (expected: 401)
--- PASS: TestHeaderAuthGuard_MissingToken (0.00s)
=== RUN   TestHeaderAuthGuard_InvalidTokenFormat

[TEST] === TestHeaderAuthGuard_InvalidTokenFormat ===
[AUTH DEBUG] === HeaderAuthGuard START ===
[AUTH DEBUG] Method: GET, Path: /protected
[AUTH DEBUG] Authorization Header: 'Basic some-token'
[AUTH DEBUG] Invalid header format: 2 parts, first part: 'Basic'
[AUTH DEBUG] No jwt cookie found: http: named cookie not present
[AUTH DEBUG] No token found - returning 401
[TEST LOG] Response status: 401 (expected: 401)
--- PASS: TestHeaderAuthGuard_InvalidTokenFormat (0.00s)
=== RUN   TestHeaderAuthGuard_InvalidToken

[TEST] === TestHeaderAuthGuard_InvalidToken ===
[AUTH DEBUG] === HeaderAuthGuard START ===
[AUTH DEBUG] Method: GET, Path: /protected
[AUTH DEBUG] Authorization Header: 'Bearer invalid-token'
[AUTH DEBUG] Token from Header (first 20 chars): 'invalid-token...'
[AUTH DEBUG] Validating token...
[TEST LOG] ValidateToken called with token: 'invalid-token...'
[AUTH DEBUG] Token validation FAILED: token expired
[TEST LOG] Response status: 401 (expected: 401)
--- PASS: TestHeaderAuthGuard_InvalidToken (0.00s)
=== RUN   TestOptionalHeaderAuthGuard_NoToken

[TEST] === TestOptionalHeaderAuthGuard_NoToken ===
[TEST LOG] Handler reached without token - context should be empty
[TEST LOG] Context userID (should be nil): <nil>
[TEST LOG] Handler was called: true (expected: true)
--- PASS: TestOptionalHeaderAuthGuard_NoToken (0.00s)
=== RUN   TestOptionalHeaderAuthGuard_ValidToken

[TEST] === TestOptionalHeaderAuthGuard_ValidToken ===
[TEST LOG] ValidateToken called with token: 'optional-token...'
[TEST LOG] Handler reached with optional token
[TEST LOG] Context userID: optional-user
--- PASS: TestOptionalHeaderAuthGuard_ValidToken (0.00s)
=== RUN   TestOptionalHeaderAuthGuard_InvalidToken

[TEST] === TestOptionalHeaderAuthGuard_InvalidToken ===
[TEST LOG] ValidateToken called with token: 'bad-optional-token...'
[TEST LOG] Response status: 401 (expected: 401)
--- PASS: TestOptionalHeaderAuthGuard_InvalidToken (0.00s)
=== RUN   TestOptionalHeaderAuthGuard_TokenFromCookie

[TEST] === TestOptionalHeaderAuthGuard_TokenFromCookie ===
[TEST LOG] ValidateToken called with token: 'cookie-optional-toke...'
--- PASS: TestOptionalHeaderAuthGuard_TokenFromCookie (0.00s)
=== RUN   TestRequireRoles_UserHasRequiredRole

[TEST] === TestRequireRoles_UserHasRequiredRole ===
[RBAC DEBUG] === RequireRoles START for GET /admin ===
[RBAC DEBUG] Required roles: [admin]
[RBAC DEBUG] Raw roles from context: [admin user] (type: []string)
[RBAC DEBUG] Extracted roles: [admin user]
[RBAC DEBUG] SUCCESS: User has required role
[TEST LOG] Handler reached - user has required role
[TEST LOG] Response status: 200 (expected: 200)
--- PASS: TestRequireRoles_UserHasRequiredRole (0.00s)
=== RUN   TestRequireRoles_UserLacksRequiredRole

[TEST] === TestRequireRoles_UserLacksRequiredRole ===
[RBAC DEBUG] === RequireRoles START for GET /admin ===
[RBAC DEBUG] Required roles: [admin superadmin]
[RBAC DEBUG] Raw roles from context: [user viewer] (type: []string)
[RBAC DEBUG] Extracted roles: [user viewer]
[RBAC DEBUG] FAILED: User roles [user viewer] do not match required [admin superadmin]
[TEST LOG] Response status: 403 (expected: 403)
--- PASS: TestRequireRoles_UserLacksRequiredRole (0.00s)
=== RUN   TestRequireRoles_CaseInsensitive

[TEST] === TestRequireRoles_CaseInsensitive ===
[RBAC DEBUG] === RequireRoles START for GET /admin ===
[RBAC DEBUG] Required roles: [admin]
[RBAC DEBUG] Raw roles from context: [ADMIN USER] (type: []string)
[RBAC DEBUG] Extracted roles: [ADMIN USER]
[RBAC DEBUG] SUCCESS: User has required role
[TEST LOG] Handler reached - case insensitive match worked
[TEST LOG] Response status: 200 (expected: 200)
--- PASS: TestRequireRoles_CaseInsensitive (0.00s)
=== RUN   TestRequireRoles_NoRolesInContext

[TEST] === TestRequireRoles_NoRolesInContext ===
[RBAC DEBUG] === RequireRoles START for GET /admin ===
[RBAC DEBUG] Required roles: [admin]
[RBAC DEBUG] Raw roles from context: <nil> (type: <nil>)
[RBAC DEBUG] Extracted roles: []
[RBAC DEBUG] FAILED: No roles found in context
[TEST LOG] Response status: 403 (expected: 403)
--- PASS: TestRequireRoles_NoRolesInContext (0.00s)
=== RUN   TestRequireRoles_MultipleAllowedRoles

[TEST] === TestRequireRoles_MultipleAllowedRoles ===
[RBAC DEBUG] === RequireRoles START for GET /manage ===
[RBAC DEBUG] Required roles: [admin moderator superadmin]
[RBAC DEBUG] Raw roles from context: [moderator] (type: []string)
[RBAC DEBUG] Extracted roles: [moderator]
[RBAC DEBUG] SUCCESS: User has required role
[TEST LOG] Handler reached - matched one of multiple allowed roles
[TEST LOG] Response status: 200 (expected: 200)
--- PASS: TestRequireRoles_MultipleAllowedRoles (0.00s)
=== RUN   TestTenantGuard_ValidTenant

[TEST] === TestTenantGuard_ValidTenant ===
[TEST LOG] Handler reached - tenant is valid
[TEST LOG] Response status: 200 (expected: 200)
--- PASS: TestTenantGuard_ValidTenant (0.00s)
=== RUN   TestTenantGuard_MissingTenant

[TEST] === TestTenantGuard_MissingTenant ===
[TEST LOG] Response status: 403 (expected: 403)
--- PASS: TestTenantGuard_MissingTenant (0.00s)
=== RUN   TestTenantGuard_EmptyTenant

[TEST] === TestTenantGuard_EmptyTenant ===
[TEST LOG] Response status: 403 (expected: 403)
--- PASS: TestTenantGuard_EmptyTenant (0.00s)
=== RUN   TestExtractRoles_FromStringSlice

[TEST] === TestExtractRoles_FromStringSlice ===
[TEST LOG] Input: [admin user viewer], Result: [admin user viewer]
--- PASS: TestExtractRoles_FromStringSlice (0.00s)
=== RUN   TestExtractRoles_FromInterfaceSlice

[TEST] === TestExtractRoles_FromInterfaceSlice ===
[TEST LOG] Input: [admin moderator], Result: [admin moderator]
--- PASS: TestExtractRoles_FromInterfaceSlice (0.00s)
=== RUN   TestExtractRoles_FromNil

[TEST] === TestExtractRoles_FromNil ===
[TEST LOG] Input: nil, Result: []
--- PASS: TestExtractRoles_FromNil (0.00s)
=== RUN   TestExtractRoles_FromUnknownType

[TEST] === TestExtractRoles_FromUnknownType ===
[TEST LOG] Input: not-a-slice (type: string), Result: []
--- PASS: TestExtractRoles_FromUnknownType (0.00s)
=== RUN   TestExtractRoles_FromMixedInterfaceSlice

[TEST] === TestExtractRoles_FromMixedInterfaceSlice ===
[TEST LOG] Input: [admin 123 user <nil>], Result: [admin user]
--- PASS: TestExtractRoles_FromMixedInterfaceSlice (0.00s)
=== RUN   TestHasRole_SingleMatch

[TEST] === TestHasRole_SingleMatch ===
[TEST LOG] User roles: [admin user], Allowed: [admin], Result: true
--- PASS: TestHasRole_SingleMatch (0.00s)
=== RUN   TestHasRole_NoMatch

[TEST] === TestHasRole_NoMatch ===
[TEST LOG] User roles: [user viewer], Allowed: [admin superadmin], Result: false
--- PASS: TestHasRole_NoMatch (0.00s)
=== RUN   TestHasRole_CaseInsensitive

[TEST] === TestHasRole_CaseInsensitive ===
[TEST LOG] User roles: [ADMIN USER], Allowed: [admin], Result: true
--- PASS: TestHasRole_CaseInsensitive (0.00s)
=== RUN   TestHasRole_EmptyUserRoles

[TEST] === TestHasRole_EmptyUserRoles ===
[TEST LOG] User roles: [], Allowed: [admin], Result: false
--- PASS: TestHasRole_EmptyUserRoles (0.00s)
=== RUN   TestHasRole_EmptyAllowedRoles

[TEST] === TestHasRole_EmptyAllowedRoles ===
[TEST LOG] User roles: [admin], Allowed: [], Result: false
--- PASS: TestHasRole_EmptyAllowedRoles (0.00s)
=== RUN   TestCORSMiddleware_AllowedOrigin

[TEST] === TestCORSMiddleware_AllowedOrigin ===
[TEST LOG] Handler reached - CORS headers should be set
[TEST LOG] Access-Control-Allow-Origin: 'http://localhost:3000'
[TEST LOG] Access-Control-Allow-Credentials: 'true'
--- PASS: TestCORSMiddleware_AllowedOrigin (0.00s)
=== RUN   TestCORSMiddleware_DeniedOrigin

[TEST] === TestCORSMiddleware_DeniedOrigin ===
[TEST LOG] Handler reached - CORS origin should be empty
[TEST LOG] Access-Control-Allow-Origin: '' (expected empty)
--- PASS: TestCORSMiddleware_DeniedOrigin (0.00s)
=== RUN   TestCORSMiddleware_WildcardOrigin

[TEST] === TestCORSMiddleware_WildcardOrigin ===
[TEST LOG] Handler reached - wildcard CORS
[TEST LOG] Access-Control-Allow-Origin: '*' (expected *)
--- PASS: TestCORSMiddleware_WildcardOrigin (0.00s)
=== RUN   TestCORSMiddleware_PreflightOptions

[TEST] === TestCORSMiddleware_PreflightOptions ===
[TEST LOG] Response status: 200 (expected: 200 for preflight)
[TEST LOG] Handler was called: false (expected: false)
[TEST LOG] Access-Control-Allow-Methods: 'POST, GET, OPTIONS, PUT, PATCH, DELETE'
--- PASS: TestCORSMiddleware_PreflightOptions (0.00s)
=== RUN   TestCORSMiddleware_DefaultOrigin

[TEST] === TestCORSMiddleware_DefaultOrigin ===
[TEST LOG] Handler reached - default origin
[TEST LOG] Access-Control-Allow-Origin: 'http://localhost:3000'
--- PASS: TestCORSMiddleware_DefaultOrigin (0.00s)
=== RUN   TestCORSMiddleware_MultipleOrigins

[TEST] === TestCORSMiddleware_MultipleOrigins ===
[TEST LOG] Access-Control-Allow-Origin: 'http://admin.example.com'
--- PASS: TestCORSMiddleware_MultipleOrigins (0.00s)
=== RUN   TestCORSMiddleware_NoOriginHeader

[TEST] === TestCORSMiddleware_NoOriginHeader ===
[TEST LOG] Handler reached - no origin header in request
[TEST LOG] Access-Control-Allow-Origin: '' (expected empty)
--- PASS: TestCORSMiddleware_NoOriginHeader (0.00s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/internal/api/middleware	0.041s
=== RUN   TestNewUser
--- PASS: TestNewUser (0.00s)
=== RUN   TestUser_AssignRole_And_HasPermission
--- PASS: TestUser_AssignRole_And_HasPermission (0.00s)
=== RUN   TestNewCompany
--- PASS: TestNewCompany (0.00s)
=== RUN   TestCompany_ActivateDeactivate
--- PASS: TestCompany_ActivateDeactivate (0.00s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/internal/core/domain/entity	0.007s
?   	github.com/rede5/gohorsejobs/backend/internal/core/dto	[no test files]
?   	github.com/rede5/gohorsejobs/backend/internal/core/ports	[no test files]
=== RUN   TestLoginUseCase_Execute_StatusCheck
=== RUN   TestLoginUseCase_Execute_StatusCheck/Active_user_(lowercase)_-_Should_Success
[LOGIN DEBUG] Searching for user: test@example.com
[LOGIN DEBUG] User found: ID=user-123, Status=active, HashPrefix=hashed_pas
[LOGIN DEBUG] Password verification PASSED
[LOGIN DEBUG] Status check PASSED
=== RUN   TestLoginUseCase_Execute_StatusCheck/Active_user_(uppercase)_-_Should_Success
[LOGIN DEBUG] Searching for user: test@example.com
[LOGIN DEBUG] User found: ID=user-123, Status=ACTIVE, HashPrefix=hashed_pas
[LOGIN DEBUG] Password verification PASSED
[LOGIN DEBUG] Status check PASSED
=== RUN   TestLoginUseCase_Execute_StatusCheck/Active_user_(mixed_case)_-_Should_Success
[LOGIN DEBUG] Searching for user: test@example.com
[LOGIN DEBUG] User found: ID=user-123, Status=Active, HashPrefix=hashed_pas
[LOGIN DEBUG] Password verification PASSED
[LOGIN DEBUG] Status check PASSED
=== RUN   TestLoginUseCase_Execute_StatusCheck/Inactive_user_-_Should_Fail
[LOGIN DEBUG] Searching for user: test@example.com
[LOGIN DEBUG] User found: ID=user-123, Status=inactive, HashPrefix=hashed_pas
[LOGIN DEBUG] Password verification PASSED
[LOGIN DEBUG] Status check FAILED: Expected active, got 'inactive'
=== RUN   TestLoginUseCase_Execute_StatusCheck/Banned_user_-_Should_Fail
[LOGIN DEBUG] Searching for user: test@example.com
[LOGIN DEBUG] User found: ID=user-123, Status=banned, HashPrefix=hashed_pas
[LOGIN DEBUG] Password verification PASSED
[LOGIN DEBUG] Status check FAILED: Expected active, got 'banned'
--- PASS: TestLoginUseCase_Execute_StatusCheck (0.00s)
    --- PASS: TestLoginUseCase_Execute_StatusCheck/Active_user_(lowercase)_-_Should_Success (0.00s)
    --- PASS: TestLoginUseCase_Execute_StatusCheck/Active_user_(uppercase)_-_Should_Success (0.00s)
    --- PASS: TestLoginUseCase_Execute_StatusCheck/Active_user_(mixed_case)_-_Should_Success (0.00s)
    --- PASS: TestLoginUseCase_Execute_StatusCheck/Inactive_user_-_Should_Fail (0.00s)
    --- PASS: TestLoginUseCase_Execute_StatusCheck/Banned_user_-_Should_Fail (0.00s)
=== RUN   TestRegisterCandidateUseCase_Execute
=== RUN   TestRegisterCandidateUseCase_Execute/Success
=== RUN   TestRegisterCandidateUseCase_Execute/EmailAlreadyExists
=== RUN   TestRegisterCandidateUseCase_Execute/MetadataSaved
=== RUN   TestRegisterCandidateUseCase_Execute/CompanyCreatedForCandidate
--- PASS: TestRegisterCandidateUseCase_Execute (0.00s)
    --- PASS: TestRegisterCandidateUseCase_Execute/Success (0.00s)
    --- PASS: TestRegisterCandidateUseCase_Execute/EmailAlreadyExists (0.00s)
    --- PASS: TestRegisterCandidateUseCase_Execute/MetadataSaved (0.00s)
    --- PASS: TestRegisterCandidateUseCase_Execute/CompanyCreatedForCandidate (0.00s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/internal/core/usecases/auth	0.004s
?   	github.com/rede5/gohorsejobs/backend/internal/core/usecases/tenant	[no test files]
?   	github.com/rede5/gohorsejobs/backend/internal/core/usecases/user	[no test files]
=== RUN   TestBuildConnectionString
2026/01/01 14:38:55 Using DATABASE_URL for connection
2026/01/01 14:38:55 Using individual DB_* params for connection
--- PASS: TestBuildConnectionString (0.00s)
=== RUN   TestRunMigrations
2026/01/01 14:38:55 📦 Running migration: 001_test.sql
2026/01/01 14:38:55 ✅ Migration 001_test.sql executed successfully
2026/01/01 14:38:55 All migrations processed
--- PASS: TestRunMigrations (0.00s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/internal/database	0.007s
?   	github.com/rede5/gohorsejobs/backend/internal/dto	[no test files]
=== RUN   TestCreateApplication_Success
--- PASS: TestCreateApplication_Success (0.00s)
=== RUN   TestCreateApplication_InvalidJSON
--- PASS: TestCreateApplication_InvalidJSON (0.00s)
=== RUN   TestCreateApplication_ServiceError
--- PASS: TestCreateApplication_ServiceError (0.00s)
=== RUN   TestGetApplications_Success
--- PASS: TestGetApplications_Success (0.00s)
=== RUN   TestGetApplications_Empty
--- PASS: TestGetApplications_Empty (0.00s)
=== RUN   TestGetApplications_Error
--- PASS: TestGetApplications_Error (0.00s)
=== RUN   TestGetApplicationByID_Success
--- PASS: TestGetApplicationByID_Success (0.00s)
=== RUN   TestGetApplicationByID_NotFound
--- PASS: TestGetApplicationByID_NotFound (0.00s)
=== RUN   TestUpdateApplicationStatus_Success
--- PASS: TestUpdateApplicationStatus_Success (0.00s)
=== RUN   TestUpdateApplicationStatus_InvalidJSON
--- PASS: TestUpdateApplicationStatus_InvalidJSON (0.00s)
=== RUN   TestUpdateApplicationStatus_Error
--- PASS: TestUpdateApplicationStatus_Error (0.00s)
=== RUN   TestGetJobs_Success
--- PASS: TestGetJobs_Success (0.00s)
=== RUN   TestGetJobs_Empty
--- PASS: TestGetJobs_Empty (0.00s)
=== RUN   TestGetJobs_Error
--- PASS: TestGetJobs_Error (0.00s)
=== RUN   TestCreateJob_Success
--- PASS: TestCreateJob_Success (0.00s)
=== RUN   TestCreateJob_InvalidJSON
--- PASS: TestCreateJob_InvalidJSON (0.00s)
=== RUN   TestCreateJob_ServiceError
--- PASS: TestCreateJob_ServiceError (0.00s)
=== RUN   TestGetJobByID_Success
--- PASS: TestGetJobByID_Success (0.00s)
=== RUN   TestGetJobByID_NotFound
--- PASS: TestGetJobByID_NotFound (0.00s)
=== RUN   TestDeleteJob_Success
--- PASS: TestDeleteJob_Success (0.00s)
=== RUN   TestDeleteJob_Error
--- PASS: TestDeleteJob_Error (0.00s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/internal/handlers	0.034s
=== RUN   TestJWTService_HashAndVerifyPassword

[TEST] === TestJWTService_HashAndVerifyPassword ===
=== RUN   TestJWTService_HashAndVerifyPassword/Should_hash_and_verify_password_correctly
[TEST LOG] Testing password hash and verify
[TEST LOG] Hash generated: $2a$10$ByAhy3YIbrYbR...
[TEST LOG] Password verification result: true
=== RUN   TestJWTService_HashAndVerifyPassword/Should_fail_verification_with_wrong_password
[TEST LOG] Testing wrong password rejection
[TEST LOG] Wrong password verification result: false (expected false)
=== RUN   TestJWTService_HashAndVerifyPassword/Should_fail_verification_with_wrong_pepper
[TEST LOG] Testing wrong pepper rejection
[TEST LOG] Wrong pepper verification result: false (expected false)
--- PASS: TestJWTService_HashAndVerifyPassword (0.98s)
    --- PASS: TestJWTService_HashAndVerifyPassword/Should_hash_and_verify_password_correctly (0.30s)
    --- PASS: TestJWTService_HashAndVerifyPassword/Should_fail_verification_with_wrong_password (0.30s)
    --- PASS: TestJWTService_HashAndVerifyPassword/Should_fail_verification_with_wrong_pepper (0.37s)
=== RUN   TestJWTService_HashPassword_NoPepper

[TEST] === TestJWTService_HashPassword_NoPepper ===
[TEST LOG] Hash without pepper: $2a$10$HqwM6UutC6X19...
[TEST LOG] Verification without pepper: true
--- PASS: TestJWTService_HashPassword_NoPepper (0.27s)
=== RUN   TestJWTService_TokenOperations

[TEST] === TestJWTService_TokenOperations ===
=== RUN   TestJWTService_TokenOperations/Should_generate_and_validate_token
[TEST LOG] Testing token generation and validation
[TEST LOG] Token generated: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N...
[TEST LOG] Claims: sub=user-123, tenant=tenant-456
=== RUN   TestJWTService_TokenOperations/Should_fail_invalid_token
[TEST LOG] Testing invalid token rejection
[TEST LOG] Invalid token error: token is malformed: token contains an invalid number of segments
--- PASS: TestJWTService_TokenOperations (0.00s)
    --- PASS: TestJWTService_TokenOperations/Should_generate_and_validate_token (0.00s)
    --- PASS: TestJWTService_TokenOperations/Should_fail_invalid_token (0.00s)
=== RUN   TestJWTService_GenerateToken_ExpirationParsing

[TEST] === TestJWTService_GenerateToken_ExpirationParsing ===
=== RUN   TestJWTService_GenerateToken_ExpirationParsing/Default_expiration_(no_env)
[TEST LOG] Testing default expiration (24h)
[TEST LOG] Token with default expiration: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N...
[TEST LOG] Token claims: exp=1.767375539e+09
=== RUN   TestJWTService_GenerateToken_ExpirationParsing/Days_format_(7d)
[TEST LOG] Testing days format expiration (7d)
[TEST LOG] Token with 7d expiration: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N...
=== RUN   TestJWTService_GenerateToken_ExpirationParsing/Duration_format_(2h)
[TEST LOG] Testing duration format expiration (2h)
[TEST LOG] Token with 2h expiration: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N...
=== RUN   TestJWTService_GenerateToken_ExpirationParsing/Invalid_days_format_fallback
[TEST LOG] Testing invalid days format (abcd)
[TEST LOG] Token with invalid format (fallback): eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N...
=== RUN   TestJWTService_GenerateToken_ExpirationParsing/Invalid_day_number_fallback
[TEST LOG] Testing invalid day number (xxd)
[TEST LOG] Token with xxd format (fallback): eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N...
--- PASS: TestJWTService_GenerateToken_ExpirationParsing (0.00s)
    --- PASS: TestJWTService_GenerateToken_ExpirationParsing/Default_expiration_(no_env) (0.00s)
    --- PASS: TestJWTService_GenerateToken_ExpirationParsing/Days_format_(7d) (0.00s)
    --- PASS: TestJWTService_GenerateToken_ExpirationParsing/Duration_format_(2h) (0.00s)
    --- PASS: TestJWTService_GenerateToken_ExpirationParsing/Invalid_days_format_fallback (0.00s)
    --- PASS: TestJWTService_GenerateToken_ExpirationParsing/Invalid_day_number_fallback (0.00s)
=== RUN   TestJWTService_ValidateToken_WrongSigningMethod

[TEST] === TestJWTService_ValidateToken_WrongSigningMethod ===
=== RUN   TestJWTService_ValidateToken_WrongSigningMethod/Malformed_token
[TEST LOG] Testing malformed token
[TEST LOG] Malformed token error: token is unverifiable: error while executing keyfunc: unexpected signing method
=== RUN   TestJWTService_ValidateToken_WrongSigningMethod/Token_with_different_secret
[TEST LOG] Testing token from different secret
[TEST LOG] Wrong secret error: token signature is invalid: signature is invalid
--- PASS: TestJWTService_ValidateToken_WrongSigningMethod (0.00s)
    --- PASS: TestJWTService_ValidateToken_WrongSigningMethod/Malformed_token (0.00s)
    --- PASS: TestJWTService_ValidateToken_WrongSigningMethod/Token_with_different_secret (0.00s)
=== RUN   TestJWTService_NewJWTService

[TEST] === TestJWTService_NewJWTService ===
[TEST LOG] Service created: &{[109 121 45 115 101 99 114 101 116] my-issuer}
--- PASS: TestJWTService_NewJWTService (0.00s)
=== RUN   TestJWTService_HashPassword_EmptyPassword

[TEST] === TestJWTService_HashPassword_EmptyPassword ===
=== RUN   TestJWTService_HashPassword_EmptyPassword/Empty_password_should_still_hash
[TEST LOG] Empty password hash: $2a$10$Th7uegfjmUOkL...
--- PASS: TestJWTService_HashPassword_EmptyPassword (0.19s)
    --- PASS: TestJWTService_HashPassword_EmptyPassword/Empty_password_should_still_hash (0.19s)
=== RUN   TestJWTService_PepperConsistency

[TEST] === TestJWTService_PepperConsistency ===
=== RUN   TestJWTService_PepperConsistency/Same_pepper_produces_verifiable_hash
=== RUN   TestJWTService_PepperConsistency/Different_peppers_produce_different_hashes
--- PASS: TestJWTService_PepperConsistency (0.49s)
    --- PASS: TestJWTService_PepperConsistency/Same_pepper_produces_verifiable_hash (0.21s)
    --- PASS: TestJWTService_PepperConsistency/Different_peppers_produce_different_hashes (0.28s)
=== RUN   TestJWTService_TokenClaims_Content

[TEST] === TestJWTService_TokenClaims_Content ===
=== RUN   TestJWTService_TokenClaims_Content/Token_should_contain_all_expected_claims
--- PASS: TestJWTService_TokenClaims_Content (0.00s)
    --- PASS: TestJWTService_TokenClaims_Content/Token_should_contain_all_expected_claims (0.00s)
=== RUN   TestJWTService_LongPassword

[TEST] === TestJWTService_LongPassword ===
=== RUN   TestJWTService_LongPassword/Very_long_password_should_work
--- PASS: TestJWTService_LongPassword (0.26s)
    --- PASS: TestJWTService_LongPassword/Very_long_password_should_work (0.26s)
=== RUN   TestJWTService_SpecialCharactersPassword

[TEST] === TestJWTService_SpecialCharactersPassword ===
=== RUN   TestJWTService_SpecialCharactersPassword/Password:_Admin@2025
=== RUN   TestJWTService_SpecialCharactersPassword/Password:_Pässwörd
=== RUN   TestJWTService_SpecialCharactersPassword/Password:_密码123
=== RUN   TestJWTService_SpecialCharactersPassword/Password:_パスワ�
=== RUN   TestJWTService_SpecialCharactersPassword/Password:_🔐Secure
=== RUN   TestJWTService_SpecialCharactersPassword/Password:_test_with_
=== RUN   TestJWTService_SpecialCharactersPassword/Password:_tab_here
--- PASS: TestJWTService_SpecialCharactersPassword (1.47s)
    --- PASS: TestJWTService_SpecialCharactersPassword/Password:_Admin@2025 (0.25s)
    --- PASS: TestJWTService_SpecialCharactersPassword/Password:_Pässwörd (0.21s)
    --- PASS: TestJWTService_SpecialCharactersPassword/Password:_密码123 (0.21s)
    --- PASS: TestJWTService_SpecialCharactersPassword/Password:_パスワ� (0.20s)
    --- PASS: TestJWTService_SpecialCharactersPassword/Password:_🔐Secure (0.21s)
    --- PASS: TestJWTService_SpecialCharactersPassword/Password:_test_with_ (0.19s)
    --- PASS: TestJWTService_SpecialCharactersPassword/Password:_tab_here (0.19s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/internal/infrastructure/auth	3.670s
?   	github.com/rede5/gohorsejobs/backend/internal/infrastructure/email	[no test files]
?   	github.com/rede5/gohorsejobs/backend/internal/infrastructure/persistence/postgres	[no test files]
?   	github.com/rede5/gohorsejobs/backend/internal/infrastructure/storage	[no test files]
=== RUN   TestLoggingMiddleware
2026/01/01 14:38:59 GET /test 200 1.558µs
--- PASS: TestLoggingMiddleware (0.00s)
=== RUN   TestAuthMiddleware_Success
--- PASS: TestAuthMiddleware_Success (0.00s)
=== RUN   TestRateLimiter_isAllowed
--- PASS: TestRateLimiter_isAllowed (0.00s)
=== RUN   TestRateLimitMiddleware
--- PASS: TestRateLimitMiddleware (0.00s)
=== RUN   TestSecurityHeadersMiddleware
--- PASS: TestSecurityHeadersMiddleware (0.00s)
=== RUN   TestAuthMiddleware_NoAuthHeader
--- PASS: TestAuthMiddleware_NoAuthHeader (0.00s)
=== RUN   TestAuthMiddleware_InvalidFormat
--- PASS: TestAuthMiddleware_InvalidFormat (0.00s)
=== RUN   TestAuthMiddleware_InvalidToken
--- PASS: TestAuthMiddleware_InvalidToken (0.00s)
=== RUN   TestRequireRole_NoClaims
--- PASS: TestRequireRole_NoClaims (0.00s)
=== RUN   TestCORSMiddleware
--- PASS: TestCORSMiddleware (0.00s)
=== RUN   TestSanitizeMiddleware
--- PASS: TestSanitizeMiddleware (0.00s)
=== RUN   TestRequireRole_Success
--- PASS: TestRequireRole_Success (0.00s)
=== RUN   TestRequireRole_Forbidden
--- PASS: TestRequireRole_Forbidden (0.00s)
=== RUN   TestSanitizeMiddleware_InvalidJSON
--- PASS: TestSanitizeMiddleware_InvalidJSON (0.00s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/internal/middleware	0.015s
?   	github.com/rede5/gohorsejobs/backend/internal/models	[no test files]
=== RUN   TestRootHandler
--- PASS: TestRootHandler (0.00s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/internal/router	0.046s
=== RUN   TestAdminService_ListCompanies
=== RUN   TestAdminService_ListCompanies/returns_empty_list_when_no_companies
=== RUN   TestAdminService_ListCompanies/filters_by_verified_status
--- PASS: TestAdminService_ListCompanies (0.00s)
    --- PASS: TestAdminService_ListCompanies/returns_empty_list_when_no_companies (0.00s)
    --- PASS: TestAdminService_ListCompanies/filters_by_verified_status (0.00s)
=== RUN   TestAdminService_ListTags
=== RUN   TestAdminService_ListTags/returns_empty_list_when_no_tags
=== RUN   TestAdminService_ListTags/filters_by_category
--- PASS: TestAdminService_ListTags (0.00s)
    --- PASS: TestAdminService_ListTags/returns_empty_list_when_no_tags (0.00s)
    --- PASS: TestAdminService_ListTags/filters_by_category (0.00s)
=== RUN   TestAdminService_CreateTag
=== RUN   TestAdminService_CreateTag/creates_a_new_tag
=== RUN   TestAdminService_CreateTag/rejects_empty_tag_name
--- PASS: TestAdminService_CreateTag (0.00s)
    --- PASS: TestAdminService_CreateTag/creates_a_new_tag (0.00s)
    --- PASS: TestAdminService_CreateTag/rejects_empty_tag_name (0.00s)
=== RUN   TestAdminService_GetUser
=== RUN   TestAdminService_GetUser/returns_user_by_id
--- PASS: TestAdminService_GetUser (0.00s)
    --- PASS: TestAdminService_GetUser/returns_user_by_id (0.00s)
=== RUN   TestAdminService_UpdateCompanyStatus
=== RUN   TestAdminService_UpdateCompanyStatus/updates_active_status_successfully
=== RUN   TestAdminService_UpdateCompanyStatus/updates_verified_status_successfully
=== RUN   TestAdminService_UpdateCompanyStatus/returns_error_when_company_not_found
--- PASS: TestAdminService_UpdateCompanyStatus (0.00s)
    --- PASS: TestAdminService_UpdateCompanyStatus/updates_active_status_successfully (0.00s)
    --- PASS: TestAdminService_UpdateCompanyStatus/updates_verified_status_successfully (0.00s)
    --- PASS: TestAdminService_UpdateCompanyStatus/returns_error_when_company_not_found (0.00s)
=== RUN   TestAdminService_ListUsers
=== RUN   TestAdminService_ListUsers/returns_users_list
--- PASS: TestAdminService_ListUsers (0.00s)
    --- PASS: TestAdminService_ListUsers/returns_users_list (0.00s)
=== RUN   TestAdminService_DuplicateJob
--- PASS: TestAdminService_DuplicateJob (0.00s)
=== RUN   TestAdminService_EmailTemplates
=== RUN   TestAdminService_EmailTemplates/ListEmailTemplates
=== RUN   TestAdminService_EmailTemplates/CreateEmailTemplate
--- PASS: TestAdminService_EmailTemplates (0.00s)
    --- PASS: TestAdminService_EmailTemplates/ListEmailTemplates (0.00s)
    --- PASS: TestAdminService_EmailTemplates/CreateEmailTemplate (0.00s)
=== RUN   TestNewApplicationService
--- PASS: TestNewApplicationService (0.00s)
=== RUN   TestApplicationService_DeleteApplication
--- PASS: TestApplicationService_DeleteApplication (0.00s)
=== RUN   TestApplicationService_CreateApplication
--- PASS: TestApplicationService_CreateApplication (0.00s)
=== RUN   TestApplicationService_GetApplications
--- PASS: TestApplicationService_GetApplications (0.00s)
=== RUN   TestApplicationService_GetApplicationByID
--- PASS: TestApplicationService_GetApplicationByID (0.00s)
=== RUN   TestAuditService_RecordLogin
=== RUN   TestAuditService_RecordLogin/records_login_successfully
=== RUN   TestAuditService_RecordLogin/records_login_without_optional_fields
--- PASS: TestAuditService_RecordLogin (0.00s)
    --- PASS: TestAuditService_RecordLogin/records_login_successfully (0.00s)
    --- PASS: TestAuditService_RecordLogin/records_login_without_optional_fields (0.00s)
=== RUN   TestAuditService_ListLogins
=== RUN   TestAuditService_ListLogins/returns_empty_list_when_no_audits
=== RUN   TestAuditService_ListLogins/respects_custom_limit
--- PASS: TestAuditService_ListLogins (0.00s)
    --- PASS: TestAuditService_ListLogins/returns_empty_list_when_no_audits (0.00s)
    --- PASS: TestAuditService_ListLogins/respects_custom_limit (0.00s)
=== RUN   TestNotificationService_ListNotifications
=== RUN   TestNotificationService_ListNotifications/returns_empty_list_when_no_notifications
--- PASS: TestNotificationService_ListNotifications (0.00s)
    --- PASS: TestNotificationService_ListNotifications/returns_empty_list_when_no_notifications (0.00s)
=== RUN   TestNotificationService_CreateNotification
=== RUN   TestNotificationService_CreateNotification/creates_a_new_notification
--- PASS: TestNotificationService_CreateNotification (0.00s)
    --- PASS: TestNotificationService_CreateNotification/creates_a_new_notification (0.00s)
=== RUN   TestNotificationService_MarkAsRead
=== RUN   TestNotificationService_MarkAsRead/marks_notification_as_read
--- PASS: TestNotificationService_MarkAsRead (0.00s)
    --- PASS: TestNotificationService_MarkAsRead/marks_notification_as_read (0.00s)
=== RUN   TestNotificationService_MarkAllAsRead
=== RUN   TestNotificationService_MarkAllAsRead/marks_all_notifications_as_read
--- PASS: TestNotificationService_MarkAllAsRead (0.00s)
    --- PASS: TestNotificationService_MarkAllAsRead/marks_all_notifications_as_read (0.00s)
=== RUN   TestNewNotificationService
--- PASS: TestNewNotificationService (0.00s)
=== RUN   TestSaveCredentials
--- PASS: TestSaveCredentials (0.00s)
=== RUN   TestGetDecryptedKey
--- PASS: TestGetDecryptedKey (0.03s)
=== RUN   TestListConfiguredServices
--- PASS: TestListConfiguredServices (0.00s)
=== RUN   TestDeleteCredentials
--- PASS: TestDeleteCredentials (0.00s)
=== RUN   TestCreateJob
=== RUN   TestCreateJob/Success
[JOB_SERVICE DEBUG] === CreateJob Started ===
[JOB_SERVICE DEBUG] CompanyID=1, CreatedBy=user-123, Title=Go Developer, Status=published
[JOB_SERVICE DEBUG] Executing INSERT query...
[JOB_SERVICE DEBUG] Job struct: &{ID: CompanyID:1 CreatedBy:user-123 Title:Go Developer Description: SalaryMin:<nil> SalaryMax:<nil> SalaryType:<nil> Currency:<nil> SalaryNegotiable:false EmploymentType:<nil> WorkMode:<nil> WorkingHours:<nil> Location:<nil> RegionID:<nil> CityID:<nil> Requirements:map[] Benefits:map[] VisaSupport:false LanguageLevel:<nil> Status:published IsFeatured:false CreatedAt:2026-01-01 14:39:05.548082416 -0300 -03 m=+0.050863726 UpdatedAt:2026-01-01 14:39:05.548082508 -0300 -03 m=+0.050863818}
[JOB_SERVICE DEBUG] Job created successfully! ID=100
=== RUN   TestCreateJob/DB_Error
[JOB_SERVICE DEBUG] === CreateJob Started ===
[JOB_SERVICE DEBUG] CompanyID=1, CreatedBy=user-123, Title=Go Developer, Status=
[JOB_SERVICE DEBUG] Executing INSERT query...
[JOB_SERVICE DEBUG] Job struct: &{ID: CompanyID:1 CreatedBy:user-123 Title:Go Developer Description: SalaryMin:<nil> SalaryMax:<nil> SalaryType:<nil> Currency:<nil> SalaryNegotiable:false EmploymentType:<nil> WorkMode:<nil> WorkingHours:<nil> Location:<nil> RegionID:<nil> CityID:<nil> Requirements:map[] Benefits:map[] VisaSupport:false LanguageLevel:<nil> Status: IsFeatured:false CreatedAt:2026-01-01 14:39:05.548610508 -0300 -03 m=+0.051391818 UpdatedAt:2026-01-01 14:39:05.548610508 -0300 -03 m=+0.051391818}
[JOB_SERVICE ERROR] INSERT query failed: assert.AnError general error for testing
--- PASS: TestCreateJob (0.00s)
    --- PASS: TestCreateJob/Success (0.00s)
    --- PASS: TestCreateJob/DB_Error (0.00s)
=== RUN   TestGetJobs
=== RUN   TestGetJobs/List_All
--- PASS: TestGetJobs (0.00s)
    --- PASS: TestGetJobs/List_All (0.00s)
=== RUN   TestGetJobByID
--- PASS: TestGetJobByID (0.00s)
=== RUN   TestUpdateJob
--- PASS: TestUpdateJob (0.00s)
=== RUN   TestDeleteJob
--- PASS: TestDeleteJob (0.00s)
=== RUN   TestCreateTicket
=== RUN   TestCreateTicket/Success
=== RUN   TestCreateTicket/Default_Priority
--- PASS: TestCreateTicket (0.00s)
    --- PASS: TestCreateTicket/Success (0.00s)
    --- PASS: TestCreateTicket/Default_Priority (0.00s)
=== RUN   TestListTickets
=== RUN   TestListTickets/Success
--- PASS: TestListTickets (0.00s)
    --- PASS: TestListTickets/Success (0.00s)
=== RUN   TestGetTicket
=== RUN   TestGetTicket/Success
--- PASS: TestGetTicket (0.00s)
    --- PASS: TestGetTicket/Success (0.00s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/internal/services	0.061s
=== RUN   TestSanitizeString
=== RUN   TestSanitizeString/simple_text
=== RUN   TestSanitizeString/with_whitespace
=== RUN   TestSanitizeString/with_html
=== RUN   TestSanitizeString/empty_string
=== RUN   TestSanitizeString/special_chars
--- PASS: TestSanitizeString (0.00s)
    --- PASS: TestSanitizeString/simple_text (0.00s)
    --- PASS: TestSanitizeString/with_whitespace (0.00s)
    --- PASS: TestSanitizeString/with_html (0.00s)
    --- PASS: TestSanitizeString/empty_string (0.00s)
    --- PASS: TestSanitizeString/special_chars (0.00s)
=== RUN   TestSanitizeSlug
=== RUN   TestSanitizeSlug/simple_text
=== RUN   TestSanitizeSlug/special_chars
=== RUN   TestSanitizeSlug/multiple_spaces
=== RUN   TestSanitizeSlug/already_slug
=== RUN   TestSanitizeSlug/numbers
--- PASS: TestSanitizeSlug (0.00s)
    --- PASS: TestSanitizeSlug/simple_text (0.00s)
    --- PASS: TestSanitizeSlug/special_chars (0.00s)
    --- PASS: TestSanitizeSlug/multiple_spaces (0.00s)
    --- PASS: TestSanitizeSlug/already_slug (0.00s)
    --- PASS: TestSanitizeSlug/numbers (0.00s)
=== RUN   TestSanitizeName
=== RUN   TestSanitizeName/short_name
=== RUN   TestSanitizeName/max_length
=== RUN   TestSanitizeName/over_limit
--- PASS: TestSanitizeName (0.00s)
    --- PASS: TestSanitizeName/short_name (0.00s)
    --- PASS: TestSanitizeName/max_length (0.00s)
    --- PASS: TestSanitizeName/over_limit (0.00s)
=== RUN   TestStripHTML
=== RUN   TestStripHTML/simple_html
=== RUN   TestStripHTML/script_tag
=== RUN   TestStripHTML/nested_tags
=== RUN   TestStripHTML/no_html
--- PASS: TestStripHTML (0.00s)
    --- PASS: TestStripHTML/simple_html (0.00s)
    --- PASS: TestStripHTML/script_tag (0.00s)
    --- PASS: TestStripHTML/nested_tags (0.00s)
    --- PASS: TestStripHTML/no_html (0.00s)
=== RUN   TestSanitizeEmail
=== RUN   TestSanitizeEmail/simple_email
=== RUN   TestSanitizeEmail/with_whitespace
=== RUN   TestSanitizeEmail/empty_string
=== RUN   TestSanitizeEmail/over_max_length
--- PASS: TestSanitizeEmail (0.00s)
    --- PASS: TestSanitizeEmail/simple_email (0.00s)
    --- PASS: TestSanitizeEmail/with_whitespace (0.00s)
    --- PASS: TestSanitizeEmail/empty_string (0.00s)
    --- PASS: TestSanitizeEmail/over_max_length (0.00s)
=== RUN   TestSanitizeDescription
=== RUN   TestSanitizeDescription/short_description
=== RUN   TestSanitizeDescription/with_html
=== RUN   TestSanitizeDescription/empty_string
=== RUN   TestSanitizeDescription/over_limit
--- PASS: TestSanitizeDescription (0.00s)
    --- PASS: TestSanitizeDescription/short_description (0.00s)
    --- PASS: TestSanitizeDescription/with_html (0.00s)
    --- PASS: TestSanitizeDescription/empty_string (0.00s)
    --- PASS: TestSanitizeDescription/over_limit (0.00s)
=== RUN   TestDefaultSanitizer
--- PASS: TestDefaultSanitizer (0.00s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/internal/utils	0.010s
?   	github.com/rede5/gohorsejobs/backend/internal/utils/uuid	[no test files]
=== RUN   TestVerifyLogin
🔍 Found hash in DB: $2a$10$x7AN/r8MpVylJnd2uq4HT.lZbbNCqHuBuadpsr4xV.KlsleITmR5.
    verify_login_test.go:73: ✅ SUCCESS! Password verifies correctly with pepper 'some-random-string-for-password-hashing'
--- PASS: TestVerifyLogin (0.83s)
=== RUN   TestVerifyLoginNoPepper
    verify_login_test.go:106: ✅ Hash was NOT created without pepper (expected)
--- PASS: TestVerifyLoginNoPepper (0.37s)
PASS
ok  	github.com/rede5/gohorsejobs/backend/tests	1.207s
?   	github.com/rede5/gohorsejobs/backend/tests/integration	[no test files]
