#include "app_core/main_toolbar.h" #include "test_harness.h" namespace { class FakeMainToolbarServices final : public pp::app::MainToolbarServices { public: void show_open_dialog() override { open_dialogs += 1; } void show_save_dialog() override { save_dialogs += 1; } void invoke_undo(const pp::app::HistoryUiPlan& plan) override { undo_calls += 1; last_history = plan; } void invoke_redo(const pp::app::HistoryUiPlan& plan) override { redo_calls += 1; last_history = plan; } void clear_history(const pp::app::HistoryUiPlan& plan) override { clear_history_calls += 1; last_history = plan; } void clear_canvas(const pp::app::DocumentCanvasClearPlan& plan) override { clear_canvas_calls += 1; last_clear = plan; } void show_message_box() override { message_boxes += 1; } void show_settings_dialog() override { settings_dialogs += 1; } [[nodiscard]] int total_calls() const noexcept { return open_dialogs + save_dialogs + undo_calls + redo_calls + clear_history_calls + clear_canvas_calls + message_boxes + settings_dialogs; } int open_dialogs = 0; int save_dialogs = 0; int undo_calls = 0; int redo_calls = 0; int clear_history_calls = 0; int clear_canvas_calls = 0; int message_boxes = 0; int settings_dialogs = 0; pp::app::HistoryUiPlan last_history; pp::app::DocumentCanvasClearPlan last_clear; }; void direct_dialog_commands_are_available(pp::tests::Harness& harness) { const auto open = pp::app::plan_main_toolbar_command(pp::app::MainToolbarCommand::open_document); PP_EXPECT(harness, open); if (open) { PP_EXPECT(harness, open.value().action == pp::app::MainToolbarAction::show_open_dialog); PP_EXPECT(harness, open.value().label == "Open"); PP_EXPECT(harness, !open.value().no_op); } const auto save = pp::app::plan_main_toolbar_command(pp::app::MainToolbarCommand::save_document); PP_EXPECT(harness, save); if (save) { PP_EXPECT(harness, save.value().action == pp::app::MainToolbarAction::show_save_dialog); PP_EXPECT(harness, save.value().label == "Save"); } const auto settings = pp::app::plan_main_toolbar_command(pp::app::MainToolbarCommand::show_settings); PP_EXPECT(harness, settings); if (settings) { PP_EXPECT(harness, settings.value().action == pp::app::MainToolbarAction::show_settings_dialog); PP_EXPECT(harness, settings.value().label == "Settings"); } } void message_box_dialog_preserves_legacy_defaults(pp::tests::Harness& harness) { const auto plan = pp::app::plan_main_toolbar_message_dialog(); PP_EXPECT(harness, plan.title == "Just a test message"); PP_EXPECT(harness, plan.message == "Longer description for the error or the message."); PP_EXPECT(harness, plan.ok_caption == "Ok"); PP_EXPECT(harness, plan.cancel_caption == "Cancel"); PP_EXPECT(harness, plan.show_cancel); } void history_commands_reuse_history_breakpoints(pp::tests::Harness& harness) { const auto undo = pp::app::plan_main_toolbar_command(pp::app::MainToolbarCommand::undo, 2); PP_EXPECT(harness, undo); if (undo) { PP_EXPECT(harness, undo.value().action == pp::app::MainToolbarAction::invoke_undo); PP_EXPECT(harness, undo.value().updates_memory_label); PP_EXPECT(harness, undo.value().updates_title); PP_EXPECT(harness, undo.value().history.operation == pp::app::HistoryUiOperation::undo); PP_EXPECT(harness, undo.value().history.invokes_undo); PP_EXPECT(harness, !undo.value().no_op); } const auto redo_empty = pp::app::plan_main_toolbar_command(pp::app::MainToolbarCommand::redo, 0, 0); PP_EXPECT(harness, redo_empty); if (redo_empty) { PP_EXPECT(harness, redo_empty.value().action == pp::app::MainToolbarAction::no_op_unavailable); PP_EXPECT(harness, redo_empty.value().label == "Redo (No history)"); PP_EXPECT(harness, redo_empty.value().no_op); } const auto clear = pp::app::plan_main_toolbar_command( pp::app::MainToolbarCommand::clear_history, 0, 0, 2048); PP_EXPECT(harness, clear); if (clear) { PP_EXPECT(harness, clear.value().action == pp::app::MainToolbarAction::clear_history); PP_EXPECT(harness, clear.value().updates_memory_label); PP_EXPECT(harness, !clear.value().updates_title); PP_EXPECT(harness, clear.value().history.operation == pp::app::HistoryUiOperation::clear); PP_EXPECT(harness, clear.value().history.clears_history); } } void canvas_clear_requires_live_canvas(pp::tests::Harness& harness) { const auto clear = pp::app::plan_main_toolbar_command( pp::app::MainToolbarCommand::clear_canvas, 0, 0, 0, true); PP_EXPECT(harness, clear); if (clear) { PP_EXPECT(harness, clear.value().action == pp::app::MainToolbarAction::clear_canvas); PP_EXPECT(harness, clear.value().requires_canvas); PP_EXPECT(harness, clear.value().records_undo); PP_EXPECT(harness, clear.value().marks_unsaved); PP_EXPECT(harness, clear.value().canvas_clear.clears_canvas); PP_EXPECT(harness, clear.value().canvas_clear.records_undo); PP_EXPECT(harness, clear.value().canvas_clear.marks_unsaved); PP_EXPECT(harness, !clear.value().no_op); } const auto missing_canvas = pp::app::plan_main_toolbar_command( pp::app::MainToolbarCommand::clear_canvas, 0, 0, 0, false); PP_EXPECT(harness, missing_canvas); if (missing_canvas) { PP_EXPECT(harness, missing_canvas.value().action == pp::app::MainToolbarAction::no_op_unavailable); PP_EXPECT(harness, missing_canvas.value().label == "Clear Canvas (No canvas)"); PP_EXPECT(harness, missing_canvas.value().requires_canvas); PP_EXPECT(harness, !missing_canvas.value().records_undo); PP_EXPECT(harness, !missing_canvas.value().marks_unsaved); PP_EXPECT(harness, !missing_canvas.value().canvas_clear.clears_canvas); PP_EXPECT(harness, missing_canvas.value().no_op); } } void rejects_negative_history_metrics(pp::tests::Harness& harness) { PP_EXPECT(harness, !pp::app::plan_main_toolbar_command(pp::app::MainToolbarCommand::undo, -1)); PP_EXPECT(harness, !pp::app::plan_main_toolbar_command(pp::app::MainToolbarCommand::redo, 0, -1)); PP_EXPECT(harness, !pp::app::plan_main_toolbar_command(pp::app::MainToolbarCommand::clear_history, 0, 0, -1)); } void executor_dispatches_to_service_boundary(pp::tests::Harness& harness) { FakeMainToolbarServices services; auto open = pp::app::plan_main_toolbar_command(pp::app::MainToolbarCommand::open_document); PP_EXPECT(harness, open); if (open) { const auto status = pp::app::execute_main_toolbar_plan(open.value(), services); PP_EXPECT(harness, status.ok()); PP_EXPECT(harness, services.open_dialogs == 1); } auto undo = pp::app::plan_main_toolbar_command(pp::app::MainToolbarCommand::undo, 1); PP_EXPECT(harness, undo); if (undo) { const auto status = pp::app::execute_main_toolbar_plan(undo.value(), services); PP_EXPECT(harness, status.ok()); PP_EXPECT(harness, services.undo_calls == 1); PP_EXPECT(harness, services.last_history.operation == pp::app::HistoryUiOperation::undo); PP_EXPECT(harness, services.last_history.undo_count == 1); } auto clear_canvas = pp::app::plan_main_toolbar_command( pp::app::MainToolbarCommand::clear_canvas, 0, 0, 0, true); PP_EXPECT(harness, clear_canvas); if (clear_canvas) { const auto status = pp::app::execute_main_toolbar_plan(clear_canvas.value(), services); PP_EXPECT(harness, status.ok()); PP_EXPECT(harness, services.clear_canvas_calls == 1); PP_EXPECT(harness, services.last_clear.clears_canvas); PP_EXPECT(harness, services.last_clear.records_undo); PP_EXPECT(harness, services.last_clear.marks_unsaved); } auto redo_empty = pp::app::plan_main_toolbar_command(pp::app::MainToolbarCommand::redo); PP_EXPECT(harness, redo_empty); if (redo_empty) { const int calls_before = services.total_calls(); const auto status = pp::app::execute_main_toolbar_plan(redo_empty.value(), services); PP_EXPECT(harness, status.ok()); PP_EXPECT(harness, services.total_calls() == calls_before); } } } // namespace int main() { pp::tests::Harness harness; harness.run("direct dialog commands are available", direct_dialog_commands_are_available); harness.run("message box dialog preserves legacy defaults", message_box_dialog_preserves_legacy_defaults); harness.run("history commands reuse history breakpoints", history_commands_reuse_history_breakpoints); harness.run("canvas clear requires live canvas", canvas_clear_requires_live_canvas); harness.run("rejects negative history metrics", rejects_negative_history_metrics); harness.run("executor dispatches to service boundary", executor_dispatches_to_service_boundary); return harness.finish(); }