Step 636: drone error synthesis
This commit is contained in:
@@ -4603,4 +4603,13 @@ target_link_libraries(step635_test PRIVATE
|
||||
tree_sitter_javascript tree_sitter_typescript
|
||||
tree_sitter_java tree_sitter_rust tree_sitter_go)
|
||||
|
||||
add_executable(step636_test tests/step636_test.cpp)
|
||||
target_include_directories(step636_test PRIVATE src)
|
||||
target_link_libraries(step636_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)
|
||||
|
||||
62
editor/src/DroneErrorSynthesis.h
Normal file
62
editor/src/DroneErrorSynthesis.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
// Step 636: Error type synthesis for drone
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
enum class DroneErrorKind {
|
||||
MqttError,
|
||||
NexusError,
|
||||
ExecutionError,
|
||||
CapabilityMismatch
|
||||
};
|
||||
|
||||
struct DroneErrorSpec {
|
||||
DroneErrorKind kind = DroneErrorKind::ExecutionError;
|
||||
std::string message;
|
||||
int code = 0;
|
||||
bool retryable = false;
|
||||
};
|
||||
|
||||
class DroneErrorSynthesis {
|
||||
public:
|
||||
static std::string className(DroneErrorKind kind) {
|
||||
if (kind == DroneErrorKind::MqttError) return "MqttError";
|
||||
if (kind == DroneErrorKind::NexusError) return "NexusError";
|
||||
if (kind == DroneErrorKind::ExecutionError) return "ExecutionError";
|
||||
return "CapabilityMismatch";
|
||||
}
|
||||
|
||||
static std::string toErrorCodeCategory(DroneErrorKind kind) {
|
||||
if (kind == DroneErrorKind::MqttError) return "mqtt";
|
||||
if (kind == DroneErrorKind::NexusError) return "nexus";
|
||||
if (kind == DroneErrorKind::ExecutionError) return "execution";
|
||||
return "capability";
|
||||
}
|
||||
|
||||
static std::string expectedAlias(DroneErrorKind kind,
|
||||
const std::string& valueType = "void") {
|
||||
return "std::expected<" + valueType + ", " + className(kind) + ">";
|
||||
}
|
||||
|
||||
static bool isRetryable(const DroneErrorSpec& spec) {
|
||||
if (spec.kind == DroneErrorKind::CapabilityMismatch) return false;
|
||||
if (spec.code < 0) return false;
|
||||
return spec.retryable;
|
||||
}
|
||||
|
||||
static std::string synthesizeHeader(const std::string& ns = "whetstone") {
|
||||
if (ns.empty()) return "";
|
||||
std::string code;
|
||||
code += "#pragma once\n";
|
||||
code += "#include <expected>\n";
|
||||
code += "#include <string>\n\n";
|
||||
code += "namespace " + ns + " {\n";
|
||||
code += "struct MqttError { int code = 0; std::string message; };\n";
|
||||
code += "struct NexusError { int code = 0; std::string message; };\n";
|
||||
code += "struct ExecutionError { int code = 0; std::string message; };\n";
|
||||
code += "struct CapabilityMismatch { int code = 0; std::string message; };\n";
|
||||
code += "} // namespace " + ns + "\n";
|
||||
return code;
|
||||
}
|
||||
};
|
||||
109
editor/tests/step636_test.cpp
Normal file
109
editor/tests/step636_test.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
// Step 636: Error type synthesis for drone (12 tests)
|
||||
|
||||
#include "DroneErrorSynthesis.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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_class_name_for_mqtt_error() {
|
||||
TEST(class_name_for_mqtt_error);
|
||||
CHECK(DroneErrorSynthesis::className(DroneErrorKind::MqttError) == "MqttError", "name mismatch");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_class_name_for_nexus_error() {
|
||||
TEST(class_name_for_nexus_error);
|
||||
CHECK(DroneErrorSynthesis::className(DroneErrorKind::NexusError) == "NexusError", "name mismatch");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_category_for_execution_error() {
|
||||
TEST(category_for_execution_error);
|
||||
CHECK(DroneErrorSynthesis::toErrorCodeCategory(DroneErrorKind::ExecutionError) == "execution", "category mismatch");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_category_for_capability_mismatch() {
|
||||
TEST(category_for_capability_mismatch);
|
||||
CHECK(DroneErrorSynthesis::toErrorCodeCategory(DroneErrorKind::CapabilityMismatch) == "capability", "category mismatch");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_expected_alias_default_value_type() {
|
||||
TEST(expected_alias_default_value_type);
|
||||
CHECK(DroneErrorSynthesis::expectedAlias(DroneErrorKind::MqttError) == "std::expected<void, MqttError>", "alias mismatch");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_expected_alias_custom_value_type() {
|
||||
TEST(expected_alias_custom_value_type);
|
||||
CHECK(DroneErrorSynthesis::expectedAlias(DroneErrorKind::NexusError, "int") == "std::expected<int, NexusError>", "alias mismatch");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_retryable_true_for_mqtt_positive_code() {
|
||||
TEST(retryable_true_for_mqtt_positive_code);
|
||||
DroneErrorSpec spec{DroneErrorKind::MqttError, "timeout", 1, true};
|
||||
CHECK(DroneErrorSynthesis::isRetryable(spec), "expected retryable");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_retryable_false_for_capability_mismatch() {
|
||||
TEST(retryable_false_for_capability_mismatch);
|
||||
DroneErrorSpec spec{DroneErrorKind::CapabilityMismatch, "missing cap", 1, true};
|
||||
CHECK(!DroneErrorSynthesis::isRetryable(spec), "capability mismatch should not retry");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_retryable_false_for_negative_code() {
|
||||
TEST(retryable_false_for_negative_code);
|
||||
DroneErrorSpec spec{DroneErrorKind::NexusError, "fatal", -1, true};
|
||||
CHECK(!DroneErrorSynthesis::isRetryable(spec), "negative code should not retry");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_synthesize_header_contains_mqtt_error() {
|
||||
TEST(synthesize_header_contains_mqtt_error);
|
||||
auto code = DroneErrorSynthesis::synthesizeHeader();
|
||||
CHECK(code.find("struct MqttError") != std::string::npos, "mqtt struct missing");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_synthesize_header_contains_expected_include() {
|
||||
TEST(synthesize_header_contains_expected_include);
|
||||
auto code = DroneErrorSynthesis::synthesizeHeader();
|
||||
CHECK(code.find("#include <expected>") != std::string::npos, "expected include missing");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_synthesize_header_rejects_empty_namespace() {
|
||||
TEST(synthesize_header_rejects_empty_namespace);
|
||||
auto code = DroneErrorSynthesis::synthesizeHeader("");
|
||||
CHECK(code.empty(), "empty namespace should produce empty output");
|
||||
PASS();
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "Step 636: Error type synthesis for drone\n";
|
||||
|
||||
test_class_name_for_mqtt_error();
|
||||
test_class_name_for_nexus_error();
|
||||
test_category_for_execution_error();
|
||||
test_category_for_capability_mismatch();
|
||||
test_expected_alias_default_value_type();
|
||||
test_expected_alias_custom_value_type();
|
||||
test_retryable_true_for_mqtt_positive_code();
|
||||
test_retryable_false_for_capability_mismatch();
|
||||
test_retryable_false_for_negative_code();
|
||||
test_synthesize_header_contains_mqtt_error();
|
||||
test_synthesize_header_contains_expected_include();
|
||||
test_synthesize_header_rejects_empty_namespace();
|
||||
|
||||
std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n";
|
||||
return failed == 0 ? 0 : 1;
|
||||
}
|
||||
32
progress.md
32
progress.md
@@ -12888,3 +12888,35 @@ a header-only `supports(...)` helper.
|
||||
- `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`
|
||||
|
||||
### Step 636: Error type synthesis for drone
|
||||
**Status:** PASS (12/12 tests)
|
||||
|
||||
Adds a drone error synthesis module covering `MqttError`, `NexusError`,
|
||||
`ExecutionError`, and `CapabilityMismatch` with category mapping, retryability
|
||||
rules, and `std::expected` alias generation helpers.
|
||||
|
||||
**Files added:**
|
||||
- `editor/src/DroneErrorSynthesis.h` - error synthesis model:
|
||||
- error kind and spec modeling
|
||||
- category and expected-alias helpers
|
||||
- header text synthesis for generated drone error types
|
||||
- `editor/tests/step636_test.cpp` - 12 tests covering:
|
||||
- class/category mapping correctness
|
||||
- expected-alias generation behavior
|
||||
- retryability edge cases
|
||||
- synthesized-header content and empty-namespace handling
|
||||
|
||||
**Files modified:**
|
||||
- `editor/CMakeLists.txt` - `step636_test` target
|
||||
|
||||
**Verification run:**
|
||||
- `cmake -S editor -B editor/build-native` - PASS
|
||||
- `cmake --build editor/build-native --target step636_test step635_test` - PASS
|
||||
- `./editor/build-native/step636_test` - PASS (12/12)
|
||||
- `./editor/build-native/step635_test` - PASS (12/12) regression coverage
|
||||
|
||||
**Architecture gate check:**
|
||||
- `editor/src/DroneErrorSynthesis.h` (`62` <= `600`)
|
||||
- `editor/tests/step636_test.cpp` within test-file size guidance (`109` lines)
|
||||
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`
|
||||
|
||||
Reference in New Issue
Block a user