2023-10-25 11:36:20 +03:00

269 lines
5.4 KiB
C++

//
// Created by erki on 12/09/23.
//
#include <catch2/catch.hpp>
#include "cpptick/cpptick.hpp"
#include <chrono>
#include <thread>
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<milliseconds>(system_clock::now().time_since_epoch())
.count());
}
};
}// namespace
TEST_CASE("Slot calls function properly with void args.", "[cpptick]")
{
cpptick::Scheduler<TestHal> scheduler;
cpptick::Slot<void()> 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<TestHal> scheduler;
cpptick::Slot<void(int)> 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<TestHal> scheduler;
cpptick::Slot<void()> 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<TestHal> scheduler;
cpptick::Slot<void()> 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<TestHal> scheduler;
cpptick::Slot<void()> 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<void()> 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;
}