154 lines
5.5 KiB
C++
Executable File
154 lines
5.5 KiB
C++
Executable File
#include <unity.h>
|
|
|
|
#include <vector>
|
|
|
|
#include "PatternEngine.h"
|
|
|
|
using namespace timbre_core;
|
|
|
|
void setUp(void) {}
|
|
void tearDown(void) {}
|
|
|
|
struct OutputEvent {
|
|
RelayId relay;
|
|
bool on;
|
|
};
|
|
|
|
static void test_absolute_deadlines_and_final_off(void) {
|
|
std::vector<OutputEvent> events;
|
|
PatternEngine engine([&events](RelayId relay, bool on) {
|
|
events.push_back(OutputEvent{relay, on});
|
|
});
|
|
const Pattern pattern{PatternId::A, {2, 1, 1, 1}};
|
|
|
|
TEST_ASSERT_TRUE(engine.start(pattern, 1000));
|
|
TEST_ASSERT_TRUE(engine.running());
|
|
TEST_ASSERT_TRUE(engine.outputOn());
|
|
TEST_ASSERT_EQUAL_UINT64(3000, engine.deadlineMs());
|
|
TEST_ASSERT_EQUAL_size_t(1, events.size());
|
|
TEST_ASSERT_TRUE(events[0].on);
|
|
TEST_ASSERT_EQUAL_UINT8(static_cast<std::uint8_t>(RelayId::Main),
|
|
static_cast<std::uint8_t>(events[0].relay));
|
|
|
|
TEST_ASSERT_FALSE(engine.update(2999));
|
|
TEST_ASSERT_TRUE(engine.outputOn());
|
|
TEST_ASSERT_TRUE(engine.update(3000));
|
|
TEST_ASSERT_FALSE(engine.outputOn());
|
|
TEST_ASSERT_EQUAL_UINT8(1, engine.activePhase());
|
|
TEST_ASSERT_EQUAL_UINT64(4000, engine.deadlineMs());
|
|
|
|
TEST_ASSERT_TRUE(engine.update(5000));
|
|
// At 5000 ms the third phase has also reached its boundary; the
|
|
// absolute-deadline engine therefore advances to the final OFF phase.
|
|
TEST_ASSERT_FALSE(engine.outputOn());
|
|
TEST_ASSERT_EQUAL_UINT8(3, engine.activePhase());
|
|
TEST_ASSERT_EQUAL_UINT64(6000, engine.deadlineMs());
|
|
|
|
TEST_ASSERT_TRUE(engine.update(7000));
|
|
TEST_ASSERT_FALSE(engine.running());
|
|
TEST_ASSERT_FALSE(engine.outputOn());
|
|
TEST_ASSERT_EQUAL_UINT8(PatternEngine::kNoPhase, engine.activePhase());
|
|
TEST_ASSERT_EQUAL_size_t(4, events.size());
|
|
TEST_ASSERT_FALSE(events.back().on);
|
|
}
|
|
|
|
static void test_clock_regression_turns_output_off(void) {
|
|
std::vector<OutputEvent> events;
|
|
PatternEngine engine([&events](RelayId relay, bool on) {
|
|
events.push_back({relay, on});
|
|
});
|
|
const Pattern pattern{PatternId::A, {2, 1}};
|
|
|
|
TEST_ASSERT_TRUE(engine.start(pattern, 1000));
|
|
TEST_ASSERT_TRUE(engine.outputOn());
|
|
TEST_ASSERT_TRUE(engine.update(500));
|
|
TEST_ASSERT_FALSE(engine.running());
|
|
TEST_ASSERT_FALSE(engine.outputOn());
|
|
TEST_ASSERT_FALSE(events.empty());
|
|
TEST_ASSERT_FALSE(events.back().on);
|
|
}
|
|
|
|
static void test_late_poll_does_not_accumulate_or_leave_on(void) {
|
|
std::vector<OutputEvent> events;
|
|
PatternEngine engine([&events](RelayId, bool on) { events.push_back({RelayId::Main, on}); });
|
|
const Pattern pattern{PatternId::B, {1, 1, 1, 1, 1, 1}};
|
|
|
|
TEST_ASSERT_TRUE(engine.start(pattern, 10));
|
|
TEST_ASSERT_TRUE(engine.update(1000000));
|
|
TEST_ASSERT_FALSE(engine.running());
|
|
TEST_ASSERT_FALSE(engine.outputOn());
|
|
TEST_ASSERT_EQUAL_UINT64(0, engine.deadlineMs());
|
|
TEST_ASSERT_FALSE(events.empty());
|
|
TEST_ASSERT_FALSE(events.back().on);
|
|
}
|
|
|
|
static void test_fixed_queue_capacity_and_absolute_request_time(void) {
|
|
std::vector<OutputEvent> events;
|
|
PatternEngine engine([&events](RelayId relay, bool on) {
|
|
events.push_back({relay, on});
|
|
});
|
|
const Pattern pattern{PatternId::C, {1, 1}};
|
|
|
|
for (std::size_t i = 0; i < 8; ++i) {
|
|
TEST_ASSERT_TRUE(engine.enqueue(pattern, 1000));
|
|
}
|
|
TEST_ASSERT_EQUAL_size_t(8, engine.queueSize());
|
|
TEST_ASSERT_FALSE(engine.enqueue(pattern, 1000));
|
|
TEST_ASSERT_EQUAL_size_t(8, engine.queueSize());
|
|
TEST_ASSERT_FALSE(engine.running());
|
|
|
|
engine.update(999);
|
|
TEST_ASSERT_FALSE(engine.running());
|
|
TEST_ASSERT_EQUAL_size_t(8, engine.queueSize());
|
|
engine.update(1000);
|
|
TEST_ASSERT_TRUE(engine.running());
|
|
TEST_ASSERT_EQUAL_size_t(7, engine.queueSize());
|
|
TEST_ASSERT_TRUE(engine.outputOn());
|
|
TEST_ASSERT_EQUAL_UINT64(2000, engine.deadlineMs());
|
|
}
|
|
|
|
static void test_invalid_pattern_id_and_zero_phase_are_safe(void) {
|
|
std::vector<OutputEvent> events;
|
|
PatternEngine engine([&events](RelayId relay, bool on) {
|
|
events.push_back({relay, on});
|
|
});
|
|
|
|
TEST_ASSERT_FALSE(engine.start(static_cast<PatternId>(99), 0));
|
|
TEST_ASSERT_FALSE(engine.running());
|
|
TEST_ASSERT_TRUE(events.empty());
|
|
|
|
const Pattern silent{PatternId::A, {0, 0}};
|
|
TEST_ASSERT_TRUE(engine.start(silent, 0));
|
|
TEST_ASSERT_FALSE(engine.running());
|
|
TEST_ASSERT_FALSE(engine.outputOn());
|
|
TEST_ASSERT_EQUAL_size_t(0, events.size());
|
|
}
|
|
|
|
static void test_reserved_gpio_is_never_driven(void) {
|
|
std::vector<OutputEvent> events;
|
|
PatternEngine engine([&events](RelayId relay, bool on) {
|
|
events.push_back({relay, on});
|
|
});
|
|
const Pattern pattern{PatternId::A, {1, 1}};
|
|
TEST_ASSERT_TRUE(engine.start(pattern, 0));
|
|
TEST_ASSERT_TRUE(engine.update(2000));
|
|
TEST_ASSERT_FALSE(engine.reservedRelayDriven());
|
|
TEST_ASSERT_EQUAL_UINT8(static_cast<std::uint8_t>(RelayId::Main),
|
|
static_cast<std::uint8_t>(engine.lastOutputRelay()));
|
|
for (const OutputEvent& event : events) {
|
|
TEST_ASSERT_EQUAL_UINT8(static_cast<std::uint8_t>(RelayId::Main),
|
|
static_cast<std::uint8_t>(event.relay));
|
|
}
|
|
}
|
|
|
|
int main(int, char**) {
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_absolute_deadlines_and_final_off);
|
|
RUN_TEST(test_clock_regression_turns_output_off);
|
|
RUN_TEST(test_late_poll_does_not_accumulate_or_leave_on);
|
|
RUN_TEST(test_fixed_queue_capacity_and_absolute_request_time);
|
|
RUN_TEST(test_invalid_pattern_id_and_zero_phase_are_safe);
|
|
RUN_TEST(test_reserved_gpio_is_never_driven);
|
|
return UNITY_END();
|
|
}
|