test: cover audited call and extraction regressions

This commit is contained in:
Colby Mchenry
2026-09-14 06:46:45 +00:00
parent f84aa1e957
commit cabe319939
3 changed files with 17 additions and 9 deletions
+6 -1
View File
@@ -115,7 +115,12 @@ function nested(holder) {
const nested = result.nodes.find((n) => n.name === 'nested' && n.kind === 'function');
expect(nested).toBeDefined();
expect(result.unresolvedReferences.filter((r) => r.referenceKind === 'calls' && r.fromNodeId === nested!.id)
.map((r) => r.referenceName)).toEqual(['readKey', 'readKey', 'readKey', 'readKey']);
// Qualified sites are retained for effects; computed keys still make no
// receiver claim. All four calls inside arguments must also survive.
.map((r) => r.referenceName)).toEqual([
'holder.values.get', 'readKey', 'holder.values.get', 'readKey',
'readKey', 'holder.deep.values.get', 'readKey',
]);
expect(result.unresolvedReferences.some((r) => r.referenceName === 'values.get')).toBe(true);
});
+8 -3
View File
@@ -35,7 +35,8 @@ beforeAll(async () => {
Array.from({ length: CALLERS }, (_, i) => `export function caller${i}(): number { return warm(${i}); }`).join('\n') +
'\n'
);
// `hot` shares its name with its file, so the answer groups per definition.
// Two real `hot` functions exercise per-definition truncation. A filename
// is not an overload of its exact-named function (#1809).
fs.writeFileSync(path.join(tmpDir, 'src', 'hot.ts'), 'export function hot(n: number): number { return n; }\n');
fs.writeFileSync(
path.join(tmpDir, 'src', 'hot-callers.ts'),
@@ -43,6 +44,10 @@ beforeAll(async () => {
Array.from({ length: CALLERS }, (_, i) => `export function hotCaller${i}(): number { return hot(${i}); }`).join('\n') +
'\n'
);
fs.writeFileSync(path.join(tmpDir, 'src', 'other-hot.ts'), 'export function hot(n: number): number { return n + 1; }\n');
fs.writeFileSync(path.join(tmpDir, 'src', 'other-hot-callers.ts'),
"import { hot } from './other-hot';\n" +
Array.from({ length: CALLERS }, (_, i) => `export function otherHotCaller${i}(): number { return hot(${i}); }`).join('\n') + '\n');
fs.writeFileSync(
path.join(tmpDir, 'src', 'fan.ts'),
Array.from({ length: CALLERS }, (_, i) => `export function helper${i}(): number { return ${i}; }`).join('\n') +
@@ -76,8 +81,8 @@ describe('codegraph_callers truncation', () => {
it('marks the cut inside each per-definition section too', async () => {
const out = await text('codegraph_callers', { symbol: 'hot' });
expect(out).toContain('distinct definitions');
expect(out).toMatch(/- … \+\d+ more \(pass `limit` to widen\)/);
expect(out).toContain('2 distinct definitions');
expect(out.match(/- … \+\d+ more \(pass `limit` to widen\)/g)).toHaveLength(2);
expect(await text('codegraph_callers', { symbol: 'hot', limit: 100 })).not.toContain('more (pass');
});
});
+3 -5
View File
@@ -9,11 +9,9 @@
* MobX/handler maps) real nodes, so `codegraph_node`/`callers` on them resolve
* instead of returning "not found" and forcing the agent to Read the store.
*
* Keyed purely on AST shape — no library names in the implementation — so any
* same-shaped store is covered. Resolution then falls out of the existing
* exact-name matcher: every call form (`const {foo}=useStore.getState(); foo()`,
* `useStore.getState().foo()`, in-store `get().foo()`) reduces to a bare `foo`
* call that resolves to the action node once it exists.
* Extraction is keyed on AST shape. The store-accessor resolver follows
* destructured bindings, `useStore.getState().foo()`, and in-store `get().foo()`
* to implementations within the store, excluding interface declarations.
*/
import { describe, it, expect, beforeAll, afterEach } from 'vitest';
import * as fs from 'fs';