#include "foundation/task_queue.h" #include "test_harness.h" using pp::foundation::StatusCode; using pp::foundation::TaskItem; using pp::foundation::TaskQueue; using pp::foundation::max_task_queue_entries; namespace { struct Counter { int value = 0; }; void increment(void* user_data) noexcept { auto* counter = static_cast(user_data); ++counter->value; } void add_two(void* user_data) noexcept { auto* counter = static_cast(user_data); counter->value += 2; } void runs_tasks_in_fifo_order(pp::tests::Harness& h) { Counter counter; TaskQueue queue(4); PP_EXPECT(h, queue.push(TaskItem { .callback = increment, .user_data = &counter, .id = 1 }).ok()); PP_EXPECT(h, queue.push(TaskItem { .callback = add_two, .user_data = &counter, .id = 2 }).ok()); PP_EXPECT(h, queue.size() == 2U); PP_EXPECT(h, queue.run_next().ok()); PP_EXPECT(h, counter.value == 1); PP_EXPECT(h, queue.run_next().ok()); PP_EXPECT(h, counter.value == 3); PP_EXPECT(h, queue.empty()); } void pops_without_running(pp::tests::Harness& h) { Counter counter; TaskQueue queue(2); PP_EXPECT(h, queue.push(TaskItem { .callback = increment, .user_data = &counter, .id = 42 }).ok()); const auto task = queue.pop(); PP_EXPECT(h, task.ok()); PP_EXPECT(h, task.value().id == 42U); PP_EXPECT(h, counter.value == 0); PP_EXPECT(h, queue.empty()); } void rejects_invalid_or_excessive_work(pp::tests::Harness& h) { Counter counter; TaskQueue queue(1); TaskQueue invalid_queue(0); TaskQueue too_large(max_task_queue_entries + 1U); const auto null_task = queue.push(TaskItem {}); PP_EXPECT(h, !null_task.ok()); PP_EXPECT(h, null_task.code == StatusCode::invalid_argument); PP_EXPECT(h, queue.push(TaskItem { .callback = increment, .user_data = &counter }).ok()); const auto full = queue.push(TaskItem { .callback = increment, .user_data = &counter }); PP_EXPECT(h, !full.ok()); PP_EXPECT(h, full.code == StatusCode::out_of_range); const auto invalid_capacity = invalid_queue.push(TaskItem { .callback = increment, .user_data = &counter }); const auto excessive_capacity = too_large.push(TaskItem { .callback = increment, .user_data = &counter }); PP_EXPECT(h, !invalid_capacity.ok()); PP_EXPECT(h, invalid_capacity.code == StatusCode::out_of_range); PP_EXPECT(h, !excessive_capacity.ok()); PP_EXPECT(h, excessive_capacity.code == StatusCode::out_of_range); } void run_all_and_clear_are_bounded(pp::tests::Harness& h) { Counter counter; TaskQueue queue(4); PP_EXPECT(h, queue.max_entries() == 4U); PP_EXPECT(h, queue.push(TaskItem { .callback = increment, .user_data = &counter }).ok()); PP_EXPECT(h, queue.push(TaskItem { .callback = increment, .user_data = &counter }).ok()); PP_EXPECT(h, queue.run_all() == 2U); PP_EXPECT(h, counter.value == 2); PP_EXPECT(h, queue.push(TaskItem { .callback = add_two, .user_data = &counter }).ok()); queue.clear(); PP_EXPECT(h, queue.empty()); const auto empty_pop = queue.pop(); PP_EXPECT(h, !empty_pop.ok()); PP_EXPECT(h, empty_pop.status().code == StatusCode::out_of_range); } } int main() { pp::tests::Harness harness; harness.run("runs_tasks_in_fifo_order", runs_tasks_in_fifo_order); harness.run("pops_without_running", pops_without_running); harness.run("rejects_invalid_or_excessive_work", rejects_invalid_or_excessive_work); harness.run("run_all_and_clear_are_bounded", run_all_and_clear_are_bounded); return harness.finish(); }