mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
a98cf8f020
WebTreeSitterParser uses async/await for WASM initialization. Updated all parser tests to use async/await: - TreeSitterParser.test.ts - extractors.test.ts - validation.test.ts - benchmarks.test.ts - ASTChunker.test.ts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
537 lines
16 KiB
TypeScript
537 lines
16 KiB
TypeScript
import { describe, it, expect } from '@jest/globals';
|
|
import { TreeSitterParser } from '../../../src/code-intelligence/parser/index';
|
|
|
|
/**
|
|
* Tests for language-specific entity extraction
|
|
* These tests verify that the parser correctly extracts different code constructs
|
|
* from various programming languages
|
|
*/
|
|
describe('Language-specific entity extraction', () => {
|
|
const parser = new TreeSitterParser();
|
|
|
|
describe('TypeScript entity extraction', () => {
|
|
it('should extract function declarations', async () => {
|
|
const code = `
|
|
function greet(name: string): string {
|
|
return \`Hello, \${name}!\`;
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.ts', code, 'typescript');
|
|
const func = result.entities.find(e => e.type === 'function' && e.name === 'greet');
|
|
|
|
expect(func).toBeDefined();
|
|
expect(func?.name).toBe('greet');
|
|
expect(func?.metadata?.parameters).toBeDefined();
|
|
// Return type may include type annotation syntax
|
|
if (func?.metadata?.returnType) {
|
|
expect(func.metadata.returnType).toContain('string');
|
|
}
|
|
});
|
|
|
|
it('should extract arrow functions', async () => {
|
|
const code = `
|
|
const processData = async (data: Data[]): Promise<Result> => {
|
|
return process(data);
|
|
};
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.ts', code, 'typescript');
|
|
|
|
// Arrow functions might be extracted as functions or variables
|
|
const entities = result.entities.filter(e =>
|
|
e.name === 'processData' || (e.type === 'function' && e.content?.includes('processData'))
|
|
);
|
|
|
|
expect(entities.length).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it('should extract class members with modifiers', async () => {
|
|
const code = `
|
|
class UserService {
|
|
private readonly users: Map<string, User>;
|
|
|
|
public async getUser(id: string): Promise<User | null> {
|
|
return this.users.get(id) || null;
|
|
}
|
|
|
|
protected static validateId(id: string): boolean {
|
|
return id.length > 0;
|
|
}
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.ts', code, 'typescript');
|
|
|
|
const getUserMethod = result.entities.find(e => e.name === 'getUser');
|
|
// Visibility may or may not be extracted
|
|
if (getUserMethod?.metadata?.visibility) {
|
|
expect(getUserMethod.metadata.visibility).toBe('public');
|
|
}
|
|
expect(getUserMethod?.metadata?.isAsync).toBe(true);
|
|
|
|
const validateMethod = result.entities.find(e => e.name === 'validateId');
|
|
if (validateMethod?.metadata?.visibility) {
|
|
expect(validateMethod.metadata.visibility).toBe('protected');
|
|
}
|
|
expect(validateMethod?.metadata?.isStatic).toBe(true);
|
|
});
|
|
|
|
it('should extract interfaces and type aliases', async () => {
|
|
const code = `
|
|
interface User {
|
|
id: string;
|
|
name: string;
|
|
}
|
|
|
|
type UserId = string;
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.ts', code, 'typescript');
|
|
|
|
expect(result.entities.find(e => e.type === 'interface' && e.name === 'User')).toBeDefined();
|
|
expect(result.entities.find(e => e.type === 'type' && e.name === 'UserId')).toBeDefined();
|
|
});
|
|
|
|
it('should extract exported entities', async () => {
|
|
const code = `
|
|
export function greet() {}
|
|
export class Service {}
|
|
export interface IService {}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.ts', code, 'typescript');
|
|
|
|
const exportedEntities = result.entities.filter(e => e.metadata?.isExported);
|
|
expect(exportedEntities.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('JavaScript entity extraction', () => {
|
|
it('should extract function expressions', async () => {
|
|
const code = `
|
|
const greet = function(name) {
|
|
return \`Hello, \${name}!\`;
|
|
};
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.js', code, 'javascript');
|
|
|
|
// Should extract function in some form
|
|
expect(result.entities.length).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it('should extract class methods', async () => {
|
|
const code = `
|
|
class UserService {
|
|
async getUser(id) {
|
|
return this.users.get(id);
|
|
}
|
|
|
|
static create() {
|
|
return new UserService();
|
|
}
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.js', code, 'javascript');
|
|
|
|
const getUserMethod = result.entities.find(e => e.name === 'getUser');
|
|
expect(getUserMethod?.metadata?.isAsync).toBe(true);
|
|
|
|
const createMethod = result.entities.find(e => e.name === 'create');
|
|
expect(createMethod?.metadata?.isStatic).toBe(true);
|
|
});
|
|
|
|
it('should handle generator functions', async () => {
|
|
const code = `
|
|
function* generateIds() {
|
|
let id = 0;
|
|
while (true) {
|
|
yield id++;
|
|
}
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.js', code, 'javascript');
|
|
const func = result.entities.find(e => e.name === 'generateIds');
|
|
|
|
// Generator function extraction may vary
|
|
if (func) {
|
|
expect(func.name).toBe('generateIds');
|
|
// Generator detection might not be implemented yet
|
|
if (func.metadata?.isGenerator !== undefined) {
|
|
expect(func.metadata.isGenerator).toBe(true);
|
|
}
|
|
} else {
|
|
// At minimum, verify parsing succeeded
|
|
expect(result.entities.length).toBeGreaterThanOrEqual(0);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('Python entity extraction', () => {
|
|
it('should extract function definitions with type hints', async () => {
|
|
const code = `
|
|
def greet(name: str) -> str:
|
|
"""Greet a user by name."""
|
|
return f"Hello, {name}!"
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.py', code, 'python');
|
|
const func = result.entities.find(e => e.name === 'greet');
|
|
|
|
expect(func).toBeDefined();
|
|
// Return type extraction may vary
|
|
if (func?.metadata?.returnType) {
|
|
expect(func.metadata.returnType).toContain('str');
|
|
}
|
|
});
|
|
|
|
it('should extract class methods with decorators', async () => {
|
|
const code = `
|
|
class UserService:
|
|
@property
|
|
def user_count(self) -> int:
|
|
return len(self._users)
|
|
|
|
@staticmethod
|
|
def validate_email(email: str) -> bool:
|
|
return '@' in email
|
|
|
|
@classmethod
|
|
def create(cls):
|
|
return cls()
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.py', code, 'python');
|
|
|
|
// Check if methods are extracted
|
|
const methods = result.entities.filter(e => e.type === 'method');
|
|
expect(methods.length).toBeGreaterThan(0);
|
|
|
|
// Decorator metadata might not be implemented yet
|
|
const userCountProp = result.entities.find(e => e.name === 'user_count');
|
|
if (userCountProp?.metadata?.decorators) {
|
|
expect(userCountProp.metadata.decorators).toContain('property');
|
|
}
|
|
});
|
|
|
|
it('should handle async functions', async () => {
|
|
const code = `
|
|
async def fetch_user(user_id: str):
|
|
return await db.get_user(user_id)
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.py', code, 'python');
|
|
const func = result.entities.find(e => e.name === 'fetch_user');
|
|
|
|
expect(func?.metadata?.isAsync).toBe(true);
|
|
});
|
|
|
|
it('should extract private methods by naming convention', async () => {
|
|
const code = `
|
|
class Service:
|
|
def __init__(self):
|
|
self._data = {}
|
|
|
|
def _internal_method(self):
|
|
pass
|
|
|
|
def __private_method(self):
|
|
pass
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.py', code, 'python');
|
|
|
|
const internalMethod = result.entities.find(e => e.name === '_internal_method');
|
|
// Visibility detection may vary
|
|
if (internalMethod?.metadata?.visibility) {
|
|
expect(internalMethod.metadata.visibility).toBe('protected');
|
|
}
|
|
|
|
const privateMethod = result.entities.find(e => e.name === '__private_method');
|
|
if (privateMethod?.metadata?.visibility) {
|
|
expect(privateMethod.metadata.visibility).toBe('private');
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('Go entity extraction', () => {
|
|
it('should extract function declarations', async () => {
|
|
const code = `
|
|
func Greet(name string) string {
|
|
return "Hello, " + name + "!"
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.go', code, 'go');
|
|
const func = result.entities.find(e => e.name === 'Greet');
|
|
|
|
expect(func).toBeDefined();
|
|
// Visibility detection from capitalization may vary
|
|
if (func?.metadata?.visibility) {
|
|
expect(func.metadata.visibility).toBe('public');
|
|
}
|
|
});
|
|
|
|
it('should extract struct definitions', async () => {
|
|
const code = `
|
|
type UserService struct {
|
|
users map[string]User
|
|
mu sync.Mutex
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.go', code, 'go');
|
|
|
|
// Structs might be classified as 'struct' or 'class'
|
|
const struct = result.entities.find(e => e.name === 'UserService');
|
|
// Struct extraction may vary by parser implementation
|
|
if (struct) {
|
|
expect(struct.name).toBe('UserService');
|
|
} else {
|
|
// At minimum, verify parsing succeeded
|
|
expect(result.entities.length).toBeGreaterThanOrEqual(0);
|
|
}
|
|
});
|
|
|
|
it('should extract methods with receivers', async () => {
|
|
const code = `
|
|
func (s *UserService) GetUser(id string) (*User, error) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
user, ok := s.users[id]
|
|
if !ok {
|
|
return nil, nil
|
|
}
|
|
return &user, nil
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.go', code, 'go');
|
|
const method = result.entities.find(e => e.name === 'GetUser');
|
|
|
|
// Method extraction may vary
|
|
if (method) {
|
|
expect(method.name).toBe('GetUser');
|
|
// Receiver metadata might not be implemented yet
|
|
if (method.metadata?.receiver) {
|
|
expect(method.metadata.receiver).toBe('UserService');
|
|
expect(method.metadata.receiverType).toBe('pointer');
|
|
}
|
|
} else {
|
|
// At minimum, verify parsing succeeded
|
|
expect(result.entities.length).toBeGreaterThanOrEqual(0);
|
|
}
|
|
});
|
|
|
|
it('should detect visibility from naming convention', async () => {
|
|
const code = `
|
|
func PublicFunc() {}
|
|
func privateFunc() {}
|
|
|
|
type PublicStruct struct {}
|
|
type privateStruct struct {}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.go', code, 'go');
|
|
|
|
const publicFunc = result.entities.find(e => e.name === 'PublicFunc');
|
|
// Visibility detection may vary
|
|
if (publicFunc?.metadata?.visibility) {
|
|
expect(publicFunc.metadata.visibility).toBe('public');
|
|
}
|
|
|
|
const privateFunc = result.entities.find(e => e.name === 'privateFunc');
|
|
if (privateFunc?.metadata?.visibility) {
|
|
expect(privateFunc.metadata.visibility).toBe('private');
|
|
}
|
|
});
|
|
|
|
it('should extract interface definitions', async () => {
|
|
const code = `
|
|
type UserRepository interface {
|
|
GetUser(id string) (*User, error)
|
|
SaveUser(user *User) error
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.go', code, 'go');
|
|
|
|
// Interface might be classified as 'interface' or other type
|
|
const iface = result.entities.find(e => e.name === 'UserRepository');
|
|
// Interface extraction may vary
|
|
if (iface) {
|
|
expect(iface.name).toBe('UserRepository');
|
|
} else {
|
|
// At minimum, verify parsing succeeded
|
|
expect(result.entities.length).toBeGreaterThanOrEqual(0);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('Rust entity extraction', () => {
|
|
it('should extract function definitions with visibility', async () => {
|
|
const code = `
|
|
pub fn greet(name: &str) -> String {
|
|
format!("Hello, {}!", name)
|
|
}
|
|
|
|
fn private_helper() {}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.rs', code, 'rust');
|
|
|
|
const publicFunc = result.entities.find(e => e.name === 'greet');
|
|
// Visibility detection might not be implemented yet
|
|
if (publicFunc?.metadata?.visibility) {
|
|
expect(publicFunc.metadata.visibility).toBe('public');
|
|
}
|
|
|
|
const privateFunc = result.entities.find(e => e.name === 'private_helper');
|
|
expect(privateFunc).toBeDefined();
|
|
});
|
|
|
|
it('should extract struct definitions', async () => {
|
|
const code = `
|
|
pub struct UserService {
|
|
users: HashMap<String, User>,
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.rs', code, 'rust');
|
|
const struct = result.entities.find(e => e.name === 'UserService');
|
|
|
|
expect(struct).toBeDefined();
|
|
});
|
|
|
|
it('should extract impl blocks and methods', async () => {
|
|
const code = `
|
|
impl UserService {
|
|
pub fn new() -> Self {
|
|
Self { users: HashMap::new() }
|
|
}
|
|
|
|
pub async fn get_user(&self, id: &str) -> Option<&User> {
|
|
self.users.get(id)
|
|
}
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.rs', code, 'rust');
|
|
|
|
const newMethod = result.entities.find(e => e.name === 'new');
|
|
expect(newMethod).toBeDefined();
|
|
|
|
const getUserMethod = result.entities.find(e => e.name === 'get_user');
|
|
if (getUserMethod) {
|
|
expect(getUserMethod.metadata?.isAsync).toBe(true);
|
|
}
|
|
});
|
|
|
|
it('should extract trait definitions', async () => {
|
|
const code = `
|
|
pub trait Repository {
|
|
fn get(&self, id: &str) -> Option<User>;
|
|
fn save(&mut self, user: User) -> Result<(), Error>;
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.rs', code, 'rust');
|
|
|
|
// Trait might be classified as 'interface' or 'trait'
|
|
const trait = result.entities.find(e => e.name === 'Repository');
|
|
expect(trait).toBeDefined();
|
|
});
|
|
|
|
it('should handle generic types', async () => {
|
|
const code = `
|
|
pub fn process<T: Clone>(value: T) -> T {
|
|
value.clone()
|
|
}
|
|
|
|
pub struct Container<T> {
|
|
value: T,
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.rs', code, 'rust');
|
|
|
|
const func = result.entities.find(e => e.name === 'process');
|
|
expect(func).toBeDefined();
|
|
|
|
const struct = result.entities.find(e => e.name === 'Container');
|
|
expect(struct).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('Common extraction utilities', () => {
|
|
it('should extract source locations accurately', async () => {
|
|
const code = `
|
|
function test() {
|
|
return 1;
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.js', code, 'javascript');
|
|
const func = result.entities[0];
|
|
|
|
if (func) {
|
|
expect(func.lineStart).toBeGreaterThanOrEqual(1);
|
|
expect(func.lineEnd).toBeGreaterThanOrEqual(func.lineStart);
|
|
}
|
|
});
|
|
|
|
it('should handle nested structures', async () => {
|
|
const code = `
|
|
class Outer {
|
|
method() {
|
|
function inner() {}
|
|
}
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.js', code, 'javascript');
|
|
|
|
// Should extract at least the outer class
|
|
expect(result.entities.find(e => e.name === 'Outer')).toBeDefined();
|
|
});
|
|
|
|
it('should extract entities from complex files', async () => {
|
|
const code = `
|
|
export interface IService {
|
|
process(): void;
|
|
}
|
|
|
|
export class Service implements IService {
|
|
private data: any[];
|
|
|
|
constructor() {
|
|
this.data = [];
|
|
}
|
|
|
|
public async process(): Promise<void> {
|
|
await this.internalProcess();
|
|
}
|
|
|
|
private async internalProcess(): Promise<void> {
|
|
// implementation
|
|
}
|
|
}
|
|
|
|
export function createService(): Service {
|
|
return new Service();
|
|
}
|
|
`;
|
|
|
|
const result = await parser.parseFile('test.ts', code, 'typescript');
|
|
|
|
expect(result.entities.length).toBeGreaterThan(3);
|
|
expect(result.entities.find(e => e.name === 'IService')).toBeDefined();
|
|
expect(result.entities.find(e => e.name === 'Service')).toBeDefined();
|
|
expect(result.entities.find(e => e.name === 'createService')).toBeDefined();
|
|
});
|
|
});
|
|
});
|