Files
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

172 lines
5.1 KiB
Go

package rerank
import (
"context"
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zzet/gortex/internal/graph"
)
func newRetrieverGraph(t *testing.T) *graph.Graph {
t.Helper()
g := graph.New()
// Seed: Hub. Out-edges: Calls h→a, h→b; References h→c.
g.AddNode(&graph.Node{ID: "h", Name: "Hub", Kind: graph.KindFunction, FilePath: "h.go"})
g.AddNode(&graph.Node{ID: "a", Name: "A", Kind: graph.KindFunction, FilePath: "a.go"})
g.AddNode(&graph.Node{ID: "b", Name: "B", Kind: graph.KindFunction, FilePath: "b.go"})
g.AddNode(&graph.Node{ID: "c", Name: "C", Kind: graph.KindFunction, FilePath: "c.go"})
g.AddEdge(&graph.Edge{From: "h", To: "a", Kind: graph.EdgeCalls})
g.AddEdge(&graph.Edge{From: "h", To: "b", Kind: graph.EdgeCalls})
g.AddEdge(&graph.Edge{From: "h", To: "c", Kind: graph.EdgeReferences})
return g
}
func seedHub(_ context.Context, g graph.Store, _ string, _ int) ([]*Candidate, error) {
n := g.GetNode("h")
if n == nil {
return nil, nil
}
return []*Candidate{{Node: n, TextRank: 0}}, nil
}
func TestGraphCompletion_OneHopExpansion(t *testing.T) {
g := newRetrieverGraph(t)
gc := &GraphCompletion{Seeder: seedHub}
cands, err := gc.Retrieve(context.Background(), g, "hub", 10)
require.NoError(t, err)
// 1 seed + 3 expanded.
require.Len(t, cands, 4)
ids := []string{}
for _, c := range cands {
ids = append(ids, c.Node.ID)
}
assert.Contains(t, ids, "h")
assert.Contains(t, ids, "a")
assert.Contains(t, ids, "b")
assert.Contains(t, ids, "c")
}
func TestGraphCompletion_EdgeKindFilter(t *testing.T) {
g := newRetrieverGraph(t)
gc := &GraphCompletion{
Seeder: seedHub,
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls}, // skip references
}
cands, err := gc.Retrieve(context.Background(), g, "hub", 10)
require.NoError(t, err)
ids := map[string]bool{}
for _, c := range cands {
ids[c.Node.ID] = true
}
assert.True(t, ids["h"])
assert.True(t, ids["a"])
assert.True(t, ids["b"])
assert.False(t, ids["c"], "C reached via References, filtered out by EdgeKinds=[Calls]")
}
func TestGraphCompletion_MaxSeedExpansion(t *testing.T) {
g := newRetrieverGraph(t)
gc := &GraphCompletion{
Seeder: seedHub,
MaxSeedExpansion: 1, // only the first out-edge per seed
}
cands, err := gc.Retrieve(context.Background(), g, "hub", 10)
require.NoError(t, err)
// 1 seed + 1 expansion = 2 total.
assert.Len(t, cands, 2)
}
func TestGraphCompletion_LimitTrimsAtBoundary(t *testing.T) {
g := newRetrieverGraph(t)
gc := &GraphCompletion{Seeder: seedHub}
cands, err := gc.Retrieve(context.Background(), g, "hub", 2)
require.NoError(t, err)
assert.Len(t, cands, 2, "limit honoured at the boundary")
}
func TestGraphCompletion_NilSeederErrors(t *testing.T) {
g := newRetrieverGraph(t)
gc := &GraphCompletion{}
_, err := gc.Retrieve(context.Background(), g, "x", 10)
assert.Error(t, err)
}
func TestGraphCompletion_SeederErrorPropagates(t *testing.T) {
g := newRetrieverGraph(t)
gc := &GraphCompletion{
Seeder: func(context.Context, graph.Store, string, int) ([]*Candidate, error) {
return nil, errors.New("seeder failed")
},
}
_, err := gc.Retrieve(context.Background(), g, "x", 10)
require.Error(t, err)
assert.Contains(t, err.Error(), "seeder failed")
}
func TestGraphCompletion_DedupesSeedFromExpansion(t *testing.T) {
g := newRetrieverGraph(t)
// Two seeds, the second is reachable from the first.
multiSeed := func(_ context.Context, gr graph.Store, _ string, _ int) ([]*Candidate, error) {
return []*Candidate{
{Node: gr.GetNode("h"), TextRank: 0},
{Node: gr.GetNode("a"), TextRank: 1}, // also reachable from h
}, nil
}
gc := &GraphCompletion{Seeder: multiSeed}
cands, err := gc.Retrieve(context.Background(), g, "x", 10)
require.NoError(t, err)
ids := map[string]int{}
for _, c := range cands {
ids[c.Node.ID]++
}
for id, count := range ids {
assert.Equal(t, 1, count, "id %s appeared %d times — dedup failed", id, count)
}
}
func TestGraphCompletion_NilSeedsIgnored(t *testing.T) {
g := newRetrieverGraph(t)
gc := &GraphCompletion{
Seeder: func(context.Context, graph.Store, string, int) ([]*Candidate, error) {
return []*Candidate{nil, {Node: nil}, {Node: g.GetNode("h")}}, nil
},
}
cands, err := gc.Retrieve(context.Background(), g, "x", 10)
require.NoError(t, err)
// Should produce the real seed + its 3 expansions, ignoring the nil entries.
assert.Len(t, cands, 4)
}
func TestGraphCompletion_ContextCancellationStops(t *testing.T) {
g := newRetrieverGraph(t)
gc := &GraphCompletion{Seeder: seedHub}
ctx, cancel := context.WithCancel(context.Background())
cancel() // already cancelled
cands, err := gc.Retrieve(ctx, g, "x", 10)
// Either the seeder completed before the cancel check or the
// cancellation surfaced — both are valid; the contract is that
// cancellation doesn't deadlock.
assert.NotNil(t, cands)
_ = err
}
func TestGraphCompletion_Name(t *testing.T) {
gc := &GraphCompletion{Seeder: seedHub}
assert.Equal(t, "graph_completion", gc.Name())
}
func TestRetrieverInterface_GraphCompletionSatisfies(t *testing.T) {
// Compile-time assertion: GraphCompletion satisfies Retriever.
var _ Retriever = (*GraphCompletion)(nil)
}