Files
gbrain/test/edge-extractor.test.ts
T
Garry TanandClaude Opus 4.7 f5c32dff98 test(v0.34): update 4 pre-existing tests for new emit shapes + sourceId contract
Three test files updated to match the v0.34 contract changes:

- test/edge-extractor.test.ts: two assertions on `toSymbol` exact-match
  were brittle to the W1 receiver-type resolution. `this.go()` /
  `self.go()` now resolve to `Foo::go` instead of bare `go`. Tests
  accept either form for back-compat with brains still on pre-W1
  extracted edges.

- test/source-id-tx-regression.test.ts: the D16 "back-compat
  cross-source view preserved" test was asserting that ctx.sourceId
  undefined → cross-source view. v0.34 STEP 0 (D4) closes that path
  by design — it's the exact cross-source-bleed bug class STEP 0
  fixed. Test renamed + assertion updated to reflect: makeCtx() with
  no override now falls back to 'default' (per the dispatch + cli
  auto-fill), and cross-source visibility is an explicit caller
  decision, not an implicit consequence of ctx omission.

- test/chunker-timeout.test.ts: the GBRAIN_CHUNKER_TIMEOUT_MS=1
  fallback case asserted edges=[] under the calls-only extractor.
  W2's extractAllEdges emits imports/references from top-level
  statements even on a partial parse, so the timeout-fallback path
  can return non-empty edges. Assertion relaxed to "edges is an
  array" — the contract that matters is "returns cleanly without
  hanging," not the edges-array shape.

Full unit suite (parallel + serial): 6132 pass / 0 fail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 09:39:05 -07:00

167 lines
5.4 KiB
TypeScript

/**
* v0.20.0 Cathedral II Layer 5 (A1) — edge extractor tests.
*
* Covers chunkCodeTextFull's edge output + per-language call capture
* + findChunkForOffset mapping. End-to-end addCodeEdges / getCallersOf
* round-trip is covered in test/code-edges.test.ts.
*/
import { describe, test, expect } from 'bun:test';
import { chunkCodeTextFull } from '../src/core/chunkers/code.ts';
import { findChunkForOffset } from '../src/core/chunkers/edge-extractor.ts';
describe('Layer 5 (A1) — TypeScript call extraction', () => {
test('captures direct function calls', async () => {
const src = `
function helper() { return 1; }
function caller() { return helper(); }
`.trim();
const result = await chunkCodeTextFull(src, 'src/foo.ts');
const calleeNames = result.edges.map(e => e.toSymbol);
expect(calleeNames).toContain('helper');
});
test('captures method calls (member expression)', async () => {
const src = `
class Foo {
run() { return this.go(); }
go() { return 1; }
}
`.trim();
const result = await chunkCodeTextFull(src, 'src/foo.ts');
// v0.34 W1: this.go() now resolves to Foo::go via receiver-type resolution.
// Pre-v0.34 emitted bare 'go'; v0.34 emits 'Foo::go'. Accept either form
// for back-compat with brains still on pre-W1 extracted edges.
const syms = result.edges.map(e => e.toSymbol);
expect(syms.some((s) => s === 'go' || s === 'Foo::go')).toBe(true);
});
test('all edges typed as calls', async () => {
const src = 'function f() { return g(); }';
const result = await chunkCodeTextFull(src, 'src/foo.ts');
for (const e of result.edges) expect(e.edgeType).toBe('calls');
});
});
describe('Layer 5 (A1) — Python call extraction', () => {
test('captures direct calls', async () => {
const src = `
def helper():
return 1
def caller():
return helper()
`.trim();
const result = await chunkCodeTextFull(src, 'src/foo.py');
expect(result.edges.map(e => e.toSymbol)).toContain('helper');
});
test('captures method calls on self', async () => {
const src = `
class Foo:
def run(self):
return self.go()
def go(self):
return 1
`.trim();
const result = await chunkCodeTextFull(src, 'src/foo.py');
// v0.34 W1: self.go() resolves to Foo::go via Python receiver-type resolution.
const syms = result.edges.map(e => e.toSymbol);
expect(syms.some((s) => s === 'go' || s === 'Foo::go')).toBe(true);
});
});
describe('Layer 5 (A1) — Ruby call extraction', () => {
test('captures method calls', async () => {
const src = `
class UsersController
def render
find_all
end
def find_all
[]
end
end
`.trim();
const result = await chunkCodeTextFull(src, 'src/u.rb');
// Ruby call extraction is best-effort; at minimum the bare-ident
// call form should show up. If grammar surprises us, don't block
// the release — just record the miss in CHANGELOG as a known gap.
const names = result.edges.map(e => e.toSymbol);
expect(names.length).toBeGreaterThanOrEqual(0);
});
});
describe('Layer 5 (A1) — Go call extraction', () => {
test('captures function calls', async () => {
const src = `
package main
func helper() int { return 1 }
func caller() int { return helper() }
`.trim();
const result = await chunkCodeTextFull(src, 'src/foo.go');
expect(result.edges.map(e => e.toSymbol)).toContain('helper');
});
});
describe('Layer 5 (A1) — Rust call extraction', () => {
test('captures function calls', async () => {
const src = `
fn helper() -> i32 { 1 }
fn caller() -> i32 { helper() }
`.trim();
const result = await chunkCodeTextFull(src, 'src/foo.rs');
expect(result.edges.map(e => e.toSymbol)).toContain('helper');
});
});
describe('Layer 5 (A1) — Java method invocation', () => {
test('captures method calls', async () => {
const src = `
class Foo {
int helper() { return 1; }
int caller() { return helper(); }
}
`.trim();
const result = await chunkCodeTextFull(src, 'src/Foo.java');
expect(result.edges.map(e => e.toSymbol)).toContain('helper');
});
});
describe('Layer 5 (A1) — findChunkForOffset mapping', () => {
test('finds innermost chunk for a given offset', () => {
const source = [
'// line 1',
'class Outer {', // line 2
' method() {}', // line 3 ← offset falls here
' other() {}', // line 4
'}', // line 5
].join('\n');
const chunks = [
{ startLine: 2, endLine: 5 }, // class-level (outer)
{ startLine: 3, endLine: 3 }, // method (innermost)
{ startLine: 4, endLine: 4 }, // other method
];
// Byte offset of "method()" on line 3.
const offset = source.indexOf('method()');
const idx = findChunkForOffset(offset, source, chunks);
expect(idx).toBe(1); // innermost = index 1
});
test('returns null when no chunk contains the offset', () => {
const source = 'abc';
const chunks = [{ startLine: 10, endLine: 20 }];
expect(findChunkForOffset(0, source, chunks)).toBeNull();
});
});
describe('Layer 5 (A1) — unknown language ships zero edges', () => {
test('unsupported language returns empty edge list without throwing', async () => {
// VHDL is not in the CALL_CONFIG shipped list (Layer 5 ships 8 langs).
const src = 'module TestBench; end module;';
const result = await chunkCodeTextFull(src, 'src/tb.vhd');
expect(result.edges).toEqual([]);
});
});