Files
MicrOBU/microbu-esp32c5/external/vanetza-idf/vanetza/common/tests/manual_runtime.cpp
T
Ashin Walpola 0e9525162d Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
2026-09-23 17:46:40 +02:00

200 lines
5.7 KiB
C++

#include <gtest/gtest.h>
#include <vanetza/common/manual_runtime.hpp>
#include <chrono>
#include <functional>
#include <string>
#include <vector>
using namespace vanetza;
using std::chrono::hours;
using std::chrono::minutes;
using std::chrono::seconds;
TEST(ManualRuntime, default_construction)
{
ManualRuntime r;
EXPECT_EQ(std::chrono::milliseconds(0), r.now().time_since_epoch());
}
TEST(ManualRuntime, time_progress_absolute)
{
ManualRuntime r;
const Clock::time_point t1 { hours(27) };
r.trigger(t1);
EXPECT_EQ(t1, r.now());
const Clock::time_point t2 { hours(28) };
r.trigger(t2);
EXPECT_EQ(t2, r.now());
}
TEST(ManualRuntime, time_progress_relative)
{
ManualRuntime r;
r.trigger(hours(3));
EXPECT_EQ(Clock::time_point { hours(3) }, r.now());
r.trigger(hours(2));
EXPECT_EQ(Clock::time_point { hours(5) }, r.now());
}
TEST(ManualRuntime, sorting)
{
ManualRuntime r;
r.trigger(hours(3));
EXPECT_EQ(Clock::time_point::max(), r.next());
auto cb = [](Clock::time_point) {};
const auto tp1 = Clock::time_point { hours(2) };
static_cast<Runtime*>(&r)->schedule(tp1, cb);
EXPECT_EQ(tp1, r.next());
r.schedule(Clock::time_point { hours(3) }, cb);
EXPECT_EQ(tp1, r.next());
const auto tp2 = Clock::time_point { hours(1) };
r.schedule(tp2, cb);
EXPECT_EQ(tp2, r.next());
r.schedule(minutes(30), cb);
EXPECT_EQ(tp2, r.next());
}
TEST(ManualRuntime, scheduling)
{
ManualRuntime r;
r.trigger(hours(5));
namespace ph = std::placeholders;
std::string seq;
std::vector<Clock::time_point> deadlines;
auto cb = [&seq, &deadlines](const char* str, Clock::time_point deadline) {
deadlines.push_back(deadline);
seq.append(str);
};
r.schedule(hours(10), std::bind<void>(cb, "1", ph::_1));
r.schedule(hours(11), std::bind<void>(cb, "2", ph::_1));
r.schedule(hours(11), std::bind<void>(cb, "2", ph::_1));
r.schedule(hours(5), std::bind<void>(cb, "3", ph::_1));
r.trigger(hours(4));
EXPECT_EQ("", seq);
r.trigger(hours(1));
EXPECT_EQ("3", seq);
r.trigger(hours(5));
EXPECT_EQ("31", seq);
// schedule expired callback (immediate invocation at next trigger)
r.schedule(Clock::time_point { hours(2) }, std::bind<void>(cb, "4", ph::_1));
r.trigger(hours(0));
EXPECT_EQ("314", seq);
r.trigger(hours(5));
EXPECT_EQ("31422", seq);
r.trigger(Clock::time_point::max());
EXPECT_EQ("31422", seq);
const std::vector<Clock::time_point> expected_deadlines = {
Clock::time_point { hours(10) },
Clock::time_point { hours(15) },
Clock::time_point { hours(2) },
Clock::time_point { hours(16) },
Clock::time_point { hours(16) },
};
EXPECT_EQ(expected_deadlines, deadlines);
}
TEST(ManualRuntime, reset)
{
ManualRuntime r;
unsigned calls = 0;
auto cb = [&calls](Clock::time_point) { ++calls; };
r.trigger(hours(23));
for (unsigned i = 10; i < 100; ++i) {
r.schedule(seconds(i), cb);
}
r.trigger(seconds(9));
EXPECT_EQ(0, calls);
r.trigger(seconds(2));
EXPECT_EQ(2, calls);
EXPECT_EQ(Clock::time_point { hours(23) + seconds(11) }, r.now());
r.reset(Clock::time_point { hours(10) });
EXPECT_EQ(Clock::time_point { hours(10) }, r.now());
EXPECT_EQ(90, calls);
r.trigger(Clock::duration::max());
EXPECT_EQ(90, calls);
}
TEST(ManualRuntime, cancel)
{
ManualRuntime r;
std::vector<char> calls;
auto cb = [&calls](char c, Clock::time_point) { calls.push_back(c); };
// some dummy scopes
const int foo = 1;
const int bar = 2;
const int doe = 3;
namespace ph = std::placeholders;
r.schedule(minutes(3), std::bind<void>(cb, 'a', ph::_1));
r.schedule(minutes(4), std::bind<void>(cb, 'b', ph::_1), &foo);
r.schedule(minutes(5), std::bind<void>(cb, 'c', ph::_1));
r.schedule(minutes(3), std::bind<void>(cb, 'd', ph::_1), &bar);
r.schedule(minutes(4), std::bind<void>(cb, 'e', ph::_1));
r.schedule(minutes(5), std::bind<void>(cb, 'f', ph::_1), &foo);
r.schedule(minutes(6), std::bind<void>(cb, 'g', ph::_1), &doe);
r.schedule(minutes(7), std::bind<void>(cb, 'h', ph::_1), nullptr);
// cancel single callback
r.cancel(&bar);
r.trigger(minutes(8));
EXPECT_EQ((std::vector<char> {'a', 'b', 'e', 'c', 'f', 'g', 'h'}), calls);
// cancel several callbacks
calls.clear();
r.schedule(minutes(1), std::bind<void>(cb, 'a', ph::_1), &foo);
r.schedule(minutes(1), std::bind<void>(cb, 'b', ph::_1), &bar);
r.schedule(minutes(1), std::bind<void>(cb, 'c', ph::_1), &bar);
r.schedule(minutes(1), std::bind<void>(cb, 'd', ph::_1), &foo);
r.cancel(&foo);
r.trigger(minutes(1));
EXPECT_EQ((std::vector<char> {'b', 'c'}), calls);
}
TEST(ManualRuntime, scope)
{
ManualRuntime r;
std::vector<char> calls;
auto cb = [&calls](char c, Clock::time_point) { calls.push_back(c); };
int scope1, scope2;
namespace ph = std::placeholders;
r.schedule(minutes(3), std::bind<void>(cb, 'a', ph::_1), &scope1);
r.schedule(minutes(1), std::bind<void>(cb, 'b', ph::_1), &scope2);
r.schedule(minutes(2), std::bind<void>(cb, 'c', ph::_1));
r.schedule(minutes(5), std::bind<void>(cb, 'd', ph::_1), &scope1);
r.schedule(minutes(4), std::bind<void>(cb, 'e', ph::_1), &scope2);
r.schedule(minutes(6), std::bind<void>(cb, 'f', ph::_1), "");
// cancel scope 1 and trigger all callbacks within 3 minutes
r.cancel(&scope1);
r.trigger(minutes(3));
EXPECT_EQ((std::vector<char> {'b', 'c'}), calls);
calls.clear();
// canceling nullptr scope has no effect
r.cancel(nullptr);
r.trigger(minutes(10));
EXPECT_EQ((std::vector<char> {'e', 'f'}), calls);
}