Files
whetstone_DSL/editor/tests/step334_test.cpp

278 lines
8.6 KiB
C++
Raw Normal View History

// Step 334: C++ Parser — Inheritance + Templates (12 tests)
// Tests multiple inheritance, virtual, access specifiers, template classes, CRTP
#include <cassert>
#include <iostream>
#include <string>
#include <memory>
#include "ast/Parser.h"
#include "ast/ClassDeclaration.h"
#include "ast/GenericType.h"
#include "ast/Serialization.h"
int main() {
int passed = 0;
// Test 1: Single inheritance backward compat
{
std::string src = R"(
class Foo : public Bar {
public:
void doStuff() {}
};
)";
auto mod = TreeSitterParser::parseCpp(src);
auto classes = mod->getChildren("classes");
assert(classes.size() >= 1);
auto* cls = dynamic_cast<ClassDeclaration*>(classes[0]);
assert(cls != nullptr);
assert(cls->name == "Foo");
// Should have at least superClass set
assert(!cls->superClass.empty() || !cls->baseClasses.empty());
std::cout << "Test 1 PASSED: Single inheritance backward compat\n";
passed++;
}
// Test 2: Multiple inheritance parsed
{
std::string src = R"(
class Widget : public Base, public Mixin {
void draw() {}
};
)";
auto mod = TreeSitterParser::parseCpp(src);
auto classes = mod->getChildren("classes");
assert(!classes.empty());
auto* cls = dynamic_cast<ClassDeclaration*>(classes[0]);
assert(cls->name == "Widget");
auto bases = cls->getBases();
assert(bases.size() >= 2);
std::cout << "Test 2 PASSED: Multiple inheritance parsed (" << bases.size() << " bases)\n";
passed++;
}
// Test 3: Access specifiers detected
{
std::string src = R"(
class D : public A, protected B, private C {
void f() {}
};
)";
auto mod = TreeSitterParser::parseCpp(src);
auto classes = mod->getChildren("classes");
assert(!classes.empty());
auto* cls = dynamic_cast<ClassDeclaration*>(classes[0]);
auto bases = cls->getBases();
assert(bases.size() >= 3);
// Check that at least different specifiers exist
bool hasPublic = false, hasProtected = false, hasPrivate = false;
for (const auto& b : bases) {
if (b.accessSpecifier == "public") hasPublic = true;
if (b.accessSpecifier == "protected") hasProtected = true;
if (b.accessSpecifier == "private") hasPrivate = true;
}
assert(hasPublic);
assert(hasProtected);
assert(hasPrivate);
std::cout << "Test 3 PASSED: Access specifiers detected\n";
passed++;
}
// Test 4: Virtual inheritance flag
{
std::string src = R"(
class D : public virtual Base {
void f() {}
};
)";
auto mod = TreeSitterParser::parseCpp(src);
auto classes = mod->getChildren("classes");
assert(!classes.empty());
auto* cls = dynamic_cast<ClassDeclaration*>(classes[0]);
auto bases = cls->getBases();
assert(!bases.empty());
assert(bases[0].isVirtual);
std::cout << "Test 4 PASSED: Virtual inheritance flag detected\n";
passed++;
}
// Test 5: Template class parsed
{
std::string src = R"(
template<typename T>
class Container {
public:
void add(T item) {}
};
)";
auto mod = TreeSitterParser::parseCpp(src);
auto classes = mod->getChildren("classes");
assert(!classes.empty());
auto* cls = dynamic_cast<ClassDeclaration*>(classes[0]);
assert(cls->name == "Container");
auto tps = cls->getChildren("typeParameters");
assert(tps.size() >= 1);
auto* tp = dynamic_cast<TypeParameter*>(tps[0]);
assert(tp != nullptr);
assert(tp->name == "T");
std::cout << "Test 5 PASSED: Template class parsed with TypeParameter\n";
passed++;
}
// Test 6: CRTP pattern detected via base class name
{
std::string src = R"(
template<typename T>
class Base {
};
class Derived : public Base<Derived> {
void f() {}
};
)";
auto mod = TreeSitterParser::parseCpp(src);
auto classes = mod->getChildren("classes");
// Find Derived class
ClassDeclaration* derived = nullptr;
for (auto* c : classes) {
auto* cls = dynamic_cast<ClassDeclaration*>(c);
if (cls && cls->name == "Derived") {
derived = cls;
break;
}
}
assert(derived != nullptr);
auto bases = derived->getBases();
assert(!bases.empty());
// Check CRTP: Base<Derived> contains "Derived" as template arg
std::vector<std::string> baseNames;
for (const auto& b : bases) baseNames.push_back(b.name);
assert(isCRTPClass("Derived", baseNames));
std::cout << "Test 6 PASSED: CRTP pattern detected\n";
passed++;
}
// Test 7: struct vs class default access
{
std::string src = R"(
struct Point {
int x;
int y;
};
)";
auto mod = TreeSitterParser::parseCpp(src);
auto classes = mod->getChildren("classes");
assert(!classes.empty());
auto* cls = dynamic_cast<ClassDeclaration*>(classes[0]);
assert(cls->name == "Point");
std::cout << "Test 7 PASSED: struct parsed as ClassDeclaration\n";
passed++;
}
// Test 8: Template with variadic (typename... Args)
{
std::string src = R"(
template<typename T, typename U>
class Pair {
void f() {}
};
)";
auto mod = TreeSitterParser::parseCpp(src);
auto classes = mod->getChildren("classes");
assert(!classes.empty());
auto* cls = dynamic_cast<ClassDeclaration*>(classes[0]);
assert(cls->name == "Pair");
auto tps = cls->getChildren("typeParameters");
assert(tps.size() == 2);
std::cout << "Test 8 PASSED: Template with 2 type params\n";
passed++;
}
// Test 9: Combined template + multiple inheritance
{
std::string src = R"(
template<typename T>
class MyClass : public Base, public Interface {
void f() {}
};
)";
auto mod = TreeSitterParser::parseCpp(src);
auto classes = mod->getChildren("classes");
assert(!classes.empty());
auto* cls = dynamic_cast<ClassDeclaration*>(classes[0]);
assert(cls->name == "MyClass");
auto bases = cls->getBases();
assert(bases.size() >= 2);
auto tps = cls->getChildren("typeParameters");
assert(tps.size() >= 1);
std::cout << "Test 9 PASSED: Template + multiple inheritance combined\n";
passed++;
}
// Test 10: Methods inside class body still parsed
{
std::string src = R"(
class Foo : public Bar {
public:
virtual void draw() {}
static void create() {}
private:
void helper() {}
};
)";
auto mod = TreeSitterParser::parseCpp(src);
auto classes = mod->getChildren("classes");
assert(!classes.empty());
auto* cls = dynamic_cast<ClassDeclaration*>(classes[0]);
auto methods = cls->getChildren("methods");
assert(methods.size() >= 2); // at least some methods parsed
std::cout << "Test 10 PASSED: Methods inside class body parsed (" << methods.size() << " methods)\n";
passed++;
}
// Test 11: Whetstone-style class signature
{
std::string src = R"(
class KotlinGenerator : public ProjectionGenerator, public AnnotationVisitorExtended {
public:
void generate() {}
};
)";
auto mod = TreeSitterParser::parseCpp(src);
auto classes = mod->getChildren("classes");
assert(!classes.empty());
auto* cls = dynamic_cast<ClassDeclaration*>(classes[0]);
assert(cls->name == "KotlinGenerator");
auto bases = cls->getBases();
assert(bases.size() >= 2);
std::cout << "Test 11 PASSED: Whetstone-style class signature\n";
passed++;
}
// Test 12: JSON roundtrip preserves parsed class with bases
{
std::string src = R"(
class D : public A, protected B {
void f() {}
};
)";
auto mod = TreeSitterParser::parseCpp(src);
json j = toJson(mod.get());
ASTNode* restored = fromJson(j);
auto* rmod = dynamic_cast<Module*>(restored);
assert(rmod != nullptr);
auto classes = rmod->getChildren("classes");
assert(!classes.empty());
auto* cls = dynamic_cast<ClassDeclaration*>(classes[0]);
assert(cls->name == "D");
auto bases = cls->getBases();
assert(bases.size() >= 2);
deleteTree(restored);
std::cout << "Test 12 PASSED: JSON roundtrip preserves parsed class\n";
passed++;
}
std::cout << "\nResults: " << passed << "/12 tests passed\n";
return (passed == 12) ? 0 : 1;
}