mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-05 02:43:32 +00:00
119 lines
4.2 KiB
TypeScript
119 lines
4.2 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
const emit = vi.hoisted(() => vi.fn());
|
|
|
|
// Only `createLogger` is mocked: the module under test imports nothing else
|
|
// from the logger. The diagnostic is opt-in via `debugEnvVar` and emits at
|
|
// `debug`, so the assertions drive that child logger.
|
|
vi.mock('../../../src/core/logger.js', () => ({
|
|
createLogger: () => ({
|
|
warn: vi.fn(),
|
|
info: vi.fn(),
|
|
error: vi.fn(),
|
|
debug: emit,
|
|
trace: vi.fn(),
|
|
fatal: vi.fn(),
|
|
isLevelEnabled: () => true,
|
|
}),
|
|
}));
|
|
|
|
import { logUnresolvedReceiverFiles } from '../../../src/core/ingestion/scope-resolution/unresolved-receivers.js';
|
|
import type { ResolutionOutcome } from '../../../src/core/ingestion/scope-resolution/resolution-outcome.js';
|
|
|
|
/**
|
|
* #2837 / #2843 review. This diagnostic exists so a reporter can see WHICH file
|
|
* lost its receivers. It must therefore count the same drops
|
|
* `summarizeUnresolvedReceivers` counts — the first version omitted both of that
|
|
* function's guards and its top-offender list was led by files that lost
|
|
* nothing (measured on this repo: the top three were all test files).
|
|
*/
|
|
describe('logUnresolvedReceiverFiles (#2843 review)', () => {
|
|
beforeEach(() => emit.mockClear());
|
|
|
|
const drop = (filePath: string, over: Partial<ResolutionOutcome> = {}): ResolutionOutcome =>
|
|
({
|
|
kind: 'suppressed',
|
|
phase: 'receiver-bound-calls',
|
|
reason: 'receiver-unresolved',
|
|
filePath,
|
|
name: 'DoWork',
|
|
range: { startLine: 1, startCol: 0, endLine: 1, endCol: 1 },
|
|
candidateIds: [],
|
|
...over,
|
|
}) as ResolutionOutcome;
|
|
|
|
const payload = (): {
|
|
totalSites: number;
|
|
filesAffected: number;
|
|
topFiles: { filePath: string; sites: number }[];
|
|
} => emit.mock.calls[0]![0] as never;
|
|
|
|
it('says nothing when there are no receiver-unresolved drops', () => {
|
|
logUnresolvedReceiverFiles([]);
|
|
expect(emit).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('counts in-program call drops per file', () => {
|
|
logUnresolvedReceiverFiles([drop('a.go'), drop('a.go'), drop('b.go')]);
|
|
expect(payload().topFiles).toEqual([
|
|
{ filePath: 'a.go', sites: 2 },
|
|
{ filePath: 'b.go', sites: 1 },
|
|
]);
|
|
expect(payload().totalSites).toBe(3);
|
|
});
|
|
|
|
// Guard 1, mirroring unresolved-receivers.ts: property reads/writes are not
|
|
// call sites. Measured there at 25 of 124 drops on the fixture corpus.
|
|
it('excludes non-call sites', () => {
|
|
logUnresolvedReceiverFiles([
|
|
drop('a.go'),
|
|
drop('a.go', { siteKind: 'read' }),
|
|
drop('a.go', { siteKind: 'write' }),
|
|
]);
|
|
expect(payload().topFiles).toEqual([{ filePath: 'a.go', sites: 1 }]);
|
|
});
|
|
|
|
// Guard 2: an external-rooted receiver (`fmt.Println`) reaches code this index
|
|
// does not contain, so no edge was ever possible and nothing was lost.
|
|
it('excludes external-rooted drops', () => {
|
|
logUnresolvedReceiverFiles([drop('a.go'), drop('a.go', { receiverOrigin: 'external' })]);
|
|
expect(payload().topFiles).toEqual([{ filePath: 'a.go', sites: 1 }]);
|
|
});
|
|
|
|
// `unknown` origin counts WITH in-program: assuming a completeness we cannot
|
|
// demonstrate is the unsafe direction.
|
|
it('counts unknown-origin drops', () => {
|
|
logUnresolvedReceiverFiles([drop('a.go', { receiverOrigin: 'unknown' })]);
|
|
expect(payload().topFiles).toEqual([{ filePath: 'a.go', sites: 1 }]);
|
|
});
|
|
|
|
it('ranks by count then by code units, and caps the sample at ten files', () => {
|
|
const outcomes = [
|
|
...Array.from({ length: 12 }, (_, i) => drop(`f${String(i).padStart(2, '0')}.go`)),
|
|
drop('zz.go'),
|
|
drop('zz.go'),
|
|
];
|
|
logUnresolvedReceiverFiles(outcomes);
|
|
expect(payload().topFiles).toHaveLength(10);
|
|
expect(payload().topFiles[0]).toEqual({ filePath: 'zz.go', sites: 2 });
|
|
// Ties break by code-unit order, so the survivors of the cap are stable.
|
|
expect(
|
|
payload()
|
|
.topFiles.slice(1)
|
|
.map((f) => f.filePath),
|
|
).toEqual([
|
|
'f00.go',
|
|
'f01.go',
|
|
'f02.go',
|
|
'f03.go',
|
|
'f04.go',
|
|
'f05.go',
|
|
'f06.go',
|
|
'f07.go',
|
|
'f08.go',
|
|
]);
|
|
// The total is the true count, not the capped sample.
|
|
expect(payload().totalSites).toBe(14);
|
|
expect(payload().filesAffected).toBe(13);
|
|
});
|
|
});
|