mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-28 22:52:00 +08:00
fix(resolution): production code never names a test suite's symbol (#2209)
A test suite is not linked into the program, so a name match from production code into one is coincidence - but only Strategy 3's receiver guess (#2171) ruled it out. Now no strategy's name match reaches a symbol in a test suite from a non-test file: a test source set (`src/test/`, `jvmTest/`), a `tests/` / `__tests__/` / `spec/` / `e2e/` directory, a `FooTest.kt` / `test_foo.py` / `foo.test.ts` / `foo_spec.rb` file. Test-support code a project ships - `testing/`, `fakes/`, `mocks/`, a `*-test` module - stays in reach, and `…Spec.java` (halo's `IndexSpecs`, okhttp's `ConnectionSpec`), `post-spec.ts` models and `useTests.ts` hooks are not test suites. typeorm -64 (`Record<K, V>` -> a test entity), okhttp -164 (117 sample `@Override` -> a test's nested `Override`), kotlinx.coroutines -318 (`import kotlinx.coroutines.*` onto one test file's package node), sttp -62, Exposed -92, halo 0, element-plus -36 (`isClient` -> a test's vueuse mock), excalidraw -10 (`actionManager.executeAction` -> the test `API` helper), tokio -30, trpc -36, AutoMapper -37, netbox -22, cats -21, mealie -10, pytest -8, Alamofire -7; zod, eShop, react-native-reusables unchanged. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b8f2bd513e
commit
de9f346ceb
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* A test suite is not linked into the program, so production code never
|
||||
* means one of its symbols by name: typeorm's `Record<string, …>` bound to a
|
||||
* test entity `Record`, okhttp's samples' `@Override` to a test's nested
|
||||
* `Override`. Test-support code a project ships (`testing/`) stays in reach,
|
||||
* and a test still reaches another test's helpers.
|
||||
*/
|
||||
import { describe, it, expect, afterAll, beforeAll } from 'vitest';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { CodeGraph } from '../src';
|
||||
|
||||
let root = '';
|
||||
let cg: CodeGraph;
|
||||
|
||||
beforeAll(async () => {
|
||||
root = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-prod-test-'));
|
||||
const files: Record<string, string> = {
|
||||
'package.json': JSON.stringify({ name: 'orm', private: true }),
|
||||
'test/functional/entity/Record.ts': `export class Record {
|
||||
id = 0;
|
||||
}
|
||||
`,
|
||||
'test/functional/helpers.ts': `export function makeFixture(): number {
|
||||
return 1;
|
||||
}
|
||||
`,
|
||||
'test/functional/record.test.ts': `export function uses(): number {
|
||||
return makeFixture();
|
||||
}
|
||||
`,
|
||||
'src/testing/stub.ts': `export function stubConnection(): number {
|
||||
return 2;
|
||||
}
|
||||
`,
|
||||
'src/columns.ts': `export function toJson(values: Record<string, number>): string {
|
||||
return JSON.stringify(values);
|
||||
}
|
||||
|
||||
export function connect(): number {
|
||||
return stubConnection();
|
||||
}
|
||||
`,
|
||||
'src/main/java/app/Service.java': `package app;
|
||||
|
||||
public class Service implements Runnable {
|
||||
@Override
|
||||
public void run() { }
|
||||
}
|
||||
`,
|
||||
'src/test/java/app/InterceptorTest.java': `package app;
|
||||
|
||||
public class InterceptorTest {
|
||||
@interface Override { }
|
||||
}
|
||||
`,
|
||||
};
|
||||
for (const [rel, content] of Object.entries(files)) {
|
||||
fs.mkdirSync(path.dirname(path.join(root, rel)), { recursive: true });
|
||||
fs.writeFileSync(path.join(root, rel), content);
|
||||
}
|
||||
cg = await CodeGraph.init(root, { index: true });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
cg?.close();
|
||||
if (root) fs.rmSync(root, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
const targetsFrom = (file: string) => {
|
||||
const ids = cg.getNodesInFile(file).map((n) => n.id);
|
||||
return cg.getOutgoingEdgesFrom(ids).filter((e) => e.kind !== 'contains').map((e) => cg.getNode(e.target)!.filePath);
|
||||
};
|
||||
|
||||
describe('production code and test suites', () => {
|
||||
it('production code never names a test suite’s symbol', () => {
|
||||
expect(targetsFrom('src/columns.ts')).not.toContain('test/functional/entity/Record.ts');
|
||||
expect(targetsFrom('src/main/java/app/Service.java')).not.toContain('src/test/java/app/InterceptorTest.java');
|
||||
});
|
||||
|
||||
it('shipped test support stays in reach, and tests reach each other', () => {
|
||||
expect(targetsFrom('src/columns.ts')).toContain('src/testing/stub.ts');
|
||||
expect(targetsFrom('test/functional/record.test.ts')).toContain('test/functional/helpers.ts');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user