// // Created by erki on 12/09/23. // #include #include "cpptick/cpptick.hpp" #include #include using namespace std::chrono_literals; namespace { int callback_count = 0; void callbackByOne() { callback_count += 1; } void callbackByN(int to_add) { callback_count += to_add; } struct TestHal { static std::uint32_t getMillis() { using std::chrono::duration_cast; using std::chrono::milliseconds; using std::chrono::system_clock; return std::uint32_t( duration_cast(system_clock::now().time_since_epoch()) .count() ); } }; } TEST_CASE("Slot calls function properly with void args.", "[cpptick]") { cpptick::Scheduler scheduler; cpptick::Slot slot(&scheduler); auto* f = slot.connect(callbackByOne); callback_count = 0; REQUIRE(callback_count == 0); SECTION("invoke() calls the slot appropriately.") { slot.invoke(); CHECK(callback_count == 0); scheduler.tick(); CHECK(callback_count == 1); SECTION("Second tick doesn't invoke the slot again.") { scheduler.tick(); CHECK(callback_count == 1); } SECTION("Second invoke() will call the slot again.") { slot.invoke(); scheduler.tick(); CHECK(callback_count == 2); } } SECTION("Multiple calls queue properly.") { const int count = 3; for (int i = 0; i < count; i++) { slot.invoke(); } for (int i = 0; i < count; i++) { CHECK(callback_count == i); scheduler.tick(); CHECK(callback_count == i + 1); } } delete f; } TEST_CASE("Slot calls function properly with args.", "[cpptick]") { cpptick::Scheduler scheduler; cpptick::Slot slot(&scheduler); auto* f = slot.connect(callbackByN); callback_count = 0; REQUIRE(callback_count == 0); SECTION("invoke() passes argument appropriately.") { const int to_add = 5; slot.invoke(to_add); CHECK(callback_count == 0); scheduler.tick(); CHECK(callback_count == to_add); } delete f; } TEST_CASE("Timer will be invoked.", "[cpptick]") { cpptick::Scheduler scheduler; cpptick::Slot slot(&scheduler); auto* f = slot.connect(callbackByOne); callback_count = 0; REQUIRE(callback_count == 0); cpptick::Timer timer(&scheduler, 100, cpptick::Timer::ONE_SHOT); timer.setSlot(slot); SECTION("Timer will be invoked after 100 milliseconds.") { timer.start(); scheduler.tick(); CHECK(callback_count == 0); SECTION("Timer won't be executed prematurely.") { std::this_thread::sleep_for(80ms); scheduler.tick(); CHECK(callback_count == 0); } SECTION("Time will be executed after period elapsed.") { std::this_thread::sleep_for(110ms); scheduler.tick(); CHECK(callback_count == 1); SECTION("Single shot timer isn't executed again.") { CHECK(callback_count == 1); std::this_thread::sleep_for(110ms); scheduler.tick(); CHECK(callback_count == 1); } } } SECTION("An unstarted timer does not run.") { scheduler.tick(); CHECK(callback_count == 0); std::this_thread::sleep_for(110ms); scheduler.tick(); CHECK(callback_count == 0); } delete f; } TEST_CASE("Periodic timers will be invoked repeatedly.", "[cpptick]") { cpptick::Scheduler scheduler; cpptick::Slot slot(&scheduler); auto* f = slot.connect(callbackByOne); callback_count = 0; REQUIRE(callback_count == 0); cpptick::Timer timer(&scheduler, 100, cpptick::Timer::PERIODIC); timer.setSlot(slot); SECTION("Timer will be invoked after 100 milliseconds.") { timer.start(); scheduler.tick(); CHECK(callback_count == 0); SECTION("Timer won't be executed prematurely.") { std::this_thread::sleep_for(80ms); scheduler.tick(); CHECK(callback_count == 0); } SECTION("Time will be executed after period elapsed.") { std::this_thread::sleep_for(110ms); scheduler.tick(); CHECK(callback_count == 1); SECTION("Periodic timer is executed again.") { CHECK(callback_count == 1); std::this_thread::sleep_for(110ms); scheduler.tick(); CHECK(callback_count == 2); } } } delete f; } TEST_CASE("Sequential timers operate appropriately.", "[cpptick]") { cpptick::Scheduler scheduler; cpptick::Slot slot_a(&scheduler); auto* f = slot_a.connect(callbackByOne); cpptick::Timer timer_a(&scheduler, 100, cpptick::Timer::PERIODIC); timer_a.setSlot(slot_a); auto callback_by_two = []() -> void { callback_count += 2; }; cpptick::Slot slot_b(&scheduler); auto* ff = slot_b.connect(callback_by_two); cpptick::Timer timer_b(&scheduler, 50, cpptick::Timer::ONE_SHOT); timer_b.setSlot(slot_b); callback_count = 0; REQUIRE(callback_count == 0); timer_a.start(); timer_b.start(); SECTION("Shorter timer is called first.", "[cpptick]") { std::this_thread::sleep_for(60ms); scheduler.tick(); CHECK(callback_count == 2); scheduler.tick(); CHECK(callback_count == 2); SECTION("Longer timer is executed afterwards.", "[cpptick]") { std::this_thread::sleep_for(50ms); scheduler.tick(); CHECK(callback_count == 3); } } delete f; delete ff; }