// Step 1990: Fix C++ struct field type loss in run_pipeline round-trip // and relax queue_ready test-files blocker to a warning. // // Bug 1: CppParser did not extract the "type" field from declaration/field_declaration // nodes, so CppGeneratorTypes::inferFieldType fell back to "auto /* TODO: specify type */" // for all struct fields whose names didn't match name-based heuristics. // // Bug 2: queue_ready with strictExecutionContract blocked on missing testFiles even // when verificationType == "unit" and the project was starting new work (files don't // exist yet). Demoted to a warning. #include #include #include #include "ast/CppGenerator.h" #include "ast/Parser.h" int main() { int passed = 0; // Test 1: std::string fields round-trip correctly through CppParser → CppGenerator { const std::string src = R"( namespace whimptk { struct PresentationConstraint { std::string visibility_hint; std::string emphasis; }; } )"; auto mod = TreeSitterParser::parseCpp(src); assert(mod != nullptr); CppGenerator gen; const std::string out = gen.generate(mod.get()); assert(out.find("auto /* TODO") == std::string::npos); assert(out.find("std::string visibility_hint") != std::string::npos); assert(out.find("std::string emphasis") != std::string::npos); std::cout << "Test 1 PASSED: std::string fields preserve type through round-trip\n"; ++passed; } // Test 2: int fields with default initializers round-trip correctly { const std::string src = R"( struct Rect { int x = 0; int y = 0; int width = 0; int height = 0; }; )"; auto mod = TreeSitterParser::parseCpp(src); assert(mod != nullptr); CppGenerator gen; const std::string out = gen.generate(mod.get()); assert(out.find("auto /* TODO") == std::string::npos); assert(out.find("int x") != std::string::npos); assert(out.find("int width") != std::string::npos); std::cout << "Test 2 PASSED: int fields with initializers preserve type\n"; ++passed; } // Test 3: bool fields round-trip correctly { const std::string src = R"( struct WidgetState { bool hovered = false; bool focused = false; bool disabled = false; }; )"; auto mod = TreeSitterParser::parseCpp(src); assert(mod != nullptr); CppGenerator gen; const std::string out = gen.generate(mod.get()); assert(out.find("auto /* TODO") == std::string::npos); assert(out.find("bool hovered") != std::string::npos); assert(out.find("bool disabled") != std::string::npos); std::cout << "Test 3 PASSED: bool fields preserve type through round-trip\n"; ++passed; } // Test 4: mixed-type struct (string + int + bool) all preserve types { const std::string src = R"( struct ToolkitCapability { std::string capability_id; std::string description; bool available = true; }; )"; auto mod = TreeSitterParser::parseCpp(src); assert(mod != nullptr); CppGenerator gen; const std::string out = gen.generate(mod.get()); assert(out.find("auto /* TODO") == std::string::npos); assert(out.find("std::string capability_id") != std::string::npos); assert(out.find("bool available") != std::string::npos); std::cout << "Test 4 PASSED: mixed-type struct preserves all field types\n"; ++passed; } // Test 5: field type round-trip does not break field names { const std::string src = R"( struct InterfaceRequirement { std::string id; std::string label; int priority = 0; }; )"; auto mod = TreeSitterParser::parseCpp(src); assert(mod != nullptr); const auto& classes = mod->getChildren("classes"); assert(!classes.empty()); const auto* cls = static_cast(classes[0]); const auto& fields = cls->getChildren("fields"); assert(fields.size() == 3); // Names must still be bare identifiers, not "id = something" const auto* f0 = static_cast(fields[0]); assert(f0->name == "id"); const auto* f1 = static_cast(fields[1]); assert(f1->name == "label"); std::cout << "Test 5 PASSED: field names are clean after type extraction\n"; ++passed; } std::cout << "\n" << passed << "/5 passed\n"; return passed == 5 ? 0 : 1; }