import { ParserGodot4 } from '../parser_godot4';
describe('ParserGodot4', () => {
let parser: ParserGodot4;
beforeEach(() => {
parser = new ParserGodot4();
});
describe('parseFirstError', () => {
it('should parse script errors with file and line', () => {
const logOutput = `
Running tests...
ERROR: Invalid call. Nonexistent function 'get_damage' in base 'Node'.
At: res://scripts/combat/fighter.gd:45 @ _ready()
Some other output
`;
const error = parser.parseFirstError(logOutput);
expect(error).toEqual({
file: 'res://scripts/combat/fighter.gd',
line: 45,
message: "Invalid call. Nonexistent function 'get_damage' in base 'Node'.",
stack: expect.any(Array),
type: 'script_error'
});
});
it('should parse alternative error format', () => {
const logOutput = `
ERROR: res://scripts/player.gd:123 - Attempt to call function 'move' on a null value
`;
const error = parser.parseFirstError(logOutput);
expect(error).toEqual({
file: 'res://scripts/player.gd',
line: 123,
message: "Attempt to call function 'move' on a null value",
stack: expect.any(Array),
type: 'script_error'
});
});
it('should parse parse errors', () => {
const logOutput = `
SCRIPT ERROR: Parse Error at line 67: Expected ')' after expression
Path: res://scripts/combat/state_machine.gd
`;
const error = parser.parseFirstError(logOutput);
expect(error).toEqual({
file: '',
line: 67,
message: "Parse Error: Expected ')' after expression",
stack: expect.any(Array),
type: 'parse_error'
});
});
it('should parse runtime errors', () => {
const logOutput = `
SCRIPT ERROR: Invalid get index 'health' (on base: 'null instance')
At: res://scripts/combat/fighter.gd:89 @ take_damage()
`;
const error = parser.parseFirstError(logOutput);
expect(error).toEqual({
file: 'res://scripts/combat/fighter.gd',
line: 89,
message: "Invalid get index 'health' (on base: 'null instance')",
stack: expect.any(Array),
type: 'runtime_error'
});
});
it('should return null for logs without errors', () => {
const logOutput = `
Running tests...
All tests completed successfully
No errors found
`;
const error = parser.parseFirstError(logOutput);
expect(error).toBeNull();
});
it('should extract stack traces', () => {
const logOutput = `
ERROR: Invalid call. Nonexistent function 'get_damage'
At: res://scripts/combat/fighter.gd:45 @ _ready()
at fighter.gd:45 @ _ready()
at main.gd:12 @ _on_start_pressed()
`;
const error = parser.parseFirstError(logOutput);
expect(error?.stack).toContain('at fighter.gd:45 @ _ready()');
expect(error?.stack).toContain('at main.gd:12 @ _on_start_pressed()');
});
});
describe('normalizeFilePath', () => {
it('should normalize file paths to res:// format', () => {
const testPaths = [
['/absolute/path/to/res/scripts/test.gd', 'res://scripts/test.gd'],
['scripts/test.gd', 'res://scripts/test.gd'],
['res://scripts/test.gd', 'res://scripts/test.gd'],
];
testPaths.forEach(([input, expected]) => {
// Access private method for testing
const result = (parser as any).normalizeFilePath(input);
expect(result).toBe(expected);
});
});
});
describe('parseAllErrors', () => {
it('should parse multiple errors from log output', () => {
const logOutput = `
ERROR: res://scripts/player.gd:10 - First error
Some output
ERROR: res://scripts/enemy.gd:20 - Second error
More output
SCRIPT ERROR: Parse Error at line 5: Third error
`;
const errors = parser.parseAllErrors(logOutput);
expect(errors).toHaveLength(3);
expect(errors[0].message).toBe('First error');
expect(errors[1].message).toBe('Second error');
expect(errors[2].message).toBe('Parse Error: Third error');
});
});
describe('isTestFailure', () => {
it('should detect test failures', () => {
const failureOutputs = [
'Test failed: assertion error',
'ERROR: Something went wrong',
'ASSERTION FAILED: condition not met'
];
failureOutputs.forEach(output => {
expect(parser.isTestFailure(output)).toBe(true);
});
});
it('should detect successful test runs', () => {
const successOutput = 'All tests passed successfully';
expect(parser.isTestFailure(successOutput)).toBe(false);
});
});
describe('extractTestResults', () => {
it('should extract gdUnit4 test results', () => {
const logOutput = `
Running CombatTest
Running PlayerTest
Running EnemyTest
Results: 15 passed, 2 failed
`;
const results = parser.extractTestResults(logOutput);
expect(results.passed).toBe(15);
expect(results.failed).toBe(2);
expect(results.total).toBe(17);
expect(results.suites).toContain('CombatTest');
expect(results.suites).toContain('PlayerTest');
expect(results.suites).toContain('EnemyTest');
});
it('should handle output without results', () => {
const logOutput = 'Some random output';
const results = parser.extractTestResults(logOutput);
expect(results.passed).toBe(0);
expect(results.failed).toBe(0);
expect(results.total).toBe(0);
expect(results.suites).toHaveLength(0);
});
});
});