Expose layer history intent in app core

This commit is contained in:
2026-06-12 19:07:19 +02:00
parent 8cd384012f
commit ae24285203
5 changed files with 192 additions and 15 deletions

View File

@@ -34,19 +34,33 @@ public:
class FakeDocumentLayerRenameServices final : public pp::app::DocumentLayerRenameServices {
public:
void rename_layer(std::string_view old_name, std::string_view new_name) override
void record_layer_rename_undo(std::string_view old_name, std::string_view new_name) override
{
rename_calls += 1;
history_calls += 1;
last_old_name = std::string(old_name);
last_new_name = std::string(new_name);
call_order += "history;";
}
void finish_layer_rename() override { finish_calls += 1; }
void set_current_layer_name(std::string_view new_name) override
{
rename_calls += 1;
last_new_name = std::string(new_name);
call_order += "rename;";
}
void finish_layer_rename() override
{
finish_calls += 1;
call_order += "finish;";
}
int history_calls = 0;
int rename_calls = 0;
int finish_calls = 0;
std::string last_old_name;
std::string last_new_name;
std::string call_order;
};
class FakeDocumentLayerOperationServices final : public pp::app::DocumentLayerOperationServices {
@@ -222,10 +236,12 @@ void layer_rename_executor_dispatches_changed_name(pp::tests::Harness& harness)
PP_EXPECT(harness, plan);
if (plan) {
PP_EXPECT(harness, pp::app::execute_document_layer_rename_plan(plan.value(), services).ok());
PP_EXPECT(harness, services.history_calls == 1);
PP_EXPECT(harness, services.rename_calls == 1);
PP_EXPECT(harness, services.finish_calls == 1);
PP_EXPECT(harness, services.last_old_name == "Base");
PP_EXPECT(harness, services.last_new_name == "Paint");
PP_EXPECT(harness, services.call_order == "history;rename;finish;");
}
}
@@ -237,8 +253,10 @@ void layer_rename_executor_finishes_no_op(pp::tests::Harness& harness)
PP_EXPECT(harness, plan);
if (plan) {
PP_EXPECT(harness, pp::app::execute_document_layer_rename_plan(plan.value(), services).ok());
PP_EXPECT(harness, services.history_calls == 0);
PP_EXPECT(harness, services.rename_calls == 0);
PP_EXPECT(harness, services.finish_calls == 1);
PP_EXPECT(harness, services.call_order == "finish;");
}
}
@@ -253,10 +271,26 @@ void layer_rename_executor_rejects_malformed_changed_plan(pp::tests::Harness& ha
const auto status = pp::app::execute_document_layer_rename_plan(malformed, services);
PP_EXPECT(harness, !status.ok());
PP_EXPECT(harness, status.code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(harness, services.history_calls == 0);
PP_EXPECT(harness, services.rename_calls == 0);
PP_EXPECT(harness, services.finish_calls == 0);
}
void layer_rename_history_requirement_matches_action(pp::tests::Harness& harness)
{
const auto rename = pp::app::plan_document_layer_rename("Base", "Paint");
const auto no_op = pp::app::plan_document_layer_rename("Ink", "Ink");
PP_EXPECT(harness, rename);
PP_EXPECT(harness, no_op);
if (rename) {
PP_EXPECT(harness, pp::app::document_layer_rename_records_history(rename.value()));
}
if (no_op) {
PP_EXPECT(harness, !pp::app::document_layer_rename_records_history(no_op.value()));
}
}
void layer_add_validates_insert_index_and_name(pp::tests::Harness& harness)
{
const auto plan = pp::app::plan_document_layer_add(2, 1, "Paint");
@@ -526,6 +560,67 @@ void layer_operation_executor_dispatches_document_mutations(pp::tests::Harness&
}
}
void layer_operation_history_requirement_matches_operation(pp::tests::Harness& harness)
{
const auto add = pp::app::plan_document_layer_add(2, 1, "Paint");
const auto duplicate = pp::app::plan_document_layer_duplicate(3, 1);
const auto select = pp::app::plan_document_layer_select(3, 2);
const auto reorder = pp::app::plan_document_layer_reorder(3, 2, 0);
const auto no_op_reorder = pp::app::plan_document_layer_reorder(3, 1, 1);
const auto remove = pp::app::plan_document_layer_remove(3, 1);
const auto opacity = pp::app::plan_document_layer_opacity(3, 1, 0.25F);
const auto visibility = pp::app::plan_document_layer_visibility(3, 1, false);
const auto alpha_lock = pp::app::plan_document_layer_alpha_lock(3, 1, true);
const auto blend = pp::app::plan_document_layer_blend_mode(3, 1, 4);
const auto highlight = pp::app::plan_document_layer_highlight(3, 1, true);
PP_EXPECT(harness, add);
PP_EXPECT(harness, duplicate);
PP_EXPECT(harness, select);
PP_EXPECT(harness, reorder);
PP_EXPECT(harness, no_op_reorder);
PP_EXPECT(harness, remove);
PP_EXPECT(harness, opacity);
PP_EXPECT(harness, visibility);
PP_EXPECT(harness, alpha_lock);
PP_EXPECT(harness, blend);
PP_EXPECT(harness, highlight);
if (add) {
PP_EXPECT(harness, pp::app::document_layer_operation_records_history(add.value()));
}
if (duplicate) {
PP_EXPECT(harness, pp::app::document_layer_operation_records_history(duplicate.value()));
}
if (select) {
PP_EXPECT(harness, !pp::app::document_layer_operation_records_history(select.value()));
}
if (reorder) {
PP_EXPECT(harness, pp::app::document_layer_operation_records_history(reorder.value()));
}
if (no_op_reorder) {
PP_EXPECT(harness, !pp::app::document_layer_operation_records_history(no_op_reorder.value()));
}
if (remove) {
PP_EXPECT(harness, pp::app::document_layer_operation_records_history(remove.value()));
}
if (opacity) {
PP_EXPECT(harness, pp::app::document_layer_operation_records_history(opacity.value()));
}
if (visibility) {
PP_EXPECT(harness, pp::app::document_layer_operation_records_history(visibility.value()));
}
if (alpha_lock) {
PP_EXPECT(harness, pp::app::document_layer_operation_records_history(alpha_lock.value()));
}
if (blend) {
PP_EXPECT(harness, pp::app::document_layer_operation_records_history(blend.value()));
}
if (highlight) {
PP_EXPECT(harness, !pp::app::document_layer_operation_records_history(highlight.value()));
}
}
void layer_operation_executor_dispatches_selection_and_metadata(pp::tests::Harness& harness)
{
FakeDocumentLayerOperationServices services;
@@ -848,6 +943,21 @@ void layer_merge_plan_validates_supported_merge(pp::tests::Harness& harness)
}
}
void layer_merge_history_requirement_matches_flag(pp::tests::Harness& harness)
{
const auto merge = pp::app::plan_document_layer_merge(3, 2, 1, 1);
const auto no_history = pp::app::plan_document_layer_merge(3, 2, 0, 1, false);
PP_EXPECT(harness, merge);
PP_EXPECT(harness, no_history);
if (merge) {
PP_EXPECT(harness, pp::app::document_layer_merge_records_history(merge.value()));
}
if (no_history) {
PP_EXPECT(harness, !pp::app::document_layer_merge_records_history(no_history.value()));
}
}
void layer_merge_plan_rejects_bad_or_unsupported_state(pp::tests::Harness& harness)
{
PP_EXPECT(harness, !pp::app::plan_document_layer_merge(0, 0, 0, 1));
@@ -900,6 +1010,7 @@ int main()
harness.run("layer rename executor dispatches changed name", layer_rename_executor_dispatches_changed_name);
harness.run("layer rename executor finishes no op", layer_rename_executor_finishes_no_op);
harness.run("layer rename executor rejects malformed changed plan", layer_rename_executor_rejects_malformed_changed_plan);
harness.run("layer rename history requirement matches action", layer_rename_history_requirement_matches_action);
harness.run("layer add validates insert index and name", layer_add_validates_insert_index_and_name);
harness.run("layer duplicate select and reorder validate indices", layer_duplicate_select_and_reorder_validate_indices);
harness.run("layer remove keeps at least one layer", layer_remove_keeps_at_least_one_layer);
@@ -908,6 +1019,7 @@ int main()
harness.run("layer panel view projects current controls and visibility", layer_panel_view_projects_current_controls_and_visibility);
harness.run("layer panel view rejects invalid document state", layer_panel_view_rejects_invalid_document_state);
harness.run("layer operation executor dispatches document mutations", layer_operation_executor_dispatches_document_mutations);
harness.run("layer operation history requirement matches operation", layer_operation_history_requirement_matches_operation);
harness.run("layer operation executor dispatches selection and metadata", layer_operation_executor_dispatches_selection_and_metadata);
harness.run("layer operation executor preserves no op and transient actions", layer_operation_executor_preserves_no_op_and_transient_actions);
harness.run("layer operation executor rejects malformed mutation plans", layer_operation_executor_rejects_malformed_mutation_plans);
@@ -917,6 +1029,7 @@ int main()
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);
harness.run("layer merge plan validates supported merge", layer_merge_plan_validates_supported_merge);
harness.run("layer merge history requirement matches flag", layer_merge_history_requirement_matches_flag);
harness.run("layer merge plan rejects bad or unsupported state", layer_merge_plan_rejects_bad_or_unsupported_state);
harness.run("layer merge executor dispatches merge", layer_merge_executor_dispatches_merge);
harness.run("layer merge executor rejects malformed plan", layer_merge_executor_rejects_malformed_plan);