mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-08 22:22:52 +00:00
84 lines
3.2 KiB
TypeScript
84 lines
3.2 KiB
TypeScript
/**
|
|
* End-to-end pipeline coverage for ingestion-side Spring interface-inheritance
|
|
* route resolution (#2288). A concrete `@RestController` that implements an
|
|
* interface declaring `@*Mapping`s must produce `Route` nodes for the inherited
|
|
* paths, attributed to the controller — and the interface itself must NOT yield
|
|
* a standalone (unprefixed, wrong-owner) Route node.
|
|
*/
|
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
import fs from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import { runPipelineFromRepo } from '../../src/core/ingestion/pipeline.js';
|
|
import type { PipelineResult } from '../../types/pipeline.js';
|
|
|
|
const ORDER_API = `package com.example;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
@RequestMapping("/orders")
|
|
public interface OrderApi {
|
|
@GetMapping("/list") Object list();
|
|
@PostMapping("/create") Object create();
|
|
}
|
|
`;
|
|
|
|
const ORDER_CONTROLLER = `package com.example;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
@RestController
|
|
public class OrderController implements OrderApi {
|
|
public Object list() { return null; }
|
|
public Object create() { return null; }
|
|
}
|
|
`;
|
|
|
|
describe('Spring interface-inheritance route ingestion pipeline (#2288)', () => {
|
|
let dir: string;
|
|
let result: PipelineResult;
|
|
|
|
beforeAll(async () => {
|
|
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gn-spring-inherit-'));
|
|
fs.writeFileSync(path.join(dir, 'OrderApi.java'), ORDER_API);
|
|
fs.writeFileSync(path.join(dir, 'OrderController.java'), ORDER_CONTROLLER);
|
|
result = await runPipelineFromRepo(dir, () => {}, {});
|
|
}, 60_000);
|
|
|
|
afterAll(() => {
|
|
if (dir) fs.rmSync(dir, { recursive: true, force: true });
|
|
});
|
|
|
|
function routeNames(): string[] {
|
|
const out: string[] = [];
|
|
result.graph.forEachNode((n) => {
|
|
if (n.label === 'Route') out.push(String(n.properties.name));
|
|
});
|
|
return out.sort();
|
|
}
|
|
|
|
it('emits exactly the two inherited Route nodes, with the interface prefix joined', () => {
|
|
// Full set-equality (not toContain) so a spurious extra Route node — e.g. a
|
|
// leaked unprefixed interface route — would fail this assertion.
|
|
expect(new Set(routeNames())).toEqual(new Set(['/orders/create', '/orders/list']));
|
|
});
|
|
|
|
it('attributes the inherited Route handler to the controller method', () => {
|
|
let handlerNode: { properties: Record<string, unknown> } | undefined;
|
|
result.graph.forEachNode((n) => {
|
|
if (n.label === 'Route' && n.properties.name === '/orders/list') {
|
|
const hid = n.properties.handlerSymbolId;
|
|
if (hid) handlerNode = result.graph.getNode(String(hid)) ?? undefined;
|
|
}
|
|
});
|
|
expect(handlerNode, 'inherited Route should resolve a handler symbol').toBeTruthy();
|
|
expect(handlerNode!.properties.name).toBe('list');
|
|
expect(String(handlerNode!.properties.filePath)).toContain('OrderController.java');
|
|
});
|
|
|
|
it('does NOT emit a standalone unprefixed Route for the interface method', () => {
|
|
const names = routeNames();
|
|
// The interface route must be attributed to the controller WITH the prefix,
|
|
// never leaked as a bare `/list` / `/create` (the pre-#2288 wrong behaviour).
|
|
expect(names).not.toContain('/list');
|
|
expect(names).not.toContain('/create');
|
|
});
|
|
});
|