Files
whetstone_DSL/editor/tests/step1935_test.cpp
Bill 99cc6319c0 Sprint 281: DAP Hardening (steps 1933–1937)
DAPRequestValidator, DAPCapabilityNegotiator, DAPEventBroadcaster,
DAPBreakpointHitDispatcher — 26/26 tests pass.
Integration step 1937: Python+Rust DAP session round-trip verified.
Also adds allBreakpoints() to ASTNodeBreakpointMapper.
Metrics: 8 whetstone calls, 8853 tokens.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 21:45:53 -07:00

90 lines
2.9 KiB
C++

// Step 1935: DAPEventBroadcaster
//
// t1: subscribe and broadcast fires handler
// t2: multiple subscribers for same event type all fire
// t3: unsubscribe stops handler from firing
// t4: broadcastAll routes by event["event"]
// t5: subscriberCount correct; different types independent
#include "DAPEventBroadcaster.h"
#include <iostream>
namespace ws = whetstone;
static int p=0,f=0;
#define T(n) { std::cout<<" "<<#n<<"... "; }
#define P() { std::cout<<"PASS\n"; ++p; }
#define F(m) { std::cout<<"FAIL: "<<m<<"\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
void t1(){
T(subscribe_and_broadcast_fires_handler);
ws::DAPEventBroadcaster b;
int count = 0;
b.subscribe("stopped", [&](const nlohmann::json&){ ++count; });
b.broadcast("stopped", {});
C(count == 1, "handler fired once");
b.broadcast("continued", {});
C(count == 1, "other event not fired");
P();
}
void t2(){
T(multiple_subscribers_all_fire);
ws::DAPEventBroadcaster b;
int a = 0, c = 0;
b.subscribe("output", [&](const nlohmann::json&){ ++a; });
b.subscribe("output", [&](const nlohmann::json&){ ++c; });
b.broadcast("output", {});
C(a == 1 && c == 1, "both handlers fired");
P();
}
void t3(){
T(unsubscribe_stops_handler);
ws::DAPEventBroadcaster b;
int count = 0;
int id = b.subscribe("stopped", [&](const nlohmann::json&){ ++count; });
b.broadcast("stopped", {});
C(count == 1, "fired before unsubscribe");
b.unsubscribe(id);
b.broadcast("stopped", {});
C(count == 1, "not fired after unsubscribe");
C(b.subscriberCount("stopped") == 0, "count 0 after unsubscribe");
P();
}
void t4(){
T(broadcastAll_routes_by_event_field);
ws::DAPEventBroadcaster b;
int stopped = 0, output = 0;
b.subscribe("stopped", [&](const nlohmann::json&){ ++stopped; });
b.subscribe("output", [&](const nlohmann::json&){ ++output; });
nlohmann::json ev = {{"type","event"},{"seq",1},{"event","stopped"},{"body",{}}};
b.broadcastAll(ev);
C(stopped == 1, "stopped handler fired");
C(output == 0, "output handler not fired");
// no event field → no-op
b.broadcastAll({{"type","event"},{"seq",2}});
C(stopped == 1, "still 1 after no-event broadcast");
P();
}
void t5(){
T(subscriberCount_independent_per_type);
ws::DAPEventBroadcaster b;
b.subscribe("stopped", [](const nlohmann::json&){});
b.subscribe("stopped", [](const nlohmann::json&){});
b.subscribe("continued",[](const nlohmann::json&){});
C(b.subscriberCount("stopped") == 2, "two stopped");
C(b.subscriberCount("continued") == 1, "one continued");
C(b.subscriberCount("output") == 0, "zero output");
P();
}
int main(){
std::cout << "Step 1935: DAPEventBroadcaster\n";
t1(); t2(); t3(); t4(); t5();
std::cout << "\n" << p << "/" << (p+f) << " passed\n";
return f > 0 ? 1 : 0;
}