Skip to content

Commit c6c4a76

Browse files
test(mcp): freeze evidence and list envelope shapes
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
1 parent 4ae1fa7 commit c6c4a76

1 file changed

Lines changed: 109 additions & 0 deletions

File tree

internal/mcp/handler_analysis_dto_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import (
77
"slices"
88
"testing"
99

10+
fallbackanalysis "github.com/tae2089/code-context-graph/internal/analysis/fallback"
1011
"github.com/tae2089/code-context-graph/internal/model"
12+
"github.com/tae2089/code-context-graph/internal/paging"
1113
)
1214

1315
func TestHandler_AnalysisResponses_WireContractFrozen(t *testing.T) {
@@ -118,6 +120,113 @@ func TestHandler_AnalysisResponses_WireContractFrozen(t *testing.T) {
118120
t.Fatalf("unexpected evidence keys: %v", sortedKeys(evidence))
119121
}
120122
})
123+
124+
t.Run("find_dead_code", func(t *testing.T) {
125+
deps := setupTestDeps(t)
126+
deps.DeadcodeAnalyzer = &mockDeadcodeAnalyzer{result: []model.Node{{QualifiedName: "pkg.Dead", Kind: model.NodeKindFunction, Name: "Dead", FilePath: "dead.go", StartLine: 10, EndLine: 20, Language: "go"}}}
127+
128+
result := callTool(t, deps, "find_dead_code", map[string]any{"limit": 10, "offset": 0})
129+
if result.IsError {
130+
t.Fatalf("find_dead_code returned error: %s", getTextContent(result))
131+
}
132+
133+
var resp map[string]any
134+
if err := json.Unmarshal([]byte(getTextContent(result)), &resp); err != nil {
135+
t.Fatalf("expected JSON response, got: %s", getTextContent(result))
136+
}
137+
138+
if !reflect.DeepEqual(sortedKeys(resp), []string{"count", "dead_code", "items", "pagination"}) {
139+
t.Fatalf("unexpected top-level keys: %v", sortedKeys(resp))
140+
}
141+
pagination, ok := resp["pagination"].(map[string]any)
142+
if !ok {
143+
t.Fatalf("pagination type = %T, want map[string]any", resp["pagination"])
144+
}
145+
if !reflect.DeepEqual(sortedKeys(pagination), []string{"has_more", "limit", "offset", "returned"}) {
146+
t.Fatalf("unexpected pagination keys: %v", sortedKeys(pagination))
147+
}
148+
})
149+
150+
t.Run("find_suspect_fallback_edges", func(t *testing.T) {
151+
deps := setupTestDeps(t)
152+
deps.FallbackAnalyzer = &mockFallbackAnalyzer{result: []fallbackanalysis.SuspectEdge{{
153+
Edge: model.Edge{Kind: model.EdgeKindFallbackCalls, Fingerprint: "fallback-edge"},
154+
Source: model.Node{QualifiedName: "pkg.Source", FilePath: "source.go"},
155+
Target: model.Node{QualifiedName: "pkg.Target", FilePath: "target.go"},
156+
Suspect: true,
157+
}}}
158+
159+
result := callTool(t, deps, "find_suspect_fallback_edges", map[string]any{"limit": 10, "offset": 0})
160+
if result.IsError {
161+
t.Fatalf("find_suspect_fallback_edges returned error: %s", getTextContent(result))
162+
}
163+
164+
var resp map[string]any
165+
if err := json.Unmarshal([]byte(getTextContent(result)), &resp); err != nil {
166+
t.Fatalf("expected JSON response, got: %s", getTextContent(result))
167+
}
168+
169+
if !reflect.DeepEqual(sortedKeys(resp), []string{"count", "items", "pagination", "suspect_fallback_edges"}) {
170+
t.Fatalf("unexpected top-level keys: %v", sortedKeys(resp))
171+
}
172+
pagination, ok := resp["pagination"].(map[string]any)
173+
if !ok {
174+
t.Fatalf("pagination type = %T, want map[string]any", resp["pagination"])
175+
}
176+
if !reflect.DeepEqual(sortedKeys(pagination), []string{"has_more", "limit", "offset", "returned"}) {
177+
t.Fatalf("unexpected pagination keys: %v", sortedKeys(pagination))
178+
}
179+
})
180+
181+
t.Run("find_large_functions", func(t *testing.T) {
182+
deps := setupTestDeps(t)
183+
deps.LargefuncAnalyzer = &mockLargefuncAnalyzer{result: []model.Node{{QualifiedName: "pkg.Big", Kind: model.NodeKindFunction, Name: "Big", FilePath: "big.go", StartLine: 1, EndLine: 100}}}
184+
185+
result := callTool(t, deps, "find_large_functions", map[string]any{"limit": 3, "offset": 0})
186+
if result.IsError {
187+
t.Fatalf("find_large_functions returned error: %s", getTextContent(result))
188+
}
189+
190+
var resp map[string]any
191+
if err := json.Unmarshal([]byte(getTextContent(result)), &resp); err != nil {
192+
t.Fatalf("expected JSON response, got: %s", getTextContent(result))
193+
}
194+
195+
if !reflect.DeepEqual(sortedKeys(resp), []string{"count", "items", "pagination", "results"}) {
196+
t.Fatalf("unexpected top-level keys: %v", sortedKeys(resp))
197+
}
198+
pagination, ok := resp["pagination"].(map[string]any)
199+
if !ok {
200+
t.Fatalf("pagination type = %T, want map[string]any", resp["pagination"])
201+
}
202+
if _, hasNext := pagination["next_offset"]; hasNext {
203+
if !reflect.DeepEqual(sortedKeys(pagination), []string{"has_more", "limit", "next_offset", "offset", "returned"}) {
204+
t.Fatalf("unexpected pagination keys: %v", sortedKeys(pagination))
205+
}
206+
} else if !reflect.DeepEqual(sortedKeys(pagination), []string{"has_more", "limit", "offset", "returned"}) {
207+
t.Fatalf("unexpected pagination keys: %v", sortedKeys(pagination))
208+
}
209+
})
210+
}
211+
212+
func TestPagedListResponse_MarshalJSON_PreservesEnvelope(t *testing.T) {
213+
b, err := json.Marshal(pagedListResponse[string]{
214+
LegacyKey: "dead_code",
215+
Items: []string{"one"},
216+
Count: 1,
217+
Pagination: paging.Page{Limit: 10, Offset: 0, Returned: 1, HasMore: false},
218+
})
219+
if err != nil {
220+
t.Fatal(err)
221+
}
222+
223+
var resp map[string]any
224+
if err := json.Unmarshal(b, &resp); err != nil {
225+
t.Fatal(err)
226+
}
227+
if !reflect.DeepEqual(sortedKeys(resp), []string{"count", "dead_code", "items", "pagination"}) {
228+
t.Fatalf("unexpected top-level keys: %v", sortedKeys(resp))
229+
}
121230
}
122231

123232
func sortedKeys(m map[string]any) []string {

0 commit comments

Comments
 (0)