205
test/integration.test.ts
Normal file
205
test/integration.test.ts
Normal file
@@ -0,0 +1,205 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { TypeParser, createTypeParser } from '../src/parsers/typeParser';
|
||||
import { DependencyGraphBuilder, createDependencyGraphBuilder } from '../src/analyzers/dependencyGraph';
|
||||
import { detectCircularDependencies } from '../src/analyzers/circularDetector';
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
const fixturesDir = path.join(__dirname, 'fixtures');
|
||||
|
||||
beforeAll(() => {
|
||||
if (!fs.existsSync(fixturesDir)) {
|
||||
fs.mkdirSync(fixturesDir, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
describe('Real-world TypeScript parsing', () => {
|
||||
it('should parse complex interfaces with generics', () => {
|
||||
const source = `
|
||||
interface ApiResponse<T> {
|
||||
data: T;
|
||||
status: number;
|
||||
message: string;
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
type UserApiResponse = ApiResponse<User>;
|
||||
`;
|
||||
|
||||
const parser = createTypeParser();
|
||||
const result = parser.parse(source, 'test.ts');
|
||||
|
||||
expect(result.types.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should parse conditional types', () => {
|
||||
const source = `
|
||||
type IfEquals<X, Y, A, B> =
|
||||
(<T>() => T extends X ? 1 : 2) extends
|
||||
(<T>() => T extends Y ? 1 : 2) ? A : B;
|
||||
|
||||
type DeepPartial<T> = {
|
||||
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
|
||||
};
|
||||
`;
|
||||
|
||||
const parser = createTypeParser();
|
||||
const result = parser.parse(source, 'test.ts');
|
||||
|
||||
expect(result.types.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should parse mapped types', () => {
|
||||
const source = `
|
||||
type Readonly<T> = {
|
||||
readonly [P in keyof T]: T[P];
|
||||
};
|
||||
|
||||
type Partial<T> = {
|
||||
[P in keyof T]?: T[P];
|
||||
};
|
||||
`;
|
||||
|
||||
const parser = createTypeParser();
|
||||
const result = parser.parse(source, 'test.ts');
|
||||
|
||||
expect(result.types.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should parse template literal types', () => {
|
||||
const source = `
|
||||
type EventName = \`on\${string}\`;
|
||||
type Color = 'red' | 'green' | 'blue';
|
||||
`;
|
||||
|
||||
const parser = createTypeParser();
|
||||
const result = parser.parse(source, 'test.ts');
|
||||
|
||||
expect(result.types.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Circular Dependency Detection Integration', () => {
|
||||
it('should detect circular dependencies in a chain', () => {
|
||||
const files = [
|
||||
{
|
||||
filePath: '/test/a.ts',
|
||||
types: [
|
||||
{ name: 'A', filePath: '/test/a.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['B'], rawNode: undefined }
|
||||
],
|
||||
imports: [],
|
||||
errors: []
|
||||
},
|
||||
{
|
||||
filePath: '/test/b.ts',
|
||||
types: [
|
||||
{ name: 'B', filePath: '/test/b.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['C'], rawNode: undefined }
|
||||
],
|
||||
imports: [],
|
||||
errors: []
|
||||
},
|
||||
{
|
||||
filePath: '/test/c.ts',
|
||||
types: [
|
||||
{ name: 'C', filePath: '/test/c.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['A'], rawNode: undefined }
|
||||
],
|
||||
imports: [],
|
||||
errors: []
|
||||
}
|
||||
];
|
||||
|
||||
const builder = createDependencyGraphBuilder();
|
||||
const graph = builder.build(files, '/test');
|
||||
const cycles = detectCircularDependencies(graph);
|
||||
|
||||
expect(cycles.length).toBeGreaterThan(0);
|
||||
expect(cycles[0].nodes).toContain('/test/a.ts#A');
|
||||
expect(cycles[0].nodes).toContain('/test/b.ts#B');
|
||||
expect(cycles[0].nodes).toContain('/test/c.ts#C');
|
||||
});
|
||||
|
||||
it('should handle multiple independent circular dependencies', () => {
|
||||
const files = [
|
||||
{
|
||||
filePath: '/test/a.ts',
|
||||
types: [
|
||||
{ name: 'A', filePath: '/test/a.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['B'], rawNode: undefined }
|
||||
],
|
||||
imports: [],
|
||||
errors: []
|
||||
},
|
||||
{
|
||||
filePath: '/test/b.ts',
|
||||
types: [
|
||||
{ name: 'B', filePath: '/test/b.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['A'], rawNode: undefined }
|
||||
],
|
||||
imports: [],
|
||||
errors: []
|
||||
},
|
||||
{
|
||||
filePath: '/test/c.ts',
|
||||
types: [
|
||||
{ name: 'C', filePath: '/test/c.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['D'], rawNode: undefined }
|
||||
],
|
||||
imports: [],
|
||||
errors: []
|
||||
},
|
||||
{
|
||||
filePath: '/test/d.ts',
|
||||
types: [
|
||||
{ name: 'D', filePath: '/test/d.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['C'], rawNode: undefined }
|
||||
],
|
||||
imports: [],
|
||||
errors: []
|
||||
}
|
||||
];
|
||||
|
||||
const builder = createDependencyGraphBuilder();
|
||||
const graph = builder.build(files, '/test');
|
||||
const cycles = detectCircularDependencies(graph);
|
||||
|
||||
expect(cycles.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Full Analysis Pipeline', () => {
|
||||
it('should parse and build graph for complex type hierarchy', () => {
|
||||
const source = `
|
||||
interface Animal {
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Dog extends Animal {
|
||||
breed: string;
|
||||
}
|
||||
|
||||
interface Cat extends Animal {
|
||||
color: string;
|
||||
}
|
||||
|
||||
type Pet = Dog | Cat;
|
||||
`;
|
||||
|
||||
const parser = createTypeParser();
|
||||
const parsedFiles = parser.parse(source, 'test.ts');
|
||||
|
||||
const builder = createDependencyGraphBuilder();
|
||||
const graph = builder.build([parsedFiles], '/test');
|
||||
|
||||
expect(graph.nodes.size).toBe(4);
|
||||
expect(graph.edges.length).toBeGreaterThanOrEqual(2);
|
||||
|
||||
const dogNode = graph.nodes.get('test.ts#Dog');
|
||||
expect(dogNode).toBeDefined();
|
||||
|
||||
const petNode = graph.nodes.get('test.ts#Pet');
|
||||
expect(petNode).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user