200 lines
6.2 KiB
C++
200 lines
6.2 KiB
C++
|
|
// Step 395: Static Members + Const/Constexpr (12 tests)
|
||
|
|
|
||
|
|
#include <cassert>
|
||
|
|
#include <iostream>
|
||
|
|
#include <string>
|
||
|
|
#include "ast/Parser.h"
|
||
|
|
#include "ast/Generator.h"
|
||
|
|
#include "ast/CppAdvancedNodes.h"
|
||
|
|
#include "ast/ClassDeclaration.h"
|
||
|
|
|
||
|
|
int main() {
|
||
|
|
int passed = 0;
|
||
|
|
|
||
|
|
// Test 1: Detect const from declaration text
|
||
|
|
{
|
||
|
|
auto q = detectQualifiers("const std::string& getName() const;");
|
||
|
|
assert(q.isConst == true);
|
||
|
|
assert(q.isStatic == false);
|
||
|
|
assert(q.isConstexpr == false);
|
||
|
|
std::cout << "PASS: test 1 — detect const\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 2: Detect constexpr from declaration text
|
||
|
|
{
|
||
|
|
auto q = detectQualifiers("static constexpr int MAX = 256;");
|
||
|
|
assert(q.isConstexpr == true);
|
||
|
|
assert(q.isStatic == true);
|
||
|
|
assert(q.isConst == false); // constexpr implies const but text doesn't say "const "
|
||
|
|
std::cout << "PASS: test 2 — detect constexpr\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 3: Detect static method
|
||
|
|
{
|
||
|
|
auto q = detectQualifiers("static void doSomething();");
|
||
|
|
assert(q.isStatic == true);
|
||
|
|
assert(q.isConst == false);
|
||
|
|
std::cout << "PASS: test 3 — detect static\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 4: Detect trailing const on method
|
||
|
|
{
|
||
|
|
assert(isConstMethod("int getValue() const { return v_; }") == true);
|
||
|
|
assert(isConstMethod("void setValue(int v) { v_ = v; }") == false);
|
||
|
|
assert(isConstMethod("const int& getRef() const;") == true);
|
||
|
|
// const_cast should not trigger false positive
|
||
|
|
assert(isConstMethod("auto p = const_cast<int*>(&x);") == false);
|
||
|
|
std::cout << "PASS: test 4 — trailing const detection\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 5: Parse class with static method
|
||
|
|
{
|
||
|
|
std::string src = R"(
|
||
|
|
class Config {
|
||
|
|
public:
|
||
|
|
static int getDefault() { return 42; }
|
||
|
|
};
|
||
|
|
)";
|
||
|
|
auto mod = TreeSitterParser::parseCpp(src);
|
||
|
|
auto& classes = mod->getChildren("classes");
|
||
|
|
assert(!classes.empty());
|
||
|
|
auto* cls = static_cast<ClassDeclaration*>(classes[0]);
|
||
|
|
auto& methods = cls->getChildren("methods");
|
||
|
|
assert(!methods.empty());
|
||
|
|
auto* meth = static_cast<MethodDeclaration*>(methods[0]);
|
||
|
|
assert(meth->isStatic == true);
|
||
|
|
std::cout << "PASS: test 5 — parse static method\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 6: Parse class with const method
|
||
|
|
{
|
||
|
|
std::string src = R"(
|
||
|
|
class Widget {
|
||
|
|
public:
|
||
|
|
int getValue() const { return value_; }
|
||
|
|
};
|
||
|
|
)";
|
||
|
|
auto mod = TreeSitterParser::parseCpp(src);
|
||
|
|
auto& classes = mod->getChildren("classes");
|
||
|
|
assert(!classes.empty());
|
||
|
|
auto* cls = static_cast<ClassDeclaration*>(classes[0]);
|
||
|
|
auto& methods = cls->getChildren("methods");
|
||
|
|
assert(!methods.empty());
|
||
|
|
// The parser doesn't currently set isConst on methods,
|
||
|
|
// but we can detect it from the source text
|
||
|
|
std::string methodText = src.substr(src.find("int getValue"));
|
||
|
|
assert(isConstMethod(methodText));
|
||
|
|
std::cout << "PASS: test 6 — parse const method\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 7: Parse class with virtual method
|
||
|
|
{
|
||
|
|
std::string src = R"(
|
||
|
|
class Base {
|
||
|
|
public:
|
||
|
|
virtual void draw() { }
|
||
|
|
};
|
||
|
|
)";
|
||
|
|
auto mod = TreeSitterParser::parseCpp(src);
|
||
|
|
auto& classes = mod->getChildren("classes");
|
||
|
|
assert(!classes.empty());
|
||
|
|
auto* cls = static_cast<ClassDeclaration*>(classes[0]);
|
||
|
|
auto& methods = cls->getChildren("methods");
|
||
|
|
assert(!methods.empty());
|
||
|
|
auto* meth = static_cast<MethodDeclaration*>(methods[0]);
|
||
|
|
assert(meth->isVirtual == true);
|
||
|
|
std::cout << "PASS: test 7 — parse virtual method\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 8: CppQualifiers JSON roundtrip
|
||
|
|
{
|
||
|
|
CppQualifiers q;
|
||
|
|
q.isConst = true;
|
||
|
|
q.isConstexpr = true;
|
||
|
|
q.isStatic = false;
|
||
|
|
q.smartPointerKind = "unique_ptr";
|
||
|
|
|
||
|
|
json j = q.toJson();
|
||
|
|
assert(j["isConst"] == true);
|
||
|
|
assert(j["isConstexpr"] == true);
|
||
|
|
assert(!j.contains("isStatic")); // false values not serialized
|
||
|
|
assert(j["smartPointerKind"] == "unique_ptr");
|
||
|
|
|
||
|
|
auto restored = CppQualifiers::fromJson(j);
|
||
|
|
assert(restored.isConst == true);
|
||
|
|
assert(restored.isConstexpr == true);
|
||
|
|
assert(restored.isStatic == false);
|
||
|
|
assert(restored.smartPointerKind == "unique_ptr");
|
||
|
|
std::cout << "PASS: test 8 — CppQualifiers JSON roundtrip\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 9: Parse class with field declarations
|
||
|
|
{
|
||
|
|
std::string src = R"(
|
||
|
|
class Counter {
|
||
|
|
private:
|
||
|
|
int count_;
|
||
|
|
public:
|
||
|
|
int getCount() { return count_; }
|
||
|
|
};
|
||
|
|
)";
|
||
|
|
auto mod = TreeSitterParser::parseCpp(src);
|
||
|
|
auto& classes = mod->getChildren("classes");
|
||
|
|
assert(!classes.empty());
|
||
|
|
auto* cls = static_cast<ClassDeclaration*>(classes[0]);
|
||
|
|
assert(cls->name == "Counter");
|
||
|
|
std::cout << "PASS: test 9 — parse class with fields\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 10: Multiple qualifiers combined
|
||
|
|
{
|
||
|
|
auto q = detectQualifiers("static constexpr const int MAX = 100;");
|
||
|
|
assert(q.isStatic == true);
|
||
|
|
assert(q.isConstexpr == true);
|
||
|
|
assert(q.isConst == true);
|
||
|
|
std::cout << "PASS: test 10 — multiple qualifiers combined\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 11: Override detection
|
||
|
|
{
|
||
|
|
std::string src = R"(
|
||
|
|
class Derived : public Base {
|
||
|
|
public:
|
||
|
|
void draw() override { }
|
||
|
|
};
|
||
|
|
)";
|
||
|
|
auto mod = TreeSitterParser::parseCpp(src);
|
||
|
|
auto& classes = mod->getChildren("classes");
|
||
|
|
assert(!classes.empty());
|
||
|
|
auto* cls = static_cast<ClassDeclaration*>(classes[0]);
|
||
|
|
auto& methods = cls->getChildren("methods");
|
||
|
|
assert(!methods.empty());
|
||
|
|
auto* meth = static_cast<MethodDeclaration*>(methods[0]);
|
||
|
|
assert(meth->isOverride == true);
|
||
|
|
std::cout << "PASS: test 11 — override detection\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 12: Mutable detection
|
||
|
|
{
|
||
|
|
auto q = detectQualifiers("mutable int cache_;");
|
||
|
|
assert(q.isMutable == true);
|
||
|
|
assert(q.isConst == false);
|
||
|
|
std::cout << "PASS: test 12 — mutable detection\n";
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::cout << "\nStep 395 result: " << passed << "/12 tests passed\n";
|
||
|
|
return (passed == 12) ? 0 : 1;
|
||
|
|
}
|