GitNexus/gitnexus/test/unit/taint/call-summary-language-and-constructor.test.ts
Gergő Magyar 78b4077d8a
Some checks are pending
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Gitleaks / gitleaks (push) Waiting to run
Publish / Classify release event (push) Waiting to run
Publish / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / ci (push) Blocked by required conditions
Publish / Publish to npm (push) Blocked by required conditions
Publish / Build & Push RC Docker images (push) Blocked by required conditions
Scorecard / Scorecard analysis (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-cli) (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-web) (push) Waiting to run
feat(impact): opt-in PDG-backed impact mode - statement + inter-procedural slicing, resolved-callee-id soundness, mutation-oracle validated (#2227)
2026-06-20 12:04:32 +01:00

56 lines
2.7 KiB
TypeScript

// U10 — characterize two sound-but-silent CALL_SUMMARY (return-value ascent)
// coverage gaps:
// 1. Non-TS/JS languages produce EMPTY summaries — only the TS/JS harvester
// stamps the producer `formalIndex` the ascent needs.
// 2. Constructors are excluded from the functionish node index, so a
// constructor never receives a CALL_SUMMARY edge (FUNCTIONISH_LABELS).
import { describe, it, expect } from 'vitest';
import { cfgOf } from '../../helpers/ts-cfg-harness.js';
import type { FunctionCfg } from '../../../src/core/ingestion/cfg/types.js';
import { computeReachingDefs } from '../../../src/core/ingestion/cfg/reaching-defs.js';
import { harvestCallSummary } from '../../../src/core/ingestion/taint/call-summary-harvest.js';
import { buildFunctionNodeIndex } from '../../../src/core/ingestion/taint/summary-harvest-driver.js';
import { createKnowledgeGraph } from '../../../src/core/graph/graph.js';
describe('CALL_SUMMARY language coverage (U10)', () => {
it('a non-TS/JS function (param bindings without producer formalIndex) yields an EMPTY summary', () => {
// Only the TS/JS harvester stamps `formalIndex`; every other language leaves
// it undefined, so return-value ascent is structurally empty there. Model
// that by stripping formalIndex from a real CFG's param bindings.
const cfg: FunctionCfg = cfgOf(`function f(a: string, b: string) { return b; }`);
const nonTs: FunctionCfg = {
...cfg,
bindings: cfg.bindings?.map(({ formalIndex: _omit, ...rest }) => rest),
};
const result = harvestCallSummary(nonTs, computeReachingDefs(nonTs));
expect(result).toMatchObject({ status: 'computed', facts: { returnFlowParams: [] } });
});
});
describe('buildFunctionNodeIndex — Constructor exclusion (U10)', () => {
it('indexes Function and Method nodes but NOT Constructor (no return-value ascent)', () => {
const graph = createKnowledgeGraph();
graph.addNode({
id: 'Function:f.ts:fn',
label: 'Function',
properties: { name: 'fn', filePath: 'f.ts', startLine: 10 },
});
graph.addNode({
id: 'Method:f.ts:m',
label: 'Method',
properties: { name: 'm', filePath: 'f.ts', startLine: 30 },
});
graph.addNode({
id: 'Constructor:f.ts:ctor',
label: 'Constructor',
properties: { name: 'ctor', filePath: 'f.ts', startLine: 20 },
});
const index = buildFunctionNodeIndex(graph);
expect(index.get('f.ts')?.get(10)).toEqual(['Function:f.ts:fn']);
expect(index.get('f.ts')?.get(30)).toEqual(['Method:f.ts:m']);
// The Constructor's start line is absent → resolveFnId returns undefined for
// it (unresolved), so no CALL_SUMMARY summary is harvested.
expect(index.get('f.ts')?.get(20)).toBeUndefined();
});
});