#include #include #include #include "service_manager.h" using namespace roro; void setUp() {} void tearDown() {} struct FakeService : Service { FakeService(const char* n, uint32_t interval, std::vector* log) : n_(n), interval_(interval), log_(log) {} const char* name() const override { return n_; } uint32_t tickIntervalMs() const override { return interval_; } void start() override { log_->push_back(std::string("start ") + n_); } void stop() override { log_->push_back(std::string("stop ") + n_); } void tick(uint32_t nowMs) override { ticks.push_back(nowMs); log_->push_back(std::string("tick ") + n_); } std::vector ticks; private: const char* n_; uint32_t interval_; std::vector* log_; }; void test_services_start_in_order_and_stop_in_reverse() { std::vector log; FakeService a("a", 100, &log), b("b", 100, &log); ServiceManager m; m.add(a); m.add(b); m.startAll(0); m.stopAll(); std::vector expected = {"start a", "start b", "stop b", "stop a"}; TEST_ASSERT_TRUE(log == expected); } void test_service_ticks_immediately_after_start_then_at_its_interval() { std::vector log; FakeService s("s", 100, &log); ServiceManager m; m.add(s); m.startAll(0); for (uint32_t t = 0; t <= 250; t += 10) m.tick(t); TEST_ASSERT_EQUAL(3, s.ticks.size()); TEST_ASSERT_EQUAL(0, s.ticks[0]); TEST_ASSERT_EQUAL(100, s.ticks[1]); TEST_ASSERT_EQUAL(200, s.ticks[2]); } void test_each_service_keeps_its_own_interval() { std::vector log; FakeService fast("fast", 10, &log), slow("slow", 100, &log); ServiceManager m; m.add(fast); m.add(slow); m.startAll(0); for (uint32_t t = 0; t < 100; t += 10) m.tick(t); TEST_ASSERT_EQUAL(10, fast.ticks.size()); TEST_ASSERT_EQUAL(1, slow.ticks.size()); } void test_late_tick_does_not_cause_a_burst_of_catch_up_ticks() { std::vector log; FakeService s("s", 100, &log); ServiceManager m; m.add(s); m.startAll(0); m.tick(0); m.tick(1000); // UI stalled for a second m.tick(1010); TEST_ASSERT_EQUAL(2, s.ticks.size()); } void test_ticking_survives_millis_wraparound() { std::vector log; FakeService s("s", 100, &log); ServiceManager m; m.add(s); const uint32_t nearWrap = 0xFFFFFFFFu - 50; m.startAll(nearWrap); m.tick(nearWrap); m.tick(nearWrap + 60); // wrapped, only 60 ms elapsed m.tick(nearWrap + 100); // wrapped, 100 ms elapsed TEST_ASSERT_EQUAL(2, s.ticks.size()); } void test_services_are_not_ticked_before_start_or_after_stop() { std::vector log; FakeService s("s", 10, &log); ServiceManager m; m.add(s); m.tick(0); m.startAll(0); m.stopAll(); m.tick(100); TEST_ASSERT_EQUAL(0, s.ticks.size()); } int main() { UNITY_BEGIN(); RUN_TEST(test_services_start_in_order_and_stop_in_reverse); RUN_TEST(test_service_ticks_immediately_after_start_then_at_its_interval); RUN_TEST(test_each_service_keeps_its_own_interval); RUN_TEST(test_late_tick_does_not_cause_a_burst_of_catch_up_ticks); RUN_TEST(test_ticking_survives_millis_wraparound); RUN_TEST(test_services_are_not_ticked_before_start_or_after_stop); return UNITY_END(); }