Step 562: add workflow-aware debug hooks model
This commit is contained in:
@@ -3937,4 +3937,13 @@ target_link_libraries(step561_test PRIVATE
|
||||
tree_sitter_javascript tree_sitter_typescript
|
||||
tree_sitter_java tree_sitter_rust tree_sitter_go)
|
||||
|
||||
add_executable(step562_test tests/step562_test.cpp)
|
||||
target_include_directories(step562_test PRIVATE src)
|
||||
target_link_libraries(step562_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)
|
||||
|
||||
77
editor/src/WorkflowAwareDebugHooks.h
Normal file
77
editor/src/WorkflowAwareDebugHooks.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
// Step 562: Workflow-Aware Debug Hooks
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct WorkflowDebugBinding {
|
||||
std::string workflowItemId;
|
||||
std::string debugSessionId;
|
||||
std::vector<std::string> diagnosticIds;
|
||||
bool active = true;
|
||||
};
|
||||
|
||||
class WorkflowAwareDebugHooks {
|
||||
public:
|
||||
bool attach(const std::string& workflowItemId,
|
||||
const std::string& debugSessionId,
|
||||
const std::vector<std::string>& diagnosticIds) {
|
||||
if (workflowItemId.empty() || debugSessionId.empty()) return false;
|
||||
if (bindings_.count(workflowItemId) != 0) return false;
|
||||
bindings_[workflowItemId] = {workflowItemId, debugSessionId, diagnosticIds, true};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool detach(const std::string& workflowItemId) {
|
||||
auto it = bindings_.find(workflowItemId);
|
||||
if (it == bindings_.end()) return false;
|
||||
bindings_.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setActive(const std::string& workflowItemId, bool active) {
|
||||
auto* b = find(workflowItemId);
|
||||
if (!b) return false;
|
||||
b->active = active;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addDiagnostic(const std::string& workflowItemId,
|
||||
const std::string& diagnosticId) {
|
||||
auto* b = find(workflowItemId);
|
||||
if (!b || diagnosticId.empty()) return false;
|
||||
for (const auto& d : b->diagnosticIds) {
|
||||
if (d == diagnosticId) return false;
|
||||
}
|
||||
b->diagnosticIds.push_back(diagnosticId);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<WorkflowDebugBinding> activeBindings() const {
|
||||
std::vector<WorkflowDebugBinding> out;
|
||||
for (const auto& kv : bindings_) {
|
||||
if (kv.second.active) out.push_back(kv.second);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool isAttached(const std::string& workflowItemId) const {
|
||||
return bindings_.count(workflowItemId) != 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> diagnosticsFor(const std::string& workflowItemId) const {
|
||||
auto it = bindings_.find(workflowItemId);
|
||||
if (it == bindings_.end()) return {};
|
||||
return it->second.diagnosticIds;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, WorkflowDebugBinding> bindings_;
|
||||
|
||||
WorkflowDebugBinding* find(const std::string& workflowItemId) {
|
||||
auto it = bindings_.find(workflowItemId);
|
||||
if (it == bindings_.end()) return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
};
|
||||
133
editor/tests/step562_test.cpp
Normal file
133
editor/tests/step562_test.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
// Step 562: Workflow-Aware Debug Hooks (12 tests)
|
||||
|
||||
#include "WorkflowAwareDebugHooks.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; } else {}
|
||||
|
||||
void test_attach_binding_succeeds() {
|
||||
TEST(attach_binding_succeeds);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(h.attach("wi-1", "ds-1", {"d1"}), "attach should succeed");
|
||||
CHECK(h.isAttached("wi-1"), "binding should exist");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_attach_rejects_duplicate_workflow_item() {
|
||||
TEST(attach_rejects_duplicate_workflow_item);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(h.attach("wi-1", "ds-1", {"d1"}), "first attach should succeed");
|
||||
CHECK(!h.attach("wi-1", "ds-2", {"d2"}), "duplicate workflow item should fail");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_attach_rejects_missing_ids() {
|
||||
TEST(attach_rejects_missing_ids);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(!h.attach("", "ds-1", {}), "missing workflow id should fail");
|
||||
CHECK(!h.attach("wi-1", "", {}), "missing session id should fail");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_detach_removes_binding() {
|
||||
TEST(detach_removes_binding);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(h.attach("wi-1", "ds-1", {"d1"}), "attach should succeed");
|
||||
CHECK(h.detach("wi-1"), "detach should succeed");
|
||||
CHECK(!h.isAttached("wi-1"), "binding should be removed");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_detach_fails_for_unknown_item() {
|
||||
TEST(detach_fails_for_unknown_item);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(!h.detach("missing"), "detach unknown should fail");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_set_active_toggles_binding_state() {
|
||||
TEST(set_active_toggles_binding_state);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(h.attach("wi-1", "ds-1", {"d1"}), "attach should succeed");
|
||||
CHECK(h.setActive("wi-1", false), "set inactive should succeed");
|
||||
CHECK(h.activeBindings().empty(), "no active bindings expected");
|
||||
CHECK(h.setActive("wi-1", true), "set active should succeed");
|
||||
CHECK(h.activeBindings().size() == 1, "one active binding expected");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_set_active_fails_for_unknown_item() {
|
||||
TEST(set_active_fails_for_unknown_item);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(!h.setActive("missing", true), "set active unknown should fail");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_add_diagnostic_appends_unique_diagnostic() {
|
||||
TEST(add_diagnostic_appends_unique_diagnostic);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(h.attach("wi-1", "ds-1", {"d1"}), "attach should succeed");
|
||||
CHECK(h.addDiagnostic("wi-1", "d2"), "add diagnostic should succeed");
|
||||
auto d = h.diagnosticsFor("wi-1");
|
||||
CHECK(d.size() == 2, "two diagnostics expected");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_add_diagnostic_rejects_duplicate() {
|
||||
TEST(add_diagnostic_rejects_duplicate);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(h.attach("wi-1", "ds-1", {"d1"}), "attach should succeed");
|
||||
CHECK(!h.addDiagnostic("wi-1", "d1"), "duplicate diagnostic should fail");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_add_diagnostic_fails_for_unknown_binding() {
|
||||
TEST(add_diagnostic_fails_for_unknown_binding);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(!h.addDiagnostic("missing", "d1"), "unknown binding should fail");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_active_bindings_returns_only_active() {
|
||||
TEST(active_bindings_returns_only_active);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(h.attach("wi-1", "ds-1", {"d1"}), "attach wi-1");
|
||||
CHECK(h.attach("wi-2", "ds-2", {"d2"}), "attach wi-2");
|
||||
CHECK(h.setActive("wi-2", false), "deactivate wi-2");
|
||||
auto active = h.activeBindings();
|
||||
CHECK(active.size() == 1, "only one active expected");
|
||||
CHECK(active[0].workflowItemId == "wi-1", "active item mismatch");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_diagnostics_for_unknown_item_empty() {
|
||||
TEST(diagnostics_for_unknown_item_empty);
|
||||
WorkflowAwareDebugHooks h;
|
||||
CHECK(h.diagnosticsFor("missing").empty(), "unknown diagnostics should be empty");
|
||||
PASS();
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "Step 562: Workflow-Aware Debug Hooks\n";
|
||||
|
||||
test_attach_binding_succeeds(); // 1
|
||||
test_attach_rejects_duplicate_workflow_item(); // 2
|
||||
test_attach_rejects_missing_ids(); // 3
|
||||
test_detach_removes_binding(); // 4
|
||||
test_detach_fails_for_unknown_item(); // 5
|
||||
test_set_active_toggles_binding_state(); // 6
|
||||
test_set_active_fails_for_unknown_item(); // 7
|
||||
test_add_diagnostic_appends_unique_diagnostic(); // 8
|
||||
test_add_diagnostic_rejects_duplicate(); // 9
|
||||
test_add_diagnostic_fails_for_unknown_binding(); // 10
|
||||
test_active_bindings_returns_only_active(); // 11
|
||||
test_diagnostics_for_unknown_item_empty(); // 12
|
||||
|
||||
std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n";
|
||||
return failed == 0 ? 0 : 1;
|
||||
}
|
||||
34
progress.md
34
progress.md
@@ -10044,3 +10044,37 @@ state transitions with session/type/window query support.
|
||||
- `editor/src/TraceTimelineModel.h` within header-size limit (`58` <= `600`)
|
||||
- `editor/tests/step561_test.cpp` within test-file size guidance (`144` lines)
|
||||
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`
|
||||
|
||||
### Step 562: Workflow-Aware Debug Hooks
|
||||
**Status:** PASS (12/12 tests)
|
||||
|
||||
Implements workflow-aware debug hooks that bind debug sessions to active
|
||||
workflow items and diagnostic IDs for coordinated runtime/debug context.
|
||||
|
||||
**Files added:**
|
||||
- `editor/src/WorkflowAwareDebugHooks.h` - workflow debug hook model:
|
||||
- workflow-item to debug-session attachment lifecycle
|
||||
- active/inactive binding state toggles
|
||||
- diagnostic linkage management per workflow item
|
||||
- active-binding and diagnostic query helpers
|
||||
- `editor/tests/step562_test.cpp` - 12 tests covering:
|
||||
- attach/detach lifecycle behavior
|
||||
- duplicate/invalid attach guards
|
||||
- active state toggle behavior
|
||||
- diagnostic add/duplicate/unknown behavior
|
||||
- active-binding filtering behavior
|
||||
- unknown diagnostic query behavior
|
||||
|
||||
**Files modified:**
|
||||
- `editor/CMakeLists.txt` - `step562_test` target
|
||||
|
||||
**Verification run:**
|
||||
- `cmake -S editor -B editor/build-native` - PASS
|
||||
- `cmake --build editor/build-native --target step562_test step561_test` - PASS
|
||||
- `./editor/build-native/step562_test` - PASS (12/12)
|
||||
- `./editor/build-native/step561_test` - PASS (12/12) regression coverage
|
||||
|
||||
**Architecture gate check:**
|
||||
- `editor/src/WorkflowAwareDebugHooks.h` within header-size limit (`77` <= `600`)
|
||||
- `editor/tests/step562_test.cpp` within test-file size guidance (`133` lines)
|
||||
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`
|
||||
|
||||
Reference in New Issue
Block a user