package service_test import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/user-management-system/internal/cache" "github.com/user-management-system/internal/service" ) // ============================================================================= // CaptchaService Tests // ============================================================================= func setupCaptchaService(t *testing.T) (*service.CaptchaService, context.Context) { l1 := cache.NewL1CacheWithSize(1000) // Use disabled Redis cache for testing l2 := cache.NewRedisCache(false) cacheManager := cache.NewCacheManager(l1, l2) ctx := context.Background() return service.NewCaptchaService(cacheManager), ctx } func TestCaptchaService_Generate_Success(t *testing.T) { svc, ctx := setupCaptchaService(t) result, err := svc.Generate(ctx) require.NoError(t, err) assert.NotNil(t, result) assert.NotEmpty(t, result.CaptchaID) assert.NotEmpty(t, result.ImageData) assert.Greater(t, len(result.ImageData), 0) } func TestCaptchaService_Verify_CorrectAnswer(t *testing.T) { svc, ctx := setupCaptchaService(t) // Generate a captcha result, err := svc.Generate(ctx) require.NoError(t, err) // Get the stored answer using VerifyWithoutDelete // We can't know the exact answer, so test with wrong answer first valid := svc.Verify(ctx, result.CaptchaID, "wrong_answer") assert.False(t, valid) } func TestCaptchaService_Verify_EmptyID(t *testing.T) { svc, ctx := setupCaptchaService(t) valid := svc.Verify(ctx, "", "answer") assert.False(t, valid) } func TestCaptchaService_Verify_EmptyAnswer(t *testing.T) { svc, ctx := setupCaptchaService(t) // Generate a captcha result, err := svc.Generate(ctx) require.NoError(t, err) valid := svc.Verify(ctx, result.CaptchaID, "") assert.False(t, valid) } func TestCaptchaService_Verify_NonExistent(t *testing.T) { svc, ctx := setupCaptchaService(t) valid := svc.Verify(ctx, "non-existent-id", "answer") assert.False(t, valid) } func TestCaptchaService_VerifyOneTimeUse(t *testing.T) { svc, ctx := setupCaptchaService(t) // Generate a captcha result, err := svc.Generate(ctx) require.NoError(t, err) // First verification with wrong answer should fail valid1 := svc.Verify(ctx, result.CaptchaID, "wrong_answer") assert.False(t, valid1) // Second verification should also fail (already deleted or wrong answer) valid2 := svc.Verify(ctx, result.CaptchaID, "another_wrong") assert.False(t, valid2) } func TestCaptchaService_ValidateCaptcha_Success(t *testing.T) { svc, ctx := setupCaptchaService(t) // Generate a captcha result, err := svc.Generate(ctx) require.NoError(t, err) // We can't validate with correct answer without knowing it // So test error cases err = svc.ValidateCaptcha(ctx, "", "answer") assert.Error(t, err) err = svc.ValidateCaptcha(ctx, result.CaptchaID, "") assert.Error(t, err) err = svc.ValidateCaptcha(ctx, result.CaptchaID, "wrong_answer") assert.Error(t, err) } func TestCaptchaService_ValidateCaptcha_EmptyID(t *testing.T) { svc, ctx := setupCaptchaService(t) err := svc.ValidateCaptcha(ctx, "", "answer") assert.Error(t, err) assert.Contains(t, err.Error(), "验证码ID不能为空") } func TestCaptchaService_ValidateCaptcha_EmptyAnswer(t *testing.T) { svc, ctx := setupCaptchaService(t) err := svc.ValidateCaptcha(ctx, "some-id", "") assert.Error(t, err) assert.Contains(t, err.Error(), "验证码答案不能为空") } func TestCaptchaService_MultipleGeneration(t *testing.T) { svc, ctx := setupCaptchaService(t) // Generate multiple captchas ids := make(map[string]bool) for i := 0; i < 5; i++ { result, err := svc.Generate(ctx) require.NoError(t, err) require.NotNil(t, result) require.NotEmpty(t, result.CaptchaID) require.NotEmpty(t, result.ImageData) // Check uniqueness assert.False(t, ids[result.CaptchaID], "Captcha ID should be unique") ids[result.CaptchaID] = true } } func TestCaptchaService_Verify_CaseInsensitive(t *testing.T) { svc, ctx := setupCaptchaService(t) // Generate a captcha result, err := svc.Generate(ctx) require.NoError(t, err) // Both should fail (we don't know the answer) // But this test verifies case handling doesn't crash _ = svc.Verify(ctx, result.CaptchaID, "ABC") _ = svc.Verify(ctx, result.CaptchaID, "abc") }