zzet--gortex
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
116 行
3.9 KiB
Go
116 行
3.9 KiB
Go
package rerank
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
func TestFileCoherenceSignal_SoloFileContributesZero(t *testing.T) {
|
|
g := newTestGraph()
|
|
a := mustNode(g, "fileA.go::A", "A", graph.KindFunction)
|
|
a.FilePath = "fileA.go"
|
|
cands := []*Candidate{candidateFor(a, 0, -1)}
|
|
|
|
ctx := &Context{Graph: g}
|
|
ctx.prepare(cands)
|
|
|
|
if got := (FileCoherenceSignal{}).Contribute("q", cands[0], ctx); got != 0 {
|
|
t.Errorf("solo-file candidate got %v, want 0", got)
|
|
}
|
|
}
|
|
|
|
func TestFileCoherenceSignal_MultiChunkFileGetsBoost(t *testing.T) {
|
|
g := newTestGraph()
|
|
// File A has 3 candidates at ranks 0, 2, 9 → strong evidence.
|
|
a1 := mustNode(g, "fileA.go::A1", "A1", graph.KindFunction)
|
|
a1.FilePath = "fileA.go"
|
|
a2 := mustNode(g, "fileA.go::A2", "A2", graph.KindFunction)
|
|
a2.FilePath = "fileA.go"
|
|
a3 := mustNode(g, "fileA.go::A3", "A3", graph.KindFunction)
|
|
a3.FilePath = "fileA.go"
|
|
// File B has 2 candidates at ranks 4, 7 → moderate evidence.
|
|
b1 := mustNode(g, "fileB.go::B1", "B1", graph.KindFunction)
|
|
b1.FilePath = "fileB.go"
|
|
b2 := mustNode(g, "fileB.go::B2", "B2", graph.KindFunction)
|
|
b2.FilePath = "fileB.go"
|
|
// File C has 1 candidate → solo, no boost.
|
|
c1 := mustNode(g, "fileC.go::C1", "C1", graph.KindFunction)
|
|
c1.FilePath = "fileC.go"
|
|
|
|
cands := []*Candidate{
|
|
candidateFor(a1, 0, -1),
|
|
candidateFor(a2, 2, -1),
|
|
candidateFor(a3, 9, -1),
|
|
candidateFor(b1, 4, -1),
|
|
candidateFor(b2, 7, -1),
|
|
candidateFor(c1, 1, -1),
|
|
}
|
|
ctx := &Context{Graph: g}
|
|
ctx.prepare(cands)
|
|
|
|
sig := FileCoherenceSignal{}
|
|
scoreA := sig.Contribute("q", cands[0], ctx)
|
|
scoreB := sig.Contribute("q", cands[3], ctx)
|
|
scoreC := sig.Contribute("q", cands[5], ctx)
|
|
|
|
// A's per-file sum = 1 + 1/3 + 1/10 = 1.433…
|
|
// B's per-file sum = 1/5 + 1/8 = 0.325
|
|
// max = A's sum → A scores 1.0, B scores 0.325/1.433 ≈ 0.227, C scores 0.
|
|
if scoreA != 1.0 {
|
|
t.Errorf("file-A leader got %v, want 1.0 (top of multi-chunk file)", scoreA)
|
|
}
|
|
if scoreB <= 0 || scoreB >= scoreA {
|
|
t.Errorf("file-B leader got %v, want a positive fraction less than file-A's %v", scoreB, scoreA)
|
|
}
|
|
if scoreC != 0 {
|
|
t.Errorf("solo-file candidate got %v, want 0", scoreC)
|
|
}
|
|
// Every candidate in a multi-chunk file gets the same per-file
|
|
// score — the signal isn't "only the leader"; it's "this file is
|
|
// strong evidence so every chunk from it benefits".
|
|
scoreA3 := sig.Contribute("q", cands[2], ctx)
|
|
if scoreA != scoreA3 {
|
|
t.Errorf("file-A non-leader got %v but leader got %v; expected equal per-file boost", scoreA3, scoreA)
|
|
}
|
|
}
|
|
|
|
func TestFileCoherenceSignal_NoFilePathOrZeroSums(t *testing.T) {
|
|
g := newTestGraph()
|
|
n := mustNode(g, "::X", "X", graph.KindFunction)
|
|
n.FilePath = ""
|
|
cands := []*Candidate{candidateFor(n, 0, -1), candidateFor(n, 1, -1)}
|
|
ctx := &Context{Graph: g}
|
|
ctx.prepare(cands)
|
|
if got := (FileCoherenceSignal{}).Contribute("q", cands[0], ctx); got != 0 {
|
|
t.Errorf("empty FilePath got %v, want 0", got)
|
|
}
|
|
|
|
// File with two candidates both at TextRank=-1 (no rank info) →
|
|
// fileScoreSum is 0 for that file → signal returns 0 (no boost).
|
|
g2 := newTestGraph()
|
|
a := mustNode(g2, "f.go::A", "A", graph.KindFunction)
|
|
a.FilePath = "f.go"
|
|
b := mustNode(g2, "f.go::B", "B", graph.KindFunction)
|
|
b.FilePath = "f.go"
|
|
cands2 := []*Candidate{candidateFor(a, -1, -1), candidateFor(b, -1, -1)}
|
|
ctx2 := &Context{Graph: g2}
|
|
ctx2.prepare(cands2)
|
|
if got := (FileCoherenceSignal{}).Contribute("q", cands2[0], ctx2); got != 0 {
|
|
t.Errorf("no-rank multi-candidate file got %v, want 0", got)
|
|
}
|
|
}
|
|
|
|
func TestFileCoherenceSignal_NilSafety(t *testing.T) {
|
|
sig := FileCoherenceSignal{}
|
|
if got := sig.Contribute("q", nil, &Context{}); got != 0 {
|
|
t.Errorf("nil candidate got %v, want 0", got)
|
|
}
|
|
if got := sig.Contribute("q", &Candidate{}, &Context{}); got != 0 {
|
|
t.Errorf("nil node got %v, want 0", got)
|
|
}
|
|
if got := sig.Contribute("q", &Candidate{Node: &graph.Node{}}, nil); got != 0 {
|
|
t.Errorf("nil context got %v, want 0", got)
|
|
}
|
|
}
|