Files
backend_v2/internal/repository/embedding_repository_test.go
toom1996 1de1ec46a6 update
2026-10-18 17:42:10 +08:00

82 lines
2.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package repository
import (
"math"
"strings"
"testing"
)
// TestFormatEmbeddingVector 向量串格式化是写入正确性的关键:
// 维度必须精确、float32 精度不能丢(截断会让相似度漂移)。
func TestFormatEmbeddingVector(t *testing.T) {
v := make([]float32, 768)
v[0] = 0.5
v[767] = -0.25
s := FormatEmbeddingVector(v)
if !strings.HasPrefix(s, "[") || !strings.HasSuffix(s, "]") {
t.Fatalf("应输出 [..] 形式的向量串,得到 %q", truncForTest(s))
}
if got := strings.Count(s, ",") + 1; got != 768 {
t.Fatalf("维度应为 768,得到 %d", got)
}
if !strings.Contains(s, "0.5") || !strings.Contains(s, "-0.25") {
t.Fatalf("首尾元素未按 float32 精度输出: %s", truncForTest(s))
}
}
// TestFormatEmbeddingVectorEmpty 空向量必须能安全格式化,不能 panic。
func TestFormatEmbeddingVectorEmpty(t *testing.T) {
if got := FormatEmbeddingVector(nil); got != "[]" {
t.Fatalf("nil 应格式化为 [],得到 %q", got)
}
}
// TestParseEmbeddingVectorRoundTrip 格式化与解析必须能精确往返,
// 否则「写进去的向量」与「读出来算相似度的向量」不是同一个,阈值校准会失真。
func TestParseEmbeddingVectorRoundTrip(t *testing.T) {
v := make([]float32, 768)
for i := range v {
v[i] = float32(i%17-8) * 0.0173
}
got := ParseEmbeddingVector(FormatEmbeddingVector(v))
if len(got) != len(v) {
t.Fatalf("往返后长度应一致:%d != %d", len(got), len(v))
}
for i := range v {
if got[i] != v[i] {
t.Fatalf("第 %d 维往返后不一致:%v != %v", i, got[i], v[i])
}
}
}
// TestParseEmbeddingVectorInvalid 非法输入返回 nil(调用方据此跳过该行,不阻断渲染)。
func TestParseEmbeddingVectorInvalid(t *testing.T) {
for _, bad := range []string{"", "[]", "0.1,0.2", "[0.1,abc]", "[", "null"} {
if got := ParseEmbeddingVector(bad); got != nil {
t.Fatalf("非法输入 %q 应返回 nil,得到 %v", bad, got)
}
}
}
// TestFormatEmbeddingVectorNormalized 归一化向量点积等于余弦相似度:
// 用同一向量的自点积验证模长≈1(服务端已归一化的前提)。
func TestFormatEmbeddingVectorNormalized(t *testing.T) {
v := []float32{0.6, 0.8} // 模长为 1
got := ParseEmbeddingVector(FormatEmbeddingVector(v))
var dot float64
for _, f := range got {
dot += float64(f) * float64(f)
}
if math.Abs(dot-1) > 1e-6 {
t.Fatalf("模长应≈1,得到 %f", dot)
}
}
func truncForTest(s string) string {
if len(s) > 80 {
return s[:80] + "..."
}
return s
}