#include "app_core/app_thread.h" #include "test_harness.h" #include namespace { void task_dispatch_executes_immediately_on_target_thread(pp::tests::Harness& harness) { const auto plan = pp::app::plan_app_task_dispatch(true, true, 3, 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); } void task_dispatch_queues_unique_work_and_waits_for_running_worker(pp::tests::Harness& harness) { const auto plan = pp::app::plan_app_task_dispatch(false, true, 2, true, true, false); 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); } void task_dispatch_does_not_wait_for_stopped_worker(pp::tests::Harness& harness) { const auto plan = pp::app::plan_app_task_dispatch(false, false, 0, false, true, false); PP_EXPECT(harness, plan.queue_task); PP_EXPECT(harness, plan.notify_worker); PP_EXPECT(harness, !plan.wait_for_completion); } 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); const auto work = pp::app::plan_app_render_queue_drain(4); PP_EXPECT(harness, empty.mark_running); PP_EXPECT(harness, !empty.drain_tasks); PP_EXPECT(harness, !empty.wrap_in_render_context); PP_EXPECT(harness, work.mark_running); PP_EXPECT(harness, work.drain_tasks); PP_EXPECT(harness, work.wrap_in_render_context); PP_EXPECT(harness, work.task_count == 4U); } void ui_thread_tick_runs_tasks_and_schedules_redraw(pp::tests::Harness& harness) { const auto plan = pp::app::plan_app_ui_thread_tick(3, true); PP_EXPECT(harness, plan.mark_running); PP_EXPECT(harness, plan.execute_tasks); PP_EXPECT(harness, plan.tick_app); PP_EXPECT(harness, plan.update_before_render); PP_EXPECT(harness, plan.enqueue_render_frame); PP_EXPECT(harness, plan.task_count == 3U); } void ui_loop_timers_report_fps_and_reload_on_threshold(pp::tests::Harness& harness) { const auto plan = pp::app::plan_app_ui_loop_timers(0.25F, 0.5F, 0.9F, 0.9F, 7, true); PP_EXPECT(harness, plan); if (plan) { PP_EXPECT(harness, plan.value().update_platform_frame); PP_EXPECT(harness, plan.value().frame_accumulator == 0.75F); PP_EXPECT(harness, plan.value().fps_accumulator == 0.0F); PP_EXPECT(harness, plan.value().report_rendered_frames); PP_EXPECT(harness, plan.value().reported_frame_count == 7); PP_EXPECT(harness, plan.value().rendered_frames_after_report == 0); PP_EXPECT(harness, plan.value().reload_accumulator == 0.0F); PP_EXPECT(harness, plan.value().check_live_asset_reload); } } void ui_loop_timers_reject_invalid_values(pp::tests::Harness& harness) { PP_EXPECT(harness, !pp::app::plan_app_ui_loop_timers(-0.1F, 0.0F, 0.0F, 0.0F, 0, false)); PP_EXPECT(harness, !pp::app::plan_app_ui_loop_timers(0.1F, std::nanf(""), 0.0F, 0.0F, 0, false)); PP_EXPECT(harness, !pp::app::plan_app_ui_loop_timers(0.1F, 0.0F, 0.0F, 0.0F, -1, false)); } void ui_loop_redraw_increments_rendered_frames(pp::tests::Harness& harness) { const auto idle = pp::app::plan_app_ui_loop_redraw(false, 2); const auto redraw = pp::app::plan_app_ui_loop_redraw(true, 2); PP_EXPECT(harness, idle.tick_app); PP_EXPECT(harness, !idle.enqueue_render_frame); PP_EXPECT(harness, idle.rendered_frames == 2); PP_EXPECT(harness, redraw.update_before_render); PP_EXPECT(harness, redraw.enqueue_render_frame); PP_EXPECT(harness, redraw.reset_frame_accumulator); PP_EXPECT(harness, redraw.rendered_frames == 3); } void thread_start_stop_preserve_legacy_intents(pp::tests::Harness& harness) { const auto start = pp::app::plan_app_thread_start(); const auto stop_joinable = pp::app::plan_app_thread_stop(true); const auto stop_detached = pp::app::plan_app_thread_stop(false); PP_EXPECT(harness, start.start_thread); PP_EXPECT(harness, start.mark_running); PP_EXPECT(harness, stop_joinable.mark_not_running); PP_EXPECT(harness, stop_joinable.notify_worker); PP_EXPECT(harness, stop_joinable.join_thread); PP_EXPECT(harness, !stop_detached.join_thread); } } // namespace int main() { pp::tests::Harness harness; 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("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); harness.run("ui loop timers reject invalid values", ui_loop_timers_reject_invalid_values); harness.run("ui loop redraw increments rendered frames", ui_loop_redraw_increments_rendered_frames); harness.run("thread start stop preserve legacy intents", thread_start_stop_preserve_legacy_intents); return harness.finish(); }