package cache import ( "context" "os" "path/filepath" "testing" ) func TestGenerateCacheKey(t *testing.T) { tests := []struct { name string text string fromLang string toLang string wantSame bool }{ { name: "相同输入应生成相同键", text: "Hello world", fromLang: "en", toLang: "zh-CN", wantSame: true, }, { name: "不同文本应生成不同键", text: "Hello universe", fromLang: "en", toLang: "zh-CN", wantSame: false, }, { name: "不同语言对应生成不同键", text: "Hello world", fromLang: "en", toLang: "zh-TW", wantSame: false, }, { name: "大小写不敏感的语言代码", text: "Hello world", fromLang: "EN", toLang: "zh-cn", wantSame: true, }, { name: "多余空白字符应规范化", text: " Hello world ", fromLang: "en", toLang: "zh-CN", wantSame: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { key1 := GenerateCacheKey(tt.text, tt.fromLang, tt.toLang) key2 := GenerateCacheKey(tt.text, tt.fromLang, tt.toLang) if key1 != key2 { t.Errorf("相同输入生成了不同的键: %s != %s", key1, key2) } // 检查键的长度(SHA256哈希应为64个字符) if len(key1) != 64 { t.Errorf("缓存键长度不正确: got %d, want 64", len(key1)) } }) } } func TestSQLiteCache(t *testing.T) { // 创建临时目录 tmpDir, err := os.MkdirTemp("", "cache_test") if err != nil { t.Fatalf("创建临时目录失败: %v", err) } defer os.RemoveAll(tmpDir) dbPath := filepath.Join(tmpDir, "test_cache.db") // 创建缓存配置 config := &CacheConfig{ Enabled: true, MaxRecords: 100, ExpireDays: 1, DBPath: dbPath, } // 创建缓存实例 cache, err := NewSQLiteCache(config) if err != nil { t.Fatalf("创建缓存实例失败: %v", err) } defer cache.Close() ctx := context.Background() // 测试设置缓存 entry := &CacheEntry{ CacheKey: "test_key_1", OriginalText: "Hello world", TranslatedText: "你好世界", FromLang: "en", ToLang: "zh-CN", Model: "gpt-3.5-turbo", PromptName: "simple", PromptContent: "请用简单易懂的语言翻译以下内容。", PromptTokens: 10, CompletionTokens: 5, TotalTokens: 15, } err = cache.Set(ctx, entry) if err != nil { t.Fatalf("设置缓存失败: %v", err) } // 测试获取缓存 cachedEntry, err := cache.Get(ctx, "test_key_1") if err != nil { t.Fatalf("获取缓存失败: %v", err) } if cachedEntry == nil { t.Fatal("缓存未命中") } if cachedEntry.TranslatedText != "你好世界" { t.Errorf("缓存翻译结果不正确: got %s, want 你好世界", cachedEntry.TranslatedText) } // 测试缓存未命中 missingEntry, err := cache.Get(ctx, "non_existent_key") if err != nil { t.Fatalf("查询不存在的缓存失败: %v", err) } if missingEntry != nil { t.Error("不存在的缓存应该返回nil") } // 测试统计信息 stats, err := cache.Stats(ctx) if err != nil { t.Fatalf("获取统计信息失败: %v", err) } if stats.TotalRecords != 1 { t.Errorf("统计记录数不正确: got %d, want 1", stats.TotalRecords) } // 测试删除缓存 err = cache.Delete(ctx, "test_key_1") if err != nil { t.Fatalf("删除缓存失败: %v", err) } // 验证删除 deletedEntry, err := cache.Get(ctx, "test_key_1") if err != nil { t.Fatalf("查询已删除的缓存失败: %v", err) } if deletedEntry != nil { t.Error("已删除的缓存应该返回nil") } // 测试清空缓存 err = cache.Set(ctx, entry) if err != nil { t.Fatalf("设置缓存失败: %v", err) } err = cache.Clear(ctx) if err != nil { t.Fatalf("清空缓存失败: %v", err) } stats, err = cache.Stats(ctx) if err != nil { t.Fatalf("获取统计信息失败: %v", err) } if stats.TotalRecords != 0 { t.Errorf("清空后记录数不正确: got %d, want 0", stats.TotalRecords) } } func TestCacheExpiration(t *testing.T) { // 创建临时目录 tmpDir, err := os.MkdirTemp("", "cache_test") if err != nil { t.Fatalf("创建临时目录失败: %v", err) } defer os.RemoveAll(tmpDir) dbPath := filepath.Join(tmpDir, "test_cache.db") // 创建缓存配置,设置很短的过期时间 config := &CacheConfig{ Enabled: true, MaxRecords: 100, ExpireDays: 0, // 0天表示立即过期 DBPath: dbPath, } // 创建缓存实例 cache, err := NewSQLiteCache(config) if err != nil { t.Fatalf("创建缓存实例失败: %v", err) } defer cache.Close() ctx := context.Background() // 设置缓存 entry := &CacheEntry{ CacheKey: "test_key_1", OriginalText: "Hello world", TranslatedText: "你好世界", FromLang: "en", ToLang: "zh-CN", Model: "gpt-3.5-turbo", PromptTokens: 10, CompletionTokens: 5, TotalTokens: 15, } err = cache.Set(ctx, entry) if err != nil { t.Fatalf("设置缓存失败: %v", err) } // 立即清理(应该删除所有记录,因为过期时间为0) err = cache.Cleanup(ctx) if err != nil { t.Fatalf("清理缓存失败: %v", err) } // 检查统计信息 stats, err := cache.Stats(ctx) if err != nil { t.Fatalf("获取统计信息失败: %v", err) } if stats.TotalRecords != 0 { t.Errorf("清理后记录数不正确: got %d, want 0", stats.TotalRecords) } } func TestNormalizeText(t *testing.T) { tests := []struct { name string input string expected string }{ { name: "正常文本", input: "Hello world", expected: "Hello world", }, { name: "多余空白字符", input: " Hello world ", expected: "Hello world", }, { name: "制表符和换行符", input: "Hello\tworld\n", expected: "Hello world", }, { name: "空字符串", input: "", expected: "", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := normalizeText(tt.input) if result != tt.expected { t.Errorf("normalizeText(%q) = %q, want %q", tt.input, result, tt.expected) } }) } } func TestNormalizeLanguageCode(t *testing.T) { tests := []struct { name string input string expected string }{ { name: "正常语言代码", input: "zh-CN", expected: "zh-cn", }, { name: "大写语言代码", input: "EN-US", expected: "en-us", }, { name: "空字符串", input: "", expected: "auto", }, { name: "auto", input: "auto", expected: "auto", }, { name: "前后空白", input: " zh-CN ", expected: "zh-cn", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := normalizeLanguageCode(tt.input) if result != tt.expected { t.Errorf("normalizeLanguageCode(%q) = %q, want %q", tt.input, result, tt.expected) } }) } }