Add renderer and package readiness validation gates

This commit is contained in:
2026-06-15 19:20:56 +02:00
parent 68617e8bc4
commit f78fc3076c
23 changed files with 2350 additions and 389 deletions

View File

@@ -0,0 +1,88 @@
#include "app_core/app_thread.h"
#include "test_harness.h"
#include <cstddef>
namespace {
void dispatch_plan_is_consistent_under_stress(pp::tests::Harness& harness)
{
constexpr std::size_t queued_sizes[] = { 0U, 1U, 4U, 8U, 16U };
for (const auto queued_task_count : queued_sizes) {
const auto plan = pp::app::plan_app_task_dispatch(
false,
true,
queued_task_count,
true,
true,
true);
PP_EXPECT(harness, !plan.execute_immediately);
PP_EXPECT(harness, plan.queue_task);
PP_EXPECT(harness, plan.remove_matching_unique_task == (queued_task_count > 0U));
PP_EXPECT(harness, plan.notify_worker);
PP_EXPECT(harness, plan.wait_for_completion);
PP_EXPECT(harness, plan.request_redraw);
PP_EXPECT(harness, !plan.reject_unsafe_cross_thread_dispatch);
}
}
void dispatch_plan_handles_target_thread_with_rejection_flag(pp::tests::Harness& harness)
{
constexpr std::size_t queued_sizes[] = { 0U, 5U };
for (const auto queued_task_count : queued_sizes) {
const auto plan = pp::app::plan_app_task_dispatch(
true,
true,
queued_task_count,
false,
true,
true,
true);
PP_EXPECT(harness, plan.execute_immediately);
PP_EXPECT(harness, !plan.queue_task);
PP_EXPECT(harness, !plan.remove_matching_unique_task);
PP_EXPECT(harness, !plan.notify_worker);
PP_EXPECT(harness, !plan.wait_for_completion);
PP_EXPECT(harness, !plan.request_redraw);
PP_EXPECT(harness, !plan.reject_unsafe_cross_thread_dispatch);
}
}
void dispatch_plan_rejects_cross_thread_mutations_under_pressure(pp::tests::Harness& harness)
{
constexpr std::size_t queued_sizes[] = { 0U, 4U, 8U };
for (const auto queued_task_count : queued_sizes) {
const auto plan = pp::app::plan_app_task_dispatch(
false,
true,
queued_task_count,
false,
true,
true,
true);
PP_EXPECT(harness, !plan.execute_immediately);
PP_EXPECT(harness, !plan.queue_task);
PP_EXPECT(harness, !plan.remove_matching_unique_task);
PP_EXPECT(harness, !plan.notify_worker);
PP_EXPECT(harness, !plan.wait_for_completion);
PP_EXPECT(harness, !plan.request_redraw);
PP_EXPECT(harness, plan.reject_unsafe_cross_thread_dispatch);
}
}
} // namespace
int main()
{
pp::tests::Harness harness;
harness.run("dispatch plan is consistent across queue sizes", dispatch_plan_is_consistent_under_stress);
harness.run("dispatch plan ignores reject flag when already on target thread", dispatch_plan_handles_target_thread_with_rejection_flag);
harness.run("dispatch plan rejects unsafe cross-thread work under load", dispatch_plan_rejects_cross_thread_mutations_under_pressure);
return harness.finish();
}

View File

@@ -38,6 +38,19 @@ void task_dispatch_does_not_wait_for_stopped_worker(pp::tests::Harness& harness)
PP_EXPECT(harness, !plan.wait_for_completion);
}
void task_dispatch_rejects_unsafe_cross_thread_mutations(pp::tests::Harness& harness)
{
const auto plan = pp::app::plan_app_task_dispatch(false, true, 2, true, true, false, true);
PP_EXPECT(harness, !plan.execute_immediately);
PP_EXPECT(harness, !plan.queue_task);
PP_EXPECT(harness, !plan.remove_matching_unique_task);
PP_EXPECT(harness, !plan.notify_worker);
PP_EXPECT(harness, !plan.wait_for_completion);
PP_EXPECT(harness, !plan.request_redraw);
PP_EXPECT(harness, plan.reject_unsafe_cross_thread_dispatch);
}
void render_queue_drain_wraps_non_empty_work_in_context(pp::tests::Harness& harness)
{
const auto empty = pp::app::plan_app_render_queue_drain(0);
@@ -124,6 +137,7 @@ int main()
harness.run("task dispatch executes immediately on target thread", task_dispatch_executes_immediately_on_target_thread);
harness.run("task dispatch queues unique work and waits for running worker", task_dispatch_queues_unique_work_and_waits_for_running_worker);
harness.run("task dispatch does not wait for stopped worker", task_dispatch_does_not_wait_for_stopped_worker);
harness.run("task dispatch can reject unsafe cross-thread mutations", task_dispatch_rejects_unsafe_cross_thread_mutations);
harness.run("render queue drain wraps non empty work in context", render_queue_drain_wraps_non_empty_work_in_context);
harness.run("ui thread tick runs tasks and schedules redraw", ui_thread_tick_runs_tasks_and_schedules_redraw);
harness.run("ui loop timers report fps and reload on threshold", ui_loop_timers_report_fps_and_reload_on_threshold);