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
100 行
3.1 KiB
Go
100 行
3.1 KiB
Go
package rerank
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
// addCallers wires n incoming EdgeCalls into target so the fan-in signal
|
|
// sees it as load-bearing. Caller nodes are throwaway functions.
|
|
func addCallers(g *graph.Graph, targetID, prefix string, n int) {
|
|
for i := range n {
|
|
cid := prefix + strconv.Itoa(i)
|
|
g.AddNode(&graph.Node{ID: cid, Name: cid, Kind: graph.KindFunction, FilePath: "callers.go"})
|
|
g.AddEdge(&graph.Edge{From: cid, To: targetID, Kind: graph.EdgeCalls})
|
|
}
|
|
}
|
|
|
|
func rankOf(out []*Candidate, id string) int {
|
|
for i, c := range out {
|
|
if c.Node.ID == id {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func idOrder(out []*Candidate) string {
|
|
var b strings.Builder
|
|
for i, c := range out {
|
|
if i > 0 {
|
|
b.WriteString(" > ")
|
|
}
|
|
b.WriteString(c.Node.ID)
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
func scoreOf(out []*Candidate, id string) float64 {
|
|
for _, c := range out {
|
|
if c.Node.ID == id {
|
|
return c.Score
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// TestCanonicalPick_TypeBeatsMethodForTypeQuery: a bare "Session" query must
|
|
// land on the type `Session`, not a `urlSession` method that merely shares the
|
|
// camelCase token — even when the method is more heavily called and BM25-ranked
|
|
// ahead. Mirrors the resolver's bestTypeCandidate canonical pick on the search
|
|
// side. Adversarial: the method gets the better BM25 rank AND far more fan-in.
|
|
func TestCanonicalPick_TypeBeatsMethodForTypeQuery(t *testing.T) {
|
|
g := newTestGraph()
|
|
sess := mustNode(g, "net/session.go::Session", "Session", graph.KindType)
|
|
sess.FilePath = "net/session.go"
|
|
urlSess := mustNode(g, "net/client.go::urlSession", "urlSession", graph.KindMethod)
|
|
urlSess.FilePath = "net/client.go"
|
|
|
|
addCallers(g, urlSess.ID, "callurl", 30)
|
|
addCallers(g, sess.ID, "refsess", 1)
|
|
|
|
// Stack the deck against the type: the method is BM25 #1.
|
|
cands := []*Candidate{
|
|
candidateFor(urlSess, 0, -1),
|
|
candidateFor(sess, 1, -1),
|
|
}
|
|
out := NewDefault().Rerank("Session", cands, &Context{Graph: g})
|
|
if rankOf(out, sess.ID) != 0 {
|
|
t.Fatalf("expected type Session ranked #1 for query \"Session\"; got %s (Session=%.3f urlSession=%.3f)",
|
|
idOrder(out), scoreOf(out, sess.ID), scoreOf(out, urlSess.ID))
|
|
}
|
|
}
|
|
|
|
// TestCanonicalPick_ProductionBeatsTestDef: a bare "Model" query must land on
|
|
// the production type, not a same-named definition in a _test.go file — even
|
|
// when the test fixture is BM25 #1 and more heavily referenced.
|
|
func TestCanonicalPick_ProductionBeatsTestDef(t *testing.T) {
|
|
g := newTestGraph()
|
|
prod := mustNode(g, "app/model.go::Model", "Model", graph.KindType)
|
|
prod.FilePath = "app/model.go"
|
|
test := mustNode(g, "app/model_test.go::Model", "Model", graph.KindType)
|
|
test.FilePath = "app/model_test.go"
|
|
|
|
addCallers(g, test.ID, "reftest", 15)
|
|
addCallers(g, prod.ID, "refprod", 1)
|
|
|
|
cands := []*Candidate{
|
|
candidateFor(test, 0, -1),
|
|
candidateFor(prod, 1, -1),
|
|
}
|
|
out := NewDefault().Rerank("Model", cands, &Context{Graph: g})
|
|
if rankOf(out, prod.ID) != 0 {
|
|
t.Fatalf("expected production Model ranked #1 for query \"Model\"; got %s (prod=%.3f test=%.3f)",
|
|
idOrder(out), scoreOf(out, prod.ID), scoreOf(out, test.ID))
|
|
}
|
|
}
|