OverviewFilesCommitsIssuesDocsReleasesPeers

codetree / test / cpp.test.js

114 lines · javascript ref:
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)')
})