Files
yoyo/internal/cache/cache_test.go

326 lines
6.8 KiB
Go
Raw Normal View History

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)
}
})
}
}