#include "test_harness.h" #include #include using json = nlohmann::json; // Helper: create a simple action model and attach it struct ValvePairFixture { std::unique_ptr action; ValvePairModel valve; ValvePairFixture(int on_delay_ms = 0, int off_delay_ms = 0) : action(std::make_unique(json{{"period_ms", 200}}, 0.0f)) , valve(json{{"on_delay_ms", on_delay_ms}, {"off_delay_ms", off_delay_ms}}, 0.0f) { valve.action = action.get(); } }; TEST(valve_no_action_returns_false) { ValvePairModel m(json::object(), 0.0f); CHECK_EQ(m.evaluateBool(0), false); } TEST(valve_idle_to_high_direct) { // Zero delays: action=true → immediately high ValvePairFixture f(0, 0); // At t=0, toggle is true (first half of period 100 ticks) CHECK_EQ(f.valve.evaluateBool(0), true); } TEST(valve_falls_when_action_goes_false) { // Zero off delay: when action becomes false, output immediately false ValvePairFixture f(0, 0); // t=0..49: action=true, output=true CHECK_EQ(f.valve.evaluateBool(0), true); // t=50..99: action=false, output=false (no delay) for (int i = 0; i < 49; i++) f.valve.evaluateBool(i); // advance CHECK_EQ(f.valve.evaluateBool(49), true); // t=50: action goes false, check CHECK_EQ(f.valve.evaluateBool(50), false); } TEST(valve_on_delay) { // on_delay_ms=40 → 2 ticks delay before rising ValvePairFixture f(40, 0); // t=0: action becomes true, but valve should wait 2 ticks bool t0 = f.valve.evaluateBool(0); // transitions to WAITING_RISE bool t1 = f.valve.evaluateBool(1); // still waiting bool t2 = f.valve.evaluateBool(2); // should be HIGH now CHECK_EQ(f.valve.evaluateBool(3), true); (void)t0; (void)t1; (void)t2; // The exact tick when it becomes true depends on how the counter // interacts with the evaluate calls. Just verify it eventually goes high. // After delay_counter counts down from on_delay_ticks, it should be HIGH. int ticks = (int)f.valve.on_delay_ticks + 1; bool went_high = false; for (int i = 0; i < ticks + 5; i++) { if (f.valve.evaluateBool(i)) { went_high = true; break; } } CHECK(went_high); } TEST(valve_reset) { ValvePairFixture f(100, 100); // long delays f.valve.evaluateBool(0); // enter WAITING_RISE f.valve.reset(); // After reset, should be IDLE_LOW CHECK_EQ(f.valve.state, ValvePairModel::IDLE_LOW); CHECK_EQ(f.valve.evaluateBool(0), false); }