#include "foundation/task_queue.h" #include "test_harness.h" #include namespace { struct NestedPushPayload { pp::foundation::TaskQueue* queue = nullptr; std::vector* order = nullptr; }; struct MarkerPayload { std::vector* order = nullptr; int marker = 0; }; struct HandoffPayload { pp::foundation::TaskQueue* ui_queue = nullptr; std::vector* order = nullptr; int worker_marker = 0; MarkerPayload* ui_marker = nullptr; }; void nested_push_task(void* user_data) noexcept { auto* payload = static_cast(user_data); payload->order->push_back(1); payload->queue->push(pp::foundation::TaskItem { .callback = [](void* callback_data) noexcept { auto* inner = static_cast*>(callback_data); inner->push_back(2); }, .user_data = payload->order, .id = 2 }); } void record_marker_task(void* user_data) noexcept { auto* payload = static_cast(user_data); payload->order->push_back(payload->marker); } void handoff_to_ui_queue_task(void* user_data) noexcept { const auto payload = static_cast(user_data); payload->order->push_back(payload->worker_marker); payload->ui_queue->push(pp::foundation::TaskItem { .callback = record_marker_task, .user_data = payload->ui_marker, .id = static_cast(payload->worker_marker), }); } void runs_nested_push_tasks_deterministically(pp::tests::Harness& harness) { pp::foundation::TaskQueue queue; std::vector order; NestedPushPayload payload { .queue = &queue, .order = &order }; PP_EXPECT(harness, queue.push(pp::foundation::TaskItem { .callback = nested_push_task, .user_data = &payload, .id = 1 }).ok()); PP_EXPECT(harness, queue.run_all() == 2U); PP_EXPECT(harness, order.size() == 2U); PP_EXPECT(harness, order[0] == 1); PP_EXPECT(harness, order[1] == 2); PP_EXPECT(harness, queue.empty()); } void worker_to_ui_queue_handoff_is_ordered(pp::tests::Harness& harness) { pp::foundation::TaskQueue worker_queue; pp::foundation::TaskQueue ui_queue; std::vector order; MarkerPayload marker_payloads[] = { { .order = &order, .marker = 2 }, { .order = &order, .marker = 3 }, }; HandoffPayload worker_payloads[] = { { .ui_queue = &ui_queue, .order = &order, .worker_marker = 1, .ui_marker = &marker_payloads[0], }, { .ui_queue = &ui_queue, .order = &order, .worker_marker = 4, .ui_marker = &marker_payloads[1], }, }; PP_EXPECT(harness, worker_queue.push(pp::foundation::TaskItem { .callback = handoff_to_ui_queue_task, .user_data = &worker_payloads[0], .id = 1, }).ok()); PP_EXPECT(harness, worker_queue.push(pp::foundation::TaskItem { .callback = handoff_to_ui_queue_task, .user_data = &worker_payloads[1], .id = 2, }).ok()); PP_EXPECT(harness, worker_queue.run_all() == 2U); PP_EXPECT(harness, order.size() == 2U); PP_EXPECT(harness, order[0] == 1); PP_EXPECT(harness, order[1] == 4); PP_EXPECT(harness, worker_queue.empty()); PP_EXPECT(harness, !ui_queue.empty()); PP_EXPECT(harness, ui_queue.run_all() == 2U); PP_EXPECT(harness, order.size() == 4U); PP_EXPECT(harness, order[2] == 2); PP_EXPECT(harness, order[3] == 3); PP_EXPECT(harness, ui_queue.empty()); } void stress_batch_push_and_overflow_reported(pp::tests::Harness& harness) { constexpr std::size_t batch_size = 32U; pp::foundation::TaskQueue queue(batch_size); int counter = 0; for (std::size_t i = 0U; i < batch_size; ++i) { PP_EXPECT(harness, queue.push(pp::foundation::TaskItem { .callback = [](void* user_data) noexcept { ++*static_cast(user_data); }, .user_data = &counter, .id = static_cast(i + 1), }).ok()); } const auto overflow = queue.push(pp::foundation::TaskItem { .callback = [](void* user_data) noexcept { ++*static_cast(user_data); }, .user_data = &counter, .id = batch_size + 1U, }); PP_EXPECT(harness, !overflow.ok()); PP_EXPECT(harness, queue.run_all() == batch_size); PP_EXPECT(harness, counter == static_cast(batch_size)); PP_EXPECT(harness, queue.empty()); } } int main() { pp::tests::Harness harness; harness.run("nested pushes are executed deterministically", runs_nested_push_tasks_deterministically); harness.run("worker to UI queue handoff preserves order", worker_to_ui_queue_handoff_is_ordered); harness.run("stress batch push reports overflow and drains deterministically", stress_batch_push_and_overflow_reported); return harness.finish(); }