diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index ede3460..e3d7520 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -4594,4 +4594,13 @@ target_link_libraries(step634_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step635_test tests/step635_test.cpp) +target_include_directories(step635_test PRIVATE src) +target_link_libraries(step635_test PRIVATE + nlohmann_json::nlohmann_json + unofficial::tree-sitter::tree-sitter + tree_sitter_python tree_sitter_cpp tree_sitter_elisp + tree_sitter_javascript tree_sitter_typescript + tree_sitter_java tree_sitter_rust tree_sitter_go) + # Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies) diff --git a/editor/src/CapabilityDeclarationGenerator.h b/editor/src/CapabilityDeclarationGenerator.h new file mode 100644 index 0000000..9fef034 --- /dev/null +++ b/editor/src/CapabilityDeclarationGenerator.h @@ -0,0 +1,68 @@ +#pragma once +// Step 635: Capability declaration struct generator + +#include +#include +#include + +struct CapabilityDeclarationOutput { + bool success = false; + std::string headerCode; + std::vector typeNames; +}; + +class CapabilityDeclarationGenerator { +public: + static CapabilityDeclarationOutput generate(const std::string& namespaceName = "whetstone") { + CapabilityDeclarationOutput out; + if (namespaceName.empty()) return out; + + out.typeNames = { + "NodeCapability", + "CapabilitySet", + "EnergyContext", + "JobRequirements" + }; + + std::string code; + code += "#pragma once\n"; + code += "#include \n"; + code += "#include \n\n"; + code += "namespace " + namespaceName + " {\n\n"; + code += "struct NodeCapability {\n"; + code += " std::string name;\n"; + code += " int level = 0;\n"; + code += "};\n\n"; + code += "struct CapabilitySet {\n"; + code += " std::vector items;\n"; + code += "};\n\n"; + code += "struct EnergyContext {\n"; + code += " std::string mode = \"Normal\";\n"; + code += " int wattsAvailable = 0;\n"; + code += "};\n\n"; + code += "struct JobRequirements {\n"; + code += " std::vector requiredCaps;\n"; + code += " int minLevel = 0;\n"; + code += "};\n\n"; + code += "inline bool supports(const CapabilitySet& caps, const JobRequirements& req) {\n"; + code += " if (req.requiredCaps.empty()) return true;\n"; + code += " for (const auto& needed : req.requiredCaps) {\n"; + code += " bool found = false;\n"; + code += " for (const auto& have : caps.items) {\n"; + code += " if (have.name == needed && have.level >= req.minLevel) { found = true; break; }\n"; + code += " }\n"; + code += " if (!found) return false;\n"; + code += " }\n"; + code += " return true;\n"; + code += "}\n\n"; + code += "} // namespace " + namespaceName + "\n"; + + out.success = true; + out.headerCode = code; + return out; + } + + static bool containsType(const CapabilityDeclarationOutput& out, const std::string& typeName) { + return std::find(out.typeNames.begin(), out.typeNames.end(), typeName) != out.typeNames.end(); + } +}; diff --git a/editor/tests/step635_test.cpp b/editor/tests/step635_test.cpp new file mode 100644 index 0000000..75f8f34 --- /dev/null +++ b/editor/tests/step635_test.cpp @@ -0,0 +1,116 @@ +// Step 635: Capability declaration struct generator (12 tests) + +#include "CapabilityDeclarationGenerator.h" + +#include + +static int passed = 0, failed = 0; +#define TEST(name) { std::cout << " " << #name << "... "; } +#define PASS() { std::cout << "PASS\n"; ++passed; } +#define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; } +#define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } + +void test_generate_requires_non_empty_namespace() { + TEST(generate_requires_non_empty_namespace); + auto out = CapabilityDeclarationGenerator::generate(""); + CHECK(!out.success, "empty namespace should fail"); + PASS(); +} + +void test_generate_succeeds_with_default_namespace() { + TEST(generate_succeeds_with_default_namespace); + auto out = CapabilityDeclarationGenerator::generate(); + CHECK(out.success, "generate should succeed"); + PASS(); +} + +void test_output_contains_node_capability_struct() { + TEST(output_contains_node_capability_struct); + auto out = CapabilityDeclarationGenerator::generate(); + CHECK(out.headerCode.find("struct NodeCapability") != std::string::npos, "NodeCapability missing"); + PASS(); +} + +void test_output_contains_capability_set_struct() { + TEST(output_contains_capability_set_struct); + auto out = CapabilityDeclarationGenerator::generate(); + CHECK(out.headerCode.find("struct CapabilitySet") != std::string::npos, "CapabilitySet missing"); + PASS(); +} + +void test_output_contains_energy_context_struct() { + TEST(output_contains_energy_context_struct); + auto out = CapabilityDeclarationGenerator::generate(); + CHECK(out.headerCode.find("struct EnergyContext") != std::string::npos, "EnergyContext missing"); + PASS(); +} + +void test_output_contains_job_requirements_struct() { + TEST(output_contains_job_requirements_struct); + auto out = CapabilityDeclarationGenerator::generate(); + CHECK(out.headerCode.find("struct JobRequirements") != std::string::npos, "JobRequirements missing"); + PASS(); +} + +void test_output_contains_supports_helper() { + TEST(output_contains_supports_helper); + auto out = CapabilityDeclarationGenerator::generate(); + CHECK(out.headerCode.find("inline bool supports") != std::string::npos, "supports helper missing"); + PASS(); +} + +void test_contains_type_detects_known_types() { + TEST(contains_type_detects_known_types); + auto out = CapabilityDeclarationGenerator::generate(); + CHECK(CapabilityDeclarationGenerator::containsType(out, "NodeCapability"), "type should exist"); + CHECK(CapabilityDeclarationGenerator::containsType(out, "JobRequirements"), "type should exist"); + PASS(); +} + +void test_contains_type_rejects_unknown_type() { + TEST(contains_type_rejects_unknown_type); + auto out = CapabilityDeclarationGenerator::generate(); + CHECK(!CapabilityDeclarationGenerator::containsType(out, "UnknownType"), "unknown type should not exist"); + PASS(); +} + +void test_header_uses_header_only_pattern() { + TEST(header_uses_header_only_pattern); + auto out = CapabilityDeclarationGenerator::generate(); + CHECK(out.headerCode.find("#pragma once") != std::string::npos, "pragma once missing"); + PASS(); +} + +void test_custom_namespace_is_applied() { + TEST(custom_namespace_is_applied); + auto out = CapabilityDeclarationGenerator::generate("hivemind"); + CHECK(out.headerCode.find("namespace hivemind") != std::string::npos, "custom namespace missing"); + PASS(); +} + +void test_type_count_matches_expected_set() { + TEST(type_count_matches_expected_set); + auto out = CapabilityDeclarationGenerator::generate(); + CHECK(out.typeNames.size() == 4, "expected 4 generated types"); + PASS(); +} + +int main() { + std::cout << "Step 635: Capability declaration struct generator\n"; + + test_generate_requires_non_empty_namespace(); + test_generate_succeeds_with_default_namespace(); + test_output_contains_node_capability_struct(); + test_output_contains_capability_set_struct(); + test_output_contains_energy_context_struct(); + test_output_contains_job_requirements_struct(); + test_output_contains_supports_helper(); + test_contains_type_detects_known_types(); + test_contains_type_rejects_unknown_type(); + test_header_uses_header_only_pattern(); + test_custom_namespace_is_applied(); + test_type_count_matches_expected_set(); + + std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n"; + return failed == 0 ? 0 : 1; +} diff --git a/progress.md b/progress.md index d57b2d0..496d2f6 100644 --- a/progress.md +++ b/progress.md @@ -12857,3 +12857,34 @@ INTERFACE target text. - `editor/src/SchemaToCppGenerator.h` (`116` <= `600`) - `editor/tests/step634_test.cpp` within test-file size guidance (`128` lines) - Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md` + +### Step 635: Capability declaration struct generator +**Status:** PASS (12/12 tests) + +Adds a capability declaration generator for shared drone/orchestrator types: +`NodeCapability`, `CapabilitySet`, `EnergyContext`, and `JobRequirements`, plus +a header-only `supports(...)` helper. + +**Files added:** +- `editor/src/CapabilityDeclarationGenerator.h` - capability type generator: + - emits shared capability structs and helper logic + - supports namespace customization for generated header text + - exposes generated type set metadata for validation/tests +- `editor/tests/step635_test.cpp` - 12 tests covering: + - namespace validation and default generation + - generated type presence and helper emission + - header-only pattern checks and type set integrity + +**Files modified:** +- `editor/CMakeLists.txt` - `step635_test` target + +**Verification run:** +- `cmake -S editor -B editor/build-native` - PASS +- `cmake --build editor/build-native --target step635_test step634_test` - PASS +- `./editor/build-native/step635_test` - PASS (12/12) +- `./editor/build-native/step634_test` - PASS (12/12) regression coverage + +**Architecture gate check:** +- `editor/src/CapabilityDeclarationGenerator.h` (`68` <= `600`) +- `editor/tests/step635_test.cpp` within test-file size guidance (`116` lines) +- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`