#include #include #include #include #include #include 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(&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 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(cb, "1", ph::_1)); r.schedule(hours(11), std::bind(cb, "2", ph::_1)); r.schedule(hours(11), std::bind(cb, "2", ph::_1)); r.schedule(hours(5), std::bind(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(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 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 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(cb, 'a', ph::_1)); r.schedule(minutes(4), std::bind(cb, 'b', ph::_1), &foo); r.schedule(minutes(5), std::bind(cb, 'c', ph::_1)); r.schedule(minutes(3), std::bind(cb, 'd', ph::_1), &bar); r.schedule(minutes(4), std::bind(cb, 'e', ph::_1)); r.schedule(minutes(5), std::bind(cb, 'f', ph::_1), &foo); r.schedule(minutes(6), std::bind(cb, 'g', ph::_1), &doe); r.schedule(minutes(7), std::bind(cb, 'h', ph::_1), nullptr); // cancel single callback r.cancel(&bar); r.trigger(minutes(8)); EXPECT_EQ((std::vector {'a', 'b', 'e', 'c', 'f', 'g', 'h'}), calls); // cancel several callbacks calls.clear(); r.schedule(minutes(1), std::bind(cb, 'a', ph::_1), &foo); r.schedule(minutes(1), std::bind(cb, 'b', ph::_1), &bar); r.schedule(minutes(1), std::bind(cb, 'c', ph::_1), &bar); r.schedule(minutes(1), std::bind(cb, 'd', ph::_1), &foo); r.cancel(&foo); r.trigger(minutes(1)); EXPECT_EQ((std::vector {'b', 'c'}), calls); } TEST(ManualRuntime, scope) { ManualRuntime r; std::vector 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(cb, 'a', ph::_1), &scope1); r.schedule(minutes(1), std::bind(cb, 'b', ph::_1), &scope2); r.schedule(minutes(2), std::bind(cb, 'c', ph::_1)); r.schedule(minutes(5), std::bind(cb, 'd', ph::_1), &scope1); r.schedule(minutes(4), std::bind(cb, 'e', ph::_1), &scope2); r.schedule(minutes(6), std::bind(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 {'b', 'c'}), calls); calls.clear(); // canceling nullptr scope has no effect r.cancel(nullptr); r.trigger(minutes(10)); EXPECT_EQ((std::vector {'e', 'f'}), calls); }