156 lines
4.3 KiB
Go
156 lines
4.3 KiB
Go
|
|
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")
|
||
|
|
}
|