mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
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 / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / Classify release event (push) Waiting to run
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
111 lines
5.9 KiB
TypeScript
111 lines
5.9 KiB
TypeScript
/**
|
|
* Issue #2325 (http-route extractor half): `RESOLVE_BY_NAME_QUERY` and
|
|
* `RESOLVE_IN_MODULE_QUERY` were converted from the `MATCH (n:A|B)` multi-label
|
|
* disjunction to the `labels(n) IN [...]` allowlist form, for consistency with
|
|
* the manifest custom-branch fix.
|
|
*
|
|
* IMPORTANT nuance (verified against the real parser): the actual #2325 failure
|
|
* was triggered by *reserved-keyword* labels. LadybugDB's parser rejects a
|
|
* disjunction that names a reserved keyword — `Macro` and `Union` both are — so
|
|
* the manifest custom branch (whose 21-label list contains `Macro`/`Union`)
|
|
* genuinely threw, and the resolver's try/catch swallowed it. The http-route
|
|
* 3-label disjunction `(n:Function|Method|CodeElement)` contains no reserved
|
|
* keyword and actually PARSES — so this half was a consistency conversion, not a
|
|
* parser fix. The value of these cases is verifying the EXPORTED production
|
|
* queries resolve and filter correctly against a real LadybugDB (the unit tests
|
|
* cover the resolution *logic* with a fake executor; these cover *parsing +
|
|
* filtering*). The last case pins the real reserved-keyword trigger so a future
|
|
* query that reintroduces a `MATCH (n:…|Macro|…)` disjunction is caught.
|
|
*/
|
|
import { it, expect, afterEach } from 'vitest';
|
|
import {
|
|
RESOLVE_BY_NAME_QUERY,
|
|
RESOLVE_IN_EXACT_MODULE_QUERY,
|
|
} from '../../../src/core/group/extractors/http-route-extractor.js';
|
|
import { initLbug, executeParameterized, closeLbug } from '../../../src/core/lbug/pool-adapter.js';
|
|
import { withTestLbugDB } from '../../helpers/test-indexed-db.js';
|
|
|
|
const SEED = [
|
|
// BY_NAME: one real-file Function + a same-named File (label excluded) + a
|
|
// same-named CodeElement with empty filePath (excluded by `n.filePath <> ''`).
|
|
`CREATE (:Function {id:'fn:getOrders', name:'getOrders', filePath:'src/handlers/orders.ts', startLine:1, endLine:9, content:'', description:''})`,
|
|
`CREATE (:File {id:'file:getOrders', name:'getOrders', filePath:'src/getOrders.ts'})`,
|
|
`CREATE (:CodeElement {id:'ce:getOrders', name:'getOrders', filePath:''})`,
|
|
// IN_MODULE: same name in two modules — only the prefixed one resolves.
|
|
`CREATE (:Function {id:'fn:listUsers:handlers', name:'listUsers', filePath:'src/handlers/users.ts', startLine:1, endLine:9, content:'', description:''})`,
|
|
`CREATE (:Function {id:'fn:listUsers:test-decoy', name:'listUsers', filePath:'src/handlers/users.test.ts', startLine:1, endLine:9, content:'', description:''})`,
|
|
`CREATE (:Function {id:'fn:listUsers:admin', name:'listUsers', filePath:'src/admin/users.ts', startLine:1, endLine:9, content:'', description:''})`,
|
|
// IN_MODULE label-allowlist decoy: same name, SAME module prefix, wrong label.
|
|
// The STARTS-WITH prefix would match it, so only the `labels(n) IN [...]` filter
|
|
// excludes it — drop the filter and this surfaces, flipping the row count.
|
|
`CREATE (:File {id:'file:listUsers:handlers', name:'listUsers', filePath:'src/handlers/users.ts'})`,
|
|
// LIMIT 2 cap: three same-named Functions — the uniqueness count must stay exact.
|
|
`CREATE (:Function {id:'fn:dup:1', name:'dup', filePath:'src/a.ts', startLine:1, endLine:9, content:'', description:''})`,
|
|
`CREATE (:Function {id:'fn:dup:2', name:'dup', filePath:'src/b.ts', startLine:1, endLine:9, content:'', description:''})`,
|
|
`CREATE (:Function {id:'fn:dup:3', name:'dup', filePath:'src/c.ts', startLine:1, endLine:9, content:'', description:''})`,
|
|
];
|
|
|
|
withTestLbugDB(
|
|
'issue-2325-http-route-resolveSymbol',
|
|
(handle) => {
|
|
afterEach(async () => {
|
|
try {
|
|
await closeLbug(handle.repoId);
|
|
} catch {
|
|
/* best-effort */
|
|
}
|
|
});
|
|
|
|
it('RESOLVE_BY_NAME_QUERY resolves a handler by name, excluding a File and an empty-filePath node', async () => {
|
|
await initLbug(handle.repoId, handle.dbPath);
|
|
const rows = await executeParameterized(handle.repoId, RESOLVE_BY_NAME_QUERY, {
|
|
name: 'getOrders',
|
|
});
|
|
// File (wrong label) and the empty-filePath CodeElement are both excluded.
|
|
expect(rows).toHaveLength(1);
|
|
expect(rows[0].uid).toBe('fn:getOrders');
|
|
expect(rows[0].filePath).toBe('src/handlers/orders.ts');
|
|
});
|
|
|
|
it('RESOLVE_IN_EXACT_MODULE_QUERY excludes sibling module stems', async () => {
|
|
await initLbug(handle.repoId, handle.dbPath);
|
|
const rows = await executeParameterized(handle.repoId, RESOLVE_IN_EXACT_MODULE_QUERY, {
|
|
name: 'listUsers',
|
|
filePaths: ['src/handlers/users.ts', 'src/handlers/users/index.ts'],
|
|
});
|
|
expect(rows).toHaveLength(1);
|
|
expect(rows[0].uid).toBe('fn:listUsers:handlers');
|
|
expect(rows[0].filePath).toBe('src/handlers/users.ts');
|
|
});
|
|
|
|
it('RESOLVE_BY_NAME_QUERY caps materialization at 2 rows (uniqueness count stays exact)', async () => {
|
|
await initLbug(handle.repoId, handle.dbPath);
|
|
const rows = await executeParameterized(handle.repoId, RESOLVE_BY_NAME_QUERY, {
|
|
name: 'dup',
|
|
});
|
|
// Three matches exist; LIMIT 2 returns exactly two so the caller treats it
|
|
// as ambiguous (>=2) without over-materializing.
|
|
expect(rows).toHaveLength(2);
|
|
});
|
|
|
|
it('LadybugDB rejects a disjunction naming a reserved-keyword label (the real #2325 trigger)', async () => {
|
|
await initLbug(handle.repoId, handle.dbPath);
|
|
// The genuine #2325 failure: a `MATCH (n:A|B)` disjunction whose label set
|
|
// includes a reserved keyword (`Macro`/`Union`) is a parser error the
|
|
// resolver's try/catch silently swallowed. The exported queries avoid this
|
|
// by using the `labels(n) IN [...]` allowlist form. (The http-route
|
|
// `Function|Method|CodeElement` form parses — this guards the real cause.)
|
|
await expect(
|
|
executeParameterized(
|
|
handle.repoId,
|
|
`MATCH (n:Function|Macro|Union) WHERE n.name = $name RETURN n.id AS uid LIMIT 2`,
|
|
{ name: 'getOrders' },
|
|
),
|
|
).rejects.toThrow(/Parser exception|Invalid input|Prepare failed/i);
|
|
});
|
|
},
|
|
{
|
|
seed: SEED,
|
|
poolAdapter: true,
|
|
},
|
|
);
|