mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 22:02:17 +01:00
The delay was counted from when the job was queued. The stop at the target is queued just before the favorite and is on air for about 245ms, so the 200ms settle delay had run out before the favorite's turn and only the 100ms beat between jobs was left. A delayed job now waits its delay after whichever came later: being queued, or the job ahead of it going off air. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
463 lines
17 KiB
C++
463 lines
17 KiB
C++
#include <unity.h>
|
|
#include "RadioScheduler.h"
|
|
|
|
static const uint32_t REMOTE_A = 0x111111;
|
|
static const uint32_t REMOTE_B = 0x222222;
|
|
|
|
void setUp() {}
|
|
void tearDown() {}
|
|
|
|
static somfy_tx_job_t makeJob(uint32_t remoteAddress, somfy_commands cmd = somfy_commands::Up) {
|
|
somfy_tx_job_t job;
|
|
job.frame.remoteAddress = remoteAddress;
|
|
job.frame.cmd = cmd;
|
|
job.repeats = 2;
|
|
return job;
|
|
}
|
|
static uint32_t submit(RadioScheduler &s, uint32_t remoteAddress, uint32_t now = 0, bool priority = false, uint16_t delayMs = 0) {
|
|
somfy_tx_job_t job = makeJob(remoteAddress, priority ? somfy_commands::My : somfy_commands::Up);
|
|
return s.submit(job, priority, delayMs, now);
|
|
}
|
|
// Takes the next job and sends all of it, as the radio task does. Returns its
|
|
// ticket, 0 when none is due.
|
|
static uint32_t runNext(RadioScheduler &s, uint32_t now = 0) {
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
if(!s.next(now, job, waitMs)) return 0;
|
|
if(!s.start(job.seq, now)) return job.seq;
|
|
s.ended(job.seq, true, now);
|
|
return job.seq;
|
|
}
|
|
static void assertEvent(RadioScheduler &s, tx_event_t type, uint32_t ticket) {
|
|
somfy_tx_event_t evt;
|
|
TEST_ASSERT_TRUE_MESSAGE(s.popEvent(evt), "expected another event");
|
|
TEST_ASSERT_EQUAL_UINT8((uint8_t)type, (uint8_t)evt.type);
|
|
TEST_ASSERT_EQUAL_UINT32(ticket, evt.seq);
|
|
}
|
|
static void assertNoEvents(RadioScheduler &s) {
|
|
somfy_tx_event_t evt;
|
|
TEST_ASSERT_FALSE(s.popEvent(evt));
|
|
}
|
|
static void discardEvents(RadioScheduler &s) {
|
|
somfy_tx_event_t evt;
|
|
while(s.popEvent(evt)) {}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Order
|
|
********************************************************************/
|
|
static void test_jobs_go_out_in_the_order_they_came() {
|
|
RadioScheduler s;
|
|
const uint32_t a = submit(s, REMOTE_A);
|
|
const uint32_t b = submit(s, REMOTE_B);
|
|
const uint32_t c = submit(s, REMOTE_A);
|
|
TEST_ASSERT_NOT_EQUAL(0, a);
|
|
TEST_ASSERT_EQUAL_UINT32(a, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(b, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(c, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(0, runNext(s));
|
|
}
|
|
static void test_tickets_are_distinct_and_set_in_the_job() {
|
|
RadioScheduler s;
|
|
somfy_tx_job_t job = makeJob(REMOTE_A);
|
|
const uint32_t a = s.submit(job, false, 0, 0);
|
|
TEST_ASSERT_EQUAL_UINT32(a, job.seq);
|
|
TEST_ASSERT_NOT_EQUAL(a, submit(s, REMOTE_A));
|
|
}
|
|
static void test_nothing_waiting_sleeps_until_woken() {
|
|
RadioScheduler s;
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs = 0;
|
|
TEST_ASSERT_FALSE(s.next(0, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(RADIO_WAIT_FOREVER, waitMs);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Stops (priority jobs)
|
|
********************************************************************/
|
|
static void test_stop_goes_ahead_of_other_remotes() {
|
|
RadioScheduler s;
|
|
const uint32_t b1 = submit(s, REMOTE_B);
|
|
const uint32_t b2 = submit(s, REMOTE_B);
|
|
const uint32_t stop = submit(s, REMOTE_A, 0, true);
|
|
TEST_ASSERT_EQUAL_UINT32(stop, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(b1, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(b2, runNext(s));
|
|
}
|
|
static void test_stop_queues_behind_its_own_remote() {
|
|
// Overtaking the remote's waiting frame would send the rolling codes out of
|
|
// order and the motor would reject the older one.
|
|
RadioScheduler s;
|
|
const uint32_t up = submit(s, REMOTE_A);
|
|
const uint32_t b = submit(s, REMOTE_B);
|
|
const uint32_t stop = submit(s, REMOTE_A, 0, true);
|
|
TEST_ASSERT_EQUAL_UINT32(up, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(b, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(stop, runNext(s));
|
|
}
|
|
static void test_stop_goes_ahead_once_its_remote_is_on_air() {
|
|
RadioScheduler s;
|
|
const uint32_t up = submit(s, REMOTE_A);
|
|
const uint32_t b = submit(s, REMOTE_B);
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
TEST_ASSERT_TRUE(s.next(0, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(up, job.seq);
|
|
// The remote's frame is already going out so the stop can't overtake it.
|
|
const uint32_t stop = submit(s, REMOTE_A, 0, true);
|
|
s.start(up, 0);
|
|
s.ended(up, true, 0);
|
|
TEST_ASSERT_EQUAL_UINT32(stop, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(b, runNext(s));
|
|
}
|
|
static void test_stops_go_out_in_the_order_they_came() {
|
|
RadioScheduler s;
|
|
const uint32_t back = submit(s, REMOTE_B);
|
|
const uint32_t stopA = submit(s, REMOTE_A, 0, true);
|
|
const uint32_t stopC = submit(s, 0x333333, 0, true);
|
|
TEST_ASSERT_EQUAL_UINT32(stopA, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(stopC, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(back, runNext(s));
|
|
}
|
|
static void test_second_stop_of_a_remote_stays_behind_the_first() {
|
|
RadioScheduler s;
|
|
const uint32_t back = submit(s, REMOTE_B);
|
|
const uint32_t first = submit(s, REMOTE_A, 0, true);
|
|
const uint32_t second = submit(s, REMOTE_A, 0, true);
|
|
TEST_ASSERT_EQUAL_UINT32(first, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(back, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(second, runNext(s));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Room
|
|
********************************************************************/
|
|
static void test_normal_jobs_leave_the_reserved_slots() {
|
|
RadioScheduler s;
|
|
for(uint8_t i = 0; i < TX_JOB_QUEUE_SIZE - TX_RESERVED_SLOTS; i++)
|
|
TEST_ASSERT_NOT_EQUAL(0, submit(s, REMOTE_B));
|
|
TEST_ASSERT_FALSE(s.hasRoom(false));
|
|
TEST_ASSERT_TRUE(s.hasRoom(true));
|
|
TEST_ASSERT_EQUAL_UINT32(0, submit(s, REMOTE_B));
|
|
}
|
|
static void test_stops_use_the_reserved_slots() {
|
|
RadioScheduler s;
|
|
for(uint8_t i = 0; i < TX_JOB_QUEUE_SIZE - TX_RESERVED_SLOTS; i++) submit(s, REMOTE_B);
|
|
for(uint8_t i = 0; i < TX_RESERVED_SLOTS; i++)
|
|
TEST_ASSERT_NOT_EQUAL(0, submit(s, REMOTE_A, 0, true));
|
|
TEST_ASSERT_FALSE(s.hasRoom(true));
|
|
TEST_ASSERT_EQUAL_UINT32(0, submit(s, REMOTE_A, 0, true));
|
|
}
|
|
static void test_a_refused_job_has_no_ticket() {
|
|
RadioScheduler s;
|
|
for(uint8_t i = 0; i < TX_JOB_QUEUE_SIZE - TX_RESERVED_SLOTS; i++) submit(s, REMOTE_B);
|
|
somfy_tx_job_t job = makeJob(REMOTE_A);
|
|
job.seq = 99;
|
|
TEST_ASSERT_EQUAL_UINT32(0, s.submit(job, false, 0, 0));
|
|
TEST_ASSERT_EQUAL_UINT32(0, job.seq);
|
|
}
|
|
static void test_taking_a_job_frees_its_slot() {
|
|
RadioScheduler s;
|
|
for(uint8_t i = 0; i < TX_JOB_QUEUE_SIZE - TX_RESERVED_SLOTS; i++) submit(s, REMOTE_B);
|
|
runNext(s);
|
|
TEST_ASSERT_TRUE(s.hasRoom(false));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Delayed jobs
|
|
********************************************************************/
|
|
static void test_delayed_job_waits_until_due() {
|
|
RadioScheduler s;
|
|
const uint32_t a = submit(s, REMOTE_A, 1000, false, 500);
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
TEST_ASSERT_FALSE(s.next(1000, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(500, waitMs);
|
|
TEST_ASSERT_FALSE(s.next(1400, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(100, waitMs);
|
|
TEST_ASSERT_TRUE(s.next(1500, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(a, job.seq);
|
|
}
|
|
static void test_delayed_job_holds_up_the_jobs_behind_it() {
|
|
RadioScheduler s;
|
|
const uint32_t a = submit(s, REMOTE_A, 0, false, 500);
|
|
const uint32_t b = submit(s, REMOTE_B);
|
|
TEST_ASSERT_EQUAL_UINT32(0, runNext(s, 100));
|
|
TEST_ASSERT_EQUAL_UINT32(a, runNext(s, 500));
|
|
TEST_ASSERT_EQUAL_UINT32(b, runNext(s, 500));
|
|
}
|
|
static void test_stop_overtakes_a_delayed_job_of_another_remote() {
|
|
RadioScheduler s;
|
|
const uint32_t a = submit(s, REMOTE_A, 0, false, 500);
|
|
const uint32_t stop = submit(s, REMOTE_B, 100, true);
|
|
TEST_ASSERT_EQUAL_UINT32(stop, runNext(s, 100));
|
|
// The stop went off air at 100 so the delay starts again from there.
|
|
TEST_ASSERT_EQUAL_UINT32(0, runNext(s, 500));
|
|
TEST_ASSERT_EQUAL_UINT32(a, runNext(s, 600));
|
|
}
|
|
static void test_delay_counts_from_the_job_ahead_going_off_air() {
|
|
// The stop at the target is queued just before the favorite and is on air
|
|
// longer than the favorite's delay.
|
|
RadioScheduler s;
|
|
const uint32_t stop = submit(s, REMOTE_A, 0, true);
|
|
const uint32_t setMy = submit(s, REMOTE_A, 0, false, 200);
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
TEST_ASSERT_TRUE(s.next(0, job, waitMs));
|
|
TEST_ASSERT_TRUE(s.start(stop, 0));
|
|
s.ended(stop, true, 250);
|
|
TEST_ASSERT_FALSE(s.next(350, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(100, waitMs);
|
|
TEST_ASSERT_TRUE(s.next(450, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(setMy, job.seq);
|
|
}
|
|
static void test_delay_ignores_a_job_that_ended_before_it_was_queued() {
|
|
RadioScheduler s;
|
|
submit(s, REMOTE_B, 0);
|
|
runNext(s, 50);
|
|
const uint32_t a = submit(s, REMOTE_A, 100, false, 200);
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
TEST_ASSERT_FALSE(s.next(100, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(200, waitMs);
|
|
TEST_ASSERT_TRUE(s.next(300, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(a, job.seq);
|
|
}
|
|
static void test_delay_after_a_job_ended_across_millis_wrap() {
|
|
RadioScheduler s;
|
|
const uint32_t stop = submit(s, REMOTE_A, 0xFFFFFF00u, true);
|
|
const uint32_t setMy = submit(s, REMOTE_A, 0xFFFFFF00u, false, 0x100);
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
s.next(0xFFFFFF00u, job, waitMs);
|
|
s.start(stop, 0xFFFFFF00u);
|
|
s.ended(stop, true, 0x80);
|
|
TEST_ASSERT_FALSE(s.next(0x100, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(0x80, waitMs);
|
|
TEST_ASSERT_TRUE(s.next(0x180, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(setMy, job.seq);
|
|
}
|
|
static void test_stop_waits_behind_its_remotes_delayed_job() {
|
|
// The favorite's long press holds a rolling code, so the stop can't go first.
|
|
RadioScheduler s;
|
|
const uint32_t setMy = submit(s, REMOTE_A, 0, false, 500);
|
|
const uint32_t stop = submit(s, REMOTE_A, 100, true);
|
|
TEST_ASSERT_EQUAL_UINT32(0, runNext(s, 100));
|
|
TEST_ASSERT_EQUAL_UINT32(setMy, runNext(s, 500));
|
|
TEST_ASSERT_EQUAL_UINT32(stop, runNext(s, 500));
|
|
}
|
|
static void test_delay_across_millis_wrap() {
|
|
RadioScheduler s;
|
|
const uint32_t a = submit(s, REMOTE_A, 0xFFFFFF00u, false, 0x200);
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
TEST_ASSERT_FALSE(s.next(0xFFFFFF00u, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(0x200, waitMs);
|
|
TEST_ASSERT_FALSE(s.next(0x50, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(0xB0, waitMs);
|
|
TEST_ASSERT_TRUE(s.next(0x100, job, waitMs));
|
|
TEST_ASSERT_EQUAL_UINT32(a, job.seq);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Outcomes
|
|
********************************************************************/
|
|
static void test_job_reports_started_then_finished() {
|
|
RadioScheduler s;
|
|
const uint32_t a = submit(s, REMOTE_A);
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
s.next(10, job, waitMs);
|
|
TEST_ASSERT_TRUE(s.start(a, 20));
|
|
TEST_ASSERT_TRUE(s.keepSending(a));
|
|
s.ended(a, true, 300);
|
|
somfy_tx_event_t evt;
|
|
TEST_ASSERT_TRUE(s.popEvent(evt));
|
|
TEST_ASSERT_EQUAL_UINT8((uint8_t)tx_event_t::started, (uint8_t)evt.type);
|
|
TEST_ASSERT_EQUAL_UINT32(a, evt.seq);
|
|
TEST_ASSERT_EQUAL_UINT32(20, evt.at);
|
|
TEST_ASSERT_EQUAL_UINT32(REMOTE_A, evt.remoteAddress);
|
|
TEST_ASSERT_EQUAL_UINT8((uint8_t)somfy_commands::Up, (uint8_t)evt.cmd);
|
|
TEST_ASSERT_TRUE(s.popEvent(evt));
|
|
TEST_ASSERT_EQUAL_UINT8((uint8_t)tx_event_t::finished, (uint8_t)evt.type);
|
|
TEST_ASSERT_EQUAL_UINT32(300, evt.at);
|
|
assertNoEvents(s);
|
|
}
|
|
static void test_cut_short_job_reports_aborted() {
|
|
RadioScheduler s;
|
|
const uint32_t a = submit(s, REMOTE_A);
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
s.next(0, job, waitMs);
|
|
s.start(a, 0);
|
|
s.ended(a, false, 0);
|
|
assertEvent(s, tx_event_t::started, a);
|
|
assertEvent(s, tx_event_t::aborted, a);
|
|
assertNoEvents(s);
|
|
}
|
|
static void test_flush_drops_every_waiting_job_once() {
|
|
RadioScheduler s;
|
|
const uint32_t a = submit(s, REMOTE_A);
|
|
const uint32_t stop = submit(s, REMOTE_B, 0, true);
|
|
const uint32_t delayed = submit(s, REMOTE_A, 0, false, 5000);
|
|
s.flush(0);
|
|
assertEvent(s, tx_event_t::dropped, stop);
|
|
assertEvent(s, tx_event_t::dropped, a);
|
|
assertEvent(s, tx_event_t::dropped, delayed);
|
|
assertNoEvents(s);
|
|
TEST_ASSERT_EQUAL_UINT32(0, runNext(s, 5000));
|
|
}
|
|
static void test_flush_cuts_short_the_job_on_air() {
|
|
RadioScheduler s;
|
|
const uint32_t a = submit(s, REMOTE_A);
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
s.next(0, job, waitMs);
|
|
s.start(a, 0);
|
|
s.flush(0);
|
|
TEST_ASSERT_FALSE(s.keepSending(a));
|
|
s.ended(a, false, 0);
|
|
assertEvent(s, tx_event_t::started, a);
|
|
assertEvent(s, tx_event_t::aborted, a);
|
|
assertNoEvents(s);
|
|
}
|
|
static void test_job_flushed_before_it_starts_is_dropped() {
|
|
// The radio task took it off the queue, then a flush came before it got the
|
|
// radio.
|
|
RadioScheduler s;
|
|
const uint32_t a = submit(s, REMOTE_A);
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
s.next(0, job, waitMs);
|
|
s.flush(0);
|
|
TEST_ASSERT_FALSE(s.start(a, 0));
|
|
assertEvent(s, tx_event_t::dropped, a);
|
|
assertNoEvents(s);
|
|
}
|
|
static void test_every_job_gets_one_outcome_across_a_flush() {
|
|
RadioScheduler s;
|
|
uint32_t tickets[6];
|
|
for(uint8_t i = 0; i < 3; i++) tickets[i] = submit(s, REMOTE_A + i);
|
|
somfy_tx_job_t job;
|
|
uint32_t waitMs;
|
|
s.next(0, job, waitMs);
|
|
s.start(job.seq, 0);
|
|
s.flush(0);
|
|
// Jobs queued after the flush are unaffected by it.
|
|
for(uint8_t i = 3; i < 6; i++) tickets[i] = submit(s, REMOTE_B + i);
|
|
s.ended(job.seq, s.keepSending(job.seq), 0);
|
|
while(runNext(s)) {}
|
|
uint8_t outcomes[6] = {};
|
|
somfy_tx_event_t evt;
|
|
while(s.popEvent(evt)) {
|
|
if(evt.type == tx_event_t::started) continue;
|
|
for(uint8_t i = 0; i < 6; i++)
|
|
if(tickets[i] == evt.seq) outcomes[i]++;
|
|
}
|
|
for(uint8_t i = 0; i < 6; i++) TEST_ASSERT_EQUAL_UINT8(1, outcomes[i]);
|
|
}
|
|
static void test_unknown_ticket_is_ignored() {
|
|
RadioScheduler s;
|
|
TEST_ASSERT_FALSE(s.keepSending(0));
|
|
TEST_ASSERT_FALSE(s.keepSending(42));
|
|
TEST_ASSERT_FALSE(s.start(42, 0));
|
|
s.ended(42, true, 0);
|
|
assertNoEvents(s);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Suspend
|
|
********************************************************************/
|
|
static void test_suspend_flushes_and_refuses_jobs() {
|
|
RadioScheduler s;
|
|
const uint32_t a = submit(s, REMOTE_A);
|
|
s.suspend(TX_SUSPEND_SCAN, 0);
|
|
TEST_ASSERT_TRUE(s.suspended());
|
|
assertEvent(s, tx_event_t::dropped, a);
|
|
TEST_ASSERT_FALSE(s.hasRoom(true));
|
|
TEST_ASSERT_EQUAL_UINT32(0, submit(s, REMOTE_A));
|
|
TEST_ASSERT_EQUAL_UINT32(0, submit(s, REMOTE_A, 0, true));
|
|
assertNoEvents(s);
|
|
}
|
|
static void test_resume_needs_every_reason_cleared() {
|
|
RadioScheduler s;
|
|
s.suspend(TX_SUSPEND_SCAN, 0);
|
|
s.suspend(TX_SUSPEND_OTA, 0);
|
|
s.resume(TX_SUSPEND_SCAN);
|
|
TEST_ASSERT_TRUE(s.suspended());
|
|
TEST_ASSERT_EQUAL_UINT32(0, submit(s, REMOTE_A));
|
|
s.resume(TX_SUSPEND_OTA);
|
|
TEST_ASSERT_FALSE(s.suspended());
|
|
TEST_ASSERT_NOT_EQUAL(0, submit(s, REMOTE_A));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Repeater frames
|
|
********************************************************************/
|
|
static void test_repeater_frames_report_nothing() {
|
|
RadioScheduler s;
|
|
somfy_tx_job_t job = makeJob(REMOTE_A);
|
|
job.raw = true;
|
|
const uint32_t r = s.submit(job, false, 0, 0);
|
|
TEST_ASSERT_NOT_EQUAL(0, r);
|
|
TEST_ASSERT_EQUAL_UINT32(r, runNext(s));
|
|
submit(s, REMOTE_B);
|
|
job = makeJob(REMOTE_A);
|
|
job.raw = true;
|
|
s.submit(job, false, 0, 0);
|
|
s.flush(0);
|
|
somfy_tx_event_t evt;
|
|
TEST_ASSERT_TRUE(s.popEvent(evt));
|
|
TEST_ASSERT_EQUAL_UINT32(REMOTE_B, evt.remoteAddress);
|
|
assertNoEvents(s);
|
|
}
|
|
static void test_repeater_frame_doesnt_hold_back_a_stop() {
|
|
// It isn't one of our remotes so it has no rolling code of ours to keep in
|
|
// order.
|
|
RadioScheduler s;
|
|
somfy_tx_job_t job = makeJob(REMOTE_A);
|
|
job.raw = true;
|
|
const uint32_t r = s.submit(job, false, 0, 0);
|
|
const uint32_t stop = submit(s, REMOTE_A, 0, true);
|
|
TEST_ASSERT_EQUAL_UINT32(stop, runNext(s));
|
|
TEST_ASSERT_EQUAL_UINT32(r, runNext(s));
|
|
discardEvents(s);
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
(void)argc;
|
|
(void)argv;
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_jobs_go_out_in_the_order_they_came);
|
|
RUN_TEST(test_tickets_are_distinct_and_set_in_the_job);
|
|
RUN_TEST(test_nothing_waiting_sleeps_until_woken);
|
|
RUN_TEST(test_stop_goes_ahead_of_other_remotes);
|
|
RUN_TEST(test_stop_queues_behind_its_own_remote);
|
|
RUN_TEST(test_stop_goes_ahead_once_its_remote_is_on_air);
|
|
RUN_TEST(test_stops_go_out_in_the_order_they_came);
|
|
RUN_TEST(test_second_stop_of_a_remote_stays_behind_the_first);
|
|
RUN_TEST(test_normal_jobs_leave_the_reserved_slots);
|
|
RUN_TEST(test_stops_use_the_reserved_slots);
|
|
RUN_TEST(test_a_refused_job_has_no_ticket);
|
|
RUN_TEST(test_taking_a_job_frees_its_slot);
|
|
RUN_TEST(test_delayed_job_waits_until_due);
|
|
RUN_TEST(test_delayed_job_holds_up_the_jobs_behind_it);
|
|
RUN_TEST(test_stop_overtakes_a_delayed_job_of_another_remote);
|
|
RUN_TEST(test_delay_counts_from_the_job_ahead_going_off_air);
|
|
RUN_TEST(test_delay_ignores_a_job_that_ended_before_it_was_queued);
|
|
RUN_TEST(test_delay_after_a_job_ended_across_millis_wrap);
|
|
RUN_TEST(test_stop_waits_behind_its_remotes_delayed_job);
|
|
RUN_TEST(test_delay_across_millis_wrap);
|
|
RUN_TEST(test_job_reports_started_then_finished);
|
|
RUN_TEST(test_cut_short_job_reports_aborted);
|
|
RUN_TEST(test_flush_drops_every_waiting_job_once);
|
|
RUN_TEST(test_flush_cuts_short_the_job_on_air);
|
|
RUN_TEST(test_job_flushed_before_it_starts_is_dropped);
|
|
RUN_TEST(test_every_job_gets_one_outcome_across_a_flush);
|
|
RUN_TEST(test_unknown_ticket_is_ignored);
|
|
RUN_TEST(test_suspend_flushes_and_refuses_jobs);
|
|
RUN_TEST(test_resume_needs_every_reason_cleared);
|
|
RUN_TEST(test_repeater_frames_report_nothing);
|
|
RUN_TEST(test_repeater_frame_doesnt_hold_back_a_stop);
|
|
return UNITY_END();
|
|
}
|