import { test } from 'brittle'
import { parseFile } from '../lib/parsers/cpp.js'
test('cpp: includes — local vs system', (t) => {
const src = `#include <godot_cpp/classes/node3d.hpp>
#include <memory>
#include "dc_density.h"
#include "dc_octree.h"
int main() { return 0; }
`
const result = parseFile(src, 'main.cpp')
t.is(result.imports.length, 2, '2 local includes (system ones skipped)')
t.is(result.imports[0].specifier, 'dc_density.h', 'first local include')
t.is(result.imports[1].specifier, 'dc_octree.h', 'second local include')
})
test('cpp: class with methods, inheritance, access specifiers', (t) => {
const src = `class DCTerrain : public Node3D {
public:
void set_resolution(int res);
int get_resolution() const;
static DCTerrain* create();
protected:
static void _bind_methods();
private:
int _resolution = 256;
};
`
const result = parseFile(src, 'dc_terrain.h')
t.is(result.classes.length, 1, '1 class')
const cls = result.classes[0]
t.is(cls.name, 'DCTerrain', 'class name')
t.is(cls.extends, 'Node3D', 'base class')
t.is(cls.kind, 'class', 'kind is class')
const methodNames = cls.methods.map(m => m.name)
t.ok(methodNames.includes('set_resolution'), 'set_resolution method')
t.ok(methodNames.includes('get_resolution'), 'get_resolution method')
const staticNames = cls.staticMethods.map(m => m.name)
t.ok(staticNames.includes('create'), 'create static method')
t.ok(staticNames.includes('_bind_methods'), '_bind_methods static method')
})
test('cpp: namespaces', (t) => {
const src = `namespace dc {
class Foo {
public:
void bar();
};
} // namespace dc
`
const result = parseFile(src, 'foo.h')
t.ok(result.namespaces.includes('dc'), 'dc namespace captured')
t.is(result.classes.length, 1, 'class inside namespace still found')
})
test('cpp: struct parsed as class with kind=struct', (t) => {
const src = `struct Point {
int x;
int y;
void translate(int dx, int dy);
};
`
const result = parseFile(src, 'point.h')
t.is(result.classes.length, 1, '1 struct')
t.is(result.classes[0].kind, 'struct', 'kind is struct')
t.is(result.classes[0].name, 'Point', 'struct name')
})
test('cpp: enum', (t) => {
const src = `enum class State { IDLE, RUNNING, DONE };
enum Mode { READ, WRITE };
`
const result = parseFile(src, 'state.h')
t.is(result.enums.length, 2, '2 enums')
t.is(result.enums[0].name, 'State', 'first enum')
t.ok(result.enums[0].values.includes('IDLE'), 'IDLE value')
t.ok(result.enums[0].values.includes('RUNNING'), 'RUNNING value')
})
test('cpp: out-of-line method definitions merge back into class', (t) => {
const src = `class Foo {
public:
void bar();
void baz();
};
void Foo::bar() {
// implementation
}
void Foo::baz() {
// implementation
}
`
const result = parseFile(src, 'foo.cpp')
t.is(result.classes.length, 1, '1 class')
// Out-of-line definitions merge into class methods
const methodNames = result.classes[0].methods.map(m => m.name)
t.ok(methodNames.includes('bar'), 'bar method')
t.ok(methodNames.includes('baz'), 'baz method')
t.is(result.functions.length, 0, 'no free functions (all are methods)')
})