项目文件夹

文件
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

149 行
5.0 KiB
Go

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
package rerank
import (
"testing"
"github.com/zzet/gortex/internal/graph"
)
func TestClassifyQuery(t *testing.T) {
cases := map[string]QueryClass{
"validateToken": QueryClassSymbol,
"HTTPServer": QueryClassSymbol,
"pkg.Type": QueryClassSymbol,
"validate_user_token": QueryClassSymbol,
"internal/auth/token.go": QueryClassPath,
"auth/handler": QueryClassPath,
"func(ctx) error": QueryClassSignature,
"(string) bool": QueryClassSignature,
"map[string]int => T": QueryClassSignature,
"how does auth refresh": QueryClassConcept,
"validate user token": QueryClassConcept,
"": QueryClassConcept,
}
for q, want := range cases {
if got := ClassifyQuery(q); got != want {
t.Errorf("ClassifyQuery(%q) = %v, want %v", q, got, want)
}
}
}
func TestParseQueryClass(t *testing.T) {
valid := map[string]QueryClass{
"": QueryClassUnknown,
"auto": QueryClassUnknown,
"symbol": QueryClassSymbol,
"CONCEPT": QueryClassConcept,
" path ": QueryClassPath,
"signature": QueryClassSignature,
}
for s, want := range valid {
got, ok := ParseQueryClass(s)
if !ok || got != want {
t.Errorf("ParseQueryClass(%q) = (%v, %v), want (%v, true)", s, got, ok, want)
}
}
if _, ok := ParseQueryClass("bogus"); ok {
t.Errorf("ParseQueryClass(bogus) should report ok=false")
}
}
func TestQueryClassString(t *testing.T) {
cases := map[QueryClass]string{
QueryClassUnknown: "unknown",
QueryClassSymbol: "symbol",
QueryClassConcept: "concept",
QueryClassPath: "path",
QueryClassSignature: "signature",
}
for c, want := range cases {
if got := c.String(); got != want {
t.Errorf("%d.String() = %q, want %q", c, got, want)
}
}
}
func TestAlphaForClassOrdering(t *testing.T) {
// Path leans hardest on BM25 (smallest α), concept the least.
if !(AlphaForClass(QueryClassPath) < AlphaForClass(QueryClassSymbol)) {
t.Errorf("path α must be below symbol α")
}
if !(AlphaForClass(QueryClassSymbol) < AlphaForClass(QueryClassSignature)) {
t.Errorf("symbol α must be below signature α")
}
if !(AlphaForClass(QueryClassSignature) < AlphaForClass(QueryClassConcept)) {
t.Errorf("signature α must be below concept α")
}
// Unknown falls back to the concept (natural-language) blend.
if AlphaForClass(QueryClassUnknown) != AlphaForClass(QueryClassConcept) {
t.Errorf("unknown α must fall back to concept α")
}
}
func TestClassWeightMultiplier(t *testing.T) {
// Concept is the neutral baseline — 1.0 across the board.
if ClassWeightMultiplier(QueryClassConcept, SignalBM25) != 1.0 ||
ClassWeightMultiplier(QueryClassConcept, SignalSemantic) != 1.0 {
t.Errorf("concept class must be the neutral 1.0/1.0 baseline")
}
// Symbol / path / signature push BM25 up and semantic down.
for _, c := range []QueryClass{QueryClassSymbol, QueryClassPath, QueryClassSignature} {
if !(ClassWeightMultiplier(c, SignalBM25) > 1.0) {
t.Errorf("%v must raise the bm25 weight", c)
}
if !(ClassWeightMultiplier(c, SignalSemantic) < 1.0) {
t.Errorf("%v must lower the semantic weight", c)
}
}
// Non-text signals and an unknown class are untouched.
if ClassWeightMultiplier(QueryClassSymbol, SignalFanIn) != 1.0 {
t.Errorf("non-text signals must not be class-scaled")
}
if ClassWeightMultiplier(QueryClassUnknown, SignalBM25) != 1.0 {
t.Errorf("unknown class must not scale any signal")
}
}
func TestRerank_QueryClassTunesTextVsSemantic(t *testing.T) {
g := newTestGraph()
textOnly := mustNode(g, "f.go::TextOnly", "TextOnly", graph.KindFunction)
vecOnly := mustNode(g, "f.go::VecOnly", "VecOnly", graph.KindFunction)
weights := map[string]float64{SignalBM25: 1.0, SignalSemantic: 1.0}
p := New(DefaultSignals(), weights)
score := func(class QueryClass, id string) float64 {
cands := []*Candidate{
{Node: textOnly, TextRank: 0, VectorRank: -1},
{Node: vecOnly, TextRank: -1, VectorRank: 0},
}
p.Rerank("q", cands, &Context{Graph: g, QueryClass: class})
for _, c := range cands {
if c.Node.ID == id {
return c.Score
}
}
t.Fatalf("candidate %s missing from rerank output", id)
return 0
}
// The symbol class boosts BM25 and trims semantic relative to the
// neutral concept baseline.
if !(score(QueryClassSymbol, textOnly.ID) > score(QueryClassConcept, textOnly.ID)) {
t.Errorf("symbol class must raise the text-only candidate's score")
}
if !(score(QueryClassSymbol, vecOnly.ID) < score(QueryClassConcept, vecOnly.ID)) {
t.Errorf("symbol class must lower the semantic-only candidate's score")
}
}
func TestRerank_AutoClassifiesWhenUnset(t *testing.T) {
g := newTestGraph()
a := mustNode(g, "f.go::A", "A", graph.KindFunction)
p := New(DefaultSignals(), map[string]float64{SignalBM25: 1.0})
ctx := &Context{Graph: g} // QueryClass left at the zero value.
p.Rerank("internal/auth/token.go", []*Candidate{{Node: a, TextRank: 0, VectorRank: -1}}, ctx)
if ctx.QueryClass != QueryClassPath {
t.Errorf("Rerank must auto-classify an unset QueryClass; got %v", ctx.QueryClass)
}
}