Add layer menu service boundary

This commit is contained in:
2026-06-03 12:56:25 +02:00
parent ea96f38875
commit defa9fc212
5 changed files with 204 additions and 17 deletions

View File

@@ -6,6 +6,31 @@
namespace {
class FakeDocumentLayerMenuServices final : public pp::app::DocumentLayerMenuServices {
public:
void clear_current_layer() override { clear_calls += 1; }
void show_rename_dialog() override { rename_dialogs += 1; }
void merge_with_lower_layer(int from_index, int to_index) override
{
merge_calls += 1;
last_from_index = from_index;
last_to_index = to_index;
}
void show_merge_animated_not_supported() override { merge_blocked_messages += 1; }
[[nodiscard]] int total_calls() const noexcept
{
return clear_calls + rename_dialogs + merge_calls + merge_blocked_messages;
}
int clear_calls = 0;
int rename_dialogs = 0;
int merge_calls = 0;
int merge_blocked_messages = 0;
int last_from_index = -1;
int last_to_index = -1;
};
void layer_rename_records_changed_name(pp::tests::Harness& harness)
{
const auto plan = pp::app::plan_document_layer_rename("Base", "Paint");
@@ -287,6 +312,98 @@ void layer_menu_handles_missing_selection_and_bad_state(pp::tests::Harness& harn
"Paint"));
}
void layer_menu_executor_dispatches_menu_actions(pp::tests::Harness& harness)
{
FakeDocumentLayerMenuServices services;
const auto clear = pp::app::plan_document_layer_menu(
pp::app::DocumentLayerMenuCommand::clear,
true,
1,
1,
"Paint",
"Base");
PP_EXPECT(harness, clear);
if (clear) {
PP_EXPECT(harness, pp::app::execute_document_layer_menu_plan(clear.value(), services).ok());
PP_EXPECT(harness, services.clear_calls == 1);
}
const auto rename = pp::app::plan_document_layer_menu(
pp::app::DocumentLayerMenuCommand::rename,
true,
1,
1,
"Paint",
"Base");
PP_EXPECT(harness, rename);
if (rename) {
PP_EXPECT(harness, pp::app::execute_document_layer_menu_plan(rename.value(), services).ok());
PP_EXPECT(harness, services.rename_dialogs == 1);
}
const auto merge = pp::app::plan_document_layer_menu(
pp::app::DocumentLayerMenuCommand::merge_down,
true,
2,
1,
"Ink",
"Paint");
PP_EXPECT(harness, merge);
if (merge) {
PP_EXPECT(harness, pp::app::execute_document_layer_menu_plan(merge.value(), services).ok());
PP_EXPECT(harness, services.merge_calls == 1);
PP_EXPECT(harness, services.last_from_index == 2);
PP_EXPECT(harness, services.last_to_index == 1);
}
const auto animated = pp::app::plan_document_layer_menu(
pp::app::DocumentLayerMenuCommand::merge_down,
true,
2,
3,
"Ink",
"Paint");
PP_EXPECT(harness, animated);
if (animated) {
PP_EXPECT(harness, pp::app::execute_document_layer_menu_plan(animated.value(), services).ok());
PP_EXPECT(harness, services.merge_blocked_messages == 1);
}
}
void layer_menu_executor_preserves_no_op_actions(pp::tests::Harness& harness)
{
FakeDocumentLayerMenuServices services;
const auto missing = pp::app::plan_document_layer_menu(
pp::app::DocumentLayerMenuCommand::clear,
false,
0,
1,
"",
"");
PP_EXPECT(harness, missing);
if (missing) {
PP_EXPECT(harness, missing.value().action == pp::app::DocumentLayerMenuAction::no_op_select_layer);
PP_EXPECT(harness, pp::app::execute_document_layer_menu_plan(missing.value(), services).ok());
}
const auto base_layer = pp::app::plan_document_layer_menu(
pp::app::DocumentLayerMenuCommand::merge_down,
true,
0,
1,
"Base",
"");
PP_EXPECT(harness, base_layer);
if (base_layer) {
PP_EXPECT(harness, base_layer.value().action == pp::app::DocumentLayerMenuAction::no_op_select_upper_layer);
PP_EXPECT(harness, pp::app::execute_document_layer_menu_plan(base_layer.value(), services).ok());
}
PP_EXPECT(harness, services.total_calls() == 0);
}
}
int main()
@@ -304,5 +421,7 @@ int main()
harness.run("layer menu labels selected layer commands", layer_menu_labels_selected_layer_commands);
harness.run("layer menu plans merge down or blocks it", layer_menu_plans_merge_down_or_blocks_it);
harness.run("layer menu handles missing selection and bad state", layer_menu_handles_missing_selection_and_bad_state);
harness.run("layer menu executor dispatches menu actions", layer_menu_executor_dispatches_menu_actions);
harness.run("layer menu executor preserves no op actions", layer_menu_executor_preserves_no_op_actions);
return harness.finish();
}