|
| 1 | +//nolint:gocritic |
| 2 | +package engine |
| 3 | + |
| 4 | +import ( |
| 5 | + "context" |
| 6 | + |
| 7 | + "github.com/GrayCodeAI/yaad/graph" |
| 8 | + "github.com/GrayCodeAI/yaad/intent" |
| 9 | + "github.com/GrayCodeAI/yaad/storage" |
| 10 | +) |
| 11 | + |
| 12 | +// This file is part of package engine tests. It holds mockGraph (the |
| 13 | +// in-memory graph.Graph test double) and newTestEngine, moved verbatim out |
| 14 | +// of engine_test.go for readability; behavior is unchanged. |
| 15 | + |
| 16 | +// --------------------------------------------------------------------------- |
| 17 | +// mockGraph — in-memory implementation of graph.Graph backed by storage |
| 18 | +// --------------------------------------------------------------------------- |
| 19 | + |
| 20 | +type mockGraph struct { |
| 21 | + store storage.Storage |
| 22 | +} |
| 23 | + |
| 24 | +func newMockGraph(store storage.Storage) *mockGraph { |
| 25 | + return &mockGraph{store: store} |
| 26 | +} |
| 27 | + |
| 28 | +func (g *mockGraph) AddNode(ctx context.Context, n *storage.Node) error { |
| 29 | + return g.store.CreateNode(ctx, n) |
| 30 | +} |
| 31 | + |
| 32 | +func (g *mockGraph) AddEdge(ctx context.Context, e *storage.Edge) error { |
| 33 | + return g.store.CreateEdge(ctx, e) |
| 34 | +} |
| 35 | + |
| 36 | +func (g *mockGraph) RemoveNode(ctx context.Context, id string) error { |
| 37 | + return g.store.DeleteNode(ctx, id) |
| 38 | +} |
| 39 | + |
| 40 | +func (g *mockGraph) RemoveEdge(ctx context.Context, id string) error { |
| 41 | + return g.store.DeleteEdge(ctx, id) |
| 42 | +} |
| 43 | + |
| 44 | +func (g *mockGraph) ExtractSubgraph(ctx context.Context, startID string, maxDepth int) (*graph.Subgraph, error) { |
| 45 | + ids, err := g.BFS(ctx, startID, maxDepth) |
| 46 | + if err != nil { |
| 47 | + return nil, err |
| 48 | + } |
| 49 | + sg := &graph.Subgraph{} |
| 50 | + for _, id := range ids { |
| 51 | + n, err := g.store.GetNode(ctx, id) |
| 52 | + if err == nil { |
| 53 | + sg.Nodes = append(sg.Nodes, n) |
| 54 | + } |
| 55 | + } |
| 56 | + idSet := make(map[string]bool, len(ids)) |
| 57 | + for _, id := range ids { |
| 58 | + idSet[id] = true |
| 59 | + } |
| 60 | + for _, id := range ids { |
| 61 | + edges, _ := g.store.GetEdgesFrom(ctx, id) |
| 62 | + for _, e := range edges { |
| 63 | + if idSet[e.ToID] { |
| 64 | + sg.Edges = append(sg.Edges, e) |
| 65 | + } |
| 66 | + } |
| 67 | + } |
| 68 | + return sg, nil |
| 69 | +} |
| 70 | + |
| 71 | +func (g *mockGraph) BFS(ctx context.Context, startID string, maxDepth int) ([]string, error) { |
| 72 | + _, err := g.store.GetNode(ctx, startID) |
| 73 | + if err != nil { |
| 74 | + return nil, nil |
| 75 | + } |
| 76 | + visited := map[string]bool{startID: true} |
| 77 | + queue := []struct { |
| 78 | + id string |
| 79 | + depth int |
| 80 | + }{{startID, 0}} |
| 81 | + var result []string |
| 82 | + result = append(result, startID) |
| 83 | + |
| 84 | + for len(queue) > 0 { |
| 85 | + curr := queue[0] |
| 86 | + queue = queue[1:] |
| 87 | + if curr.depth >= maxDepth { |
| 88 | + continue |
| 89 | + } |
| 90 | + edges, _ := g.store.GetEdgesFrom(ctx, curr.id) |
| 91 | + edgesTo, _ := g.store.GetEdgesTo(ctx, curr.id) |
| 92 | + allEdges := append(edges, edgesTo...) |
| 93 | + for _, e := range allEdges { |
| 94 | + var next string |
| 95 | + if e.FromID == curr.id { |
| 96 | + next = e.ToID |
| 97 | + } else { |
| 98 | + next = e.FromID |
| 99 | + } |
| 100 | + if !visited[next] { |
| 101 | + visited[next] = true |
| 102 | + result = append(result, next) |
| 103 | + queue = append(queue, struct { |
| 104 | + id string |
| 105 | + depth int |
| 106 | + }{next, curr.depth + 1}) |
| 107 | + } |
| 108 | + } |
| 109 | + } |
| 110 | + return result, nil |
| 111 | +} |
| 112 | + |
| 113 | +func (g *mockGraph) IntentBFS(ctx context.Context, startID string, maxDepth int, queryIntent intent.Intent) ([]string, error) { |
| 114 | + // For mock, delegate to plain BFS (intent weights are ignored) |
| 115 | + return g.BFS(ctx, startID, maxDepth) |
| 116 | +} |
| 117 | + |
| 118 | +func (g *mockGraph) Impact(ctx context.Context, filePath string, maxDepth int) ([]string, error) { |
| 119 | + return nil, nil |
| 120 | +} |
| 121 | + |
| 122 | +func (g *mockGraph) Ancestors(ctx context.Context, id string) ([]string, error) { |
| 123 | + return nil, nil |
| 124 | +} |
| 125 | + |
| 126 | +func (g *mockGraph) Descendants(ctx context.Context, id string) ([]string, error) { |
| 127 | + return nil, nil |
| 128 | +} |
| 129 | + |
| 130 | +// --------------------------------------------------------------------------- |
| 131 | +// helper |
| 132 | +// --------------------------------------------------------------------------- |
| 133 | + |
| 134 | +func newTestEngine() *Engine { |
| 135 | + ms := newMockStorage() |
| 136 | + return New(ms, newMockGraph(ms)) |
| 137 | +} |
| 138 | + |
| 139 | +// --------------------------------------------------------------------------- |
| 140 | +// Tests |
| 141 | +// --------------------------------------------------------------------------- |
0 commit comments