mirror of
https://github.com/storytold/photocraft.git
synced 2026-11-01 13:57:18 -06:00
11133 lines
1.4 MiB
Plaintext
11133 lines
1.4 MiB
Plaintext
{
|
||
"integration_code_sha": "46c1347951eac7f62d4be317c915f73ec6ee5d43",
|
||
"cases": [
|
||
{
|
||
"id": "PR-3455",
|
||
"pr": 3455,
|
||
"subsystem": "Actions and automation",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked recording_and_appending_steps_can_be_undone_without_restarting_recording -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked definition_edits_undo_redo_without_touching_document_or_journal -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked enabled_step_edits_undo_and_invalidate_redo -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked undo_pending_step_deletion_does_not_duplicate_recording -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked actions_shortcut_undo_and_redo_edit_script_without_undoing_pixels -- --nocapture"
|
||
],
|
||
"expected": "recording and appending steps can be undone without restarting recording; definition edits undo redo without touching document or journal; enabled step edits undo and invalidate redo; undo pending step deletion does not duplicate recording; actions shortcut undo and redo edit script without undoing pixels",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked recording_and_appending_steps_can_be_undone_without_restarting_recording -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked definition_edits_undo_redo_without_touching_document_or_journal -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked enabled_step_edits_undo_and_invalidate_redo -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked undo_pending_step_deletion_does_not_duplicate_recording -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked actions_shortcut_undo_and_redo_edit_script_without_undoing_pixels -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "recording_and_appending_steps_can_be_undone_without_restarting_recording",
|
||
"path": "crates/engine/src/actions_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked recording_and_appending_steps_can_be_undone_without_restarting_recording -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.execute(\"file.new\", json!({\"width\": 8, \"height\": 8})).unwrap();\n s.execute(\"actions.record\", json!({\"name\": \"A\"})).unwrap();\n s.execute(\"layer.new.layer\", json!({})).unwrap();\n s.execute(\"actions.stop\", json!({})).unwrap();\n s.execute(\"actions.record\", json!({\"action\": \"A\"})).unwrap();\n s.execute(\"select.all\", json!({})).unwrap();\n s.execute(\"actions.stop\", json!({})).unwrap();\n let doc = s.active().unwrap().doc.clone();\n assert_eq!(s.actions.list[0].steps.len(), 2);\n s.execute(\"actions.undo\", json!({})).unwrap();\n assert_eq!(s.actions.list[0].steps.len(), 1);",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.actions.list[0].steps.len(), 2);\n s.execute(\"actions.undo\", json!({})).unwrap();\n assert_eq!(s.actions.list[0].steps.len(), 1);\n assert!(s.actions.recording.is_none());",
|
||
" assert_eq!(s.actions.list[0].steps.len(), 1);\n assert!(s.actions.recording.is_none());\n s.execute(\"actions.redo\", json!({})).unwrap();\n assert_eq!(s.actions.list[0].steps.len(), 2);",
|
||
" assert!(s.actions.recording.is_none());\n s.execute(\"actions.redo\", json!({})).unwrap();\n assert_eq!(s.actions.list[0].steps.len(), 2);\n assert!(s.actions.recording.is_none());",
|
||
" assert_eq!(s.actions.list[0].steps.len(), 2);\n assert!(s.actions.recording.is_none());\n assert_eq!(s.active().unwrap().doc, doc);\n }",
|
||
" assert!(s.actions.recording.is_none());\n assert_eq!(s.active().unwrap().doc, doc);\n }",
|
||
" assert_eq!(s.active().unwrap().doc, doc);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d84fa7955d260505378a1a596ec80d602036319d/crates/engine/src/actions_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "definition_edits_undo_redo_without_touching_document_or_journal",
|
||
"path": "crates/engine/src/actions_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked definition_edits_undo_redo_without_touching_document_or_journal -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.execute(\"file.new\", json!({\"width\": 8, \"height\": 8})).unwrap();\n s.actions.list.push(Action {\n name: \"A\".into(),\n steps: vec![(\"layer.new.layer\".into(), json!({})), (\"select.all\".into(), json!({}))],\n disabled: Default::default(),\n });\n s.actions.list.push(Action { name: \"Caller\".into(), steps: vec![(\"actions.play\".into(), json!({\"action\": \"A\"}))], disabled: Default::default() });\n s.edit_prefs(|p| {\n p.shortcuts.insert(\"actions.play:A\".into(), \"F6\".into());\n });\n let before = s.actions.list.clone();",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.actions.list, before);\n assert_eq!(s.prefs().shortcuts.get(\"actions.play:A\").map(String::as_str), Some(\"F6\"));\n assert!(!s.prefs().shortcuts.contains_key(\"actions.play:B\"));\n for _ in 0..3 {",
|
||
" assert_eq!(s.prefs().shortcuts.get(\"actions.play:A\").map(String::as_str), Some(\"F6\"));\n assert!(!s.prefs().shortcuts.contains_key(\"actions.play:B\"));\n for _ in 0..3 {\n s.execute(\"actions.redo\", json!({})).unwrap();",
|
||
" assert!(!s.prefs().shortcuts.contains_key(\"actions.play:B\"));\n for _ in 0..3 {\n s.execute(\"actions.redo\", json!({})).unwrap();\n }",
|
||
" assert_eq!(s.actions.list, after);\n assert_eq!(s.active().unwrap().doc, doc);\n assert_eq!(s.journal, journal);\n s.execute(\"actions.undo\", json!({})).unwrap();",
|
||
" assert_eq!(s.active().unwrap().doc, doc);\n assert_eq!(s.journal, journal);\n s.execute(\"actions.undo\", json!({})).unwrap();\n s.execute(\"actions.delete\", json!({\"action\": \"Caller\"})).unwrap();",
|
||
" assert_eq!(s.journal, journal);\n s.execute(\"actions.undo\", json!({})).unwrap();\n s.execute(\"actions.delete\", json!({\"action\": \"Caller\"})).unwrap();\n assert!(!can_redo(&s));",
|
||
" assert!(!can_redo(&s));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d84fa7955d260505378a1a596ec80d602036319d/crates/engine/src/actions_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "enabled_step_edits_undo_and_invalidate_redo",
|
||
"path": "crates/engine/src/actions_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked enabled_step_edits_undo_and_invalidate_redo -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.actions.list.push(Action::new(\"A\", vec![(\"select.all\".into(), json!({}))]));\n s.execute(\"actions.toggle\", json!({\"action\": \"A\", \"step\": 0})).unwrap();\n assert!(s.actions.list[0].disabled.contains(&0));\n s.execute(\"actions.undo\", json!({})).unwrap();\n assert!(s.actions.list[0].disabled.is_empty());\n s.execute(\"actions.redo\", json!({})).unwrap();\n assert!(s.actions.list[0].disabled.contains(&0));\n s.execute(\"actions.undo\", json!({})).unwrap();\n s.execute(\"actions.toggle\", json!({\"action\": \"A\"})).unwrap();\n assert!(!can_redo(&s));\n }",
|
||
"expected_assertions": [
|
||
" assert!(s.actions.list[0].disabled.contains(&0));\n s.execute(\"actions.undo\", json!({})).unwrap();\n assert!(s.actions.list[0].disabled.is_empty());\n s.execute(\"actions.redo\", json!({})).unwrap();",
|
||
" assert!(s.actions.list[0].disabled.is_empty());\n s.execute(\"actions.redo\", json!({})).unwrap();\n assert!(s.actions.list[0].disabled.contains(&0));\n s.execute(\"actions.undo\", json!({})).unwrap();",
|
||
" assert!(s.actions.list[0].disabled.contains(&0));\n s.execute(\"actions.undo\", json!({})).unwrap();\n s.execute(\"actions.toggle\", json!({\"action\": \"A\"})).unwrap();\n assert!(!can_redo(&s));",
|
||
" assert!(!can_redo(&s));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d84fa7955d260505378a1a596ec80d602036319d/crates/engine/src/actions_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "undo_pending_step_deletion_does_not_duplicate_recording",
|
||
"path": "crates/engine/src/actions_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked undo_pending_step_deletion_does_not_duplicate_recording -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.execute(\"file.new\", json!({\"width\": 8, \"height\": 8})).unwrap();\n s.execute(\"actions.record\", json!({\"name\": \"A\"})).unwrap();\n s.execute(\"layer.new.layer\", json!({})).unwrap();\n s.execute(\"actions.delete\", json!({\"action\": \"A\", \"step\": 0})).unwrap();\n s.execute(\"actions.undo\", json!({})).unwrap();\n s.execute(\"actions.stop\", json!({})).unwrap();\n assert_eq!(s.actions.list[0].steps.len(), 1);\n assert_eq!(s.active().unwrap().doc.layers.len(), 2);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.actions.list[0].steps.len(), 1);\n assert_eq!(s.active().unwrap().doc.layers.len(), 2);\n }",
|
||
" assert_eq!(s.active().unwrap().doc.layers.len(), 2);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d84fa7955d260505378a1a596ec80d602036319d/crates/engine/src/actions_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "actions_shortcut_undo_and_redo_edit_script_without_undoing_pixels",
|
||
"path": "crates/ui-egui/src/actions.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked actions_shortcut_undo_and_redo_edit_script_without_undoing_pixels -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::{Harness, kittest::Queryable};\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 8, \"height\": 8})).unwrap();\n app.run(\"layer.new.layer\", json!({})).unwrap();\n app.session.actions.list.push(Action { name: \"A\".into(), steps: vec![(\"select.all\".into(), json!({}))], disabled: Default::default() });\n let doc = app.session.active().unwrap().doc.clone();\n let mut h = Harness::builder().with_size(vec2(320.0, 260.0)).build_ui_state(|ui, app| panel(app, ui), app);\n h.run_steps(3);\n h.get_by_label(\"A\").click();\n h.run_steps(3);\n assert!(h.state().ui.actions.focused);\n h.state_mut().run(\"actions.delete\", json!({\"action\": \"A\", \"step\": 0})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.actions.focused);\n h.state_mut().run(\"actions.delete\", json!({\"action\": \"A\", \"step\": 0})).unwrap();\n let ctx = egui::Context::default();\n crate::shortcut_dispatch::dispatch(h.state_mut(), &ctx, \"edit.undo\");",
|
||
" assert_eq!(h.state().session.actions.list[0].steps.len(), 1);\n assert_eq!(h.state().session.active().unwrap().doc, doc);\n crate::shortcut_dispatch::dispatch(h.state_mut(), &ctx, \"edit.redo\");\n assert!(h.state().session.actions.list[0].steps.is_empty());",
|
||
" assert_eq!(h.state().session.active().unwrap().doc, doc);\n crate::shortcut_dispatch::dispatch(h.state_mut(), &ctx, \"edit.redo\");\n assert!(h.state().session.actions.list[0].steps.is_empty());\n h.state_mut().ui.actions.focused = false;",
|
||
" assert!(h.state().session.actions.list[0].steps.is_empty());\n h.state_mut().ui.actions.focused = false;\n crate::shortcut_dispatch::dispatch(h.state_mut(), &ctx, \"edit.undo\");\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1);",
|
||
" assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d84fa7955d260505378a1a596ec80d602036319d/crates/ui-egui/src/actions.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-3748",
|
||
"pr": 3748,
|
||
"subsystem": "Actions and automation",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-automation --locked unknown_names_suggest_the_right_method_or_command -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked errors_are_tool_errors_not_crashes -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked protocol_listing_method_points_at_command_list -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked near_misses_suggest_registered_ids -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked suggestions_are_capped_and_ordered -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked protocol_method_hints -- --nocapture",
|
||
"cargo test -p photocraft-text --locked tokenizer_and_distance -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked unknown_names_suggest_the_right_method_or_command -- --nocapture"
|
||
],
|
||
"expected": "unknown names suggest the right method or command; errors are tool errors not crashes; protocol listing method points at command list; near misses suggest registered ids; suggestions are capped and ordered; protocol method hints; tokenizer and distance; unknown names suggest the right method or command",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-automation --locked unknown_names_suggest_the_right_method_or_command -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked errors_are_tool_errors_not_crashes -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked protocol_listing_method_points_at_command_list -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked near_misses_suggest_registered_ids -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked suggestions_are_capped_and_ordered -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked protocol_method_hints -- --nocapture",
|
||
"cargo test -p photocraft-text --locked tokenizer_and_distance -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked unknown_names_suggest_the_right_method_or_command -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "unknown_names_suggest_the_right_method_or_command",
|
||
"path": "crates/automation/src/rpc.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked unknown_names_suggest_the_right_method_or_command -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = Headless::new();\n let err = |h: &mut Headless, m: &str, p: Value| h.handle(m, p).unwrap_err().to_string();\n let e = err(&mut h, \"engine.execute\", json!({\"command\": \"engine.commands\"}));\n assert!(e.contains(\"did you mean `command.list`\") && e.contains(\"protocol method\"), \"{e}\");\n let e = err(&mut h, \"engine.execute\", json!({\"command\": \"doc.inspect\"}));\n assert!(e.contains(\"`doc.inspect` is a protocol method\"), \"{e}\");\n let e = err(&mut h, \"engine.execute\", json!({\"command\": \"edit.undoo\"}));\n assert!(e.contains(\"did you mean `edit.undo`\"), \"{e}\");\n let e = err(&mut h, \"doc.inspct\", Value::Null);\n assert!(e.contains(\"did you mean `doc.inspect`\") && e.contains(\"(try `methods`)\"), \"{e}\");\n let e = err(&mut h, \"edit.undo\", Value::Null);\n assert!(e.contains(\"engine.execute {\\\"command\\\": \\\"edit.undo\\\"}\"), \"{e}\");",
|
||
"expected_assertions": [
|
||
" assert!(e.contains(\"did you mean `command.list`\") && e.contains(\"protocol method\"), \"{e}\");\n let e = err(&mut h, \"engine.execute\", json!({\"command\": \"doc.inspect\"}));\n assert!(e.contains(\"`doc.inspect` is a protocol method\"), \"{e}\");\n let e = err(&mut h, \"engine.execute\", json!({\"command\": \"edit.undoo\"}));",
|
||
" assert!(e.contains(\"`doc.inspect` is a protocol method\"), \"{e}\");\n let e = err(&mut h, \"engine.execute\", json!({\"command\": \"edit.undoo\"}));\n assert!(e.contains(\"did you mean `edit.undo`\"), \"{e}\");\n let e = err(&mut h, \"doc.inspct\", Value::Null);",
|
||
" assert!(e.contains(\"did you mean `edit.undo`\"), \"{e}\");\n let e = err(&mut h, \"doc.inspct\", Value::Null);\n assert!(e.contains(\"did you mean `doc.inspect`\") && e.contains(\"(try `methods`)\"), \"{e}\");\n let e = err(&mut h, \"edit.undo\", Value::Null);",
|
||
" assert!(e.contains(\"did you mean `doc.inspect`\") && e.contains(\"(try `methods`)\"), \"{e}\");\n let e = err(&mut h, \"edit.undo\", Value::Null);\n assert!(e.contains(\"engine.execute {\\\"command\\\": \\\"edit.undo\\\"}\"), \"{e}\");\n }",
|
||
" assert!(e.contains(\"engine.execute {\\\"command\\\": \\\"edit.undo\\\"}\"), \"{e}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c45d01eafe84e600bb28033a6853cc19c827b7bf/crates/automation/src/rpc.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "errors_are_tool_errors_not_crashes",
|
||
"path": "crates/automation/tests/mcp.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked errors_are_tool_errors_not_crashes -- --nocapture",
|
||
"fixture_and_action_excerpt": " let client = connect(PhotocraftMcp::headless()).await;\n let r = call(&client, \"command_run\", json!({\"id\": \"no.such.command\"})).await;\n assert_eq!(r.is_error, Some(true));\n assert!(text(&r).contains(\"unknown command\"));\n // #3674: the error names the nearest registered id.\n let r = call(&client, \"command_run\", json!({\"id\": \"engine.commands\"})).await;\n assert_eq!(r.is_error, Some(true));\n assert!(text(&r).contains(\"did you mean `command.list`\"), \"{}\", text(&r));\n let r = call(&client, \"doc_inspect\", json!({\"index\": 0})).await;\n assert_eq!(r.is_error, Some(true));\n let r = call(&client, \"doc_open\", json!({\"path\": \"/definitely/missing.png\"})).await;\n assert_eq!(r.is_error, Some(true));",
|
||
"expected_assertions": [
|
||
" assert_eq!(r.is_error, Some(true));\n assert!(text(&r).contains(\"unknown command\"));\n // #3674: the error names the nearest registered id.\n let r = call(&client, \"command_run\", json!({\"id\": \"engine.commands\"})).await;",
|
||
" assert!(text(&r).contains(\"unknown command\"));\n // #3674: the error names the nearest registered id.\n let r = call(&client, \"command_run\", json!({\"id\": \"engine.commands\"})).await;\n assert_eq!(r.is_error, Some(true));",
|
||
" assert_eq!(r.is_error, Some(true));\n assert!(text(&r).contains(\"did you mean `command.list`\"), \"{}\", text(&r));\n let r = call(&client, \"doc_inspect\", json!({\"index\": 0})).await;\n assert_eq!(r.is_error, Some(true));",
|
||
" assert!(text(&r).contains(\"did you mean `command.list`\"), \"{}\", text(&r));\n let r = call(&client, \"doc_inspect\", json!({\"index\": 0})).await;\n assert_eq!(r.is_error, Some(true));\n let r = call(&client, \"doc_open\", json!({\"path\": \"/definitely/missing.png\"})).await;",
|
||
" assert_eq!(r.is_error, Some(true));\n let r = call(&client, \"doc_open\", json!({\"path\": \"/definitely/missing.png\"})).await;\n assert_eq!(r.is_error, Some(true));\n let r = call(&client, \"ui_inspect\", json!({})).await;",
|
||
" assert_eq!(r.is_error, Some(true));\n let r = call(&client, \"ui_inspect\", json!({})).await;\n assert_eq!(r.is_error, Some(true));\n assert!(text(&r).contains(\"bridge\"));",
|
||
" assert_eq!(r.is_error, Some(true));\n assert!(text(&r).contains(\"bridge\"));\n let r = call(&client, \"doc_export\", json!({})).await;\n assert_eq!(r.is_error, Some(true));",
|
||
" assert!(text(&r).contains(\"bridge\"));\n let r = call(&client, \"doc_export\", json!({})).await;\n assert_eq!(r.is_error, Some(true));\n // Server still alive.",
|
||
" assert_eq!(r.is_error, Some(true));\n // Server still alive.\n json_of(&call(&client, \"session_list\", json!({})).await);\n client.cancel().await.unwrap();"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c45d01eafe84e600bb28033a6853cc19c827b7bf/crates/automation/tests/mcp.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "protocol_listing_method_points_at_command_list",
|
||
"path": "crates/engine/src/command_hints.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked protocol_listing_method_points_at_command_list -- --nocapture",
|
||
"fixture_and_action_excerpt": " assert_eq!(unknown(\"engine.commands\"), \"unknown command `engine.commands`; did you mean `command.list`?\");\n let mut s = Session::new();\n let e = s.execute(\"engine.commands\", json!({})).unwrap_err().to_string();\n assert!(e.contains(\"did you mean `command.list`\"), \"{e}\");\n assert!(s.disabled_reason(\"engine.commands\").unwrap().contains(\"`command.list`\"));\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(unknown(\"engine.commands\"), \"unknown command `engine.commands`; did you mean `command.list`?\");\n let mut s = Session::new();\n let e = s.execute(\"engine.commands\", json!({})).unwrap_err().to_string();\n assert!(e.contains(\"did you mean `command.list`\"), \"{e}\");",
|
||
" assert!(e.contains(\"did you mean `command.list`\"), \"{e}\");\n assert!(s.disabled_reason(\"engine.commands\").unwrap().contains(\"`command.list`\"));\n }",
|
||
" assert!(s.disabled_reason(\"engine.commands\").unwrap().contains(\"`command.list`\"));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c45d01eafe84e600bb28033a6853cc19c827b7bf/crates/engine/src/command_hints.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "near_misses_suggest_registered_ids",
|
||
"path": "crates/engine/src/command_hints.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked near_misses_suggest_registered_ids -- --nocapture",
|
||
"fixture_and_action_excerpt": " // Typo, case, and the same verb in another namespace.\n assert!(unknown(\"edit.undoo\").contains(\"did you mean `edit.undo`\"), \"{}\", unknown(\"edit.undoo\"));\n assert!(unknown(\"Edit.Undo\").contains(\"did you mean `edit.undo`\"), \"{}\", unknown(\"Edit.Undo\"));\n let e = unknown(\"document.undo\");\n assert!(e.contains(\"did you mean `edit.undo`\"), \"{e}\");\n assert!(unknown(\"document.redo\").contains(\"did you mean `edit.redo`\"));\n // A namespace prefix, a truncated id, a shorter last segment.\n assert!(unknown(\"layer.new\").contains(\"`layer.new.layer`\"), \"{}\", unknown(\"layer.new\"));\n assert!(unknown(\"filter.blur.gaussian\").contains(\"did you mean `filter.blur.gaussianBlur`\"));\n assert!(unknown(\"image.size\").contains(\"did you mean `image.imageSize`\"), \"{}\", unknown(\"image.size\"));\n assert!(e.len() < 200, \"a few suggestions, not a listing: {e}\");\n // Nothing close: the plain error.",
|
||
"expected_assertions": [
|
||
" assert!(unknown(\"edit.undoo\").contains(\"did you mean `edit.undo`\"), \"{}\", unknown(\"edit.undoo\"));\n assert!(unknown(\"Edit.Undo\").contains(\"did you mean `edit.undo`\"), \"{}\", unknown(\"Edit.Undo\"));\n let e = unknown(\"document.undo\");\n assert!(e.contains(\"did you mean `edit.undo`\"), \"{e}\");",
|
||
" assert!(unknown(\"Edit.Undo\").contains(\"did you mean `edit.undo`\"), \"{}\", unknown(\"Edit.Undo\"));\n let e = unknown(\"document.undo\");\n assert!(e.contains(\"did you mean `edit.undo`\"), \"{e}\");\n assert!(unknown(\"document.redo\").contains(\"did you mean `edit.redo`\"));",
|
||
" assert!(e.contains(\"did you mean `edit.undo`\"), \"{e}\");\n assert!(unknown(\"document.redo\").contains(\"did you mean `edit.redo`\"));\n // A namespace prefix, a truncated id, a shorter last segment.\n assert!(unknown(\"layer.new\").contains(\"`layer.new.layer`\"), \"{}\", unknown(\"layer.new\"));",
|
||
" assert!(unknown(\"document.redo\").contains(\"did you mean `edit.redo`\"));\n // A namespace prefix, a truncated id, a shorter last segment.\n assert!(unknown(\"layer.new\").contains(\"`layer.new.layer`\"), \"{}\", unknown(\"layer.new\"));\n assert!(unknown(\"filter.blur.gaussian\").contains(\"did you mean `filter.blur.gaussianBlur`\"));",
|
||
" assert!(unknown(\"layer.new\").contains(\"`layer.new.layer`\"), \"{}\", unknown(\"layer.new\"));\n assert!(unknown(\"filter.blur.gaussian\").contains(\"did you mean `filter.blur.gaussianBlur`\"));\n assert!(unknown(\"image.size\").contains(\"did you mean `image.imageSize`\"), \"{}\", unknown(\"image.size\"));\n assert!(e.len() < 200, \"a few suggestions, not a listing: {e}\");",
|
||
" assert!(unknown(\"filter.blur.gaussian\").contains(\"did you mean `filter.blur.gaussianBlur`\"));\n assert!(unknown(\"image.size\").contains(\"did you mean `image.imageSize`\"), \"{}\", unknown(\"image.size\"));\n assert!(e.len() < 200, \"a few suggestions, not a listing: {e}\");\n // Nothing close: the plain error.",
|
||
" assert!(unknown(\"image.size\").contains(\"did you mean `image.imageSize`\"), \"{}\", unknown(\"image.size\"));\n assert!(e.len() < 200, \"a few suggestions, not a listing: {e}\");\n // Nothing close: the plain error.\n assert_eq!(unknown(\"zzzz.qqqq\"), \"unknown command `zzzz.qqqq`\");",
|
||
" assert!(e.len() < 200, \"a few suggestions, not a listing: {e}\");\n // Nothing close: the plain error.\n assert_eq!(unknown(\"zzzz.qqqq\"), \"unknown command `zzzz.qqqq`\");\n assert_eq!(unknown(\"\"), \"unknown command ``\");",
|
||
" assert_eq!(unknown(\"zzzz.qqqq\"), \"unknown command `zzzz.qqqq`\");\n assert_eq!(unknown(\"\"), \"unknown command ``\");\n }",
|
||
" assert_eq!(unknown(\"\"), \"unknown command ``\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c45d01eafe84e600bb28033a6853cc19c827b7bf/crates/engine/src/command_hints.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "suggestions_are_capped_and_ordered",
|
||
"path": "crates/engine/src/command_hints.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked suggestions_are_capped_and_ordered -- --nocapture",
|
||
"fixture_and_action_excerpt": " let c = [\"a.bc\", \"a.bd\", \"a.be\", \"a.bf\", \"x.y\"];\n assert_eq!(near_matches(\"a.bb\", c), [\"a.bc\", \"a.bd\", \"a.be\"]);\n assert_eq!(did_you_mean(&[]), \"\");\n assert_eq!(did_you_mean(&[\"a\"]), \"; did you mean `a`?\");\n assert_eq!(did_you_mean(&[\"a\", \"b\", \"c\"]), \"; did you mean `a`, `b` or `c`?\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(near_matches(\"a.bb\", c), [\"a.bc\", \"a.bd\", \"a.be\"]);\n assert_eq!(did_you_mean(&[]), \"\");\n assert_eq!(did_you_mean(&[\"a\"]), \"; did you mean `a`?\");\n assert_eq!(did_you_mean(&[\"a\", \"b\", \"c\"]), \"; did you mean `a`, `b` or `c`?\");",
|
||
" assert_eq!(did_you_mean(&[]), \"\");\n assert_eq!(did_you_mean(&[\"a\"]), \"; did you mean `a`?\");\n assert_eq!(did_you_mean(&[\"a\", \"b\", \"c\"]), \"; did you mean `a`, `b` or `c`?\");\n }",
|
||
" assert_eq!(did_you_mean(&[\"a\"]), \"; did you mean `a`?\");\n assert_eq!(did_you_mean(&[\"a\", \"b\", \"c\"]), \"; did you mean `a`, `b` or `c`?\");\n }",
|
||
" assert_eq!(did_you_mean(&[\"a\", \"b\", \"c\"]), \"; did you mean `a`, `b` or `c`?\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c45d01eafe84e600bb28033a6853cc19c827b7bf/crates/engine/src/command_hints.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "protocol_method_hints",
|
||
"path": "crates/engine/src/command_hints.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked protocol_method_hints -- --nocapture",
|
||
"fixture_and_action_excerpt": " let methods = [\"engine.execute\", \"doc.inspect\", \"doc.open\", \"methods\"];\n assert_eq!(unknown_method(\"doc.inspct\", &methods), \"unknown method `doc.inspct`; did you mean `doc.inspect`?\");\n assert!(unknown_method(\"edit.undo\", &methods).contains(\"engine.execute {\\\"command\\\": \\\"edit.undo\\\"}\"));\n assert_eq!(unknown_method(\"zzzz\", &methods), \"unknown method `zzzz`\");\n assert!(protocol_method_as_command(\"doc.inspect\").contains(\"`doc.inspect` is a protocol method\"));\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(unknown_method(\"doc.inspct\", &methods), \"unknown method `doc.inspct`; did you mean `doc.inspect`?\");\n assert!(unknown_method(\"edit.undo\", &methods).contains(\"engine.execute {\\\"command\\\": \\\"edit.undo\\\"}\"));\n assert_eq!(unknown_method(\"zzzz\", &methods), \"unknown method `zzzz`\");\n assert!(protocol_method_as_command(\"doc.inspect\").contains(\"`doc.inspect` is a protocol method\"));",
|
||
" assert!(unknown_method(\"edit.undo\", &methods).contains(\"engine.execute {\\\"command\\\": \\\"edit.undo\\\"}\"));\n assert_eq!(unknown_method(\"zzzz\", &methods), \"unknown method `zzzz`\");\n assert!(protocol_method_as_command(\"doc.inspect\").contains(\"`doc.inspect` is a protocol method\"));\n }",
|
||
" assert_eq!(unknown_method(\"zzzz\", &methods), \"unknown method `zzzz`\");\n assert!(protocol_method_as_command(\"doc.inspect\").contains(\"`doc.inspect` is a protocol method\"));\n }",
|
||
" assert!(protocol_method_as_command(\"doc.inspect\").contains(\"`doc.inspect` is a protocol method\"));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c45d01eafe84e600bb28033a6853cc19c827b7bf/crates/engine/src/command_hints.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "tokenizer_and_distance",
|
||
"path": "crates/text/src/spell.rs",
|
||
"package": "photocraft-text",
|
||
"command": "cargo test -p photocraft-text --locked tokenizer_and_distance -- --nocapture",
|
||
"fixture_and_action_excerpt": " let t = \"it's well-known 'quoted' café\";\n let w: Vec<&str> = words(t).into_iter().map(|(a, b)| &t[a..b]).collect();\n assert_eq!(w, vec![\"it's\", \"well\", \"known\", \"quoted\", \"café\"]);\n let c = |s: &str| s.chars().collect::<Vec<char>>();\n let mut r = Rows::default();\n assert_eq!(distance(&c(\"teh\"), &c(\"the\"), 2, &mut r), Some(1));\n assert_eq!(distance(&c(\"teh\"), &c(\"toe\"), 2, &mut r), Some(2));\n assert_eq!(distance(&c(\"teh\"), &c(\"banana\"), 2, &mut r), None);\n assert_eq!(edit_distance(\"edit.undoo\", \"edit.undo\", 2), Some(1));\n assert_eq!(edit_distance(\"teh\", \"banana\", 2), None);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(w, vec![\"it's\", \"well\", \"known\", \"quoted\", \"café\"]);\n let c = |s: &str| s.chars().collect::<Vec<char>>();\n let mut r = Rows::default();\n assert_eq!(distance(&c(\"teh\"), &c(\"the\"), 2, &mut r), Some(1));",
|
||
" assert_eq!(distance(&c(\"teh\"), &c(\"the\"), 2, &mut r), Some(1));\n assert_eq!(distance(&c(\"teh\"), &c(\"toe\"), 2, &mut r), Some(2));\n assert_eq!(distance(&c(\"teh\"), &c(\"banana\"), 2, &mut r), None);\n assert_eq!(edit_distance(\"edit.undoo\", \"edit.undo\", 2), Some(1));",
|
||
" assert_eq!(distance(&c(\"teh\"), &c(\"toe\"), 2, &mut r), Some(2));\n assert_eq!(distance(&c(\"teh\"), &c(\"banana\"), 2, &mut r), None);\n assert_eq!(edit_distance(\"edit.undoo\", \"edit.undo\", 2), Some(1));\n assert_eq!(edit_distance(\"teh\", \"banana\", 2), None);",
|
||
" assert_eq!(distance(&c(\"teh\"), &c(\"banana\"), 2, &mut r), None);\n assert_eq!(edit_distance(\"edit.undoo\", \"edit.undo\", 2), Some(1));\n assert_eq!(edit_distance(\"teh\", \"banana\", 2), None);\n }",
|
||
" assert_eq!(edit_distance(\"edit.undoo\", \"edit.undo\", 2), Some(1));\n assert_eq!(edit_distance(\"teh\", \"banana\", 2), None);\n }",
|
||
" assert_eq!(edit_distance(\"teh\", \"banana\", 2), None);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c45d01eafe84e600bb28033a6853cc19c827b7bf/crates/text/src/spell.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "unknown_names_suggest_the_right_method_or_command",
|
||
"path": "crates/ui-egui/src/control.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked unknown_names_suggest_the_right_method_or_command -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n let ctx = egui::Context::default();\n let mut error = |method: &str, params: Value| {\n let reply = call(&mut app, &ctx, method, params);\n assert_eq!(reply[\"ok\"], false, \"{reply}\");\n reply[\"error\"].as_str().unwrap_or_default().to_owned()\n };\n let e = error(\"engine.execute\", json!({\"command\": \"engine.commands\"}));\n assert!(e.contains(\"did you mean `command.list`\") && e.contains(\"protocol method\"), \"{e}\");\n let e = error(\"engine.execute\", json!({\"command\": \"ui.inspect\"}));\n assert!(e.contains(\"`ui.inspect` is a protocol method\"), \"{e}\");\n let e = error(\"engine.execute\", json!({\"command\": \"edit.undoo\"}));",
|
||
"expected_assertions": [
|
||
" assert_eq!(reply[\"ok\"], false, \"{reply}\");\n reply[\"error\"].as_str().unwrap_or_default().to_owned()\n };\n let e = error(\"engine.execute\", json!({\"command\": \"engine.commands\"}));",
|
||
" assert!(e.contains(\"did you mean `command.list`\") && e.contains(\"protocol method\"), \"{e}\");\n let e = error(\"engine.execute\", json!({\"command\": \"ui.inspect\"}));\n assert!(e.contains(\"`ui.inspect` is a protocol method\"), \"{e}\");\n let e = error(\"engine.execute\", json!({\"command\": \"edit.undoo\"}));",
|
||
" assert!(e.contains(\"`ui.inspect` is a protocol method\"), \"{e}\");\n let e = error(\"engine.execute\", json!({\"command\": \"edit.undoo\"}));\n assert!(e.contains(\"did you mean `edit.undo`\"), \"{e}\");\n let e = error(\"ui.inspct\", json!({}));",
|
||
" assert!(e.contains(\"did you mean `edit.undo`\"), \"{e}\");\n let e = error(\"ui.inspct\", json!({}));\n assert!(e.contains(\"did you mean `ui.inspect`\"), \"{e}\");\n let e = error(\"edit.undo\", json!({}));",
|
||
" assert!(e.contains(\"did you mean `ui.inspect`\"), \"{e}\");\n let e = error(\"edit.undo\", json!({}));\n assert!(e.contains(\"engine.execute {\\\"command\\\": \\\"edit.undo\\\"}\"), \"{e}\");\n for m in METHODS {",
|
||
" assert!(e.contains(\"engine.execute {\\\"command\\\": \\\"edit.undo\\\"}\"), \"{e}\");\n for m in METHODS {\n let (req, _rx) = ControlRequest::new(*m, json!({}));\n if let Outcome::Done(v) = handle(&mut app, &ctx, &req) {",
|
||
" assert!(!v.to_string().contains(\"unknown method\"), \"{m} is listed but not served: {v}\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c45d01eafe84e600bb28033a6853cc19c827b7bf/crates/ui-egui/src/control.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-4993",
|
||
"pr": 4993,
|
||
"subsystem": "Actions and automation",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked engine_execute_cannot_change_document_behind_adjustment_dialog -- --nocapture"
|
||
],
|
||
"expected": "engine execute cannot change document behind adjustment dialog",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked engine_execute_cannot_change_document_behind_adjustment_dialog -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "engine_execute_cannot_change_document_behind_adjustment_dialog",
|
||
"path": "crates/ui-egui/src/control.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked engine_execute_cannot_change_document_behind_adjustment_dialog -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n let ctx = egui::Context::default();\n app.run(\"file.new\", json!({\"width\": 60, \"height\": 40, \"background\": \"#3366cc\"})).unwrap();\n let opened = call(&mut app, &ctx, \"ui.menu.invoke\", json!({\"id\": \"image.adjustments.hueSaturation\"}));\n assert_eq!(opened[\"ok\"], true, \"{opened}\");\n let dialog = opened[\"result\"][\"dialog\"].as_u64().unwrap();\n let revision = app.session.active().unwrap().revision;\n let fields = call(&mut app, &ctx, \"ui.inspect\", json!({}))[\"result\"][\"dialogs\"][0][\"fields\"].clone();\n\n for method in [\"engine.execute\", \"ui.menu.invoke\"] {\n let blocked = call(&mut app, &ctx, method, json!({\"command\": \"image.adjustments.invert\"}));\n assert_eq!(blocked[\"ok\"], false, \"{method}: {blocked}\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(opened[\"ok\"], true, \"{opened}\");\n let dialog = opened[\"result\"][\"dialog\"].as_u64().unwrap();\n let revision = app.session.active().unwrap().revision;\n let fields = call(&mut app, &ctx, \"ui.inspect\", json!({}))[\"result\"][\"dialogs\"][0][\"fields\"].clone();",
|
||
" assert_eq!(blocked[\"ok\"], false, \"{method}: {blocked}\");\n assert_eq!(app.session.active().unwrap().revision, revision, \"{method} changed the document\");\n let snapshot = call(&mut app, &ctx, \"ui.inspect\", json!({}));\n assert_eq!(snapshot[\"result\"][\"dialogs\"][0][\"id\"], dialog);",
|
||
" assert_eq!(app.session.active().unwrap().revision, revision, \"{method} changed the document\");\n let snapshot = call(&mut app, &ctx, \"ui.inspect\", json!({}));\n assert_eq!(snapshot[\"result\"][\"dialogs\"][0][\"id\"], dialog);\n assert_eq!(snapshot[\"result\"][\"dialogs\"][0][\"fields\"], fields);",
|
||
" assert_eq!(snapshot[\"result\"][\"dialogs\"][0][\"id\"], dialog);\n assert_eq!(snapshot[\"result\"][\"dialogs\"][0][\"fields\"], fields);\n }\n",
|
||
" assert_eq!(snapshot[\"result\"][\"dialogs\"][0][\"fields\"], fields);\n }\n\n assert_eq!(call(&mut app, &ctx, \"ui.dialog.cancel\", json!({\"dialog\": dialog}))[\"ok\"], true);",
|
||
" assert_eq!(call(&mut app, &ctx, \"ui.dialog.cancel\", json!({\"dialog\": dialog}))[\"ok\"], true);\n assert_eq!(call(&mut app, &ctx, \"engine.execute\", json!({\"command\": \"image.adjustments.invert\"}))[\"ok\"], true);\n assert!(app.session.active().unwrap().revision > revision);\n }",
|
||
" assert_eq!(call(&mut app, &ctx, \"engine.execute\", json!({\"command\": \"image.adjustments.invert\"}))[\"ok\"], true);\n assert!(app.session.active().unwrap().revision > revision);\n }",
|
||
" assert!(app.session.active().unwrap().revision > revision);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/81964dc5ef77a71a2ae2a938958cf3ed77d90719/crates/ui-egui/src/control.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-5090",
|
||
"pr": 5090,
|
||
"subsystem": "Actions and automation",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-web --locked generated_defaults_are_persisted_without_unsaved_user_work -- --nocapture",
|
||
"cargo test -p photocraft-web --locked denied_storage_marks_default_edits_unsaved_and_retry_saves_them -- --nocapture",
|
||
"cargo test -p photocraft-web --locked finishing_default_transaction_keeps_newer_action_edits_unsaved -- --nocapture",
|
||
"cargo test -p photocraft-web --locked failed_default_transaction_does_not_warn_until_a_user_edit -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked load_defaults_preserves_names_and_edits_and_is_idempotent -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked defaults_seed_once_and_restore_only_when_requested -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked old_store_and_early_actions_win_over_defaults -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked unreadable_actions_are_not_seeded_or_overwritten -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked auto_defaults_play_on_pixels_and_undo_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked subject_default_samples_visible_layers_and_undo_restores_selection -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked actions_persist_with_the_preset_store -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked blur_background_preserves_subject_and_undoes_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked blur_background_preserves_selection_alpha_masks_and_other_layers -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked background_sampling_excludes_subject_colors_for_both_blur_paths -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked blur_background_without_subject_or_when_cancelled_changes_nothing -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked blur_background_rejects_invalid_targets_params_and_effective_locks -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked blur_background_24mp_timing -- --nocapture --ignored",
|
||
"cargo test -p photocraft-engine --locked group_with_sampled_8_and_16_bit_tips_round_trips -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked commands_persist_and_delete_removes_from_disk -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked default_actions_load_from_empty_panel_and_play -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked default_actions_flyout_preserves_custom_actions_and_reveals_restored_set -- --nocapture"
|
||
],
|
||
"expected": "generated defaults are persisted without unsaved user work; denied storage marks default edits unsaved and retry saves them; finishing default transaction keeps newer action edits unsaved; failed default transaction does not warn until a user edit; load defaults preserves names and edits and is idempotent; defaults seed once and restore only when requested; old store and early actions win over defaults; unreadable actions are not seeded or overwritten; auto defaults play on pixels and undo at every depth; subject default samples visible layers and undo restores selection; actions persist with the preset store; blur background preserves subject and undoes at every depth; blur background preserves selection alpha masks and other layers; background sampling excludes subject colors for both blur paths; blur background without subject or when cancelled changes nothing; blur background rejects invalid targets params and effective locks; blur background 24mp timing; group with sampled 8 and 16 bit tips round trips; commands persist and delete removes from disk; default actions load from empty panel and play; default actions flyout preserves custom actions and reveals restored set",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-web --locked generated_defaults_are_persisted_without_unsaved_user_work -- --nocapture",
|
||
"cargo test -p photocraft-web --locked denied_storage_marks_default_edits_unsaved_and_retry_saves_them -- --nocapture",
|
||
"cargo test -p photocraft-web --locked finishing_default_transaction_keeps_newer_action_edits_unsaved -- --nocapture",
|
||
"cargo test -p photocraft-web --locked failed_default_transaction_does_not_warn_until_a_user_edit -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked load_defaults_preserves_names_and_edits_and_is_idempotent -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked defaults_seed_once_and_restore_only_when_requested -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked old_store_and_early_actions_win_over_defaults -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked unreadable_actions_are_not_seeded_or_overwritten -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked auto_defaults_play_on_pixels_and_undo_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked subject_default_samples_visible_layers_and_undo_restores_selection -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked actions_persist_with_the_preset_store -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked blur_background_preserves_subject_and_undoes_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked blur_background_preserves_selection_alpha_masks_and_other_layers -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked background_sampling_excludes_subject_colors_for_both_blur_paths -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked blur_background_without_subject_or_when_cancelled_changes_nothing -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked blur_background_rejects_invalid_targets_params_and_effective_locks -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked blur_background_24mp_timing -- --nocapture --ignored",
|
||
"cargo test -p photocraft-engine --locked group_with_sampled_8_and_16_bit_tips_round_trips -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked commands_persist_and_delete_removes_from_disk -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked default_actions_load_from_empty_panel_and_play -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked default_actions_flyout_preserves_custom_actions_and_reveals_restored_set -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "generated_defaults_are_persisted_without_unsaved_user_work",
|
||
"path": "apps/photocraft-web/src/preset_bridge.rs",
|
||
"package": "photocraft-web",
|
||
"command": "cargo test -p photocraft-web --locked generated_defaults_are_persisted_without_unsaved_user_work -- --nocapture",
|
||
"fixture_and_action_excerpt": " let b = Bridge::default();\n let (s, warnings) = session(b.clone());\n assert!(warnings.is_empty());\n assert_eq!(s.actions.list.len(), 5);\n assert!(!b.unsaved());\n let batch = b.begin().unwrap();\n let actions: serde_json::Value = serde_json::from_slice(batch.get(ACTIONS_FILE).unwrap().as_deref().unwrap()).unwrap();\n assert_eq!(actions[\"defaults_version\"], 1);\n assert_eq!(actions[\"actions\"].as_array().unwrap().len(), 5);\n assert!(!b.unsaved(), \"generated defaults in flight can be recreated on reload\");\n let restored = Bridge::default();\n for (name, bytes) in &batch {",
|
||
"expected_assertions": [
|
||
" assert!(warnings.is_empty());\n assert_eq!(s.actions.list.len(), 5);\n assert!(!b.unsaved());\n let batch = b.begin().unwrap();",
|
||
" assert_eq!(s.actions.list.len(), 5);\n assert!(!b.unsaved());\n let batch = b.begin().unwrap();\n let actions: serde_json::Value = serde_json::from_slice(batch.get(ACTIONS_FILE).unwrap().as_deref().unwrap()).unwrap();",
|
||
" assert!(!b.unsaved());\n let batch = b.begin().unwrap();\n let actions: serde_json::Value = serde_json::from_slice(batch.get(ACTIONS_FILE).unwrap().as_deref().unwrap()).unwrap();\n assert_eq!(actions[\"defaults_version\"], 1);",
|
||
" assert_eq!(actions[\"defaults_version\"], 1);\n assert_eq!(actions[\"actions\"].as_array().unwrap().len(), 5);\n assert!(!b.unsaved(), \"generated defaults in flight can be recreated on reload\");\n let restored = Bridge::default();",
|
||
" assert_eq!(actions[\"actions\"].as_array().unwrap().len(), 5);\n assert!(!b.unsaved(), \"generated defaults in flight can be recreated on reload\");\n let restored = Bridge::default();\n for (name, bytes) in &batch {",
|
||
" assert!(!b.unsaved(), \"generated defaults in flight can be recreated on reload\");\n let restored = Bridge::default();\n for (name, bytes) in &batch {\n if let Some(bytes) = bytes {",
|
||
" assert!(warnings.is_empty());\n assert_eq!(reloaded.actions.list, s.actions.list);\n assert!(restored.begin().is_none(), \"the persisted marker avoids reseeding on reload\");\n assert!(!b.unsaved());",
|
||
" assert_eq!(reloaded.actions.list, s.actions.list);\n assert!(restored.begin().is_none(), \"the persisted marker avoids reseeding on reload\");\n assert!(!b.unsaved());\n }",
|
||
" assert!(restored.begin().is_none(), \"the persisted marker avoids reseeding on reload\");\n assert!(!b.unsaved());\n }",
|
||
" assert!(!b.unsaved());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/apps/photocraft-web/src/preset_bridge.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "denied_storage_marks_default_edits_unsaved_and_retry_saves_them",
|
||
"path": "apps/photocraft-web/src/preset_bridge.rs",
|
||
"package": "photocraft-web",
|
||
"command": "cargo test -p photocraft-web --locked denied_storage_marks_default_edits_unsaved_and_retry_saves_them -- --nocapture",
|
||
"fixture_and_action_excerpt": " for command in [\"actions.delete\", \"actions.rename\"] {\n let b = Bridge::default();\n b.unavailable(\"SecurityError\".into());\n let (mut s, _) = session(b.clone());\n assert!(!b.unsaved());\n s.execute(command, json!({\"action\": \"Auto Tone\", \"name\": \"My Tone\"})).unwrap();\n assert!(b.unsaved(), \"editing generated defaults is user work: {command}\");\n assert!(b.begin().is_none());\n assert!(b.error().unwrap().contains(\"SecurityError\"));\n b.retry();\n let batch = b.begin().unwrap();\n assert!(b.unsaved(), \"the edit remains unsaved while its transaction runs\");",
|
||
"expected_assertions": [
|
||
" assert!(!b.unsaved());\n s.execute(command, json!({\"action\": \"Auto Tone\", \"name\": \"My Tone\"})).unwrap();\n assert!(b.unsaved(), \"editing generated defaults is user work: {command}\");\n assert!(b.begin().is_none());",
|
||
" assert!(b.unsaved(), \"editing generated defaults is user work: {command}\");\n assert!(b.begin().is_none());\n assert!(b.error().unwrap().contains(\"SecurityError\"));\n b.retry();",
|
||
" assert!(b.begin().is_none());\n assert!(b.error().unwrap().contains(\"SecurityError\"));\n b.retry();\n let batch = b.begin().unwrap();",
|
||
" assert!(b.error().unwrap().contains(\"SecurityError\"));\n b.retry();\n let batch = b.begin().unwrap();\n assert!(b.unsaved(), \"the edit remains unsaved while its transaction runs\");",
|
||
" assert!(b.unsaved(), \"the edit remains unsaved while its transaction runs\");\n let restored = Bridge::default();\n for (name, bytes) in &batch {\n if let Some(bytes) = bytes {",
|
||
" assert!(!b.unsaved());\n assert!(b.error().is_none());\n let (reloaded, warnings) = session(restored);\n assert!(warnings.is_empty());",
|
||
" assert!(b.error().is_none());\n let (reloaded, warnings) = session(restored);\n assert!(warnings.is_empty());\n assert_eq!(reloaded.actions.list, s.actions.list);",
|
||
" assert!(warnings.is_empty());\n assert_eq!(reloaded.actions.list, s.actions.list);\n assert!(!reloaded.actions.list.iter().any(|a| a.name == \"Auto Tone\"));\n }",
|
||
" assert_eq!(reloaded.actions.list, s.actions.list);\n assert!(!reloaded.actions.list.iter().any(|a| a.name == \"Auto Tone\"));\n }\n }",
|
||
" assert!(!reloaded.actions.list.iter().any(|a| a.name == \"Auto Tone\"));\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/apps/photocraft-web/src/preset_bridge.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "finishing_default_transaction_keeps_newer_action_edits_unsaved",
|
||
"path": "apps/photocraft-web/src/preset_bridge.rs",
|
||
"package": "photocraft-web",
|
||
"command": "cargo test -p photocraft-web --locked finishing_default_transaction_keeps_newer_action_edits_unsaved -- --nocapture",
|
||
"fixture_and_action_excerpt": " for result in [Ok(()), Err(\"QuotaExceededError\".into())] {\n let b = Bridge::default();\n let (mut s, _) = session(b.clone());\n let defaults = b.begin().unwrap();\n s.execute(\"actions.delete\", json!({\"action\": \"Auto Tone\"})).unwrap();\n b.finish(defaults, result);\n assert!(b.unsaved(), \"the bootstrap transaction cannot save a later edit\");\n b.retry();\n let edited = b.begin().unwrap();\n let actions: serde_json::Value = serde_json::from_slice(edited.get(ACTIONS_FILE).unwrap().as_deref().unwrap()).unwrap();\n assert!(!actions[\"actions\"].as_array().unwrap().iter().any(|a| a[\"name\"] == \"Auto Tone\"));\n b.finish(edited, Ok(()));",
|
||
"expected_assertions": [
|
||
" assert!(b.unsaved(), \"the bootstrap transaction cannot save a later edit\");\n b.retry();\n let edited = b.begin().unwrap();\n let actions: serde_json::Value = serde_json::from_slice(edited.get(ACTIONS_FILE).unwrap().as_deref().unwrap()).unwrap();",
|
||
" assert!(!actions[\"actions\"].as_array().unwrap().iter().any(|a| a[\"name\"] == \"Auto Tone\"));\n b.finish(edited, Ok(()));\n assert!(!b.unsaved());\n }",
|
||
" assert!(!b.unsaved());\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/apps/photocraft-web/src/preset_bridge.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "failed_default_transaction_does_not_warn_until_a_user_edit",
|
||
"path": "apps/photocraft-web/src/preset_bridge.rs",
|
||
"package": "photocraft-web",
|
||
"command": "cargo test -p photocraft-web --locked failed_default_transaction_does_not_warn_until_a_user_edit -- --nocapture",
|
||
"fixture_and_action_excerpt": " let b = Bridge::default();\n let (mut s, _) = session(b.clone());\n b.finish(b.begin().unwrap(), Err(\"QuotaExceededError\".into()));\n assert!(!b.unsaved(), \"the defaults are still reproducible after a failed write\");\n assert!(b.begin().is_none());\n import(&mut s);\n assert!(b.unsaved());\n assert!(b.error().unwrap().contains(\"QuotaExceededError\"));\n let (reloaded, warnings) = session(b.clone());\n assert!(warnings.is_empty());\n assert_eq!(reloaded.tools.presets, s.tools.presets);\n assert!(b.unsaved(), \"reattaching must not hide already pending user edits\");",
|
||
"expected_assertions": [
|
||
" assert!(!b.unsaved(), \"the defaults are still reproducible after a failed write\");\n assert!(b.begin().is_none());\n import(&mut s);\n assert!(b.unsaved());",
|
||
" assert!(b.begin().is_none());\n import(&mut s);\n assert!(b.unsaved());\n assert!(b.error().unwrap().contains(\"QuotaExceededError\"));",
|
||
" assert!(b.unsaved());\n assert!(b.error().unwrap().contains(\"QuotaExceededError\"));\n let (reloaded, warnings) = session(b.clone());\n assert!(warnings.is_empty());",
|
||
" assert!(b.error().unwrap().contains(\"QuotaExceededError\"));\n let (reloaded, warnings) = session(b.clone());\n assert!(warnings.is_empty());\n assert_eq!(reloaded.tools.presets, s.tools.presets);",
|
||
" assert!(warnings.is_empty());\n assert_eq!(reloaded.tools.presets, s.tools.presets);\n assert!(b.unsaved(), \"reattaching must not hide already pending user edits\");\n b.retry();",
|
||
" assert_eq!(reloaded.tools.presets, s.tools.presets);\n assert!(b.unsaved(), \"reattaching must not hide already pending user edits\");\n b.retry();\n b.finish(b.begin().unwrap(), Ok(()));",
|
||
" assert!(b.unsaved(), \"reattaching must not hide already pending user edits\");\n b.retry();\n b.finish(b.begin().unwrap(), Ok(()));\n assert!(!b.unsaved());",
|
||
" assert!(!b.unsaved());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/apps/photocraft-web/src/preset_bridge.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "load_defaults_preserves_names_and_edits_and_is_idempotent",
|
||
"path": "crates/engine/src/action_defaults.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked load_defaults_preserves_names_and_edits_and_is_idempotent -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n assert!(s.actions.list.is_empty(), \"headless sessions remain hermetic\");\n let custom = Action::new(\"Auto Tone\", vec![(\"image.flipCanvasHorizontal\".into(), json!({}))]);\n s.actions.list.push(custom.clone());\n let loaded = s.execute(\"actions.loadDefaults\", json!({})).unwrap();\n assert_eq!(loaded[\"added\"], json!([\"Auto Contrast\", \"Auto Color\", \"Select Subject\", \"Blur Background\"]));\n assert_eq!(s.actions.list[0], custom);\n assert!(s.actions.list.iter().skip(1).all(|a| a.set.as_deref() == Some(SET)));\n let rev = s.actions.rev;\n assert_eq!(s.execute(\"actions.loadDefaults\", json!({})).unwrap()[\"added\"], json!([]));\n assert_eq!(s.actions.rev, rev, \"unchanged defaults do not cause a store write\");\n assert!(s.journal.is_empty());",
|
||
"expected_assertions": [
|
||
" assert!(s.actions.list.is_empty(), \"headless sessions remain hermetic\");\n let custom = Action::new(\"Auto Tone\", vec![(\"image.flipCanvasHorizontal\".into(), json!({}))]);\n s.actions.list.push(custom.clone());\n let loaded = s.execute(\"actions.loadDefaults\", json!({})).unwrap();",
|
||
" assert_eq!(loaded[\"added\"], json!([\"Auto Contrast\", \"Auto Color\", \"Select Subject\", \"Blur Background\"]));\n assert_eq!(s.actions.list[0], custom);\n assert!(s.actions.list.iter().skip(1).all(|a| a.set.as_deref() == Some(SET)));\n let rev = s.actions.rev;",
|
||
" assert_eq!(s.actions.list[0], custom);\n assert!(s.actions.list.iter().skip(1).all(|a| a.set.as_deref() == Some(SET)));\n let rev = s.actions.rev;\n assert_eq!(s.execute(\"actions.loadDefaults\", json!({})).unwrap()[\"added\"], json!([]));",
|
||
" assert!(s.actions.list.iter().skip(1).all(|a| a.set.as_deref() == Some(SET)));\n let rev = s.actions.rev;\n assert_eq!(s.execute(\"actions.loadDefaults\", json!({})).unwrap()[\"added\"], json!([]));\n assert_eq!(s.actions.rev, rev, \"unchanged defaults do not cause a store write\");",
|
||
" assert_eq!(s.execute(\"actions.loadDefaults\", json!({})).unwrap()[\"added\"], json!([]));\n assert_eq!(s.actions.rev, rev, \"unchanged defaults do not cause a store write\");\n assert!(s.journal.is_empty());\n assert!(s.active().is_none());",
|
||
" assert_eq!(s.actions.rev, rev, \"unchanged defaults do not cause a store write\");\n assert!(s.journal.is_empty());\n assert!(s.active().is_none());\n",
|
||
" assert!(s.journal.is_empty());\n assert!(s.active().is_none());\n\n for bad in [Value::Null, json!([]), json!(\"defaults\"), json!(true), json!(1)] {",
|
||
" assert!(s.active().is_none());\n\n for bad in [Value::Null, json!([]), json!(\"defaults\"), json!(true), json!(1)] {\n assert!(s.execute(\"actions.loadDefaults\", bad).is_err());",
|
||
" assert!(s.execute(\"actions.loadDefaults\", bad).is_err());\n }\n s.execute(\"actions.record\", json!({\"name\": \"Recording\"})).unwrap();\n assert!(!s.is_enabled(\"actions.loadDefaults\"));",
|
||
" assert!(!s.is_enabled(\"actions.loadDefaults\"));\n assert!(s.execute(\"actions.loadDefaults\", json!({})).is_err());\n s.execute(\"actions.stop\", json!({})).unwrap();\n s.actions.playing = 1;",
|
||
" assert!(s.execute(\"actions.loadDefaults\", json!({})).is_err());\n s.execute(\"actions.stop\", json!({})).unwrap();\n s.actions.playing = 1;\n assert!(load(&mut s, &json!({})).is_err());",
|
||
" assert!(load(&mut s, &json!({})).is_err());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/action_defaults.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "defaults_seed_once_and_restore_only_when_requested",
|
||
"path": "crates/engine/src/action_defaults.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked defaults_seed_once_and_restore_only_when_requested -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mem = MemBackend::default();\n let mut s = attached(&mem);\n assert_eq!(s.actions.list, defaults());\n assert_eq!(saved(&mem).defaults_version, VERSION);\n s.execute(\"actions.delete\", json!({\"action\": \"Auto Tone\"})).unwrap();\n s.execute(\"actions.rename\", json!({\"action\": \"Auto Color\", \"name\": \"My Color\"})).unwrap();\n let customized = s.actions.list.clone();\n let mut restarted = attached(&mem);\n assert_eq!(restarted.actions.list, customized, \"deleted and renamed defaults stay customized on restart\");\n assert_eq!(restarted.execute(\"actions.loadDefaults\", json!({})).unwrap()[\"added\"], json!([\"Auto Tone\", \"Auto Color\"]));\n assert_eq!(attached(&mem).actions.list, restarted.actions.list);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.actions.list, defaults());\n assert_eq!(saved(&mem).defaults_version, VERSION);\n s.execute(\"actions.delete\", json!({\"action\": \"Auto Tone\"})).unwrap();\n s.execute(\"actions.rename\", json!({\"action\": \"Auto Color\", \"name\": \"My Color\"})).unwrap();",
|
||
" assert_eq!(saved(&mem).defaults_version, VERSION);\n s.execute(\"actions.delete\", json!({\"action\": \"Auto Tone\"})).unwrap();\n s.execute(\"actions.rename\", json!({\"action\": \"Auto Color\", \"name\": \"My Color\"})).unwrap();\n let customized = s.actions.list.clone();",
|
||
" assert_eq!(restarted.actions.list, customized, \"deleted and renamed defaults stay customized on restart\");\n assert_eq!(restarted.execute(\"actions.loadDefaults\", json!({})).unwrap()[\"added\"], json!([\"Auto Tone\", \"Auto Color\"]));\n assert_eq!(attached(&mem).actions.list, restarted.actions.list);\n }",
|
||
" assert_eq!(restarted.execute(\"actions.loadDefaults\", json!({})).unwrap()[\"added\"], json!([\"Auto Tone\", \"Auto Color\"]));\n assert_eq!(attached(&mem).actions.list, restarted.actions.list);\n }",
|
||
" assert_eq!(attached(&mem).actions.list, restarted.actions.list);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/action_defaults.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "old_store_and_early_actions_win_over_defaults",
|
||
"path": "crates/engine/src/action_defaults.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked old_store_and_early_actions_win_over_defaults -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mem = MemBackend::default();\n let custom = Action::new(\"Auto Tone\", vec![(\"select.all\".into(), json!({}))]);\n let disk = Action::new(\"My Workflow\", vec![]);\n // Old files have no defaults_version field.\n mem.write(ACTIONS_FILE, &serde_json::to_vec(&json!({\"version\": 1, \"actions\": [custom, disk]})).unwrap()).unwrap();\n let mut s = Session::new();\n let early = Action::new(\"Auto Color\", vec![(\"select.deselect\".into(), json!({}))]);\n s.actions.list.push(early.clone());\n s.attach_preset_store(open(Box::new(mem.clone())));\n assert_eq!(&s.actions.list[..3], &[early, custom, disk]);\n assert_eq!(\n s.actions.list.iter().map(|a| a.name.as_str()).collect::<Vec<_>>(),",
|
||
"expected_assertions": [
|
||
" assert_eq!(&s.actions.list[..3], &[early, custom, disk]);\n assert_eq!(\n s.actions.list.iter().map(|a| a.name.as_str()).collect::<Vec<_>>(),\n [\"Auto Color\", \"Auto Tone\", \"My Workflow\", \"Auto Contrast\", \"Select Subject\", \"Blur Background\"]",
|
||
" assert_eq!(\n s.actions.list.iter().map(|a| a.name.as_str()).collect::<Vec<_>>(),\n [\"Auto Color\", \"Auto Tone\", \"My Workflow\", \"Auto Contrast\", \"Select Subject\", \"Blur Background\"]\n );",
|
||
" assert_eq!(saved(&mem).defaults_version, VERSION);\n assert_eq!(attached(&mem).actions.list, s.actions.list);\n }",
|
||
" assert_eq!(attached(&mem).actions.list, s.actions.list);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/action_defaults.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "unreadable_actions_are_not_seeded_or_overwritten",
|
||
"path": "crates/engine/src/action_defaults.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked unreadable_actions_are_not_seeded_or_overwritten -- --nocapture",
|
||
"fixture_and_action_excerpt": " for bytes in [b\"{\".as_slice(), br#\"{\"version\":999,\"actions\":[]}\"#.as_slice()] {\n let mem = MemBackend::default();\n mem.write(ACTIONS_FILE, bytes).unwrap();\n let mut s = Session::new();\n assert!(!s.attach_preset_store(open(Box::new(mem.clone()))).is_empty());\n assert!(s.actions.list.is_empty());\n s.execute(\"actions.loadDefaults\", json!({})).unwrap();\n assert_eq!(s.actions.list, defaults(), \"explicit recovery is available in memory\");\n assert_eq!(mem.read(ACTIONS_FILE, 1 << 20).unwrap(), bytes, \"the unreadable original remains recoverable\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(!s.attach_preset_store(open(Box::new(mem.clone()))).is_empty());\n assert!(s.actions.list.is_empty());\n s.execute(\"actions.loadDefaults\", json!({})).unwrap();\n assert_eq!(s.actions.list, defaults(), \"explicit recovery is available in memory\");",
|
||
" assert!(s.actions.list.is_empty());\n s.execute(\"actions.loadDefaults\", json!({})).unwrap();\n assert_eq!(s.actions.list, defaults(), \"explicit recovery is available in memory\");\n assert_eq!(mem.read(ACTIONS_FILE, 1 << 20).unwrap(), bytes, \"the unreadable original remains recoverable\");",
|
||
" assert_eq!(s.actions.list, defaults(), \"explicit recovery is available in memory\");\n assert_eq!(mem.read(ACTIONS_FILE, 1 << 20).unwrap(), bytes, \"the unreadable original remains recoverable\");\n }\n }",
|
||
" assert_eq!(mem.read(ACTIONS_FILE, 1 << 20).unwrap(), bytes, \"the unreadable original remains recoverable\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/action_defaults.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "auto_defaults_play_on_pixels_and_undo_at_every_depth",
|
||
"path": "crates/engine/src/action_defaults.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked auto_defaults_play_on_pixels_and_undo_at_every_depth -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [8, 16, 32] {\n let mut s = Session::new();\n s.execute(\"actions.loadDefaults\", json!({})).unwrap();\n s.execute(\"file.new\", json!({\"width\": 64, \"height\": 64, \"depth\": depth})).unwrap();\n s.edit(\"ramp\", |doc, _| {\n let surf = doc.layers[0].surface_mut().unwrap();\n for x in 0..64 {\n let v = 0.3 + 0.4 * x as f32 / 63.0;\n surf.fill_rect(Rect::new(x, 0, x + 1, 64), &[v, v * 0.9, v * 0.8, 1.0]);\n }\n Ok(())\n })",
|
||
"expected_assertions": [
|
||
" assert_eq!(played[\"ran\"], 1, \"{name} at {depth}: {played}\");\n assert!(played.get(\"failed\").is_none());\n let (a, b) = (pixel(&s, 0), pixel(&s, 63));\n let (lo, hi) = if name == \"Auto Contrast\" { (a[2], b[0]) } else { (a[0], b[0]) };",
|
||
" assert!(played.get(\"failed\").is_none());\n let (a, b) = (pixel(&s, 0), pixel(&s, 63));\n let (lo, hi) = if name == \"Auto Contrast\" { (a[2], b[0]) } else { (a[0], b[0]) };\n assert!(lo < 0.05 && hi > 0.95, \"{name} at {depth}: {a:?} {b:?}\");",
|
||
" assert!(lo < 0.05 && hi > 0.95, \"{name} at {depth}: {a:?} {b:?}\");\n assert_eq!(s.active().unwrap().history.past_len(), history + 1);\n assert!(s.undo());\n assert_eq!((pixel(&s, 0), pixel(&s, 63)), before);",
|
||
" assert_eq!(s.active().unwrap().history.past_len(), history + 1);\n assert!(s.undo());\n assert_eq!((pixel(&s, 0), pixel(&s, 63)), before);\n }",
|
||
" assert!(s.undo());\n assert_eq!((pixel(&s, 0), pixel(&s, 63)), before);\n }\n }",
|
||
" assert_eq!((pixel(&s, 0), pixel(&s, 63)), before);\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/action_defaults.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "subject_default_samples_visible_layers_and_undo_restores_selection",
|
||
"path": "crates/engine/src/action_defaults.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked subject_default_samples_visible_layers_and_undo_restores_selection -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [8, 16, 32] {\n let mut s = Session::new();\n s.execute(\"actions.loadDefaults\", json!({})).unwrap();\n s.execute(\"file.new\", json!({\"width\": 200, \"height\": 160, \"depth\": depth})).unwrap();\n s.edit(\"disc\", |doc, _| {\n let surf = doc.layers[0].surface_mut().unwrap();\n surf.fill_rect(Rect::new(0, 0, 200, 160), &[0.25, 0.45, 0.7, 1.0]);\n for y in 0..160 {\n for x in 0..200 {\n if (x - 100) * (x - 100) + (y - 80) * (y - 80) <= 45 * 45 {\n surf.fill_rect(Rect::new(x, y, x + 1, y + 1), &[0.9, 0.3, 0.15, 1.0]);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(played[\"ran\"], 1, \"{depth}: {played}\");\n assert!(played.get(\"failed\").is_none());\n let coverage = |s: &Session, x, y| s.active().unwrap().doc.selection.as_ref().unwrap().sample_channel(x, y, 0);\n assert!(coverage(&s, 100, 80) > 0.9, \"the subject on the underlying layer is selected\");",
|
||
" assert!(played.get(\"failed\").is_none());\n let coverage = |s: &Session, x, y| s.active().unwrap().doc.selection.as_ref().unwrap().sample_channel(x, y, 0);\n assert!(coverage(&s, 100, 80) > 0.9, \"the subject on the underlying layer is selected\");\n assert!(coverage(&s, 0, 0) < 0.1, \"replace mode removes the old background selection\");",
|
||
" assert!(coverage(&s, 100, 80) > 0.9, \"the subject on the underlying layer is selected\");\n assert!(coverage(&s, 0, 0) < 0.1, \"replace mode removes the old background selection\");\n assert!(s.undo());\n assert!(coverage(&s, 0, 0) > 0.9);",
|
||
" assert!(coverage(&s, 0, 0) < 0.1, \"replace mode removes the old background selection\");\n assert!(s.undo());\n assert!(coverage(&s, 0, 0) > 0.9);\n }",
|
||
" assert!(s.undo());\n assert!(coverage(&s, 0, 0) > 0.9);\n }\n }",
|
||
" assert!(coverage(&s, 0, 0) > 0.9);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/action_defaults.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "actions_persist_with_the_preset_store",
|
||
"path": "crates/engine/src/actions_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked actions_persist_with_the_preset_store -- --nocapture",
|
||
"fixture_and_action_excerpt": " let dir = std::env::temp_dir().join(format!(\"pc-actions-{}-persist\", std::process::id()));\n let _ = std::fs::remove_dir_all(&dir);\n let mut s = Session::new();\n let warnings = s.attach_preset_store(crate::preset_store::open_dir(&dir));\n assert!(warnings.iter().all(|w| !w.contains(\"actions\")), \"{warnings:?}\");\n s.execute(\"file.new\", json!({\"width\": 4, \"height\": 4})).unwrap();\n s.execute(\"actions.record\", json!({\"name\": \"Kept\"})).unwrap();\n s.execute(\"layer.new.layer\", json!({})).unwrap();\n s.execute(\"actions.stop\", json!({})).unwrap();\n drop(s);\n\n let mut t = Session::new();",
|
||
"expected_assertions": [
|
||
" assert!(warnings.iter().all(|w| !w.contains(\"actions\")), \"{warnings:?}\");\n s.execute(\"file.new\", json!({\"width\": 4, \"height\": 4})).unwrap();\n s.execute(\"actions.record\", json!({\"name\": \"Kept\"})).unwrap();\n s.execute(\"layer.new.layer\", json!({})).unwrap();",
|
||
" assert_eq!(kept[\"steps\"], 1);\n assert_eq!(t.execute(\"actions.get\", json!({\"action\": \"Kept\"})).unwrap()[\"steps\"][0][0], \"layer.new.layer\");\n\n // An action created before the store finishes loading is kept, and a different one on",
|
||
" assert_eq!(t.execute(\"actions.get\", json!({\"action\": \"Kept\"})).unwrap()[\"steps\"][0][0], \"layer.new.layer\");\n\n // An action created before the store finishes loading is kept, and a different one on\n // disk is merged in.",
|
||
" assert!(names.contains(&\"Early\".into()) && names.contains(&\"Kept\".into()), \"{names:?}\");\n\n std::fs::write(dir.join(\"actions.json\"), b\"{\").unwrap();\n let mut bad = Session::new();",
|
||
" assert!(warnings.iter().any(|w| w.contains(\"actions\")), \"{warnings:?}\");\n assert!(bad.actions.list.is_empty());\n let _ = std::fs::remove_dir_all(&dir);\n }",
|
||
" assert!(bad.actions.list.is_empty());\n let _ = std::fs::remove_dir_all(&dir);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/actions_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "blur_background_preserves_subject_and_undoes_at_every_depth",
|
||
"path": "crates/engine/src/background_blur_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked blur_background_preserves_subject_and_undoes_at_every_depth -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [8, 16, 32] {\n let mut s = disc(200, 160, depth);\n let layer = id(&s);\n let before = s.active().unwrap().doc.clone();\n let history = s.active().unwrap().history.past_len();\n assert!(s.is_enabled(CMD));\n // Exercise the shipping action, including its command params and single-step undo.\n s.execute(\"actions.loadDefaults\", json!({})).unwrap();\n let result = s.execute(\"actions.play\", json!({\"action\": \"Blur Background\"})).unwrap();\n assert_eq!(result[\"ran\"], 1, \"{depth}: {result}\");\n assert!(result.get(\"failed\").is_none(), \"{depth}: {result}\");\n assert_eq!(s.active().unwrap().history.past_len(), history + 1);",
|
||
"expected_assertions": [
|
||
" assert!(s.is_enabled(CMD));\n // Exercise the shipping action, including its command params and single-step undo.\n s.execute(\"actions.loadDefaults\", json!({})).unwrap();\n let result = s.execute(\"actions.play\", json!({\"action\": \"Blur Background\"})).unwrap();",
|
||
" assert_eq!(result[\"ran\"], 1, \"{depth}: {result}\");\n assert!(result.get(\"failed\").is_none(), \"{depth}: {result}\");\n assert_eq!(s.active().unwrap().history.past_len(), history + 1);\n let old = before.layer(layer).unwrap().surface().unwrap();",
|
||
" assert!(result.get(\"failed\").is_none(), \"{depth}: {result}\");\n assert_eq!(s.active().unwrap().history.past_len(), history + 1);\n let old = before.layer(layer).unwrap().surface().unwrap();\n let new = surface(&s, layer);",
|
||
" assert_eq!(s.active().unwrap().history.past_len(), history + 1);\n let old = before.layer(layer).unwrap().surface().unwrap();\n let new = surface(&s, layer);\n assert_eq!(",
|
||
" assert_eq!(\n new.read_region(Rect::new(85, 65, 115, 95)),\n old.read_region(Rect::new(85, 65, 115, 95)),\n \"the subject interior remains sharp at {depth}\"",
|
||
" assert!(background_energy(new) < background_energy(old) * 0.1, \"background noise is reduced at {depth}\");\n let after = s.active().unwrap().doc.clone();\n assert!(s.undo());\n assert_eq!(s.active().unwrap().doc, before);",
|
||
" assert!(s.undo());\n assert_eq!(s.active().unwrap().doc, before);\n assert!(s.redo());\n assert_eq!(s.active().unwrap().doc, after);",
|
||
" assert_eq!(s.active().unwrap().doc, before);\n assert!(s.redo());\n assert_eq!(s.active().unwrap().doc, after);\n }",
|
||
" assert!(s.redo());\n assert_eq!(s.active().unwrap().doc, after);\n }\n }",
|
||
" assert_eq!(s.active().unwrap().doc, after);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/background_blur_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "blur_background_preserves_selection_alpha_masks_and_other_layers",
|
||
"path": "crates/engine/src/background_blur_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked blur_background_preserves_selection_alpha_masks_and_other_layers -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = disc(200, 160, 16);\n let layer = id(&s);\n s.execute(\"layer.new.layer\", json!({\"name\": \"Unchanged overlay\"})).unwrap();\n s.edit(\"existing state\", |doc, _| {\n let layer = doc.layer_mut(layer).unwrap();\n let surf = layer.surface_mut().unwrap();\n for y in 0..160 {\n for x in 0..200 {\n let mut pixel = surf.pixel(x, y);\n *pixel.last_mut().unwrap() = if x < 50 { 0.5 } else { 1.0 };\n surf.write_pixel(x, y, &pixel);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(*s.active().unwrap().doc, expected, \"only target layer pixels may change\");\n let (old, new) = (before.layer(layer).unwrap().surface().unwrap(), surface(&s, layer));\n assert_ne!(new.read_region(Rect::new(10, 10, 40, 40)), old.read_region(Rect::new(10, 10, 40, 40)));\n assert_eq!(new.read_region(Rect::new(60, 0, 200, 160)), old.read_region(Rect::new(60, 0, 200, 160)), \"outside the user's selection\");",
|
||
" assert_ne!(new.read_region(Rect::new(10, 10, 40, 40)), old.read_region(Rect::new(10, 10, 40, 40)));\n assert_eq!(new.read_region(Rect::new(60, 0, 200, 160)), old.read_region(Rect::new(60, 0, 200, 160)), \"outside the user's selection\");\n assert_eq!(new.read_region(Rect::new(-8, -8, 0, 0)), old.read_region(Rect::new(-8, -8, 0, 0)));\n for y in 0..160 {",
|
||
" assert_eq!(new.read_region(Rect::new(60, 0, 200, 160)), old.read_region(Rect::new(60, 0, 200, 160)), \"outside the user's selection\");\n assert_eq!(new.read_region(Rect::new(-8, -8, 0, 0)), old.read_region(Rect::new(-8, -8, 0, 0)));\n for y in 0..160 {\n for x in 0..200 {",
|
||
" assert_eq!(new.read_region(Rect::new(-8, -8, 0, 0)), old.read_region(Rect::new(-8, -8, 0, 0)));\n for y in 0..160 {\n for x in 0..200 {\n assert_eq!(new.sample_channel(x, y, 3), old.sample_channel(x, y, 3));",
|
||
" assert_eq!(new.sample_channel(x, y, 3), old.sample_channel(x, y, 3));\n }\n }\n assert_eq!(s.active().unwrap().channel_view.target, crate::channel_cmds::ChannelTarget::LayerMask);",
|
||
" assert_eq!(s.active().unwrap().channel_view.target, crate::channel_cmds::ChannelTarget::LayerMask);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/background_blur_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "background_sampling_excludes_subject_colors_for_both_blur_paths",
|
||
"path": "crates/engine/src/background_blur_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked background_sampling_excludes_subject_colors_for_both_blur_paths -- --nocapture",
|
||
"fixture_and_action_excerpt": " let bounds = Rect::new(0, 0, 80, 60);\n let subject = Region { bbox: Rect::new(30, 10, 50, 50), mask: vec![255; 20 * 40] };\n use photocraft_color::ColorMode;\n for mode in [ColorMode::Rgb, ColorMode::Grayscale, ColorMode::Cmyk, ColorMode::Lab] {\n for depth in [SampleType::U8, SampleType::U16, SampleType::F32] {\n let mut source = Surface::new(PixelFormat::new(mode, depth, true));\n let colors = mode.color_channels();\n let mut background = vec![0.2; colors];\n let mut foreground = vec![0.9; colors];\n if mode == ColorMode::Rgb {\n background = vec![0.0, 0.3, 0.85];\n foreground = vec![1.0, 0.0, 0.0];",
|
||
"expected_assertions": [
|
||
" assert_eq!(output.format(), source.format());\n let edge = output.pixel(29, 30);\n for (c, value) in edge.iter().take(colors).enumerate() {\n assert!(",
|
||
" assert!(\n (value - source.sample_channel(29, 30, c)).abs() < 0.005,\n \"foreground leaked into {mode:?} channel {c}, {depth:?}, radius {radius}: {edge:?}\"\n );",
|
||
" assert!(edge[0] < 1e-6, \"subject red leaked through at {depth:?}, radius {radius}: {edge:?}\");\n }\n assert_eq!(output.read_region(subject.bbox), source.read_region(subject.bbox));\n assert_eq!(edge[colors], source.sample_channel(29, 30, colors));",
|
||
" assert_eq!(output.read_region(subject.bbox), source.read_region(subject.bbox));\n assert_eq!(edge[colors], source.sample_channel(29, 30, colors));\n }\n }",
|
||
" assert_eq!(edge[colors], source.sample_channel(29, 30, colors));\n }\n }\n }",
|
||
" assert_eq!(output, tiny_alpha, \"no usable background contribution must not turn into black\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/background_blur_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "blur_background_without_subject_or_when_cancelled_changes_nothing",
|
||
"path": "crates/engine/src/background_blur_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked blur_background_without_subject_or_when_cancelled_changes_nothing -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.execute(\"file.new\", json!({\"width\": 32, \"height\": 32, \"background\": \"white\"})).unwrap();\n s.execute(\"select.rect\", json!({\"x\": 4, \"y\": 4, \"width\": 16, \"height\": 16})).unwrap();\n let before = s.active().unwrap().doc.clone();\n let steps = s.active().unwrap().history.past_len();\n assert!(s.execute(CMD, json!({})).is_err());\n assert!(Arc::ptr_eq(&before, &s.active().unwrap().doc));\n assert_eq!(steps, s.active().unwrap().history.past_len());\n\n let mut s = disc(200, 160, 8);\n let before = s.active().unwrap().doc.clone();\n let steps = s.active().unwrap().history.past_len();",
|
||
"expected_assertions": [
|
||
" assert!(s.execute(CMD, json!({})).is_err());\n assert!(Arc::ptr_eq(&before, &s.active().unwrap().doc));\n assert_eq!(steps, s.active().unwrap().history.past_len());\n",
|
||
" assert!(Arc::ptr_eq(&before, &s.active().unwrap().doc));\n assert_eq!(steps, s.active().unwrap().history.past_len());\n\n let mut s = disc(200, 160, 8);",
|
||
" assert_eq!(steps, s.active().unwrap().history.past_len());\n\n let mut s = disc(200, 160, 8);\n let before = s.active().unwrap().doc.clone();",
|
||
" assert!(matches!(s.execute(CMD, json!({})), Err(EngineError::Cancelled)));\n assert!(Arc::ptr_eq(&before, &s.active().unwrap().doc));\n assert_eq!(steps, s.active().unwrap().history.past_len());\n }",
|
||
" assert!(Arc::ptr_eq(&before, &s.active().unwrap().doc));\n assert_eq!(steps, s.active().unwrap().history.past_len());\n }",
|
||
" assert_eq!(steps, s.active().unwrap().history.past_len());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/background_blur_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "blur_background_rejects_invalid_targets_params_and_effective_locks",
|
||
"path": "crates/engine/src/background_blur_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked blur_background_rejects_invalid_targets_params_and_effective_locks -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut empty = Session::new();\n assert!(!empty.is_enabled(CMD));\n assert!(empty.execute(CMD, json!({})).is_err());\n let mut s = disc(200, 160, 8);\n let before = s.active().unwrap().doc.clone();\n for params in [\n Value::Null,\n json!([]),\n json!(false),\n json!({\"radius\": \"8\"}),\n json!({\"radius\": null}),\n json!({\"radius\": 0}),",
|
||
"expected_assertions": [
|
||
" assert!(!empty.is_enabled(CMD));\n assert!(empty.execute(CMD, json!({})).is_err());\n let mut s = disc(200, 160, 8);\n let before = s.active().unwrap().doc.clone();",
|
||
" assert!(empty.execute(CMD, json!({})).is_err());\n let mut s = disc(200, 160, 8);\n let before = s.active().unwrap().doc.clone();\n for params in [",
|
||
" assert!(s.execute(CMD, params.clone()).is_err(), \"{params}\");\n assert!(Arc::ptr_eq(&before, &s.active().unwrap().doc));\n }\n s.execute(\"layer.setProps\", json!({\"locks\": {\"pixels\": true}})).unwrap();",
|
||
" assert!(Arc::ptr_eq(&before, &s.active().unwrap().doc));\n }\n s.execute(\"layer.setProps\", json!({\"locks\": {\"pixels\": true}})).unwrap();\n assert!(!s.is_enabled(CMD));",
|
||
" assert!(!s.is_enabled(CMD));\n assert!(s.execute(CMD, json!({})).is_err());\n s.execute(\"layer.setProps\", json!({\"locks\": {\"pixels\": false}})).unwrap();\n s.execute(\"layer.groupLayers\", json!({})).unwrap();",
|
||
" assert!(s.execute(CMD, json!({})).is_err());\n s.execute(\"layer.setProps\", json!({\"locks\": {\"pixels\": false}})).unwrap();\n s.execute(\"layer.groupLayers\", json!({})).unwrap();\n // The group is not a raster target; a locked parent also protects the member's pixels.",
|
||
" assert!(!s.is_enabled(CMD));\n assert!(s.execute(CMD, json!({})).is_err());\n let group = id(&s);\n s.execute(\"layer.setProps\", json!({\"locks\": {\"all\": true}})).unwrap();",
|
||
" assert!(s.execute(CMD, json!({})).is_err());\n let group = id(&s);\n s.execute(\"layer.setProps\", json!({\"locks\": {\"all\": true}})).unwrap();\n let child = s.active().unwrap().doc.layer(group).unwrap().children().unwrap().first().unwrap().id;",
|
||
" assert!(s.execute(CMD, json!({\"layer\": child.0})).is_err());\n assert!(Arc::ptr_eq(&before, &s.active().unwrap().doc));\n }",
|
||
" assert!(Arc::ptr_eq(&before, &s.active().unwrap().doc));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/background_blur_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "blur_background_24mp_timing",
|
||
"path": "crates/engine/src/background_blur_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked blur_background_24mp_timing -- --nocapture --ignored",
|
||
"fixture_and_action_excerpt": " let mut s = disc(6000, 4000, 8);\n let started = std::time::Instant::now();\n let result = s.execute(CMD, json!({})).unwrap();\n println!(\"Blur Background 24 MP: {:?}; {result}\", started.elapsed());\n }",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/background_blur_cmds.rs",
|
||
"ignored_requires_explicit_execution": true
|
||
},
|
||
{
|
||
"name": "group_with_sampled_8_and_16_bit_tips_round_trips",
|
||
"path": "crates/engine/src/preset_store/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked group_with_sampled_8_and_16_bit_tips_round_trips -- --nocapture",
|
||
"fixture_and_action_excerpt": " let dir = TempDir::new(\"roundtrip\");\n let (mut s, w) = session(&dir);\n assert!(w.is_empty(), \"{w:?}\");\n assert_eq!(dir.files(), [ACTIONS_FILE], \"only starter actions are written when attaching an empty store\");\n let mut a = sampled(\"Eight\", \"Inks\", tip8(64, 48, 1));\n a.brush.dual_brush.tip = TipShape::Sampled(tip8(12, 12, 5));\n a.brush.texture.pattern = Pattern::Tile(tip16(32, 32, 7));\n let b = sampled(\"Sixteen\", \"Inks\", tip16(50, 70, 2));\n let mut c = sampled(\"Shared tip\", \"Other\", tip8(64, 48, 1));\n c.brush.size = 9.0;\n s.tools.presets.extend([a, b, c]);\n s.brush_presets_changed();",
|
||
"expected_assertions": [
|
||
" assert!(w.is_empty(), \"{w:?}\");\n assert_eq!(dir.files(), [ACTIONS_FILE], \"only starter actions are written when attaching an empty store\");\n let mut a = sampled(\"Eight\", \"Inks\", tip8(64, 48, 1));\n a.brush.dual_brush.tip = TipShape::Sampled(tip8(12, 12, 5));",
|
||
" assert_eq!(dir.files(), [ACTIONS_FILE], \"only starter actions are written when attaching an empty store\");\n let mut a = sampled(\"Eight\", \"Inks\", tip8(64, 48, 1));\n a.brush.dual_brush.tip = TipShape::Sampled(tip8(12, 12, 5));\n a.brush.texture.pattern = Pattern::Tile(tip16(32, 32, 7));",
|
||
" assert_eq!(files.iter().filter(|f| f.ends_with(\".pcbrushes\")).count(), 2, \"{files:?}\");\n // Four distinct bitmaps (the 64×48 tip is shared by two presets) plus the previews of the two\n // 16-bit ones: an 8-bit tip this small is its own preview.\n assert_eq!(files.iter().filter(|f| f.starts_with(\"tips/\")).count(), 6, \"{files:?}\");",
|
||
" assert_eq!(files.iter().filter(|f| f.starts_with(\"tips/\")).count(), 6, \"{files:?}\");\n // The session keeps previews, not the bitmaps (#1843).\n assert!(user(&s).iter().all(|p| matches!(&p.brush.tip, TipShape::Stored(r) if !r.is_loaded())));\n assert!(files.contains(&INDEX_FILE.to_string()));",
|
||
" assert!(user(&s).iter().all(|p| matches!(&p.brush.tip, TipShape::Stored(r) if !r.is_loaded())));\n assert!(files.contains(&INDEX_FILE.to_string()));\n\n let (t, w) = session(&dir);",
|
||
" assert!(files.contains(&INDEX_FILE.to_string()));\n\n let (t, w) = session(&dir);\n assert!(w.is_empty(), \"{w:?}\");",
|
||
" assert!(w.is_empty(), \"{w:?}\");\n assert_eq!(user(&t), user(&s));\n let order: Vec<String> = user(&t).into_iter().map(|p| p.name).collect();\n assert_eq!(order, [\"Eight\", \"Sixteen\", \"Shared tip\"]);",
|
||
" assert_eq!(user(&t), user(&s));\n let order: Vec<String> = user(&t).into_iter().map(|p| p.name).collect();\n assert_eq!(order, [\"Eight\", \"Sixteen\", \"Shared tip\"]);\n // Nothing changed: reloading rewrote nothing.",
|
||
" assert_eq!(order, [\"Eight\", \"Sixteen\", \"Shared tip\"]);\n // Nothing changed: reloading rewrote nothing.\n let before: Vec<_> = DirBackend::new(&dir.0).list().unwrap();\n let mut t = t;",
|
||
" assert_eq!(DirBackend::new(&dir.0).list().unwrap(), before);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/preset_store/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "commands_persist_and_delete_removes_from_disk",
|
||
"path": "crates/engine/src/preset_store/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked commands_persist_and_delete_removes_from_disk -- --nocapture",
|
||
"fixture_and_action_excerpt": " let dir = TempDir::new(\"commands\");\n let (mut s, _) = session(&dir);\n s.tools.brush.tip = TipShape::Sampled(tip16(20, 20, 4));\n s.execute(\"brush.presets.save\", json!({\"name\": \"Scribble\"})).unwrap();\n assert_eq!(dir.files().iter().filter(|f| f.starts_with(\"tips/\")).count(), 2, \"the tip and its preview\");\n // The tool's brush now is the saved preset's stored tip, still loaded.\n assert!(matches!(&s.tools.brush.tip, TipShape::Stored(r) if r.is_loaded()));\n let (t, _) = session(&dir);\n let p = photocraft_paint::presets::find(&t.tools.presets, \"Scribble\").expect(\"saved preset reloads\");\n assert_eq!(p.brush.tip, s.tools.brush.tip);\n\n // Rename through the Preset Manager, then delete.",
|
||
"expected_assertions": [
|
||
" assert_eq!(dir.files().iter().filter(|f| f.starts_with(\"tips/\")).count(), 2, \"the tip and its preview\");\n // The tool's brush now is the saved preset's stored tip, still loaded.\n assert!(matches!(&s.tools.brush.tip, TipShape::Stored(r) if r.is_loaded()));\n let (t, _) = session(&dir);",
|
||
" assert!(matches!(&s.tools.brush.tip, TipShape::Stored(r) if r.is_loaded()));\n let (t, _) = session(&dir);\n let p = photocraft_paint::presets::find(&t.tools.presets, \"Scribble\").expect(\"saved preset reloads\");\n assert_eq!(p.brush.tip, s.tools.brush.tip);",
|
||
" assert_eq!(p.brush.tip, s.tools.brush.tip);\n\n // Rename through the Preset Manager, then delete.\n s.execute(\"edit.presets.presetManager\", json!({\"action\": \"rename\", \"kind\": \"brushes\", \"name\": \"Scribble\", \"newName\": \"Doodle\"})).unwrap();",
|
||
" assert!(photocraft_paint::presets::find(&t.tools.presets, \"Doodle\").is_some());\n assert!(photocraft_paint::presets::find(&t.tools.presets, \"Scribble\").is_none());\n s.execute(\"brush.presets.delete\", json!({\"name\": \"Doodle\"})).unwrap();\n assert_eq!(dir.files(), [ACTIONS_FILE, INDEX_FILE], \"the group file and its tip are gone\");",
|
||
" assert!(photocraft_paint::presets::find(&t.tools.presets, \"Scribble\").is_none());\n s.execute(\"brush.presets.delete\", json!({\"name\": \"Doodle\"})).unwrap();\n assert_eq!(dir.files(), [ACTIONS_FILE, INDEX_FILE], \"the group file and its tip are gone\");\n let (t, _) = session(&dir);",
|
||
" assert_eq!(dir.files(), [ACTIONS_FILE, INDEX_FILE], \"the group file and its tip are gone\");\n let (t, _) = session(&dir);\n assert!(photocraft_paint::presets::find(&t.tools.presets, \"Doodle\").is_none());\n}",
|
||
" assert!(photocraft_paint::presets::find(&t.tools.presets, \"Doodle\").is_none());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/engine/src/preset_store/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "default_actions_load_from_empty_panel_and_play",
|
||
"path": "crates/ui-egui/src/actions.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked default_actions_load_from_empty_panel_and_play -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::{Harness, kittest::Queryable};\n let app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n let mut h = Harness::builder().with_size(vec2(360.0, 400.0)).build_ui_state(|ui, app| panel(app, ui), app);\n h.run_steps(3);\n h.get_by_label(\"Load Default Actions\").click();\n h.run_steps(3);\n assert!(h.query_by_label(\"PhotoCraft Essentials\").is_some());\n for name in [\"Auto Tone\", \"Auto Contrast\", \"Auto Color\", \"Select Subject\", \"Blur Background\"] {\n assert!(h.query_by_label(name).is_some(), \"missing preset {name}\");\n }\n assert_eq!(h.state().ui.actions.selected, Some(0));\n h.state_mut().run(\"file.new\", json!({\"width\": 16, \"height\": 16})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(h.query_by_label(\"PhotoCraft Essentials\").is_some());\n for name in [\"Auto Tone\", \"Auto Contrast\", \"Auto Color\", \"Select Subject\", \"Blur Background\"] {\n assert!(h.query_by_label(name).is_some(), \"missing preset {name}\");\n }",
|
||
" assert!(h.query_by_label(name).is_some(), \"missing preset {name}\");\n }\n assert_eq!(h.state().ui.actions.selected, Some(0));\n h.state_mut().run(\"file.new\", json!({\"width\": 16, \"height\": 16})).unwrap();",
|
||
" assert_eq!(h.state().ui.actions.selected, Some(0));\n h.state_mut().run(\"file.new\", json!({\"width\": 16, \"height\": 16})).unwrap();\n h.run_steps(3);\n h.get_by_label(\"Play selection\").click();",
|
||
" assert!(!h.state().ui.status_error, \"{}\", h.state().ui.status);\n assert!(h.state().session.journal.iter().any(|(id, _)| id == \"image.autoTone\"));\n }",
|
||
" assert!(h.state().session.journal.iter().any(|(id, _)| id == \"image.autoTone\"));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/ui-egui/src/actions.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "default_actions_flyout_preserves_custom_actions_and_reveals_restored_set",
|
||
"path": "crates/ui-egui/src/actions.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked default_actions_flyout_preserves_custom_actions_and_reveals_restored_set -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::{Harness, kittest::Queryable};\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n let custom = Action::new(\"Auto Tone\", vec![(\"view.fitOnScreen\".into(), json!({}))]);\n app.session.actions.list.push(custom.clone());\n app.ui.actions.collapsed_sets.push(\"PhotoCraft Essentials\".into());\n let mut h = Harness::builder().with_size(vec2(360.0, 400.0)).build_ui_state(\n |ui, app| {\n ui.menu_button(\"Actions menu\", |ui| panel_menu(app, ui));\n panel(app, ui);\n },\n app,\n );",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().session.actions.list[0], custom);\n assert_eq!(h.state().session.actions.list.len(), 5);\n assert_eq!(h.state().ui.actions.selected, Some(1));\n assert!(h.state().ui.actions.collapsed_sets.is_empty());",
|
||
" assert_eq!(h.state().session.actions.list.len(), 5);\n assert_eq!(h.state().ui.actions.selected, Some(1));\n assert!(h.state().ui.actions.collapsed_sets.is_empty());\n assert!(h.query_by_label(\"Select Subject\").is_some());",
|
||
" assert_eq!(h.state().ui.actions.selected, Some(1));\n assert!(h.state().ui.actions.collapsed_sets.is_empty());\n assert!(h.query_by_label(\"Select Subject\").is_some());\n }",
|
||
" assert!(h.state().ui.actions.collapsed_sets.is_empty());\n assert!(h.query_by_label(\"Select Subject\").is_some());\n }",
|
||
" assert!(h.query_by_label(\"Select Subject\").is_some());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61d9e8cc1aed29ed6bea0d0fd2702fa87c4f0206/crates/ui-egui/src/actions.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-5176",
|
||
"pr": 5176,
|
||
"subsystem": "Actions and automation",
|
||
"fixture_setup": "Synthetic ATN mappings, smart-object Edit Contents action, temporary pattern stores and matting hard/soft edges",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked every_mapped_command_exports_and_imports_back -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked save_in_edit_contents_updates_the_smart_object -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked patterns_survive_a_restart -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked corrupt_pattern_files_are_skipped_and_kept -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked large_patterns_load_on_use -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked matting::tests -- --nocapture"
|
||
],
|
||
"expected": "Mappings round-trip parameters; Save in Edit Contents updates parent smart content. Pattern names/pixels and rename/delete survive restart; corrupt assets are warned about and preserved; large patterns load full pixels lazily. Hard edge ±100% shifts one pixel, ±50% gives half coverage within 0.02; feather 4/+100% reaches four pixels.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Named CopyCat/AJ/Line and Color playback needs licensed fixture identities and required document/pattern setup; missing action sets leave that subcase BLOCKED. Mapping tests alone do not prove full set playback. Also run all new legacy/new-store migration, interruption, corruption, duplicate-ID and deletion-authority regressions.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked every_mapped_command_exports_and_imports_back -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked save_in_edit_contents_updates_the_smart_object -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked patterns_survive_a_restart -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked corrupt_pattern_files_are_skipped_and_kept -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked large_patterns_load_on_use -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked matting::tests -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-6492",
|
||
"pr": 6492,
|
||
"subsystem": "Actions and automation",
|
||
"fixture_setup": "Process-isolated occupied loopback listener and successful prebound control-server fixtures in apps/photocraft tests",
|
||
"action": [
|
||
"cargo test -p photocraft --locked an_occupied_control_port_exits_with_status_2 -- --nocapture",
|
||
"cargo test -p photocraft --locked a_prebound_listener_authenticates_and_dispatches_requests -- --nocapture"
|
||
],
|
||
"expected": "Occupied port exits with status 2 before window/GPU initialization; successful prebound control authenticates and dispatches requests. Preserve timing, cleanup and child-exit assertions.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Use only the test-owned listener and process.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft --locked an_occupied_control_port_exits_with_status_2 -- --nocapture",
|
||
"cargo test -p photocraft --locked a_prebound_listener_authenticates_and_dispatches_requests -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-7742",
|
||
"pr": 7742,
|
||
"subsystem": "Actions and automation",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked a_fractional_setting_an_integer_field_cannot_hold_is_refused_not_rounded -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked whole_number_settings_for_integer_fields_still_round_trip -- --nocapture"
|
||
],
|
||
"expected": "a fractional setting an integer field cannot hold is refused not rounded; whole number settings for integer fields still round trip",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked a_fractional_setting_an_integer_field_cannot_hold_is_refused_not_rounded -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked whole_number_settings_for_integer_fields_still_round_trip -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "a_fractional_setting_an_integer_field_cannot_hold_is_refused_not_rounded",
|
||
"path": "crates/engine/src/atn_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked a_fractional_setting_an_integer_field_cannot_hold_is_refused_not_rounded -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (id, params) in [(\"filter.pixelate.crystallize\", json!({\"cellSize\": 5.4})), (\"filter.distort.ripple\", json!({\"amount\": 81.4, \"size\": \"small\"}))] {\n let mut s = Session::new();\n s.actions.list.push(Action::new(\"A\", vec![(id.into(), params)]));\n let e = s.execute(\"actions.save\", json!({\"action\": \"A\"})).unwrap_err().to_string();\n assert!(e.contains(id), \"{id}: {e}\");\n let r = s.execute(\"actions.save\", json!({\"action\": \"A\", \"skipUnsupported\": true})).unwrap();\n assert_eq!(r[\"skipped\"], json!([{\"action\": \"A\", \"step\": 0, \"id\": id}]), \"{id}\");\n }\n}",
|
||
"expected_assertions": [
|
||
" assert!(e.contains(id), \"{id}: {e}\");\n let r = s.execute(\"actions.save\", json!({\"action\": \"A\", \"skipUnsupported\": true})).unwrap();\n assert_eq!(r[\"skipped\"], json!([{\"action\": \"A\", \"step\": 0, \"id\": id}]), \"{id}\");\n }",
|
||
" assert_eq!(r[\"skipped\"], json!([{\"action\": \"A\", \"step\": 0, \"id\": id}]), \"{id}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ab844f9cbcd1f1839ed7f286776331cb72e399aa/crates/engine/src/atn_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "whole_number_settings_for_integer_fields_still_round_trip",
|
||
"path": "crates/engine/src/atn_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked whole_number_settings_for_integer_fields_still_round_trip -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (id, params) in [\n (\"filter.pixelate.crystallize\", json!({\"cellSize\": 5})),\n (\"filter.distort.ripple\", json!({\"amount\": 81, \"size\": \"small\"})),\n (\"edit.stroke\", json!({\"width\": 2, \"color\": \"#d03060\", \"location\": \"inside\"})),\n ] {\n let mut s = Session::new();\n s.actions.list.push(Action::new(\"A\", vec![(id.into(), params.clone())]));\n let r = s.execute(\"actions.save\", json!({\"action\": \"A\"})).unwrap();\n assert_eq!(r[\"skipped\"], json!([]), \"{id}\");\n let imported = import(&photocraft_paint::tile::b64_decode(r[\"data\"].as_str().unwrap()).unwrap()).unwrap();\n let (back_id, back) = &imported.actions[0].steps[0];\n assert_eq!(back_id, id);",
|
||
"expected_assertions": [
|
||
" assert_eq!(r[\"skipped\"], json!([]), \"{id}\");\n let imported = import(&photocraft_paint::tile::b64_decode(r[\"data\"].as_str().unwrap()).unwrap()).unwrap();\n let (back_id, back) = &imported.actions[0].steps[0];\n assert_eq!(back_id, id);",
|
||
" assert_eq!(back_id, id);\n for (key, want) in params.as_object().unwrap() {\n let got = back.get(key);\n match want.as_f64() {",
|
||
" Some(n) => assert_eq!(got.and_then(Value::as_f64), Some(n), \"{id}: {key} is {got:?}\"),\n None => assert_eq!(got, Some(want), \"{id}: {key} is {got:?}\"),\n }\n }",
|
||
" None => assert_eq!(got, Some(want), \"{id}: {key} is {got:?}\"),\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ab844f9cbcd1f1839ed7f286776331cb72e399aa/crates/engine/src/atn_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-8905",
|
||
"pr": 8905,
|
||
"subsystem": "Actions and automation",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-plugins --locked parallel_bands_fit_the_total_memory_budget -- --nocapture",
|
||
"cargo test -p photocraft-plugins --locked one_band_at_a_time_matches_parallel_bands -- --nocapture"
|
||
],
|
||
"expected": "parallel bands fit the total memory budget; one band at a time matches parallel bands",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-plugins --locked parallel_bands_fit_the_total_memory_budget -- --nocapture",
|
||
"cargo test -p photocraft-plugins --locked one_band_at_a_time_matches_parallel_bands -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "parallel_bands_fit_the_total_memory_budget",
|
||
"path": "crates/plugins/tests/abi.rs",
|
||
"package": "photocraft-plugins",
|
||
"command": "cargo test -p photocraft-plugins --locked parallel_bands_fit_the_total_memory_budget -- --nocapture",
|
||
"fixture_and_action_excerpt": " let d = Limits::default();\n assert_eq!(d.parallel_bands(16), 4);\n assert!(d.parallel_bands(64) * d.max_memory_bytes <= d.max_total_memory_bytes);\n assert_eq!(d.parallel_bands(2), 2, \"fewer workers than the budget allows\");\n let small = Limits { max_memory_bytes: 64 << 20, ..Limits::default() };\n assert_eq!(small.parallel_bands(16), 16, \"small instances keep every worker busy\");\n let tight = Limits { max_total_memory_bytes: 1 << 20, ..Limits::default() };\n assert_eq!(tight.parallel_bands(16), 1, \"at least one band runs\");\n assert_eq!(d.parallel_bands(0), 1);\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(d.parallel_bands(16), 4);\n assert!(d.parallel_bands(64) * d.max_memory_bytes <= d.max_total_memory_bytes);\n assert_eq!(d.parallel_bands(2), 2, \"fewer workers than the budget allows\");\n let small = Limits { max_memory_bytes: 64 << 20, ..Limits::default() };",
|
||
" assert!(d.parallel_bands(64) * d.max_memory_bytes <= d.max_total_memory_bytes);\n assert_eq!(d.parallel_bands(2), 2, \"fewer workers than the budget allows\");\n let small = Limits { max_memory_bytes: 64 << 20, ..Limits::default() };\n assert_eq!(small.parallel_bands(16), 16, \"small instances keep every worker busy\");",
|
||
" assert_eq!(d.parallel_bands(2), 2, \"fewer workers than the budget allows\");\n let small = Limits { max_memory_bytes: 64 << 20, ..Limits::default() };\n assert_eq!(small.parallel_bands(16), 16, \"small instances keep every worker busy\");\n let tight = Limits { max_total_memory_bytes: 1 << 20, ..Limits::default() };",
|
||
" assert_eq!(small.parallel_bands(16), 16, \"small instances keep every worker busy\");\n let tight = Limits { max_total_memory_bytes: 1 << 20, ..Limits::default() };\n assert_eq!(tight.parallel_bands(16), 1, \"at least one band runs\");\n assert_eq!(d.parallel_bands(0), 1);",
|
||
" assert_eq!(tight.parallel_bands(16), 1, \"at least one band runs\");\n assert_eq!(d.parallel_bands(0), 1);\n}",
|
||
" assert_eq!(d.parallel_bands(0), 1);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/0fdc6259193aab32b8feab7347ddc36196f40a19/crates/plugins/tests/abi.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "one_band_at_a_time_matches_parallel_bands",
|
||
"path": "crates/plugins/tests/abi.rs",
|
||
"package": "photocraft-plugins",
|
||
"command": "cargo test -p photocraft-plugins --locked one_band_at_a_time_matches_parallel_bands -- --nocapture",
|
||
"fixture_and_action_excerpt": " let pool = rayon::ThreadPoolBuilder::new().num_threads(8).build().unwrap();\n let s = surface(PixelFormat::RGBA8, 600, 300);\n let canvas = Rect::new(0, 0, 600, 300);\n let run = |limits: Limits| {\n let p = Plugin::load(INVERT, limits).unwrap();\n pool.install(|| p.apply(&s, canvas, None, &json!({}))).unwrap()\n };\n let parallel = run(Limits { band_bytes: 1, ..Limits::default() });\n let serial = run(Limits { band_bytes: 1, max_total_memory_bytes: 512 << 20, ..Limits::default() });\n assert_eq!(serial, parallel);\n assert_ne!(serial, s, \"the filter ran\");\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(serial, parallel);\n assert_ne!(serial, s, \"the filter ran\");\n}",
|
||
" assert_ne!(serial, s, \"the filter ran\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/0fdc6259193aab32b8feab7347ddc36196f40a19/crates/plugins/tests/abi.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-3874",
|
||
"pr": 3874,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked blend_if_alt_split_and_drag_behavior -- --nocapture"
|
||
],
|
||
"expected": "blend if alt split and drag behavior",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked blend_if_alt_split_and_drag_behavior -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "blend_if_alt_split_and_drag_behavior",
|
||
"path": "crates/ui-egui/src/layer_style.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked blend_if_alt_split_and_drag_behavior -- --nocapture",
|
||
"fixture_and_action_excerpt": " // Case 1: Alt-drag on unsplit black handle [0, 0, 255, 255] splits the right half\n let mut mode = BlendDrag::Pair { pair: 0, origin_v: 0 };\n let q = [0, 0, 255, 255];\n let q1 = step_blend_drag(&mut mode, &q, 45, true);\n assert_eq!(q1, [0, 45, 255, 255], \"Alt-drag right must split black triangle into [0, 45]\");\n\n // Case 2: Moving the split right half further to 70\n let q2 = step_blend_drag(&mut mode, &q1, 70, false);\n assert_eq!(q2, [0, 70, 255, 255]);\n\n // Case 3: Dragging the split half back to 0 merges the handle\n let q3 = step_blend_drag(&mut mode, &q2, 0, false);",
|
||
"expected_assertions": [
|
||
" assert_eq!(q1, [0, 45, 255, 255], \"Alt-drag right must split black triangle into [0, 45]\");\n\n // Case 2: Moving the split right half further to 70\n let q2 = step_blend_drag(&mut mode, &q1, 70, false);",
|
||
" assert_eq!(q2, [0, 70, 255, 255]);\n\n // Case 3: Dragging the split half back to 0 merges the handle\n let q3 = step_blend_drag(&mut mode, &q2, 0, false);",
|
||
" assert_eq!(q3, [0, 0, 255, 255], \"Dragging back to origin reunites the triangle\");\n\n // Case 4: Alt-drag on unsplit white handle [0, 0, 255, 255] splits the left half\n let mut mode_w = BlendDrag::Pair { pair: 2, origin_v: 255 };",
|
||
" assert_eq!(qw1, [0, 0, 200, 255], \"Alt-drag left must split white triangle into [200, 255]\");\n\n // Case 5: Dragging without Alt moves both halves together\n let mut mode_solid = BlendDrag::Pair { pair: 0, origin_v: 0 };",
|
||
" assert_eq!(qs1, [35, 35, 255, 255], \"Drag without Alt moves solid handle together\");\n\n // Case 6: Clamping prevents black handle from crossing white handle\n let q_close = [0, 100, 150, 255];",
|
||
" assert_eq!(q_clamped, [0, 150, 150, 255], \"Black max cannot exceed white min\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/92488307722c3b840507827cac7ee9a88470fc8a/crates/ui-egui/src/layer_style.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-3967",
|
||
"pr": 3967,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_moves_and_deletes_the_clicked_filter_with_one_undo_step -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked two_filter_row_context_offers_reorder_and_delete -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked existing_filter_move_delete_commands_preserve_source_and_undo_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_disables_edges_and_deletes_the_only_remaining_filter -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked stale_row_menu_closes_on_edits_undo_redo_document_switch_and_same_id_reopen -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked parameter_and_camera_raw_modals_close_the_row_menu_without_mutation -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pending_document_job_closes_row_menu_and_refuses_new_choices -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked existing_eye_and_name_double_click_remain_distinct_from_secondary_actions -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked capture_native_popup_at_two_scales_and_in_french -- --nocapture --ignored",
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_reorder_keeps_the_selected_filter_identity -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_delete_before_selection_keeps_the_remaining_filter_selected -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_delete_selected_filter_clears_its_row_selection -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_refused_edit_preserves_filter_order_and_selection -- --nocapture"
|
||
],
|
||
"expected": "row menu moves and deletes the clicked filter with one undo step; two filter row context offers reorder and delete; existing filter move delete commands preserve source and undo at every depth; row menu disables edges and deletes the only remaining filter; stale row menu closes on edits undo redo document switch and same id reopen; parameter and camera raw modals close the row menu without mutation; pending document job closes row menu and refuses new choices; existing eye and name double click remain distinct from secondary actions; capture native popup at two scales and in french; row menu reorder keeps the selected filter identity; row menu delete before selection keeps the remaining filter selected; row menu delete selected filter clears its row selection; row menu refused edit preserves filter order and selection",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_moves_and_deletes_the_clicked_filter_with_one_undo_step -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked two_filter_row_context_offers_reorder_and_delete -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked existing_filter_move_delete_commands_preserve_source_and_undo_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_disables_edges_and_deletes_the_only_remaining_filter -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked stale_row_menu_closes_on_edits_undo_redo_document_switch_and_same_id_reopen -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked parameter_and_camera_raw_modals_close_the_row_menu_without_mutation -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pending_document_job_closes_row_menu_and_refuses_new_choices -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked existing_eye_and_name_double_click_remain_distinct_from_secondary_actions -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked capture_native_popup_at_two_scales_and_in_french -- --nocapture --ignored",
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_reorder_keeps_the_selected_filter_identity -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_delete_before_selection_keeps_the_remaining_filter_selected -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_delete_selected_filter_clears_its_row_selection -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked row_menu_refused_edit_preserves_filter_order_and_selection -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "row_menu_moves_and_deletes_the_clicked_filter_with_one_undo_step",
|
||
"path": "crates/ui-egui/src/smart_ui/context_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked row_menu_moves_and_deletes_the_clicked_filter_with_one_undo_step -- --nocapture",
|
||
"fixture_and_action_excerpt": " let _language = crate::i18n::language_scope(crate::i18n::Lang::EN);\n for depth in [8, 16, 32] {\n for ppp in [1.0, 2.0] {\n let (mut h, layer) = harness_at(depth, ppp);\n let before = filters(h.state(), layer);\n let before_pixels = pixels(h.state(), layer);\n let source = photocraft_engine::smart_cmds::contents_of(&h.state().session.active().unwrap().doc, layer).unwrap();\n let st = h.state().session.active().unwrap();\n let active = st.active_layer;\n let selected = st.selected_layers.clone();\n let history = st.history.past_len();\n let other = st.doc.layer(active.unwrap()).unwrap().clone();",
|
||
"expected_assertions": [
|
||
" assert!(h.query_by_label(\"Move Up\").is_some(), \"actual filter row has Move Up\");\n h.get_by_label(\"Move Up\").click();\n h.run_steps(4);\n assert_eq!(filters(h.state(), layer).iter().map(|f| f.command.as_str()).collect::<Vec<_>>(), [\"filter.blur.gaussianBlur\", \"filter.other.offset\"]);",
|
||
" assert_eq!(filters(h.state(), layer).iter().map(|f| f.command.as_str()).collect::<Vec<_>>(), [\"filter.blur.gaussianBlur\", \"filter.other.offset\"]);\n assert!(text_position(&h, \"Offset\").y < text_position(&h, \"Gaussian Blur\").y);\n assert_ne!(pixels(h.state(), layer), before_pixels);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 1);",
|
||
" assert!(text_position(&h, \"Offset\").y < text_position(&h, \"Gaussian Blur\").y);\n assert_ne!(pixels(h.state(), layer), before_pixels);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 1);\n assert_eq!(h.state().session.active().unwrap().active_layer, active);",
|
||
" assert_ne!(pixels(h.state(), layer), before_pixels);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 1);\n assert_eq!(h.state().session.active().unwrap().active_layer, active);\n assert_eq!(h.state().session.active().unwrap().selected_layers, selected);",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 1);\n assert_eq!(h.state().session.active().unwrap().active_layer, active);\n assert_eq!(h.state().session.active().unwrap().selected_layers, selected);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&h.state().session.active().unwrap().doc, layer).unwrap(), source);",
|
||
" assert_eq!(h.state().session.active().unwrap().active_layer, active);\n assert_eq!(h.state().session.active().unwrap().selected_layers, selected);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&h.state().session.active().unwrap().doc, layer).unwrap(), source);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(h.state().session.active().unwrap().selected_layers, selected);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&h.state().session.active().unwrap().doc, layer).unwrap(), source);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n h.run_steps(3);",
|
||
" assert_eq!(photocraft_engine::smart_cmds::contents_of(&h.state().session.active().unwrap().doc, layer).unwrap(), source);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n h.run_steps(3);\n assert_eq!(serde_json::to_value(filters(h.state(), layer)).unwrap(), serde_json::to_value(&before).unwrap());",
|
||
" assert_eq!(serde_json::to_value(filters(h.state(), layer)).unwrap(), serde_json::to_value(&before).unwrap());\n assert_eq!(pixels(h.state(), layer), before_pixels);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();\n h.run_steps(3);",
|
||
" assert_eq!(pixels(h.state(), layer), before_pixels);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();\n h.run_steps(3);\n let offset = text_position(&h, \"Offset\");",
|
||
" assert_eq!(serde_json::to_value(filters(h.state(), layer)).unwrap(), serde_json::to_value(&before).unwrap());\n assert_eq!(pixels(h.state(), layer), before_pixels);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 2);\n let offset = text_position(&h, \"Offset\");",
|
||
" assert_eq!(pixels(h.state(), layer), before_pixels);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 2);\n let offset = text_position(&h, \"Offset\");\n click(&mut h, offset, PointerButton::Secondary);",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 2);\n let offset = text_position(&h, \"Offset\");\n click(&mut h, offset, PointerButton::Secondary);\n h.get_by_label(\"Delete Smart Filter\").click();",
|
||
" assert_eq!(filters(h.state(), layer).len(), 1);\n assert_eq!(filters(h.state(), layer)[0].command, \"filter.blur.gaussianBlur\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 3);\n assert_eq!(h.state().session.active().unwrap().active_layer, active);",
|
||
" assert_eq!(filters(h.state(), layer)[0].command, \"filter.blur.gaussianBlur\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 3);\n assert_eq!(h.state().session.active().unwrap().active_layer, active);\n assert_eq!(h.state().session.active().unwrap().selected_layers, selected);",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 3);\n assert_eq!(h.state().session.active().unwrap().active_layer, active);\n assert_eq!(h.state().session.active().unwrap().selected_layers, selected);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&h.state().session.active().unwrap().doc, layer).unwrap(), source);",
|
||
" assert_eq!(h.state().session.active().unwrap().active_layer, active);\n assert_eq!(h.state().session.active().unwrap().selected_layers, selected);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&h.state().session.active().unwrap().doc, layer).unwrap(), source);\n let unchanged = h.state().session.active().unwrap().doc.layer(other.id).unwrap();",
|
||
" assert_eq!(h.state().session.active().unwrap().selected_layers, selected);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&h.state().session.active().unwrap().doc, layer).unwrap(), source);\n let unchanged = h.state().session.active().unwrap().doc.layer(other.id).unwrap();\n assert_eq!(unchanged, &other);",
|
||
" assert_eq!(photocraft_engine::smart_cmds::contents_of(&h.state().session.active().unwrap().doc, layer).unwrap(), source);\n let unchanged = h.state().session.active().unwrap().doc.layer(other.id).unwrap();\n assert_eq!(unchanged, &other);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(unchanged, &other);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(pixels(h.state(), layer), before_pixels);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();",
|
||
" assert_eq!(pixels(h.state(), layer), before_pixels);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();\n assert_eq!(filters(h.state(), layer).len(), 1);\n }",
|
||
" assert_eq!(filters(h.state(), layer).len(), 1);\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/context_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "two_filter_row_context_offers_reorder_and_delete",
|
||
"path": "crates/ui-egui/src/smart_ui/context_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked two_filter_row_context_offers_reorder_and_delete -- --nocapture",
|
||
"fixture_and_action_excerpt": " let _language = crate::i18n::language_scope(crate::i18n::Lang::EN);\n let (mut h, layer) = harness();\n let top = text_position(&h, \"Gaussian Blur\");\n let bottom = text_position(&h, \"Offset\");\n assert!(top.y < bottom.y, \"index1 is visually above index0\");\n let before = h.state().session.active().unwrap().doc.clone();\n let history = h.state().session.active().unwrap().history.past_len();\n click(&mut h, bottom, PointerButton::Secondary);\n assert!(std::sync::Arc::ptr_eq(&before, &h.state().session.active().unwrap().doc));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n let missing = [\"Move Up\", \"Move Down\", \"Delete Smart Filter\"].into_iter().filter(|label| h.query_by_label(label).is_none()).collect::<Vec<_>>();\n assert!(missing.is_empty(), \"filter row lacks context choices {missing:?}; stack has {} filters\", smart(h.state(), layer).smart_filters.len());",
|
||
"expected_assertions": [
|
||
" assert!(top.y < bottom.y, \"index1 is visually above index0\");\n let before = h.state().session.active().unwrap().doc.clone();\n let history = h.state().session.active().unwrap().history.past_len();\n click(&mut h, bottom, PointerButton::Secondary);",
|
||
" assert!(std::sync::Arc::ptr_eq(&before, &h.state().session.active().unwrap().doc));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n let missing = [\"Move Up\", \"Move Down\", \"Delete Smart Filter\"].into_iter().filter(|label| h.query_by_label(label).is_none()).collect::<Vec<_>>();\n assert!(missing.is_empty(), \"filter row lacks context choices {missing:?}; stack has {} filters\", smart(h.state(), layer).smart_filters.len());",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n let missing = [\"Move Up\", \"Move Down\", \"Delete Smart Filter\"].into_iter().filter(|label| h.query_by_label(label).is_none()).collect::<Vec<_>>();\n assert!(missing.is_empty(), \"filter row lacks context choices {missing:?}; stack has {} filters\", smart(h.state(), layer).smart_filters.len());\n}",
|
||
" assert!(missing.is_empty(), \"filter row lacks context choices {missing:?}; stack has {} filters\", smart(h.state(), layer).smart_filters.len());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/context_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "existing_filter_move_delete_commands_preserve_source_and_undo_at_every_depth",
|
||
"path": "crates/ui-egui/src/smart_ui/context_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked existing_filter_move_delete_commands_preserve_source_and_undo_at_every_depth -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [8, 16, 32] {\n let (mut app, layer) = app(depth);\n let original = filters(&app, layer);\n let original_pixels = pixels(&app, layer);\n let source = photocraft_engine::smart_cmds::contents_of(&app.session.active().unwrap().doc, layer).unwrap();\n let active = app.session.active().unwrap().active_layer;\n let history = app.session.active().unwrap().history.past_len();\n app.run(\"layer.smartFilter.move\", json!({\"layer\": layer.0, \"index\": 0, \"to\": 1})).unwrap();\n assert_eq!(filters(&app, layer).iter().map(|f| f.command.as_str()).collect::<Vec<_>>(), [\"filter.blur.gaussianBlur\", \"filter.other.offset\"]);\n assert_ne!(pixels(&app, layer), original_pixels, \"noncommuting operations really rerender\");\n assert_eq!(app.session.active().unwrap().history.past_len(), history + 1);\n assert_eq!(app.session.active().unwrap().active_layer, active);",
|
||
"expected_assertions": [
|
||
" assert_eq!(filters(&app, layer).iter().map(|f| f.command.as_str()).collect::<Vec<_>>(), [\"filter.blur.gaussianBlur\", \"filter.other.offset\"]);\n assert_ne!(pixels(&app, layer), original_pixels, \"noncommuting operations really rerender\");\n assert_eq!(app.session.active().unwrap().history.past_len(), history + 1);\n assert_eq!(app.session.active().unwrap().active_layer, active);",
|
||
" assert_ne!(pixels(&app, layer), original_pixels, \"noncommuting operations really rerender\");\n assert_eq!(app.session.active().unwrap().history.past_len(), history + 1);\n assert_eq!(app.session.active().unwrap().active_layer, active);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&app.session.active().unwrap().doc, layer).unwrap(), source);",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), history + 1);\n assert_eq!(app.session.active().unwrap().active_layer, active);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&app.session.active().unwrap().doc, layer).unwrap(), source);\n app.run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(app.session.active().unwrap().active_layer, active);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&app.session.active().unwrap().doc, layer).unwrap(), source);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(serde_json::to_value(filters(&app, layer)).unwrap(), serde_json::to_value(&original).unwrap());",
|
||
" assert_eq!(photocraft_engine::smart_cmds::contents_of(&app.session.active().unwrap().doc, layer).unwrap(), source);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(serde_json::to_value(filters(&app, layer)).unwrap(), serde_json::to_value(&original).unwrap());\n assert_eq!(pixels(&app, layer), original_pixels);",
|
||
" assert_eq!(serde_json::to_value(filters(&app, layer)).unwrap(), serde_json::to_value(&original).unwrap());\n assert_eq!(pixels(&app, layer), original_pixels);\n app.run(\"edit.redo\", json!({})).unwrap();\n let reordered_pixels = pixels(&app, layer);",
|
||
" assert_eq!(pixels(&app, layer), original_pixels);\n app.run(\"edit.redo\", json!({})).unwrap();\n let reordered_pixels = pixels(&app, layer);\n app.run(\"layer.smartFilter.delete\", json!({\"layer\": layer.0, \"index\": 1})).unwrap();",
|
||
" assert_eq!(filters(&app, layer).len(), 1);\n assert_eq!(filters(&app, layer)[0].command, \"filter.blur.gaussianBlur\");\n assert_eq!(app.session.active().unwrap().history.past_len(), history + 2);\n assert_eq!(app.session.active().unwrap().active_layer, active);",
|
||
" assert_eq!(filters(&app, layer)[0].command, \"filter.blur.gaussianBlur\");\n assert_eq!(app.session.active().unwrap().history.past_len(), history + 2);\n assert_eq!(app.session.active().unwrap().active_layer, active);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&app.session.active().unwrap().doc, layer).unwrap(), source);",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), history + 2);\n assert_eq!(app.session.active().unwrap().active_layer, active);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&app.session.active().unwrap().doc, layer).unwrap(), source);\n app.run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(app.session.active().unwrap().active_layer, active);\n assert_eq!(photocraft_engine::smart_cmds::contents_of(&app.session.active().unwrap().doc, layer).unwrap(), source);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(pixels(&app, layer), reordered_pixels);",
|
||
" assert_eq!(photocraft_engine::smart_cmds::contents_of(&app.session.active().unwrap().doc, layer).unwrap(), source);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(pixels(&app, layer), reordered_pixels);\n app.run(\"edit.redo\", json!({})).unwrap();",
|
||
" assert_eq!(pixels(&app, layer), reordered_pixels);\n app.run(\"edit.redo\", json!({})).unwrap();\n assert_eq!(filters(&app, layer).len(), 1);\n }",
|
||
" assert_eq!(filters(&app, layer).len(), 1);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/context_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "row_menu_disables_edges_and_deletes_the_only_remaining_filter",
|
||
"path": "crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked row_menu_disables_edges_and_deletes_the_only_remaining_filter -- --nocapture",
|
||
"fixture_and_action_excerpt": " let _language = crate::i18n::language_scope(crate::i18n::Lang::EN);\n for ppp in [1.0, 2.0] {\n let (mut h, layer) = harness_at(8, ppp);\n let top = text_position(&h, \"Gaussian Blur\");\n click(&mut h, top, PointerButton::Secondary);\n assert!(h.get_by_label(\"Move Up\").accesskit_node().is_disabled());\n assert!(!h.get_by_label(\"Move Down\").accesskit_node().is_disabled());\n let before = h.state().session.active().unwrap().doc.clone();\n let history = h.state().session.active().unwrap().history.past_len();\n h.get_by_label(\"Move Up\").click();\n h.run_steps(3);\n assert!(Arc::ptr_eq(&before, &h.state().session.active().unwrap().doc));",
|
||
"expected_assertions": [
|
||
" assert!(h.get_by_label(\"Move Up\").accesskit_node().is_disabled());\n assert!(!h.get_by_label(\"Move Down\").accesskit_node().is_disabled());\n let before = h.state().session.active().unwrap().doc.clone();\n let history = h.state().session.active().unwrap().history.past_len();",
|
||
" assert!(!h.get_by_label(\"Move Down\").accesskit_node().is_disabled());\n let before = h.state().session.active().unwrap().doc.clone();\n let history = h.state().session.active().unwrap().history.past_len();\n h.get_by_label(\"Move Up\").click();",
|
||
" assert!(Arc::ptr_eq(&before, &h.state().session.active().unwrap().doc));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n egui::Popup::close_all(&h.ctx);\n h.state_mut().run(\"layer.smartFilter.delete\", json!({\"layer\":layer.0,\"index\":0})).unwrap();",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n egui::Popup::close_all(&h.ctx);\n h.state_mut().run(\"layer.smartFilter.delete\", json!({\"layer\":layer.0,\"index\":0})).unwrap();\n h.run_steps(3);",
|
||
" assert!(h.get_by_label(\"Move Up\").accesskit_node().is_disabled());\n assert!(h.get_by_label(\"Move Down\").accesskit_node().is_disabled());\n assert!(!h.get_by_label(\"Delete Smart Filter\").accesskit_node().is_disabled());\n h.get_by_label(\"Delete Smart Filter\").click();",
|
||
" assert!(h.get_by_label(\"Move Down\").accesskit_node().is_disabled());\n assert!(!h.get_by_label(\"Delete Smart Filter\").accesskit_node().is_disabled());\n h.get_by_label(\"Delete Smart Filter\").click();\n h.run_steps(4);",
|
||
" assert!(!h.get_by_label(\"Delete Smart Filter\").accesskit_node().is_disabled());\n h.get_by_label(\"Delete Smart Filter\").click();\n h.run_steps(4);\n assert!(filters(h.state(), layer).is_empty());",
|
||
" assert!(filters(h.state(), layer).is_empty());\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 2);\n assert!(!egui::Popup::is_any_open(&h.ctx));\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 2);\n assert!(!egui::Popup::is_any_open(&h.ctx));\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(filters(h.state(), layer).len(), 1);",
|
||
" assert!(!egui::Popup::is_any_open(&h.ctx));\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(filters(h.state(), layer).len(), 1);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();",
|
||
" assert_eq!(filters(h.state(), layer).len(), 1);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();\n assert!(filters(h.state(), layer).is_empty());\n }",
|
||
" assert!(filters(h.state(), layer).is_empty());\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "stale_row_menu_closes_on_edits_undo_redo_document_switch_and_same_id_reopen",
|
||
"path": "crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked stale_row_menu_closes_on_edits_undo_redo_document_switch_and_same_id_reopen -- --nocapture",
|
||
"fixture_and_action_excerpt": " let _language = crate::i18n::language_scope(crate::i18n::Lang::EN);\n for change in [\"move\", \"delete\", \"undo\", \"redo\", \"switch\", \"reopen\", \"close\"] {\n let (mut h, layer) = harness();\n let offset = text_position(&h, \"Offset\");\n click(&mut h, offset, PointerButton::Secondary);\n assert!(h.query_by_label(\"Delete Smart Filter\").is_some());\n match change {\n \"move\" => {\n h.state_mut().run(\"layer.smartFilter.move\", json!({\"layer\":layer.0,\"index\":0,\"to\":1})).unwrap();\n }\n \"delete\" => {\n h.state_mut().run(\"layer.smartFilter.delete\", json!({\"layer\":layer.0,\"index\":0})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(h.query_by_label(\"Delete Smart Filter\").is_some());\n match change {\n \"move\" => {\n h.state_mut().run(\"layer.smartFilter.move\", json!({\"layer\":layer.0,\"index\":0,\"to\":1})).unwrap();",
|
||
" assert_eq!(session.documents()[index].doc.id, old.doc.id);\n session.active_mut().unwrap().revision = old.revision;\n assert!(!Arc::ptr_eq(&session.active().unwrap().doc, &old.doc));\n }",
|
||
" assert!(!Arc::ptr_eq(&session.active().unwrap().doc, &old.doc));\n }\n \"close\" => {\n let session = &mut h.state_mut().session;",
|
||
" assert!(h.query_by_label(\"Delete Smart Filter\").is_none(), \"{change} closes stale choices\");\n assert!(!egui::Popup::is_any_open(&h.ctx), \"{change} closes popup memory too\");\n if let Some((doc, revision, history)) = before {\n let st = h.state().session.active().unwrap();",
|
||
" assert!(!egui::Popup::is_any_open(&h.ctx), \"{change} closes popup memory too\");\n if let Some((doc, revision, history)) = before {\n let st = h.state().session.active().unwrap();\n assert!(Arc::ptr_eq(&doc, &st.doc), \"{change} adds no accidental edit\");",
|
||
" assert!(Arc::ptr_eq(&doc, &st.doc), \"{change} adds no accidental edit\");\n assert_eq!((st.revision, st.history.past_len()), (revision, history));\n }\n }",
|
||
" assert_eq!((st.revision, st.history.past_len()), (revision, history));\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "parameter_and_camera_raw_modals_close_the_row_menu_without_mutation",
|
||
"path": "crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked parameter_and_camera_raw_modals_close_the_row_menu_without_mutation -- --nocapture",
|
||
"fixture_and_action_excerpt": " let _language = crate::i18n::language_scope(crate::i18n::Lang::EN);\n for raw in [false, true] {\n let (mut h, layer) = harness();\n let offset = text_position(&h, \"Offset\");\n click(&mut h, offset, PointerButton::Secondary);\n let ctx = h.ctx.clone();\n if raw {\n crate::camera_raw_ui::open(h.state_mut(), &ctx).unwrap();\n } else {\n let sm = smart(h.state(), layer).clone();\n open_editor(h.state_mut(), &ctx, layer.0, &sm, 0);\n assert!(h.state().ui.dialogs.last().unwrap().fields.contains_key(\"__smartFilter\"));",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.dialogs.last().unwrap().fields.contains_key(\"__smartFilter\"));\n }\n let before = h.state().session.active().unwrap().doc.clone();\n let history = h.state().session.active().unwrap().history.past_len();",
|
||
" assert!(h.query_by_label(\"Delete Smart Filter\").is_none());\n assert!(!egui::Popup::is_any_open(&h.ctx));\n assert!(Arc::ptr_eq(&before, &h.state().session.active().unwrap().doc));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);",
|
||
" assert!(!egui::Popup::is_any_open(&h.ctx));\n assert!(Arc::ptr_eq(&before, &h.state().session.active().unwrap().doc));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n }",
|
||
" assert!(Arc::ptr_eq(&before, &h.state().session.active().unwrap().doc));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n }\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "pending_document_job_closes_row_menu_and_refuses_new_choices",
|
||
"path": "crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked pending_document_job_closes_row_menu_and_refuses_new_choices -- --nocapture",
|
||
"fixture_and_action_excerpt": " let _language = crate::i18n::language_scope(crate::i18n::Lang::EN);\n let (mut h, _layer) = harness();\n let offset = text_position(&h, \"Offset\");\n click(&mut h, offset, PointerButton::Secondary);\n let before = h.state().session.active().unwrap().doc.clone();\n let started = h\n .state_mut()\n .session\n .start_job(\n \"test.wait\",\n json!({}),\n \"Waiting filter\",",
|
||
"expected_assertions": [
|
||
" assert!(h.query_by_label(\"Delete Smart Filter\").is_none());\n assert!(!egui::Popup::is_any_open(&h.ctx));\n click(&mut h, offset, PointerButton::Secondary);\n assert!(h.query_by_label(\"Delete Smart Filter\").is_none());",
|
||
" assert!(!egui::Popup::is_any_open(&h.ctx));\n click(&mut h, offset, PointerButton::Secondary);\n assert!(h.query_by_label(\"Delete Smart Filter\").is_none());\n assert!(Arc::ptr_eq(&before, &h.state().session.active().unwrap().doc));",
|
||
" assert!(h.query_by_label(\"Delete Smart Filter\").is_none());\n assert!(Arc::ptr_eq(&before, &h.state().session.active().unwrap().doc));\n h.state_mut().session.cancel_job(id);\n h.state_mut().session.join_cancelled_jobs();",
|
||
" assert!(Arc::ptr_eq(&before, &h.state().session.active().unwrap().doc));\n h.state_mut().session.cancel_job(id);\n h.state_mut().session.join_cancelled_jobs();\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "existing_eye_and_name_double_click_remain_distinct_from_secondary_actions",
|
||
"path": "crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked existing_eye_and_name_double_click_remain_distinct_from_secondary_actions -- --nocapture",
|
||
"fixture_and_action_excerpt": " let _language = crate::i18n::language_scope(crate::i18n::Lang::EN);\n for ppp in [1.0, 2.0] {\n let (mut h, layer) = harness_at(8, ppp);\n let offset = text_position(&h, \"Offset\");\n let layer_row = crate::layer_row_ui::recorded(&h.ctx).into_iter().find(|r| r.layer == layer.0).unwrap().row;\n let eye = pos2(layer_row.left() + 15.0, offset.y);\n let history = h.state().session.active().unwrap().history.past_len();\n click(&mut h, eye, PointerButton::Primary);\n assert!(!filters(h.state(), layer)[0].visible);\n assert!(h.query_by_label(\"Delete Smart Filter\").is_none());\n assert!(h.state().ui.dialogs.is_empty());\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(!filters(h.state(), layer)[0].visible);\n assert!(h.query_by_label(\"Delete Smart Filter\").is_none());\n assert!(h.state().ui.dialogs.is_empty());\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert!(h.query_by_label(\"Delete Smart Filter\").is_none());\n assert!(h.state().ui.dialogs.is_empty());\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n h.run_steps(40);",
|
||
" assert!(h.state().ui.dialogs.is_empty());\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n h.run_steps(40);\n click(&mut h, offset, PointerButton::Primary);",
|
||
" assert_eq!(dialog.fields[\"__command\"], json!(\"filter.other.offset\"));\n assert_eq!(dialog.fields[\"__smartFilter\"], json!({\"layer\":layer.0,\"index\":0}));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n }",
|
||
" assert_eq!(dialog.fields[\"__smartFilter\"], json!({\"layer\":layer.0,\"index\":0}));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n }\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "capture_native_popup_at_two_scales_and_in_french",
|
||
"path": "crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked capture_native_popup_at_two_scales_and_in_french -- --nocapture --ignored",
|
||
"fixture_and_action_excerpt": " let out = std::env::var(\"PHOTOCRAFT_SMART_FILTER_CAPTURE_DIR\").expect(\"capture destination\");\n for (language, ppp) in [(\"en\", 1.0), (\"fr\", 2.0)] {\n let (mut app, layer) = app(8);\n app.run(\"prefs.set\", json!({\"path\":\"interface.language\",\"value\":language})).unwrap();\n let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1440.0, 900.0)).with_pixels_per_point(ppp).with_max_steps(64).wgpu().build_eframe(\n move |cc| {\n PhotocraftApp::setup_context(&cc.egui_ctx, Default::default());\n app\n },\n );\n let ctx = h.ctx.clone();\n let (req, _) = crate::control::ControlRequest::new(\"ui.set\", json!({\"zoom\":12.0,\"dock\":{\"collapsed\":[\"color\",\"properties\",\"history\",\"navigator\"]}}));",
|
||
"expected_assertions": [
|
||
" assert!(h.query_by_label(label).is_some(), \"localized popup item {label}\");\n }\n h.run_steps(12);\n let file = std::path::Path::new(&out).join(format!(\"smart-filter-menu-{language}-{}x.png\", ppp as u32));"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"ignored_requires_explicit_execution": true
|
||
},
|
||
{
|
||
"name": "row_menu_reorder_keeps_the_selected_filter_identity",
|
||
"path": "crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked row_menu_reorder_keeps_the_selected_filter_identity -- --nocapture",
|
||
"fixture_and_action_excerpt": " let _language = crate::i18n::language_scope(crate::i18n::Lang::EN);\n for ppp in [1.0, 2.0] {\n for (target, choice) in [(\"Offset\", \"Move Up\"), (\"Gaussian Blur\", \"Move Down\")] {\n let (mut h, layer) = harness_at(8, ppp);\n let at = text_position(&h, \"Offset\");\n click(&mut h, at, PointerButton::Primary);\n assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));\n let st = h.state().session.active().unwrap();\n let (active, selected, history) = (st.active_layer, st.selected_layers.clone(), st.history.past_len());\n let at = text_position(&h, target);\n click(&mut h, at, PointerButton::Secondary);",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));\n let st = h.state().session.active().unwrap();\n let (active, selected, history) = (st.active_layer, st.selected_layers.clone(), st.history.past_len());",
|
||
" assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));\n let st = h.state().session.active().unwrap();\n let (active, selected, history) = (st.active_layer, st.selected_layers.clone(), st.history.past_len());\n let at = text_position(&h, target);",
|
||
" assert_eq!(filters(h.state(), layer).iter().map(|f| f.command.as_str()).collect::<Vec<_>>(), [\"filter.blur.gaussianBlur\", \"filter.other.offset\"]);\n assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True), \"{target}/{choice} keeps Offset selected\");\n assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));\n let st = h.state().session.active().unwrap();",
|
||
" assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True), \"{target}/{choice} keeps Offset selected\");\n assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));\n let st = h.state().session.active().unwrap();\n assert_eq!((st.active_layer, &st.selected_layers, st.history.past_len()), (active, &selected, history + 1));",
|
||
" assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));\n let st = h.state().session.active().unwrap();\n assert_eq!((st.active_layer, &st.selected_layers, st.history.past_len()), (active, &selected, history + 1));\n }",
|
||
" assert_eq!((st.active_layer, &st.selected_layers, st.history.past_len()), (active, &selected, history + 1));\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "row_menu_delete_before_selection_keeps_the_remaining_filter_selected",
|
||
"path": "crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked row_menu_delete_before_selection_keeps_the_remaining_filter_selected -- --nocapture",
|
||
"fixture_and_action_excerpt": " let _language = crate::i18n::language_scope(crate::i18n::Lang::EN);\n for ppp in [1.0, 2.0] {\n let (mut h, layer) = harness_at(8, ppp);\n let at = text_position(&h, \"Gaussian Blur\");\n click(&mut h, at, PointerButton::Primary);\n assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n let st = h.state().session.active().unwrap();\n let (active, selected, history) = (st.active_layer, st.selected_layers.clone(), st.history.past_len());\n let at = text_position(&h, \"Offset\");\n click(&mut h, at, PointerButton::Secondary);\n h.get_by_label(\"Delete Smart Filter\").click();\n h.run_steps(4);",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n let st = h.state().session.active().unwrap();\n let (active, selected, history) = (st.active_layer, st.selected_layers.clone(), st.history.past_len());\n let at = text_position(&h, \"Offset\");",
|
||
" assert_eq!(filters(h.state(), layer).iter().map(|f| f.command.as_str()).collect::<Vec<_>>(), [\"filter.blur.gaussianBlur\"]);\n assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n let st = h.state().session.active().unwrap();\n assert_eq!((st.active_layer, &st.selected_layers, st.history.past_len()), (active, &selected, history + 1));",
|
||
" assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n let st = h.state().session.active().unwrap();\n assert_eq!((st.active_layer, &st.selected_layers, st.history.past_len()), (active, &selected, history + 1));\n }",
|
||
" assert_eq!((st.active_layer, &st.selected_layers, st.history.past_len()), (active, &selected, history + 1));\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "row_menu_delete_selected_filter_clears_its_row_selection",
|
||
"path": "crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked row_menu_delete_selected_filter_clears_its_row_selection -- --nocapture",
|
||
"fixture_and_action_excerpt": " let _language = crate::i18n::language_scope(crate::i18n::Lang::EN);\n for ppp in [1.0, 2.0] {\n let (mut h, layer) = harness_at(8, ppp);\n let at = text_position(&h, \"Offset\");\n click(&mut h, at, PointerButton::Primary);\n assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n let st = h.state().session.active().unwrap();\n let (active, selected, history) = (st.active_layer, st.selected_layers.clone(), st.history.past_len());\n let at = text_position(&h, \"Offset\");\n click(&mut h, at, PointerButton::Secondary);\n h.get_by_label(\"Delete Smart Filter\").click();\n h.run_steps(4);",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n let st = h.state().session.active().unwrap();\n let (active, selected, history) = (st.active_layer, st.selected_layers.clone(), st.history.past_len());\n let at = text_position(&h, \"Offset\");",
|
||
" assert_eq!(filters(h.state(), layer).iter().map(|f| f.command.as_str()).collect::<Vec<_>>(), [\"filter.blur.gaussianBlur\"]);\n assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));\n let doc = h.state().session.active().unwrap().doc.id;\n assert!(h.ctx.data(|d| d.get_temp::<FilterDrag>(selected_key(doc))).is_none());",
|
||
" assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));\n let doc = h.state().session.active().unwrap().doc.id;\n assert!(h.ctx.data(|d| d.get_temp::<FilterDrag>(selected_key(doc))).is_none());\n let st = h.state().session.active().unwrap();",
|
||
" assert!(h.ctx.data(|d| d.get_temp::<FilterDrag>(selected_key(doc))).is_none());\n let st = h.state().session.active().unwrap();\n assert_eq!((st.active_layer, &st.selected_layers, st.history.past_len()), (active, &selected, history + 1));\n }",
|
||
" assert_eq!((st.active_layer, &st.selected_layers, st.history.past_len()), (active, &selected, history + 1));\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "row_menu_refused_edit_preserves_filter_order_and_selection",
|
||
"path": "crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked row_menu_refused_edit_preserves_filter_order_and_selection -- --nocapture",
|
||
"fixture_and_action_excerpt": " let _language = crate::i18n::language_scope(crate::i18n::Lang::EN);\n let (mut h, layer) = harness();\n let at = text_position(&h, \"Offset\");\n click(&mut h, at, PointerButton::Primary);\n assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n let before = h.state().session.active().unwrap().doc.clone();\n let st = h.state().session.active().unwrap();\n let (active, selected, history) = (st.active_layer, st.selected_layers.clone(), st.history.past_len());\n h.state_mut().session.authorize =\n Some(|command, _| if command == \"layer.smartFilter.move\" { Err(photocraft_engine::EngineError::Other(\"refused menu edit\".into())) } else { Ok(()) });\n let at = text_position(&h, \"Offset\");\n click(&mut h, at, PointerButton::Secondary);",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n let before = h.state().session.active().unwrap().doc.clone();\n let st = h.state().session.active().unwrap();\n let (active, selected, history) = (st.active_layer, st.selected_layers.clone(), st.history.past_len());",
|
||
" assert!(Arc::ptr_eq(&before, &st.doc));\n assert_eq!((st.active_layer, &st.selected_layers, st.history.past_len()), (active, &selected, history));\n assert_eq!(filters(h.state(), layer).iter().map(|f| f.command.as_str()).collect::<Vec<_>>(), [\"filter.other.offset\", \"filter.blur.gaussianBlur\"]);\n assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));",
|
||
" assert_eq!((st.active_layer, &st.selected_layers, st.history.past_len()), (active, &selected, history));\n assert_eq!(filters(h.state(), layer).iter().map(|f| f.command.as_str()).collect::<Vec<_>>(), [\"filter.other.offset\", \"filter.blur.gaussianBlur\"]);\n assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));",
|
||
" assert_eq!(filters(h.state(), layer).iter().map(|f| f.command.as_str()).collect::<Vec<_>>(), [\"filter.other.offset\", \"filter.blur.gaussianBlur\"]);\n assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));\n}",
|
||
" assert_eq!(h.get_by_label(\"Offset\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::True));\n assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));\n}",
|
||
" assert_eq!(h.get_by_label(\"Gaussian Blur\").accesskit_node().toggled(), Some(egui::accesskit::Toggled::False));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3a77519ce2cef0fb60cebd4ea796d599f68868cb/crates/ui-egui/src/smart_ui/menu_guard_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-4023",
|
||
"pr": 4023,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Select Spanish UI; open a synthetic document and the filter/video menus affected by this PR.",
|
||
"action": "Inspect Interpret/Replace Footage, Tilt-Shift, Mezzotint and Smart Sharpen; exercise labels containing parameter placeholders.",
|
||
"expected": "All affected labels use the intended reviewed Spanish terminology; placeholders retain their values and no missing-key fallback appears.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": ""
|
||
},
|
||
{
|
||
"id": "PR-4305",
|
||
"pr": 4305,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked low_and_high_composite_back_to_the_source_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked high_must_be_on_linear_light -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked builds_a_named_group_above_the_source_and_targets_high -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked low_is_the_gaussian_blur_of_the_source_at_the_radius -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked one_undo_removes_everything_and_redo_brings_it_back -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked works_on_the_background -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked needs_a_pixel_layer_with_pixels -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked refuses_a_channel_or_mask_target -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked refuses_cmyk_and_lab -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked a_layer_of_transparent_tiles_is_refused_when_run -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked bad_params_are_rejected_without_changes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked frequency_separation_sits_in_filter_other_after_color_to_alpha -- --nocapture"
|
||
],
|
||
"expected": "low and high composite back to the source at every depth; high must be on linear light; builds a named group above the source and targets high; low is the gaussian blur of the source at the radius; one undo removes everything and redo brings it back; works on the background; needs a pixel layer with pixels; refuses a channel or mask target; refuses cmyk and lab; a layer of transparent tiles is refused when run; bad params are rejected without changes; frequency separation sits in filter other after color to alpha",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked low_and_high_composite_back_to_the_source_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked high_must_be_on_linear_light -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked builds_a_named_group_above_the_source_and_targets_high -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked low_is_the_gaussian_blur_of_the_source_at_the_radius -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked one_undo_removes_everything_and_redo_brings_it_back -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked works_on_the_background -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked needs_a_pixel_layer_with_pixels -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked refuses_a_channel_or_mask_target -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked refuses_cmyk_and_lab -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked a_layer_of_transparent_tiles_is_refused_when_run -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked bad_params_are_rejected_without_changes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked frequency_separation_sits_in_filter_other_after_color_to_alpha -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "low_and_high_composite_back_to_the_source_at_every_depth",
|
||
"path": "crates/engine/src/frequency_separation_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked low_and_high_composite_back_to_the_source_at_every_depth -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (depth, mode, tol) in [(8, \"rgb\", 1.0 / 255.0), (16, \"rgb\", 1.0 / 65535.0), (32, \"rgb\", 1e-5), (8, \"gray\", 1.0 / 255.0), (32, \"gray\", 1e-5)] {\n let tol = tol + 1e-6;\n let mut s = session(depth, mode);\n let source = active(&s);\n let before = composite(doc(&s));\n s.execute(ID, json!({\"radius\": 3})).unwrap_or_else(|e| panic!(\"{depth} {mode}: {e}\"));\n let d = doc(&s);\n let (_, [low, high]) = group_of(d, source);\n // The group alone rebuilds the source: hide the source so it can't show through.\n let rebuilt = composite(&without(d, source));\n let err = max_diff(&before, &rebuilt);\n assert!(err <= tol, \"{depth} {mode}: Low + High is off by {err} (tolerance {tol})\");",
|
||
"expected_assertions": [
|
||
" assert!(err <= tol, \"{depth} {mode}: Low + High is off by {err} (tolerance {tol})\");\n assert!(max_diff(&composite(d), &rebuilt) <= 1e-6, \"{depth} {mode}: the group covers the source\");\n // Low alone is visibly smoother than the source; High carries what it lost.\n let low_only = composite(&without(&without(d, source), high));",
|
||
" assert!(max_diff(&composite(d), &rebuilt) <= 1e-6, \"{depth} {mode}: the group covers the source\");\n // Low alone is visibly smoother than the source; High carries what it lost.\n let low_only = composite(&without(&without(d, source), high));\n assert!(max_diff(&before, &low_only) > 0.1, \"{depth} {mode}: Low is blurred\");",
|
||
" assert!(max_diff(&before, &low_only) > 0.1, \"{depth} {mode}: Low is blurred\");\n let h = d.layer(high).unwrap().surface().unwrap();\n assert!((0..W).any(|x| (h.rgba(x, 5)[0] - 0.5).abs() > 0.05), \"{depth} {mode}: High holds the detail\");\n assert_ne!(pixels(d, low), pixels(d, source), \"{depth} {mode}\");",
|
||
" assert!((0..W).any(|x| (h.rgba(x, 5)[0] - 0.5).abs() > 0.05), \"{depth} {mode}: High holds the detail\");\n assert_ne!(pixels(d, low), pixels(d, source), \"{depth} {mode}\");\n }\n }",
|
||
" assert_ne!(pixels(d, low), pixels(d, source), \"{depth} {mode}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/engine/src/frequency_separation_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "high_must_be_on_linear_light",
|
||
"path": "crates/engine/src/frequency_separation_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked high_must_be_on_linear_light -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session(16, \"rgb\");\n let source = active(&s);\n let before = composite(doc(&s));\n s.execute(ID, json!({})).unwrap();\n let (_, [_, high]) = group_of(doc(&s), source);\n let mut d = doc(&s).clone();\n d.layer_mut(high).unwrap().blend = BlendMode::Normal;\n assert!(max_diff(&before, &composite(&d)) > 0.1);\n }",
|
||
"expected_assertions": [
|
||
" assert!(max_diff(&before, &composite(&d)) > 0.1);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/engine/src/frequency_separation_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "builds_a_named_group_above_the_source_and_targets_high",
|
||
"path": "crates/engine/src/frequency_separation_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked builds_a_named_group_above_the_source_and_targets_high -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session(8, \"rgb\");\n let source = active(&s);\n let source_px = pixels(doc(&s), source);\n let r = s.execute(ID, json!({})).unwrap();\n let d = doc(&s);\n let (group, [low, high]) = group_of(d, source);\n let g = d.layer(group).unwrap();\n assert_eq!(g.name, \"Frequency Separation\");\n assert_eq!(g.blend, BlendMode::PassThrough);\n let (l, h) = (d.layer(low).unwrap(), d.layer(high).unwrap());\n assert_eq!((l.name.as_str(), l.blend), (\"Low Frequency\", BlendMode::Normal));\n assert_eq!((h.name.as_str(), h.blend), (\"High Frequency\", BlendMode::LinearLight));",
|
||
"expected_assertions": [
|
||
" assert_eq!(g.name, \"Frequency Separation\");\n assert_eq!(g.blend, BlendMode::PassThrough);\n let (l, h) = (d.layer(low).unwrap(), d.layer(high).unwrap());\n assert_eq!((l.name.as_str(), l.blend), (\"Low Frequency\", BlendMode::Normal));",
|
||
" assert_eq!(g.blend, BlendMode::PassThrough);\n let (l, h) = (d.layer(low).unwrap(), d.layer(high).unwrap());\n assert_eq!((l.name.as_str(), l.blend), (\"Low Frequency\", BlendMode::Normal));\n assert_eq!((h.name.as_str(), h.blend), (\"High Frequency\", BlendMode::LinearLight));",
|
||
" assert_eq!((l.name.as_str(), l.blend), (\"Low Frequency\", BlendMode::Normal));\n assert_eq!((h.name.as_str(), h.blend), (\"High Frequency\", BlendMode::LinearLight));\n assert!(matches!(l.content, LayerContent::Raster(_)) && matches!(h.content, LayerContent::Raster(_)));\n assert!(l.visible && h.visible && g.visible);",
|
||
" assert_eq!((h.name.as_str(), h.blend), (\"High Frequency\", BlendMode::LinearLight));\n assert!(matches!(l.content, LayerContent::Raster(_)) && matches!(h.content, LayerContent::Raster(_)));\n assert!(l.visible && h.visible && g.visible);\n // High draws where the source does, not grey over the transparent rest of its tiles.",
|
||
" assert!(matches!(l.content, LayerContent::Raster(_)) && matches!(h.content, LayerContent::Raster(_)));\n assert!(l.visible && h.visible && g.visible);\n // High draws where the source does, not grey over the transparent rest of its tiles.\n let bounds = |id: LayerId| d.layer(id).unwrap().surface().unwrap().content_bounds();",
|
||
" assert!(l.visible && h.visible && g.visible);\n // High draws where the source does, not grey over the transparent rest of its tiles.\n let bounds = |id: LayerId| d.layer(id).unwrap().surface().unwrap().content_bounds();\n assert_eq!(bounds(source), Rect::new(0, 0, W, H));",
|
||
" assert_eq!(bounds(source), Rect::new(0, 0, W, H));\n assert_eq!(bounds(high), bounds(source));\n // The source is left exactly as it was, visible, below the group.\n let src = d.layer(source).unwrap();",
|
||
" assert_eq!(bounds(high), bounds(source));\n // The source is left exactly as it was, visible, below the group.\n let src = d.layer(source).unwrap();\n assert_eq!((src.name.as_str(), src.visible), (\"Skin\", true));",
|
||
" assert_eq!((src.name.as_str(), src.visible), (\"Skin\", true));\n assert_eq!(pixels(d, source), source_px);\n assert_eq!(active(&s), high, \"retouching starts on the High layer\");\n assert_eq!(r, json!({\"group\": group.0, \"low\": low.0, \"high\": high.0, \"radius\": 4.0}));",
|
||
" assert_eq!(pixels(d, source), source_px);\n assert_eq!(active(&s), high, \"retouching starts on the High layer\");\n assert_eq!(r, json!({\"group\": group.0, \"low\": low.0, \"high\": high.0, \"radius\": 4.0}));\n }",
|
||
" assert_eq!(active(&s), high, \"retouching starts on the High layer\");\n assert_eq!(r, json!({\"group\": group.0, \"low\": low.0, \"high\": high.0, \"radius\": 4.0}));\n }",
|
||
" assert_eq!(r, json!({\"group\": group.0, \"low\": low.0, \"high\": high.0, \"radius\": 4.0}));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/engine/src/frequency_separation_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "low_is_the_gaussian_blur_of_the_source_at_the_radius",
|
||
"path": "crates/engine/src/frequency_separation_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked low_is_the_gaussian_blur_of_the_source_at_the_radius -- --nocapture",
|
||
"fixture_and_action_excerpt": " for radius in [2.0, 6.5] {\n let mut s = session(16, \"rgb\");\n let source = active(&s);\n s.execute(ID, json!({\"radius\": radius})).unwrap();\n let (_, [low, _]) = group_of(doc(&s), source);\n let mut t = session(16, \"rgb\");\n t.execute(\"filter.blur.gaussianBlur\", json!({\"radius\": radius})).unwrap();\n assert_eq!(pixels(doc(&s), low), pixels(doc(&t), active(&t)), \"radius {radius}\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(pixels(doc(&s), low), pixels(doc(&t), active(&t)), \"radius {radius}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/engine/src/frequency_separation_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "one_undo_removes_everything_and_redo_brings_it_back",
|
||
"path": "crates/engine/src/frequency_separation_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked one_undo_removes_everything_and_redo_brings_it_back -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session(8, \"rgb\");\n let source = active(&s);\n let before = doc(&s).clone();\n let steps = s.active().unwrap().history.past_len();\n s.execute(ID, json!({})).unwrap();\n assert_eq!(s.active().unwrap().history.past_len(), steps + 1);\n assert_eq!(s.active().unwrap().history.undo_label(), Some(\"Frequency Separation\"));\n let after = doc(&s).clone();\n s.execute(\"edit.undo\", json!({})).unwrap();\n assert_eq!(*doc(&s), before);\n assert_eq!(active(&s), source);\n s.execute(\"edit.redo\", json!({})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.active().unwrap().history.past_len(), steps + 1);\n assert_eq!(s.active().unwrap().history.undo_label(), Some(\"Frequency Separation\"));\n let after = doc(&s).clone();\n s.execute(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(s.active().unwrap().history.undo_label(), Some(\"Frequency Separation\"));\n let after = doc(&s).clone();\n s.execute(\"edit.undo\", json!({})).unwrap();\n assert_eq!(*doc(&s), before);",
|
||
" assert_eq!(*doc(&s), before);\n assert_eq!(active(&s), source);\n s.execute(\"edit.redo\", json!({})).unwrap();\n assert_eq!(*doc(&s), after);",
|
||
" assert_eq!(active(&s), source);\n s.execute(\"edit.redo\", json!({})).unwrap();\n assert_eq!(*doc(&s), after);\n }",
|
||
" assert_eq!(*doc(&s), after);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/engine/src/frequency_separation_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "works_on_the_background",
|
||
"path": "crates/engine/src/frequency_separation_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked works_on_the_background -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.execute(\"file.new\", json!({\"width\": W, \"height\": H})).unwrap();\n paint(&mut s);\n let source = active(&s);\n assert!(doc(&s).is_background(source));\n let before = composite(doc(&s));\n s.execute(ID, json!({\"radius\": 2})).unwrap();\n let d = doc(&s);\n assert!(d.is_background(source));\n let (_, [low, high]) = group_of(d, source);\n for id in [low, high] {\n assert_eq!(d.layer(id).unwrap().locks, Default::default());",
|
||
"expected_assertions": [
|
||
" assert!(doc(&s).is_background(source));\n let before = composite(doc(&s));\n s.execute(ID, json!({\"radius\": 2})).unwrap();\n let d = doc(&s);",
|
||
" assert!(d.is_background(source));\n let (_, [low, high]) = group_of(d, source);\n for id in [low, high] {\n assert_eq!(d.layer(id).unwrap().locks, Default::default());",
|
||
" assert_eq!(d.layer(id).unwrap().locks, Default::default());\n }\n assert!(max_diff(&before, &composite(d)) <= 1.0 / 255.0 + 1e-6);\n }",
|
||
" assert!(max_diff(&before, &composite(d)) <= 1.0 / 255.0 + 1e-6);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/engine/src/frequency_separation_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "needs_a_pixel_layer_with_pixels",
|
||
"path": "crates/engine/src/frequency_separation_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked needs_a_pixel_layer_with_pixels -- --nocapture",
|
||
"fixture_and_action_excerpt": " refused(&mut Session::new(), \"no document\");\n\n let mut s = session(8, \"rgb\");\n s.execute(\"layer.new.layer\", json!({})).unwrap();\n refused(&mut s, \"an empty layer\");\n let e = s.execute(ID, json!({})).unwrap_err().to_string();\n assert!(e.contains(\"no pixels\"), \"{e}\");\n\n let mut s = session(8, \"rgb\");\n s.execute(\"type.create\", json!({\"x\": 4, \"y\": 20, \"text\": \"Hi\", \"size\": 12})).unwrap();\n refused(&mut s, \"a type layer\");\n let e = s.execute(ID, json!({})).unwrap_err().to_string();",
|
||
"expected_assertions": [
|
||
" assert!(e.contains(\"no pixels\"), \"{e}\");\n\n let mut s = session(8, \"rgb\");\n s.execute(\"type.create\", json!({\"x\": 4, \"y\": 20, \"text\": \"Hi\", \"size\": 12})).unwrap();",
|
||
" assert!(e.contains(\"pixel layer\"), \"{e}\");\n\n let mut s = session(8, \"rgb\");\n s.execute(\"layer.newAdjustmentLayer.invert\", json!({})).unwrap();"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/engine/src/frequency_separation_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "refuses_a_channel_or_mask_target",
|
||
"path": "crates/engine/src/frequency_separation_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked refuses_a_channel_or_mask_target -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session(8, \"rgb\");\n s.execute(\"select.all\", json!({})).unwrap();\n s.execute(\"select.saveSelection\", json!({})).unwrap();\n s.execute(\"select.deselect\", json!({})).unwrap();\n s.execute(\"channel.target\", json!({\"channel\": \"Alpha 1\"})).unwrap();\n assert!(crate::channel_cmds::edits_channel(&s));\n refused(&mut s, \"an alpha channel\");\n\n let mut s = session(8, \"rgb\");\n s.execute(\"layer.layerMask.revealAll\", json!({})).unwrap();\n s.execute(\"channel.target\", json!({\"channel\": \"mask\"})).unwrap();\n assert_eq!(s.active().unwrap().channel_view.target, crate::channel_cmds::ChannelTarget::LayerMask);",
|
||
"expected_assertions": [
|
||
" assert!(crate::channel_cmds::edits_channel(&s));\n refused(&mut s, \"an alpha channel\");\n\n let mut s = session(8, \"rgb\");",
|
||
" assert_eq!(s.active().unwrap().channel_view.target, crate::channel_cmds::ChannelTarget::LayerMask);\n refused(&mut s, \"a targeted layer mask\");\n // The same layer, its pixels targeted again: allowed (the refusal was the target's).\n s.execute(\"channel.target\", json!({\"channel\": \"composite\"})).unwrap();",
|
||
" assert!(s.is_enabled(ID));\n s.execute(ID, json!({})).unwrap();\n\n // Showing the mask (⌥-click its thumbnail) targets it too.",
|
||
" assert!(s.is_enabled(ID));\n s.execute(\"view.layerMask\", json!({\"mode\": \"gray\"})).unwrap();\n refused(&mut s, \"a mask shown in mask view\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/engine/src/frequency_separation_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "refuses_cmyk_and_lab",
|
||
"path": "crates/engine/src/frequency_separation_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked refuses_cmyk_and_lab -- --nocapture",
|
||
"fixture_and_action_excerpt": " for mode in [\"cmyk\", \"lab\"] {\n let mut s = session(8, mode);\n refused(&mut s, mode);\n let e = s.execute(ID, json!({})).unwrap_err().to_string();\n assert!(e.contains(\"RGB or Grayscale\"), \"{mode}: {e}\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(e.contains(\"RGB or Grayscale\"), \"{mode}: {e}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/engine/src/frequency_separation_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_layer_of_transparent_tiles_is_refused_when_run",
|
||
"path": "crates/engine/src/frequency_separation_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked a_layer_of_transparent_tiles_is_refused_when_run -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session(8, \"rgb\");\n s.execute(\"layer.new.layer\", json!({})).unwrap();\n s.edit(\"clear\", |doc, active| {\n let surf = doc.layer_mut(active.unwrap()).unwrap().surface_mut().unwrap();\n surf.write_region(Rect::new(0, 0, 8, 8), &vec![0.0; 8 * 8 * surf.channels()]);\n Ok(())\n })\n .unwrap();\n assert!(s.is_enabled(ID));\n let before = doc(&s).clone();\n let e = s.execute(ID, json!({})).unwrap_err().to_string();\n assert!(e.contains(\"no pixels\"), \"{e}\");",
|
||
"expected_assertions": [
|
||
" assert!(s.is_enabled(ID));\n let before = doc(&s).clone();\n let e = s.execute(ID, json!({})).unwrap_err().to_string();\n assert!(e.contains(\"no pixels\"), \"{e}\");",
|
||
" assert!(e.contains(\"no pixels\"), \"{e}\");\n assert_eq!(*doc(&s), before);\n }",
|
||
" assert_eq!(*doc(&s), before);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/engine/src/frequency_separation_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "bad_params_are_rejected_without_changes",
|
||
"path": "crates/engine/src/frequency_separation_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked bad_params_are_rejected_without_changes -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session(8, \"rgb\");\n let before = doc(&s).clone();\n for p in [\n json!(7),\n json!(\"4\"),\n json!({\"radius\": 0}),\n json!({\"radius\": 0.05}),\n json!({\"radius\": -3}),\n json!({\"radius\": 1000.5}),\n json!({\"radius\": 1e308}),\n json!({\"radius\": \"4\"}),\n json!({\"radius\": null}),",
|
||
"expected_assertions": [
|
||
" assert!(matches!(s.execute(ID, p.clone()), Err(EngineError::BadParams { .. })), \"{p}\");\n }\n assert_eq!(*doc(&s), before);\n }",
|
||
" assert_eq!(*doc(&s), before);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/engine/src/frequency_separation_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "frequency_separation_sits_in_filter_other_after_color_to_alpha",
|
||
"path": "crates/ui-egui/src/menus.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked frequency_separation_sits_in_filter_other_after_color_to_alpha -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 32, \"height\": 32})).unwrap();\n let items = menu_items(&app);\n let at = |id: &str| items.iter().position(|i| i.id == id).unwrap_or_else(|| panic!(\"{id} missing\"));\n let (c2a, fs) = (at(\"filter.other.colorToAlpha\"), at(\"layer.frequencySeparation\"));\n assert_eq!(fs, c2a + 1);\n assert_eq!(items[fs].path, items[at(\"filter.other.highPass\")].path);\n assert_eq!(items[fs].label, \"Frequency Separation…\");\n assert!(items[fs].enabled, \"the Background is a pixel layer with pixels\");\n assert!(crate::filter_dialog::has_dialog(\"layer.frequencySeparation\"));\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(fs, c2a + 1);\n assert_eq!(items[fs].path, items[at(\"filter.other.highPass\")].path);\n assert_eq!(items[fs].label, \"Frequency Separation…\");\n assert!(items[fs].enabled, \"the Background is a pixel layer with pixels\");",
|
||
" assert_eq!(items[fs].path, items[at(\"filter.other.highPass\")].path);\n assert_eq!(items[fs].label, \"Frequency Separation…\");\n assert!(items[fs].enabled, \"the Background is a pixel layer with pixels\");\n assert!(crate::filter_dialog::has_dialog(\"layer.frequencySeparation\"));",
|
||
" assert_eq!(items[fs].label, \"Frequency Separation…\");\n assert!(items[fs].enabled, \"the Background is a pixel layer with pixels\");\n assert!(crate::filter_dialog::has_dialog(\"layer.frequencySeparation\"));\n }",
|
||
" assert!(items[fs].enabled, \"the Background is a pixel layer with pixels\");\n assert!(crate::filter_dialog::has_dialog(\"layer.frequencySeparation\"));\n }",
|
||
" assert!(crate::filter_dialog::has_dialog(\"layer.frequencySeparation\"));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b74873991dbb2e9803d228a969291f09c6f1032/crates/ui-egui/src/menus.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-4711",
|
||
"pr": 4711,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-compose --locked clipped_dissolve_is_binary_and_preserves_the_base_shape -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked clipped_dissolve_matches_whole_render_at_offset_regions_and_depths -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked dissolve_adjustment_is_a_per_pixel_choice -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked clipped_dissolve_fill_is_a_per_pixel_choice -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked color_overlay_keeps_dissolve_coverage -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked groups_masks_and_clipping -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked dissolve_adjustments_and_effects_match_cpu_in_offset_regions -- --nocapture"
|
||
],
|
||
"expected": "clipped dissolve is binary and preserves the base shape; clipped dissolve matches whole render at offset regions and depths; dissolve adjustment is a per pixel choice; clipped dissolve fill is a per pixel choice; color overlay keeps dissolve coverage; groups masks and clipping; dissolve adjustments and effects match cpu in offset regions",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-compose --locked clipped_dissolve_is_binary_and_preserves_the_base_shape -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked clipped_dissolve_matches_whole_render_at_offset_regions_and_depths -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked dissolve_adjustment_is_a_per_pixel_choice -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked clipped_dissolve_fill_is_a_per_pixel_choice -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked color_overlay_keeps_dissolve_coverage -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked groups_masks_and_clipping -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked dissolve_adjustments_and_effects_match_cpu_in_offset_regions -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "clipped_dissolve_is_binary_and_preserves_the_base_shape",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked clipped_dissolve_is_binary_and_preserves_the_base_shape -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut d = doc_white(40, 12);\n d.layers.push(solid_layer(\"base\", Rect::new(0, 0, 20, 12), [0.0, 0.0, 1.0, 1.0]));\n let mut clip = solid_layer(\"clip\", d.bounds(), [1.0, 0.0, 0.0, 1.0]);\n clip.clipped = true;\n clip.blend = BlendMode::Dissolve;\n clip.opacity = 0.6;\n clip.fill_opacity = 0.5;\n d.layers.push(clip);\n let mut red = 0;\n let mut blue = 0;\n for y in 0..12 {\n for x in 0..20 {",
|
||
"expected_assertions": [
|
||
" assert!(close4(p, [0.0, 0.0, 1.0, 1.0]), \"Dissolve must not interpolate: {p:?} at ({x},{y})\");\n blue += 1;\n }\n }",
|
||
" assert!(close4(px(&d, 30, y), [1.0; 4]), \"outside the base the clip is invisible\");\n }\n assert!(red > 0 && blue > 0, \"Dissolve must expose both source and base: {red}/{blue}\");\n assert!((red as f32 / (red + blue) as f32 - 0.3).abs() < 0.1, \"coverage should follow 60% opacity × 50% fill: {red}/{blue}\");",
|
||
" assert!(red > 0 && blue > 0, \"Dissolve must expose both source and base: {red}/{blue}\");\n assert!((red as f32 / (red + blue) as f32 - 0.3).abs() < 0.1, \"coverage should follow 60% opacity × 50% fill: {red}/{blue}\");\n}",
|
||
" assert!((red as f32 / (red + blue) as f32 - 0.3).abs() < 0.1, \"coverage should follow 60% opacity × 50% fill: {red}/{blue}\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/db546ff4822a011a7915b66af3834f94c05767db/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "clipped_dissolve_matches_whole_render_at_offset_regions_and_depths",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked clipped_dissolve_matches_whole_render_at_offset_regions_and_depths -- --nocapture",
|
||
"fixture_and_action_excerpt": " for fmt in [PixelFormat::RGBA8, PixelFormat::RGBA16, PixelFormat::RGBA32F] {\n let mut d = Document::new(\"coverage\", Size::new(32, 18), ColorMode::Rgb, fmt.sample);\n let bounds = Rect::new(-3, -2, 32, 18);\n let mut base = Layer::raster(\"base\", fmt);\n base.surface_mut().unwrap().fill_rect(bounds, &[0.0, 0.0, 1.0, 0.5]);\n d.layers.push(base);\n let mut clip = Layer::raster(\"clip\", fmt);\n clip.surface_mut().unwrap().fill_rect(bounds, &[1.0, 0.0, 0.0, 0.75]);\n clip.clipped = true;\n clip.blend = BlendMode::Dissolve;\n clip.opacity = 0.6;\n clip.fill_opacity = 0.5;",
|
||
"expected_assertions": [
|
||
" assert!(close4(part.get(x, y), whole.get(x, y)), \"{fmt:?}: region mismatch at ({x},{y})\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/db546ff4822a011a7915b66af3834f94c05767db/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "dissolve_adjustment_is_a_per_pixel_choice",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked dissolve_adjustment_is_a_per_pixel_choice -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut d = doc_white(16, 16);\n let mut inv = Layer::new(\"inv\", LayerContent::Adjustment(Adjustment::Invert));\n inv.blend = photocraft_color::BlendMode::Dissolve;\n inv.opacity = 0.5;\n d.layers.push(inv);\n let b = flatten(&d);\n let (black, white, other) = b.px.iter().fold((0, 0, 0), |(k, w, o), p| {\n if close4(*p, [0.0, 0.0, 0.0, 1.0]) {\n (k + 1, w, o)\n } else if close4(*p, [1.0, 1.0, 1.0, 1.0]) {\n (k, w + 1, o)\n } else {",
|
||
"expected_assertions": [
|
||
" assert_eq!(other, 0, \"a partial mix would be gray\");\n assert!(black > 40 && white > 40, \"black {black} white {white}\");\n}",
|
||
" assert!(black > 40 && white > 40, \"black {black} white {white}\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/db546ff4822a011a7915b66af3834f94c05767db/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "clipped_dissolve_fill_is_a_per_pixel_choice",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked clipped_dissolve_fill_is_a_per_pixel_choice -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut d = doc_white(16, 16);\n let mut l = solid_layer(\"k\", Rect::new(0, 0, 16, 16), [0.0, 0.0, 0.0, 1.0]);\n l.clipped = true;\n l.blend = photocraft_color::BlendMode::Dissolve;\n l.opacity = 0.5;\n d.layers.push(l);\n let b = flatten(&d);\n assert!(b.px.iter().all(|p| close4(*p, [0.0, 0.0, 0.0, 1.0]) || close4(*p, [1.0; 4])));\n}",
|
||
"expected_assertions": [
|
||
" assert!(b.px.iter().all(|p| close4(*p, [0.0, 0.0, 0.0, 1.0]) || close4(*p, [1.0; 4])));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/db546ff4822a011a7915b66af3834f94c05767db/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "color_overlay_keeps_dissolve_coverage",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked color_overlay_keeps_dissolve_coverage -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_doc::effects::{Effect, FxCommon};\n let mut d = doc_white(16, 16);\n let mut l = Layer::new(\"ink\", LayerContent::Fill(Fill::Solid(photocraft_color::Color::BLACK)));\n l.effects.items.push(Effect::ColorOverlay { common: FxCommon::new(photocraft_color::BlendMode::Normal, 1.0), color: photocraft_color::Color::BLACK });\n l.blend = photocraft_color::BlendMode::Dissolve;\n l.opacity = 0.5;\n d.layers.push(l);\n let b = flatten(&d);\n assert!(b.px.iter().all(|p| close4(*p, [0.0, 0.0, 0.0, 1.0]) || close4(*p, [1.0; 4])));\n}",
|
||
"expected_assertions": [
|
||
" assert!(b.px.iter().all(|p| close4(*p, [0.0, 0.0, 0.0, 1.0]) || close4(*p, [1.0; 4])));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/db546ff4822a011a7915b66af3834f94c05767db/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "groups_masks_and_clipping",
|
||
"path": "crates/gpu/tests/parity.rs",
|
||
"package": "photocraft-gpu",
|
||
"command": "cargo test -p photocraft-gpu --locked groups_masks_and_clipping -- --nocapture",
|
||
"fixture_and_action_excerpt": " let Some(mut g) = gpu() else { return };\n let child = |seed, mode| {\n let mut l = noise_layer(\"c\", PixelFormat::RGBA8, Rect::new(5, 5, 50, 40), seed, 0.0);\n l.blend = mode;\n l\n };\n for isolated in [false, true] {\n let mut d = base_doc(56, 44);\n let mut grp = Layer::group(\"g\", vec![child(11, BlendMode::Normal), child(12, BlendMode::Screen), child(13, BlendMode::Multiply)]);\n if isolated {\n grp.blend = BlendMode::Overlay;\n }",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/db546ff4822a011a7915b66af3834f94c05767db/crates/gpu/tests/parity.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "dissolve_adjustments_and_effects_match_cpu_in_offset_regions",
|
||
"path": "crates/gpu/tests/parity.rs",
|
||
"package": "photocraft-gpu",
|
||
"command": "cargo test -p photocraft-gpu --locked dissolve_adjustments_and_effects_match_cpu_in_offset_regions -- --nocapture",
|
||
"fixture_and_action_excerpt": " let Some(mut g) = gpu() else { return };\n for depth in [SampleType::U8, SampleType::U16, SampleType::F32] {\n for effects in [false, true] {\n let mut d = Document::new(\"Dissolve\", Size::new(300, 280), ColorMode::Rgb, depth);\n d.layers.push(noise_layer(\"base\", d.pixel_format(), Rect::new(0, 0, 300, 280), 19, 0.4));\n let mut layer = if effects {\n let mut l = noise_layer(\"effect\", d.pixel_format(), Rect::new(-8, 13, 290, 270), 27, 0.6);\n l.effects.items = vec![Effect::ColorOverlay { common: FxCommon::new(BlendMode::Normal, 0.7), color: Color::rgb(0.2, 0.8, 0.4) }];\n l\n } else {\n Layer::new(\"adjustment\", LayerContent::Adjustment(Adjustment::Invert))\n };",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/db546ff4822a011a7915b66af3834f94c05767db/crates/gpu/tests/parity.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-4992",
|
||
"pr": 4992,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-compose --locked clipped_dissolve_is_binary_and_preserves_the_base_shape -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked clipped_dissolve_matches_whole_render_at_offset_regions_and_depths -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked groups_masks_and_clipping -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked native_rotate_event_reaches_canvas_when_trackpad_rotation_is_enabled -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked native_pinch_resets_legacy_gesture_continuation -- --nocapture"
|
||
],
|
||
"expected": "clipped dissolve is binary and preserves the base shape; clipped dissolve matches whole render at offset regions and depths; groups masks and clipping; native rotate event reaches canvas when trackpad rotation is enabled; native pinch resets legacy gesture continuation",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-compose --locked clipped_dissolve_is_binary_and_preserves_the_base_shape -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked clipped_dissolve_matches_whole_render_at_offset_regions_and_depths -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked groups_masks_and_clipping -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked native_rotate_event_reaches_canvas_when_trackpad_rotation_is_enabled -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked native_pinch_resets_legacy_gesture_continuation -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "clipped_dissolve_is_binary_and_preserves_the_base_shape",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked clipped_dissolve_is_binary_and_preserves_the_base_shape -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut d = doc_white(40, 12);\n d.layers.push(solid_layer(\"base\", Rect::new(0, 0, 20, 12), [0.0, 0.0, 1.0, 1.0]));\n let mut clip = solid_layer(\"clip\", d.bounds(), [1.0, 0.0, 0.0, 1.0]);\n clip.clipped = true;\n clip.blend = BlendMode::Dissolve;\n clip.opacity = 0.6;\n clip.fill_opacity = 0.5;\n d.layers.push(clip);\n let mut red = 0;\n let mut blue = 0;\n for y in 0..12 {\n for x in 0..20 {",
|
||
"expected_assertions": [
|
||
" assert!(close4(p, [0.0, 0.0, 1.0, 1.0]), \"Dissolve must not interpolate: {p:?} at ({x},{y})\");\n blue += 1;\n }\n }",
|
||
" assert!(close4(px(&d, 30, y), [1.0; 4]), \"outside the base the clip is invisible\");\n }\n assert!(red > 0 && blue > 0, \"Dissolve must expose both source and base: {red}/{blue}\");\n assert!((red as f32 / (red + blue) as f32 - 0.3).abs() < 0.1, \"coverage should follow 60% opacity × 50% fill: {red}/{blue}\");",
|
||
" assert!(red > 0 && blue > 0, \"Dissolve must expose both source and base: {red}/{blue}\");\n assert!((red as f32 / (red + blue) as f32 - 0.3).abs() < 0.1, \"coverage should follow 60% opacity × 50% fill: {red}/{blue}\");\n}",
|
||
" assert!((red as f32 / (red + blue) as f32 - 0.3).abs() < 0.1, \"coverage should follow 60% opacity × 50% fill: {red}/{blue}\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/194a8976cd6c14441222b287b9b4f4841a0eb2f9/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "clipped_dissolve_matches_whole_render_at_offset_regions_and_depths",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked clipped_dissolve_matches_whole_render_at_offset_regions_and_depths -- --nocapture",
|
||
"fixture_and_action_excerpt": " for fmt in [PixelFormat::RGBA8, PixelFormat::RGBA16, PixelFormat::RGBA32F] {\n let mut d = Document::new(\"coverage\", Size::new(32, 18), ColorMode::Rgb, fmt.sample);\n let bounds = Rect::new(-3, -2, 32, 18);\n let mut base = Layer::raster(\"base\", fmt);\n base.surface_mut().unwrap().fill_rect(bounds, &[0.0, 0.0, 1.0, 0.5]);\n d.layers.push(base);\n let mut clip = Layer::raster(\"clip\", fmt);\n clip.surface_mut().unwrap().fill_rect(bounds, &[1.0, 0.0, 0.0, 0.75]);\n clip.clipped = true;\n clip.blend = BlendMode::Dissolve;\n clip.opacity = 0.6;\n clip.fill_opacity = 0.5;",
|
||
"expected_assertions": [
|
||
" assert!(close4(part.get(x, y), whole.get(x, y)), \"{fmt:?}: region mismatch at ({x},{y})\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/194a8976cd6c14441222b287b9b4f4841a0eb2f9/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "groups_masks_and_clipping",
|
||
"path": "crates/gpu/tests/parity.rs",
|
||
"package": "photocraft-gpu",
|
||
"command": "cargo test -p photocraft-gpu --locked groups_masks_and_clipping -- --nocapture",
|
||
"fixture_and_action_excerpt": " let Some(mut g) = gpu() else { return };\n let child = |seed, mode| {\n let mut l = noise_layer(\"c\", PixelFormat::RGBA8, Rect::new(5, 5, 50, 40), seed, 0.0);\n l.blend = mode;\n l\n };\n for isolated in [false, true] {\n let mut d = base_doc(56, 44);\n let mut grp = Layer::group(\"g\", vec![child(11, BlendMode::Normal), child(12, BlendMode::Screen), child(13, BlendMode::Multiply)]);\n if isolated {\n grp.blend = BlendMode::Overlay;\n }",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/194a8976cd6c14441222b287b9b4f4841a0eb2f9/crates/gpu/tests/parity.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "native_rotate_event_reaches_canvas_when_trackpad_rotation_is_enabled",
|
||
"path": "crates/ui-egui/src/rotate_view.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked native_rotate_event_reaches_canvas_when_trackpad_rotation_is_enabled -- --nocapture",
|
||
"fixture_and_action_excerpt": " let ctx = egui::Context::default();\n let mut enabled = None;\n let mut disabled = None;\n let raw = egui::RawInput { events: vec![Event::Rotate(std::f32::consts::FRAC_PI_6)], ..Default::default() };\n let mut output = ctx.run_ui(raw, |ui| {\n enabled = trackpad_delta(ui.ctx(), true);\n disabled = trackpad_delta(ui.ctx(), false);\n });\n output.textures_delta.clear();\n\n assert!(enabled.is_some_and(|degrees| (degrees - 30.0).abs() < 1e-3), \"{enabled:?}\");\n assert_eq!(disabled, None);",
|
||
"expected_assertions": [
|
||
" assert!(enabled.is_some_and(|degrees| (degrees - 30.0).abs() < 1e-3), \"{enabled:?}\");\n assert_eq!(disabled, None);\n }",
|
||
" assert_eq!(disabled, None);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/194a8976cd6c14441222b287b9b4f4841a0eb2f9/crates/ui-egui/src/rotate_view.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "native_pinch_resets_legacy_gesture_continuation",
|
||
"path": "crates/ui-egui/src/wheel_nav.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked native_pinch_resets_legacy_gesture_continuation -- --nocapture",
|
||
"fixture_and_action_excerpt": " let ctx = Context::default();\n let mut legacy = RawInput { time: Some(1.0), events: vec![wheel(Vec2::new(0.0, 0.25), CTRL)], ..Default::default() };\n fold_legacy_pinch(&ctx, &mut legacy);\n assert!(matches!(legacy.events[0], Event::Zoom(_)));\n\n // Native magnification takes over before the synthetic gesture times out.\n let mut native = RawInput { time: Some(1.1), events: vec![Event::Zoom(1.1), wheel(Vec2::new(0.0, 0.25), CTRL)], ..Default::default() };\n fold_legacy_pinch(&ctx, &mut native);\n assert!(matches!(native.events[0], Event::Zoom(f) if (f - 1.1).abs() < 1e-5));\n assert!(matches!(native.events[1], Event::MouseWheel { .. }));\n\n // A notched mouse scroll must no longer inherit the previous pinch.",
|
||
"expected_assertions": [
|
||
" assert!(matches!(legacy.events[0], Event::Zoom(_)));\n\n // Native magnification takes over before the synthetic gesture times out.\n let mut native = RawInput { time: Some(1.1), events: vec![Event::Zoom(1.1), wheel(Vec2::new(0.0, 0.25), CTRL)], ..Default::default() };",
|
||
" assert!(matches!(native.events[0], Event::Zoom(f) if (f - 1.1).abs() < 1e-5));\n assert!(matches!(native.events[1], Event::MouseWheel { .. }));\n\n // A notched mouse scroll must no longer inherit the previous pinch.",
|
||
" assert!(matches!(native.events[1], Event::MouseWheel { .. }));\n\n // A notched mouse scroll must no longer inherit the previous pinch.\n let mut notch = RawInput { time: Some(1.12), events: vec![wheel(Vec2::new(0.0, 1.0), CTRL)], ..Default::default() };",
|
||
" assert!(matches!(notch.events[0], Event::MouseWheel { .. }));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/194a8976cd6c14441222b287b9b4f4841a0eb2f9/crates/ui-egui/src/wheel_nav.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-7153",
|
||
"pr": 7153,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Synthetic smart object with Liquify and Gaussian Blur filters; record original parameters, pixels and history",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked smart_filter_edit_after_the_stack_changed_updates_nothing -- --nocapture"
|
||
],
|
||
"expected": "Double-click opens existing Liquify in its workspace with stored settings; commit updates intended filter rather than appending; Undo/Redo restores it; Cancel preserves parameters/pixels/history. Reordered stale stack refuses without history and says Reopen its dialog.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Automated stale-stack guard and native happy path/Cancel/undo are separate required subcases. Use supported controls for stale-target reproduction.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked smart_filter_edit_after_the_stack_changed_updates_nothing -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-7903",
|
||
"pr": 7903,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-algo --locked rough_pastels_and_angled_strokes_respond_to_every_slider -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked cutout_makes_flat_shapes_with_clean_edges -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked cutout_keeps_the_tone_of_surviving_islands_at_low_fidelity -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_stack_around_a_cutout_is_tile_independent -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked oklab_round_trips_and_marks_the_gamut -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked out_of_gamut_colours_lose_strength_not_hue -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked smoothing_flattens_noise_and_keeps_edges -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked the_palette_finds_the_pictures_own_colours -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_tone_of_two_different_hues_splits_in_two -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_empty_image_still_has_a_palette -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked douglas_peucker_keeps_only_points_off_the_line -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked lines_cross_where_they_should -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked rounding_off_keeps_an_open_chains_ends -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_square_keeps_its_four_corners_and_straight_sides -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_rounded_corner_is_squared_back -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_open_chain_ends_where_it_started_at_any_fidelity -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked curves_pass_through_their_vertices -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked fitting_keeps_small_islands_and_their_winding -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked bounds_cover_every_point -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked the_edge_between_two_regions_is_one_chain_between_junctions -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_island_is_one_closed_chain -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_anti_aliased_edge_is_placed_inside_its_pixel -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_square_covers_its_area_exactly -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked shapes_cover_every_pixel_once_with_no_seams -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked edge_fidelity_changes_the_outlines -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked empty_images_stop_before_the_transpose_and_row_passes -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked filling_does_not_depend_on_the_tiling -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked noise_merges_into_neighbours_and_noise_apart_colours_are_one -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked components_are_four_connected_and_numbered_in_raster_order -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked small_regions_merge_into_the_neighbour_they_share_most_border_with -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked slivers_merge_though_they_are_large -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked paper_is_stretched_towards_black_and_white_and_keeps_its_hue -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked local_colour_drifts_within_a_shape_but_never_crosses_a_cut -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked transposing_twice_gives_the_image_back -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked find_returns_the_root_and_shortens_the_path -- --nocapture"
|
||
],
|
||
"expected": "rough pastels and angled strokes respond to every slider; cutout makes flat shapes with clean edges; cutout keeps the tone of surviving islands at low fidelity; a stack around a cutout is tile independent; oklab round trips and marks the gamut; out of gamut colours lose strength not hue; smoothing flattens noise and keeps edges; the palette finds the pictures own colours; a tone of two different hues splits in two; an empty image still has a palette; douglas peucker keeps only points off the line; lines cross where they should; rounding off keeps an open chains ends; a square keeps its four corners and straight sides; a rounded corner is squared back; an open chain ends where it started at any fidelity; curves pass through their vertices; fitting keeps small islands and their winding; bounds cover every point; the edge between two regions is one chain between junctions; an island is one closed chain; an anti aliased edge is placed inside its pixel; a square covers its area exactly; shapes cover every pixel once with no seams; edge fidelity changes the outlines; empty images stop before the transpose and row passes; filling does not depend on the tiling; noise merges into neighbours and noise apart colours are one; components are four connected and numbered in raster order; small regions merge into the neighbour they share most border with; slivers merge though they are large; paper is stretched towards black and white and keeps its hue; local colour drifts within a shape but never crosses a cut; transposing twice gives the image back; find returns the root and shortens the path",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-algo --locked rough_pastels_and_angled_strokes_respond_to_every_slider -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked cutout_makes_flat_shapes_with_clean_edges -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked cutout_keeps_the_tone_of_surviving_islands_at_low_fidelity -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_stack_around_a_cutout_is_tile_independent -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked oklab_round_trips_and_marks_the_gamut -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked out_of_gamut_colours_lose_strength_not_hue -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked smoothing_flattens_noise_and_keeps_edges -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked the_palette_finds_the_pictures_own_colours -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_tone_of_two_different_hues_splits_in_two -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_empty_image_still_has_a_palette -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked douglas_peucker_keeps_only_points_off_the_line -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked lines_cross_where_they_should -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked rounding_off_keeps_an_open_chains_ends -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_square_keeps_its_four_corners_and_straight_sides -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_rounded_corner_is_squared_back -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_open_chain_ends_where_it_started_at_any_fidelity -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked curves_pass_through_their_vertices -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked fitting_keeps_small_islands_and_their_winding -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked bounds_cover_every_point -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked the_edge_between_two_regions_is_one_chain_between_junctions -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_island_is_one_closed_chain -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_anti_aliased_edge_is_placed_inside_its_pixel -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_square_covers_its_area_exactly -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked shapes_cover_every_pixel_once_with_no_seams -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked edge_fidelity_changes_the_outlines -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked empty_images_stop_before_the_transpose_and_row_passes -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked filling_does_not_depend_on_the_tiling -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked noise_merges_into_neighbours_and_noise_apart_colours_are_one -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked components_are_four_connected_and_numbered_in_raster_order -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked small_regions_merge_into_the_neighbour_they_share_most_border_with -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked slivers_merge_though_they_are_large -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked paper_is_stretched_towards_black_and_white_and_keeps_its_hue -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked local_colour_drifts_within_a_shape_but_never_crosses_a_cut -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked transposing_twice_gives_the_image_back -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked find_returns_the_root_and_shortens_the_path -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "rough_pastels_and_angled_strokes_respond_to_every_slider",
|
||
"path": "crates/algo/src/artistic_fx.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked rough_pastels_and_angled_strokes_respond_to_every_slider -- --nocapture",
|
||
"fixture_and_action_excerpt": " // #879: these smeared or drowned the image in texture, and some sliders did nothing.\n use crate::GalleryFilter as G;\n let b = Rect::new(0, 0, 56, 40);\n let s = pattern(SampleType::F32);\n let run = |e: &GalleryEffect, tile: i32| {\n let fp = FilterParams::FilterGallery { effects: vec![e.clone()] };\n apply_tiled(&s, &fp, b, b, None, tile, Some(b)).read_region(b)\n };\n for f in [G::RoughPastels, G::AngledStrokes, G::Cutout] {\n let base = run(&GalleryEffect::new(f), 256);\n for prm in f.params() {\n let crate::GalleryParamKind::Range { min, max, .. } = prm.kind else { continue };",
|
||
"expected_assertions": [
|
||
" assert_ne!(a, base, \"{} {} = {v} changed nothing\", f.key(), prm.key);\n let t = run(&e, 16);\n let worst = a.iter().zip(&t).map(|(x, y)| (x - y).abs()).fold(0.0, f32::max);\n assert!(worst < 1e-3, \"{} {} = {v} differs across tilings by {worst}\", f.key(), prm.key);",
|
||
" assert!(worst < 1e-3, \"{} {} = {v} differs across tilings by {worst}\", f.key(), prm.key);\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/artistic_fx.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "cutout_makes_flat_shapes_with_clean_edges",
|
||
"path": "crates/algo/src/artistic_fx.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked cutout_makes_flat_shapes_with_clean_edges -- --nocapture",
|
||
"fixture_and_action_excerpt": " // It used to posterize every pixel after a blur: noise survived as speckle, edges were\n // ragged and smooth gradients banded instead of becoming flat paper.\n let noisy: Vec<Vec<f32>> = (0..32).map(|y| (0..64).map(|x| if x < 32 { 0.2 } else { 0.8 } + (hash01(x, y, 0, 7) - 0.5) * 0.16).collect()).collect();\n let out = cutout_on(&noisy, &[]);\n for (x0, x1) in [(2, 28), (36, 62)] {\n let vals: Vec<f32> = (2..30).flat_map(|y| out[y][x0..x1].to_vec()).collect();\n let spread = vals.iter().fold(f32::MIN, |a, &v| a.max(v)) - vals.iter().fold(f32::MAX, |a, &v| a.min(v));\n assert!(spread < 1e-4, \"a noisy area should be one flat tone, spread {spread}\");\n }\n // The cut is an anti-aliased pixel or two, not a blur.\n for y in 0..32 {\n let (lo, hi) = (out[y][16], out[y][48]);",
|
||
"expected_assertions": [
|
||
" assert!(spread < 1e-4, \"a noisy area should be one flat tone, spread {spread}\");\n }\n // The cut is an anti-aliased pixel or two, not a blur.\n for y in 0..32 {",
|
||
" assert!(soft <= 2, \"row {y}: {soft} edge pixels\");\n }\n // A ramp becomes `numberOfLevels` flat steps (the palette is the image's own colours, so\n // one may go to the wide flat margins and merge as noise).",
|
||
" assert!(tones.len() <= levels as usize && tones.len() + 1 >= levels as usize, \"levels {levels}: tones {tones:?}\");\n assert!(tones.windows(2).all(|t| t[0] < t[1]), \"levels {levels}: tones {tones:?}\");\n }\n // Edge Simplicity drops specks.",
|
||
" assert!(tones.windows(2).all(|t| t[0] < t[1]), \"levels {levels}: tones {tones:?}\");\n }\n // Edge Simplicity drops specks.\n let speck: Vec<Vec<f32>> = (0..32).map(|y| (0..32).map(|x| if (15..18).contains(&x) && (15..18).contains(&y) { 0.9 } else { 0.2 }).collect()).collect();",
|
||
" assert!(detailed[16][16] - detailed[2][2] > 0.5, \"the speck should survive at simplicity 0\");\n assert!((simple[16][16] - simple[2][2]).abs() < 1e-4, \"the speck should go at simplicity 10\");\n }",
|
||
" assert!((simple[16][16] - simple[2][2]).abs() < 1e-4, \"the speck should go at simplicity 10\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/artistic_fx.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "cutout_keeps_the_tone_of_surviving_islands_at_low_fidelity",
|
||
"path": "crates/algo/src/artistic_fx.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked cutout_keeps_the_tone_of_surviving_islands_at_low_fidelity -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (size, simplicity) in [(2, 0.0), (3, 2.0), (4, 0.0), (4, 2.0), (6, 2.0)] {\n let rows: Vec<Vec<f32>> =\n (0..32).map(|y| (0..32).map(|x| if (12..12 + size).contains(&x) && (12..12 + size).contains(&y) { 0.9 } else { 0.2 }).collect()).collect();\n let reference = cutout_on(&rows, &[(\"edgeSimplicity\", simplicity), (\"edgeFidelity\", 2.0)]);\n let centre = 12 + size / 2;\n for fidelity in [1.0, 1.5, 2.0] {\n let out = cutout_on(&rows, &[(\"edgeSimplicity\", simplicity), (\"edgeFidelity\", fidelity)]);\n assert!(\n size == 2 || (out[centre][centre] - reference[centre][centre]).abs() < 0.02,\n \"{size}x{size}, simplicity {simplicity}, fidelity {fidelity}: {} vs {}\",\n out[centre][centre],\n reference[centre][centre]",
|
||
"expected_assertions": [
|
||
" assert!(\n size == 2 || (out[centre][centre] - reference[centre][centre]).abs() < 0.02,\n \"{size}x{size}, simplicity {simplicity}, fidelity {fidelity}: {} vs {}\",\n out[centre][centre],",
|
||
" assert!(out[centre][centre] - out[2][2] > 0.5, \"the island keeps its contrast\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/artistic_fx.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_stack_around_a_cutout_is_tile_independent",
|
||
"path": "crates/algo/src/artistic_fx.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked a_stack_around_a_cutout_is_tile_independent -- --nocapture",
|
||
"fixture_and_action_excerpt": " // Effects before a Cutout are traced with it over the whole image; effects after it run\n // per tile on the filled-in shapes.\n use crate::GalleryFilter as G;\n let b = Rect::new(0, 0, 56, 40);\n let s = pattern(SampleType::F32);\n let fp =\n FilterParams::FilterGallery { effects: vec![GalleryEffect::new(G::Spatter), GalleryEffect::new(G::Cutout), GalleryEffect::new(G::GlowingEdges)] };\n let a = apply_tiled(&s, &fp, b, b, None, 256, Some(b)).read_region(b);\n let t = apply_tiled(&s, &fp, b, b, None, 16, Some(b)).read_region(b);\n let worst = a.iter().zip(&t).map(|(x, y)| (x - y).abs()).fold(0.0, f32::max);\n assert!(worst < 1e-3, \"differs across tilings by {worst}\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(worst < 1e-3, \"differs across tilings by {worst}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/artistic_fx.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "oklab_round_trips_and_marks_the_gamut",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked oklab_round_trips_and_marks_the_gamut -- --nocapture",
|
||
"fixture_and_action_excerpt": " let white = oklab([1.0, 1.0, 1.0]);\n assert!((white[0] - 1.0).abs() < 1e-3 && white[1].abs() < 1e-3 && white[2].abs() < 1e-3, \"{white:?}\");\n assert!(oklab([0.0, 0.0, 0.0])[0].abs() < 1e-6);\n for p in [[0.2, 0.5, 0.9], [0.95, 0.1, 0.3], [0.5, 0.5, 0.5], [0.0, 1.0, 0.0]] {\n let back = srgb(oklab(p)).unwrap_or([-1.0; 3]);\n assert!(dist2(back, p) < 1e-6, \"{p:?} came back as {back:?}\");\n }\n // Very light and very colourful: no sRGB colour is that.\n assert_eq!(srgb([0.95, 0.3, 0.0]), None);\n }",
|
||
"expected_assertions": [
|
||
" assert!((white[0] - 1.0).abs() < 1e-3 && white[1].abs() < 1e-3 && white[2].abs() < 1e-3, \"{white:?}\");\n assert!(oklab([0.0, 0.0, 0.0])[0].abs() < 1e-6);\n for p in [[0.2, 0.5, 0.9], [0.95, 0.1, 0.3], [0.5, 0.5, 0.5], [0.0, 1.0, 0.0]] {\n let back = srgb(oklab(p)).unwrap_or([-1.0; 3]);",
|
||
" assert!(oklab([0.0, 0.0, 0.0])[0].abs() < 1e-6);\n for p in [[0.2, 0.5, 0.9], [0.95, 0.1, 0.3], [0.5, 0.5, 0.5], [0.0, 1.0, 0.0]] {\n let back = srgb(oklab(p)).unwrap_or([-1.0; 3]);\n assert!(dist2(back, p) < 1e-6, \"{p:?} came back as {back:?}\");",
|
||
" assert!(dist2(back, p) < 1e-6, \"{p:?} came back as {back:?}\");\n }\n // Very light and very colourful: no sRGB colour is that.\n assert_eq!(srgb([0.95, 0.3, 0.0]), None);",
|
||
" assert_eq!(srgb([0.95, 0.3, 0.0]), None);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "out_of_gamut_colours_lose_strength_not_hue",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked out_of_gamut_colours_lose_strength_not_hue -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (l, a, b) = (0.95, 0.3, 0.1);\n let c = in_gamut(l, a, b);\n let lab = oklab(c);\n assert!((lab[0] - l).abs() < 0.01, \"lightness kept: {lab:?}\");\n let chroma = (lab[1] * lab[1] + lab[2] * lab[2]).sqrt();\n assert!(chroma > 0.01 && chroma < (a * a + b * b).sqrt(), \"weaker but still coloured: {chroma}\");\n assert!((lab[2] / lab[1] - b / a).abs() < 0.05, \"same hue: {lab:?}\");\n // In gamut it is just the conversion.\n assert_eq!(in_gamut(0.6, 0.02, -0.03), srgb([0.6, 0.02, -0.03]).unwrap_or_default());\n }",
|
||
"expected_assertions": [
|
||
" assert!((lab[0] - l).abs() < 0.01, \"lightness kept: {lab:?}\");\n let chroma = (lab[1] * lab[1] + lab[2] * lab[2]).sqrt();\n assert!(chroma > 0.01 && chroma < (a * a + b * b).sqrt(), \"weaker but still coloured: {chroma}\");\n assert!((lab[2] / lab[1] - b / a).abs() < 0.05, \"same hue: {lab:?}\");",
|
||
" assert!(chroma > 0.01 && chroma < (a * a + b * b).sqrt(), \"weaker but still coloured: {chroma}\");\n assert!((lab[2] / lab[1] - b / a).abs() < 0.05, \"same hue: {lab:?}\");\n // In gamut it is just the conversion.\n assert_eq!(in_gamut(0.6, 0.02, -0.03), srgb([0.6, 0.02, -0.03]).unwrap_or_default());",
|
||
" assert!((lab[2] / lab[1] - b / a).abs() < 0.05, \"same hue: {lab:?}\");\n // In gamut it is just the conversion.\n assert_eq!(in_gamut(0.6, 0.02, -0.03), srgb([0.6, 0.02, -0.03]).unwrap_or_default());\n }",
|
||
" assert_eq!(in_gamut(0.6, 0.02, -0.03), srgb([0.6, 0.02, -0.03]).unwrap_or_default());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "smoothing_flattens_noise_and_keeps_edges",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked smoothing_flattens_noise_and_keeps_edges -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h) = (40usize, 20usize);\n let lab = noisy(w, h, 0.02, |x| if x < 20 { [0.3, 0.0, 0.0] } else { [0.8, 0.0, 0.0] });\n let out = smooth(lab.clone(), w, h, 2);\n let spread = |v: &[Px], xs: std::ops::Range<usize>| {\n let l: Vec<f32> = (0..h).flat_map(|y| xs.clone().map(move |x| y * w + x)).map(|i| v[i][0]).collect();\n let mean = l.iter().sum::<f32>() / l.len() as f32;\n (l.iter().map(|v| (v - mean).powi(2)).sum::<f32>() / l.len() as f32).sqrt()\n };\n assert!(spread(&out, 2..16) < spread(&lab, 2..16) / 2.0, \"noise kept: {} vs {}\", spread(&out, 2..16), spread(&lab, 2..16));\n // The step stays a step: the pixels either side of it keep most of their difference.\n let step = (0..h).map(|y| out[y * w + 20][0] - out[y * w + 19][0]).sum::<f32>() / h as f32;\n assert!(step > 0.4, \"edge blurred to {step}\");",
|
||
"expected_assertions": [
|
||
" assert!(spread(&out, 2..16) < spread(&lab, 2..16) / 2.0, \"noise kept: {} vs {}\", spread(&out, 2..16), spread(&lab, 2..16));\n // The step stays a step: the pixels either side of it keep most of their difference.\n let step = (0..h).map(|y| out[y * w + 20][0] - out[y * w + 19][0]).sum::<f32>() / h as f32;\n assert!(step > 0.4, \"edge blurred to {step}\");",
|
||
" assert!(step > 0.4, \"edge blurred to {step}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_palette_finds_the_pictures_own_colours",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked the_palette_finds_the_pictures_own_colours -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h) = (60usize, 20usize);\n let (dark, light) = ([0.25, 0.02, -0.03], [0.75, -0.04, 0.05]);\n let lab = noisy(w, h, 0.01, |x| if x < 30 { dark } else { light });\n // Asked for up to six, it gives two: colours only noise apart are one.\n let p = palette(&lab, 6);\n assert_eq!(p.len(), 2, \"{p:?}\");\n for c in [dark, light] {\n assert!(p.iter().any(|q| dist2(*q, c).sqrt() < 0.02), \"{c:?} not in {p:?}\");\n }\n assert_eq!(nearest(&p, dark), nearest(&p, [0.27, 0.0, -0.02]));\n assert_ne!(nearest(&p, dark), nearest(&p, light));\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(p.len(), 2, \"{p:?}\");\n for c in [dark, light] {\n assert!(p.iter().any(|q| dist2(*q, c).sqrt() < 0.02), \"{c:?} not in {p:?}\");\n }",
|
||
" assert!(p.iter().any(|q| dist2(*q, c).sqrt() < 0.02), \"{c:?} not in {p:?}\");\n }\n assert_eq!(nearest(&p, dark), nearest(&p, [0.27, 0.0, -0.02]));\n assert_ne!(nearest(&p, dark), nearest(&p, light));",
|
||
" assert_eq!(nearest(&p, dark), nearest(&p, [0.27, 0.0, -0.02]));\n assert_ne!(nearest(&p, dark), nearest(&p, light));\n }",
|
||
" assert_ne!(nearest(&p, dark), nearest(&p, light));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_tone_of_two_different_hues_splits_in_two",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked a_tone_of_two_different_hues_splits_in_two -- --nocapture",
|
||
"fixture_and_action_excerpt": " // A dark tone and a light one, the light one half blue and half pink: two levels give\n // three colours, or the blue and pink areas would be one shape of their grey average.\n let (w, h) = (60usize, 20usize);\n let (dark, blue, pink) = ([0.2, 0.0, 0.0], [0.7, -0.03, -0.1], [0.7, 0.12, 0.0]);\n let lab = noisy(w, h, 0.005, |x| {\n if x < 30 {\n dark\n } else if x < 45 {\n blue\n } else {\n pink\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(p.len(), 3, \"{p:?}\");\n for c in [dark, blue, pink] {\n assert!(p.iter().any(|q| dist2(*q, c).sqrt() < 0.03), \"{c:?} not in {p:?}\");\n }",
|
||
" assert!(p.iter().any(|q| dist2(*q, c).sqrt() < 0.03), \"{c:?} not in {p:?}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "an_empty_image_still_has_a_palette",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked an_empty_image_still_has_a_palette -- --nocapture",
|
||
"fixture_and_action_excerpt": " assert_eq!(palette(&[], 4).len(), 1);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(palette(&[], 4).len(), 1);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "douglas_peucker_keeps_only_points_off_the_line",
|
||
"path": "crates/algo/src/cutout/curves.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked douglas_peucker_keeps_only_points_off_the_line -- --nocapture",
|
||
"fixture_and_action_excerpt": " // An L, slightly ragged: only its corner is further from the end-to-end line than the\n // tolerance, and the two arms are straight within it.\n let wobble = |i: usize| 0.05 * (i % 2) as f32;\n let p: Vec<Pt> = (0..9).map(|i| if i <= 4 { [i as f32, wobble(i)] } else { [4.0 + wobble(i), (i - 4) as f32] }).collect();\n let mut marks = vec![false; p.len()];\n simplify(&p, 0, 8, 0.5, &mut marks);\n assert_eq!(marks.iter().filter(|m| **m).count(), 1, \"{marks:?}\");\n assert!(marks[4]);\n let mut marks = vec![false; p.len()];\n simplify(&p, 0, 8, 3.0, &mut marks);\n assert!(marks.iter().all(|m| !m), \"under the tolerance nothing is kept\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(marks.iter().filter(|m| **m).count(), 1, \"{marks:?}\");\n assert!(marks[4]);\n let mut marks = vec![false; p.len()];\n simplify(&p, 0, 8, 3.0, &mut marks);",
|
||
" assert!(marks[4]);\n let mut marks = vec![false; p.len()];\n simplify(&p, 0, 8, 3.0, &mut marks);\n assert!(marks.iter().all(|m| !m), \"under the tolerance nothing is kept\");",
|
||
" assert!(marks.iter().all(|m| !m), \"under the tolerance nothing is kept\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/curves.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "lines_cross_where_they_should",
|
||
"path": "crates/algo/src/cutout/curves.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked lines_cross_where_they_should -- --nocapture",
|
||
"fixture_and_action_excerpt": " let q = intersect([0.0, 0.0], [1.0, 1.0], [0.0, 2.0], [1.0, 1.0]);\n assert!(q.is_some_and(|q| close(q, [1.0, 1.0])), \"{q:?}\");\n assert_eq!(intersect([0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [2.0, 1.0]), None);\n }",
|
||
"expected_assertions": [
|
||
" assert!(q.is_some_and(|q| close(q, [1.0, 1.0])), \"{q:?}\");\n assert_eq!(intersect([0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [2.0, 1.0]), None);\n }",
|
||
" assert_eq!(intersect([0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [2.0, 1.0]), None);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/curves.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "rounding_off_keeps_an_open_chains_ends",
|
||
"path": "crates/algo/src/cutout/curves.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked rounding_off_keeps_an_open_chains_ends -- --nocapture",
|
||
"fixture_and_action_excerpt": " let p: Vec<Pt> = (0..12).map(|i| [i as f32, if i % 2 == 0 { 0.0 } else { 1.0 }]).collect();\n let r = round_off(&p, false, 3);\n assert_eq!((r[0], r[11]), (p[0], p[11]));\n assert!(r[5][1] > 0.2 && r[5][1] < 0.8, \"the zigzag is averaged out: {:?}\", r[5]);\n assert_eq!(round_off(&p, false, 0), p);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!((r[0], r[11]), (p[0], p[11]));\n assert!(r[5][1] > 0.2 && r[5][1] < 0.8, \"the zigzag is averaged out: {:?}\", r[5]);\n assert_eq!(round_off(&p, false, 0), p);\n }",
|
||
" assert!(r[5][1] > 0.2 && r[5][1] < 0.8, \"the zigzag is averaged out: {:?}\", r[5]);\n assert_eq!(round_off(&p, false, 0), p);\n }",
|
||
" assert_eq!(round_off(&p, false, 0), p);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/curves.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_square_keeps_its_four_corners_and_straight_sides",
|
||
"path": "crates/algo/src/cutout/curves.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked a_square_keeps_its_four_corners_and_straight_sides -- --nocapture",
|
||
"fixture_and_action_excerpt": " let out = fit(&square(), true, &settings(2.0));\n for c in [[2.0, 2.0], [12.0, 2.0], [12.0, 12.0], [2.0, 12.0]] {\n assert!(out.iter().any(|p| close(*p, c)), \"corner {c:?} lost: {out:?}\");\n }\n let on_side = |p: &Pt| [p[0] - 2.0, p[0] - 12.0, p[1] - 2.0, p[1] - 12.0].iter().any(|d| d.abs() < 1e-3);\n assert!(out.iter().all(on_side), \"{out:?}\");\n assert!(out.len() < 10, \"the sides are simplified to their ends: {out:?}\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(out.iter().any(|p| close(*p, c)), \"corner {c:?} lost: {out:?}\");\n }\n let on_side = |p: &Pt| [p[0] - 2.0, p[0] - 12.0, p[1] - 2.0, p[1] - 12.0].iter().any(|d| d.abs() < 1e-3);\n assert!(out.iter().all(on_side), \"{out:?}\");",
|
||
" assert!(out.iter().all(on_side), \"{out:?}\");\n assert!(out.len() < 10, \"the sides are simplified to their ends: {out:?}\");\n }",
|
||
" assert!(out.len() < 10, \"the sides are simplified to their ends: {out:?}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/curves.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_rounded_corner_is_squared_back",
|
||
"path": "crates/algo/src/cutout/curves.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked a_rounded_corner_is_squared_back -- --nocapture",
|
||
"fixture_and_action_excerpt": " // The pixels cut the corner at (12, 2): the outline goes (11, 2), (12, 3) instead.\n let mut p = square();\n p[10] = [11.5, 2.5];\n let out = fit(&p, true, &settings(2.0));\n assert!(out.iter().any(|q| close(*q, [12.0, 2.0])), \"{out:?}\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(out.iter().any(|q| close(*q, [12.0, 2.0])), \"{out:?}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/curves.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "an_open_chain_ends_where_it_started_at_any_fidelity",
|
||
"path": "crates/algo/src/cutout/curves.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked an_open_chain_ends_where_it_started_at_any_fidelity -- --nocapture",
|
||
"fixture_and_action_excerpt": " let p: Vec<Pt> = (0..30).map(|i| [i as f32, (i as f32 / 5.0).sin() * 4.0 + 0.3 * (i % 3) as f32]).collect();\n for f in [1.0, 2.0, 3.0] {\n let out = fit(&p, false, &settings(f));\n assert_eq!((out.first(), out.last()), (p.first(), p.last()), \"fidelity {f}\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!((out.first(), out.last()), (p.first(), p.last()), \"fidelity {f}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/curves.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "curves_pass_through_their_vertices",
|
||
"path": "crates/algo/src/cutout/curves.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked curves_pass_through_their_vertices -- --nocapture",
|
||
"fixture_and_action_excerpt": " let v = [[0.0, 0.0], [4.0, 3.0], [8.0, 0.0], [12.0, 4.0]];\n let out = curves(&v, &[false; 4], false);\n for p in v {\n assert!(out.iter().any(|q| close(*q, p)), \"{p:?} missed: {out:?}\");\n }\n assert!(out.len() > 8, \"flattened into steps: {}\", out.len());\n // Between two corners a segment is straight.\n assert_eq!(curves(&v, &[true; 4], false), v.to_vec());\n }",
|
||
"expected_assertions": [
|
||
" assert!(out.iter().any(|q| close(*q, p)), \"{p:?} missed: {out:?}\");\n }\n assert!(out.len() > 8, \"flattened into steps: {}\", out.len());\n // Between two corners a segment is straight.",
|
||
" assert!(out.len() > 8, \"flattened into steps: {}\", out.len());\n // Between two corners a segment is straight.\n assert_eq!(curves(&v, &[true; 4], false), v.to_vec());\n }",
|
||
" assert_eq!(curves(&v, &[true; 4], false), v.to_vec());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/curves.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "fitting_keeps_small_islands_and_their_winding",
|
||
"path": "crates/algo/src/cutout/curves.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked fitting_keeps_small_islands_and_their_winding -- --nocapture",
|
||
"fixture_and_action_excerpt": " use super::super::edges::follow_edges;\n let (w, h) = (32, 32);\n for size in [2, 3, 4, 6] {\n let reg: Vec<u32> = (0..w * h).map(|i| u32::from((12..12 + size).contains(&(i % w)) && (12..12 + size).contains(&(i / w)))).collect();\n let colours = [[0.2; 3], [0.9; 3]];\n let c: Vec<_> = reg.iter().map(|&r| colours[r as usize]).collect();\n let (chains, _) = follow_edges(®, &colours, &c, w, h);\n let (pts, closed) = chains.iter().find(|(_, closed)| *closed).unwrap();\n assert!(*closed);\n let area = |p: &[Pt]| p.iter().zip(p.iter().cycle().skip(1)).map(|(a, b)| a[0] as f64 * b[1] as f64 - b[0] as f64 * a[1] as f64).sum::<f64>() / 2.0;\n let original = area(pts);\n for simplicity in [0.0, 2.0] {",
|
||
"expected_assertions": [
|
||
" assert!(*closed);\n let area = |p: &[Pt]| p.iter().zip(p.iter().cycle().skip(1)).map(|(a, b)| a[0] as f64 * b[1] as f64 - b[0] as f64 * a[1] as f64).sum::<f64>() / 2.0;\n let original = area(pts);\n for simplicity in [0.0, 2.0] {",
|
||
" assert!(\n fitted * original > 0.0 && fitted.abs() >= original.abs() * 0.5,\n \"{size}x{size}, simplicity {simplicity}, fidelity {fidelity}: {original} -> {fitted}\"\n );",
|
||
" assert_eq!(out.first(), out.last(), \"fallbacks must close the loop for the fill\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/curves.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "bounds_cover_every_point",
|
||
"path": "crates/algo/src/cutout/curves.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked bounds_cover_every_point -- --nocapture",
|
||
"fixture_and_action_excerpt": " assert_eq!(bounds(&[[1.0, 5.0], [-2.0, 3.0], [4.0, 4.0]]), [-2.0, 3.0, 4.0, 5.0]);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(bounds(&[[1.0, 5.0], [-2.0, 3.0], [4.0, 4.0]]), [-2.0, 3.0, 4.0, 5.0]);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/curves.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_edge_between_two_regions_is_one_chain_between_junctions",
|
||
"path": "crates/algo/src/cutout/edges.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked the_edge_between_two_regions_is_one_chain_between_junctions -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (reg, colours, w, h) = regions(&[\"000111\", \"000111\", \"000111\", \"000111\"]);\n let c: Vec<Px> = reg.iter().map(|&r| colours[r as usize]).collect();\n let (chains, sides) = follow_edges(®, &colours, &c, w, h);\n let inner = between(&chains, &sides, 0, 1);\n assert_eq!(inner.len(), 1, \"{chains:?}\");\n let (pts, closed) = &inner[0];\n assert!(!closed);\n // From junction to junction (where it meets the canvas edge), one point per crack.\n let ends = [pts[0], pts[pts.len() - 1]];\n assert!(ends.contains(&[3.0, 0.0]) && ends.contains(&[3.0, 4.0]), \"{pts:?}\");\n assert_eq!(pts.len(), 2 + 4);\n assert!(pts.iter().all(|p| p[0] == 3.0), \"flat colours: the edge is on the crack: {pts:?}\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(inner.len(), 1, \"{chains:?}\");\n let (pts, closed) = &inner[0];\n assert!(!closed);\n // From junction to junction (where it meets the canvas edge), one point per crack.",
|
||
" assert!(!closed);\n // From junction to junction (where it meets the canvas edge), one point per crack.\n let ends = [pts[0], pts[pts.len() - 1]];\n assert!(ends.contains(&[3.0, 0.0]) && ends.contains(&[3.0, 4.0]), \"{pts:?}\");",
|
||
" assert!(ends.contains(&[3.0, 0.0]) && ends.contains(&[3.0, 4.0]), \"{pts:?}\");\n assert_eq!(pts.len(), 2 + 4);\n assert!(pts.iter().all(|p| p[0] == 3.0), \"flat colours: the edge is on the crack: {pts:?}\");\n // Every crack between two regions, the canvas edge included, is in exactly one chain.",
|
||
" assert_eq!(pts.len(), 2 + 4);\n assert!(pts.iter().all(|p| p[0] == 3.0), \"flat colours: the edge is on the crack: {pts:?}\");\n // Every crack between two regions, the canvas edge included, is in exactly one chain.\n let cracks: usize = chains.iter().map(|(p, closed)| p.len() - if *closed { 0 } else { 2 }).sum();",
|
||
" assert!(pts.iter().all(|p| p[0] == 3.0), \"flat colours: the edge is on the crack: {pts:?}\");\n // Every crack between two regions, the canvas edge included, is in exactly one chain.\n let cracks: usize = chains.iter().map(|(p, closed)| p.len() - if *closed { 0 } else { 2 }).sum();\n assert_eq!(cracks, 4 + 2 * (w + h));",
|
||
" assert_eq!(cracks, 4 + 2 * (w + h));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/edges.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "an_island_is_one_closed_chain",
|
||
"path": "crates/algo/src/cutout/edges.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked an_island_is_one_closed_chain -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (reg, colours, w, h) = regions(&[\"00000\", \"01100\", \"01100\", \"00000\"]);\n let c: Vec<Px> = reg.iter().map(|&r| colours[r as usize]).collect();\n let (chains, sides) = follow_edges(®, &colours, &c, w, h);\n let island = between(&chains, &sides, 0, 1);\n assert_eq!(island.len(), 1);\n assert!(island[0].1, \"closed\");\n assert_eq!(island[0].0.len(), 8, \"one point per crack around the 2x2 island\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(island.len(), 1);\n assert!(island[0].1, \"closed\");\n assert_eq!(island[0].0.len(), 8, \"one point per crack around the 2x2 island\");\n }",
|
||
" assert!(island[0].1, \"closed\");\n assert_eq!(island[0].0.len(), 8, \"one point per crack around the 2x2 island\");\n }",
|
||
" assert_eq!(island[0].0.len(), 8, \"one point per crack around the 2x2 island\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/edges.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "an_anti_aliased_edge_is_placed_inside_its_pixel",
|
||
"path": "crates/algo/src/cutout/edges.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked an_anti_aliased_edge_is_placed_inside_its_pixel -- --nocapture",
|
||
"fixture_and_action_excerpt": " // Region 0 is black and region 1 white; the last column of region 0 is half white, so\n // the edge runs down the middle of that column.\n let (reg, _, w, h) = regions(&[\"000111\", \"000111\", \"000111\"]);\n let colours = vec![[0.0; 3], [1.0; 3]];\n let c: Vec<Px> = reg.iter().enumerate().map(|(i, &r)| if i % w == 2 { [0.5; 3] } else { colours[r as usize] }).collect();\n let (chains, sides) = follow_edges(®, &colours, &c, w, h);\n let inner = between(&chains, &sides, 0, 1);\n let pts = &inner[0].0;\n assert!(pts[1..pts.len() - 1].iter().all(|p| (p[0] - 2.5).abs() < 1e-5), \"{pts:?}\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(pts[1..pts.len() - 1].iter().all(|p| (p[0] - 2.5).abs() < 1e-5), \"{pts:?}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/edges.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_square_covers_its_area_exactly",
|
||
"path": "crates/algo/src/cutout/fill.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked a_square_covers_its_area_exactly -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut acc = vec![0.0f32; 12 * 10];\n let sq = [[2.25, 2.5], [7.75, 2.5], [7.75, 6.5], [2.25, 6.5], [2.25, 2.5]];\n for s in sq.windows(2) {\n line_clipped(&mut acc, 12, 10, s[0], s[1]);\n }\n let mut total = 0.0;\n for y in 0..10 {\n let mut sum = 0.0;\n for x in 0..10 {\n sum += acc[y * 12 + x];\n total += sum.abs().min(1.0);\n }",
|
||
"expected_assertions": [
|
||
" assert!((total - 5.5 * 4.0).abs() < 1e-4, \"{total}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/fill.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "shapes_cover_every_pixel_once_with_no_seams",
|
||
"path": "crates/algo/src/cutout/mod.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked shapes_cover_every_pixel_once_with_no_seams -- --nocapture",
|
||
"fixture_and_action_excerpt": " // Blobs of four colours touching each other and the canvas edge, with T-junctions,\n // saddles and holes.\n let (w, h) = (48usize, 36usize);\n let pal = [[0.1, 0.1, 0.1], [0.9, 0.2, 0.2], [0.2, 0.7, 0.3], [0.95, 0.95, 0.9]];\n let c: Vec<Px> = (0..w * h)\n .map(|i| {\n let (x, y) = ((i % w) as f32, (i / w) as f32);\n let k = ((x / 7.0).sin() + (y / 5.0).cos() + (x * y / 90.0).sin()).abs() * 1.6;\n pal[(k as usize).min(3)]\n })\n .collect();\n let r = Rect::new(0, 0, w as i32, h as i32);",
|
||
"expected_assertions": [
|
||
" assert!(t.regions.len() > 4);\n let cov = coverage(&t, r);\n let worst = cov.iter().map(|v| (v - 1.0).abs()).fold(0.0, f32::max);\n assert!(worst < 1e-3, \"coverage off by {worst}\");",
|
||
" assert!(worst < 1e-3, \"coverage off by {worst}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/mod.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "edge_fidelity_changes_the_outlines",
|
||
"path": "crates/algo/src/cutout/mod.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked edge_fidelity_changes_the_outlines -- --nocapture",
|
||
"fixture_and_action_excerpt": " // It used to set only which bends count as corners: on smooth shapes 0.5% of pixels\n // changed from fidelity 1 to 2 and 2.8% from 2 to 3 (now about 9% and 5%).\n // Large smooth shapes, as in a photo: few corners, long curved outlines.\n let (w, h) = (160usize, 120usize);\n let pal = [[0.1, 0.1, 0.1], [0.9, 0.3, 0.2], [0.3, 0.6, 0.9]];\n let c: Vec<Px> = (0..w * h)\n .map(|i| {\n let (x, y) = ((i % w) as f32, (i / w) as f32);\n let k = ((x / 17.0).sin() * 1.3 + (y / 13.0).cos() + (x * y / 900.0).sin()).abs();\n pal[(k as usize).min(2)]\n })\n .collect();",
|
||
"expected_assertions": [
|
||
" assert!(changed(&loose, &normal) > 0.04, \"fidelity 1 vs 2: {}\", changed(&loose, &normal));\n assert!(changed(&normal, &tight) > 0.04, \"fidelity 2 vs 3: {}\", changed(&normal, &tight));\n }",
|
||
" assert!(changed(&normal, &tight) > 0.04, \"fidelity 2 vs 3: {}\", changed(&normal, &tight));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/mod.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "empty_images_stop_before_the_transpose_and_row_passes",
|
||
"path": "crates/algo/src/cutout/mod.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked empty_images_stop_before_the_transpose_and_row_passes -- --nocapture",
|
||
"fixture_and_action_excerpt": " for r in [Rect::new(0, 0, 0, 4), Rect::new(0, 0, 4, 0), Rect::new(0, 0, 0, 0)] {\n let t = trace(&[], r, &settings(4, 2.0, 1.0));\n assert!(t.regions.is_empty());\n assert!(t.chains.is_empty());\n assert!(t.field.is_empty());\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(t.regions.is_empty());\n assert!(t.chains.is_empty());\n assert!(t.field.is_empty());\n }",
|
||
" assert!(t.chains.is_empty());\n assert!(t.field.is_empty());\n }\n }",
|
||
" assert!(t.field.is_empty());\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/mod.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "filling_does_not_depend_on_the_tiling",
|
||
"path": "crates/algo/src/cutout/mod.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked filling_does_not_depend_on_the_tiling -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h) = (40usize, 30usize);\n let c: Vec<Px> = (0..w * h).map(|i| if ((i % w) / 6 + (i / w) / 5) % 3 == 0 { [0.8, 0.3, 0.1] } else { [0.1, 0.3, 0.7] }).collect();\n let r = Rect::new(10, 20, 10 + w as i32, 20 + h as i32);\n let t = trace(&c, r, &settings(3, 1.0, 2.0));\n let whole = t.render(r);\n for tile in [Rect::new(10, 20, 23, 31), Rect::new(23, 31, 50, 50), Rect::new(37, 20, 50, 33)] {\n let part = t.render(tile);\n for y in tile.y0..tile.y1 {\n for x in tile.x0..tile.x1 {\n let a = whole[((y - r.y0) as usize) * w + (x - r.x0) as usize];\n let b = part[((y - tile.y0) as usize) * tile.width() as usize + (x - tile.x0) as usize];\n assert!(dist2(a, b) < 1e-8, \"({x}, {y}): {a:?} vs {b:?}\");",
|
||
"expected_assertions": [
|
||
" assert!(dist2(a, b) < 1e-8, \"({x}, {y}): {a:?} vs {b:?}\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/mod.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "noise_merges_into_neighbours_and_noise_apart_colours_are_one",
|
||
"path": "crates/algo/src/cutout/mod.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked noise_merges_into_neighbours_and_noise_apart_colours_are_one -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h) = (32usize, 32usize);\n let c: Vec<Px> = (0..w * h)\n .map(|i| {\n let v = 0.3 + crate::photo_util::hash01((i % w) as i64, (i / w) as i64, 5) * 0.06;\n if (11..14).contains(&(i % w)) && (11..14).contains(&(i / w)) { [0.9, 0.9, 0.9] } else { [v, v, v] }\n })\n .collect();\n let r = Rect::new(0, 0, w as i32, h as i32);\n assert_eq!(trace(&c, r, &settings(6, 0.0, 2.0)).regions.len(), 2, \"the speck stays at simplicity 0\");\n assert_eq!(trace(&c, r, &settings(6, 10.0, 2.0)).regions.len(), 1, \"the speck merges at simplicity 10\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(trace(&c, r, &settings(6, 0.0, 2.0)).regions.len(), 2, \"the speck stays at simplicity 0\");\n assert_eq!(trace(&c, r, &settings(6, 10.0, 2.0)).regions.len(), 1, \"the speck merges at simplicity 10\");\n }",
|
||
" assert_eq!(trace(&c, r, &settings(6, 10.0, 2.0)).regions.len(), 1, \"the speck merges at simplicity 10\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/mod.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "components_are_four_connected_and_numbered_in_raster_order",
|
||
"path": "crates/algo/src/cutout/regions.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked components_are_four_connected_and_numbered_in_raster_order -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (l, w, h) = labels(&[\"aab\", \"abb\", \"bba\"]);\n let (comp, n) = components(&l, w, h);\n // The top-left `a`s, the `b`s (one area), then the lone `a` (touching the first only\n // diagonally), in the order their first pixels come.\n assert_eq!(n, 3);\n assert_eq!(comp, vec![0, 0, 1, 0, 1, 1, 1, 1, 2]);\n // A U shape: both arms are found as separate runs first and joined further down.\n let (l, w, h) = labels(&[\"a.a\", \"a.a\", \"aaa\"]);\n let (comp, n) = components(&l, w, h);\n assert_eq!(n, 2);\n assert_eq!(comp[0], comp[2]);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(n, 3);\n assert_eq!(comp, vec![0, 0, 1, 0, 1, 1, 1, 1, 2]);\n // A U shape: both arms are found as separate runs first and joined further down.\n let (l, w, h) = labels(&[\"a.a\", \"a.a\", \"aaa\"]);",
|
||
" assert_eq!(comp, vec![0, 0, 1, 0, 1, 1, 1, 1, 2]);\n // A U shape: both arms are found as separate runs first and joined further down.\n let (l, w, h) = labels(&[\"a.a\", \"a.a\", \"aaa\"]);\n let (comp, n) = components(&l, w, h);",
|
||
" assert_eq!(n, 2);\n assert_eq!(comp[0], comp[2]);\n }",
|
||
" assert_eq!(comp[0], comp[2]);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/regions.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "small_regions_merge_into_the_neighbour_they_share_most_border_with",
|
||
"path": "crates/algo/src/cutout/regions.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked small_regions_merge_into_the_neighbour_they_share_most_border_with -- --nocapture",
|
||
"fixture_and_action_excerpt": " let rows = [\"aaaaaaaa\", \"aaaaaaaa\", \"aacaaaaa\", \"aaccbbbb\", \"aaaabbbb\", \"aaaabbbb\", \"aaaabbbb\"];\n // At Edge Simplicity 0 every region is kept.\n assert_eq!(merged(&rows, 0.0).1.len(), 3);\n // At 1 (regions under four pixels merge) the three `c`s go into the `a`s, which they share seven\n // cracks with (one with the `b`s).\n let (reg, colours) = merged(&rows, 1.0);\n assert_eq!(colours.len(), 2);\n assert_eq!(reg[2 * 8 + 2], reg[0]);\n assert_ne!(reg[3 * 8 + 4], reg[0]);\n // A region's colour is the mean of its pixels: 37 `a`s (0.0) and 3 `c`s (0.5).\n let a = colours[reg[0] as usize][0];\n assert!((a - 1.5 / 40.0).abs() < 1e-6, \"{a}\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(merged(&rows, 0.0).1.len(), 3);\n // At 1 (regions under four pixels merge) the three `c`s go into the `a`s, which they share seven\n // cracks with (one with the `b`s).\n let (reg, colours) = merged(&rows, 1.0);",
|
||
" assert_eq!(colours.len(), 2);\n assert_eq!(reg[2 * 8 + 2], reg[0]);\n assert_ne!(reg[3 * 8 + 4], reg[0]);\n // A region's colour is the mean of its pixels: 37 `a`s (0.0) and 3 `c`s (0.5).",
|
||
" assert_eq!(reg[2 * 8 + 2], reg[0]);\n assert_ne!(reg[3 * 8 + 4], reg[0]);\n // A region's colour is the mean of its pixels: 37 `a`s (0.0) and 3 `c`s (0.5).\n let a = colours[reg[0] as usize][0];",
|
||
" assert_ne!(reg[3 * 8 + 4], reg[0]);\n // A region's colour is the mean of its pixels: 37 `a`s (0.0) and 3 `c`s (0.5).\n let a = colours[reg[0] as usize][0];\n assert!((a - 1.5 / 40.0).abs() < 1e-6, \"{a}\");",
|
||
" assert!((a - 1.5 / 40.0).abs() < 1e-6, \"{a}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/regions.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "slivers_merge_though_they_are_large",
|
||
"path": "crates/algo/src/cutout/regions.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked slivers_merge_though_they_are_large -- --nocapture",
|
||
"fixture_and_action_excerpt": " // A line one pixel wide between two areas: the blend along an edge, not a shape.\n let rows: Vec<String> = (0..40).map(|_| format!(\"{}c{}\", \"a\".repeat(10), \"b\".repeat(9))).collect();\n let rows: Vec<&str> = rows.iter().map(String::as_str).collect();\n assert_eq!(merged(&rows, 0.0).1.len(), 3, \"kept at Edge Simplicity 0\");\n let (_, colours) = merged(&rows, 4.0);\n assert_eq!(colours.len(), 2, \"40 pixels is over the 25 that merge at 4, but it is a sliver\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(merged(&rows, 0.0).1.len(), 3, \"kept at Edge Simplicity 0\");\n let (_, colours) = merged(&rows, 4.0);\n assert_eq!(colours.len(), 2, \"40 pixels is over the 25 that merge at 4, but it is a sliver\");\n }",
|
||
" assert_eq!(colours.len(), 2, \"40 pixels is over the 25 that merge at 4, but it is a sliver\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/regions.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "paper_is_stretched_towards_black_and_white_and_keeps_its_hue",
|
||
"path": "crates/algo/src/cutout/regions.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked paper_is_stretched_towards_black_and_white_and_keeps_its_hue -- --nocapture",
|
||
"fixture_and_action_excerpt": " // Three regions: a dark and a light grey, and a mid-tone orange.\n let lab = [[0.35, 0.0, 0.0], [0.65, 0.0, 0.0], [0.5, 0.06, 0.05]];\n let reg: Vec<u32> = (0..300).map(|i| (i / 100) as u32).collect();\n let px: Vec<Px> = reg.iter().map(|&r| lab[r as usize]).collect();\n let paper: Vec<Px> = paper_colours(®, 3, &px).into_iter().map(oklab).collect();\n assert!(paper[0][0] < 0.25 && paper[1][0] > 0.75, \"{paper:?}\");\n assert!((paper[2][0] - 0.5).abs() < 0.05, \"a middle tone stays in the middle: {paper:?}\");\n assert!((paper[2][2] / paper[2][1] - 0.05 / 0.06).abs() < 0.05, \"hue kept: {paper:?}\");\n assert!(paper[0][1].abs() < 1e-3 && paper[0][2].abs() < 1e-3, \"grey stays grey: {paper:?}\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(paper[0][0] < 0.25 && paper[1][0] > 0.75, \"{paper:?}\");\n assert!((paper[2][0] - 0.5).abs() < 0.05, \"a middle tone stays in the middle: {paper:?}\");\n assert!((paper[2][2] / paper[2][1] - 0.05 / 0.06).abs() < 0.05, \"hue kept: {paper:?}\");\n assert!(paper[0][1].abs() < 1e-3 && paper[0][2].abs() < 1e-3, \"grey stays grey: {paper:?}\");",
|
||
" assert!((paper[2][0] - 0.5).abs() < 0.05, \"a middle tone stays in the middle: {paper:?}\");\n assert!((paper[2][2] / paper[2][1] - 0.05 / 0.06).abs() < 0.05, \"hue kept: {paper:?}\");\n assert!(paper[0][1].abs() < 1e-3 && paper[0][2].abs() < 1e-3, \"grey stays grey: {paper:?}\");\n }",
|
||
" assert!((paper[2][2] / paper[2][1] - 0.05 / 0.06).abs() < 0.05, \"hue kept: {paper:?}\");\n assert!(paper[0][1].abs() < 1e-3 && paper[0][2].abs() < 1e-3, \"grey stays grey: {paper:?}\");\n }",
|
||
" assert!(paper[0][1].abs() < 1e-3 && paper[0][2].abs() < 1e-3, \"grey stays grey: {paper:?}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/regions.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "local_colour_drifts_within_a_shape_but_never_crosses_a_cut",
|
||
"path": "crates/algo/src/cutout/regions.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked local_colour_drifts_within_a_shape_but_never_crosses_a_cut -- --nocapture",
|
||
"fixture_and_action_excerpt": " // One light region, pink on the left and cream on the right, next to a blue one.\n let (w, h) = (30usize, 4usize);\n let reg: Vec<u32> = (0..w * h).map(|i| u32::from(i % w >= 20)).collect();\n let lab: Vec<Px> = (0..w * h)\n .map(|i| match i % w {\n 0..10 => [0.8, 0.08, 0.02],\n 10..20 => [0.8, 0.01, 0.04],\n _ => [0.4, -0.02, -0.12],\n })\n .collect();\n let paper = [srgb([0.8, 0.04, 0.03]).unwrap_or_default(), srgb([0.4, -0.02, -0.12]).unwrap_or_default()];\n let out: Vec<Px> = local_paper(®, &paper, &lab, w, h, 3.0).into_iter().map(oklab).collect();",
|
||
"expected_assertions": [
|
||
" assert!(left[1] > right[1] + 0.03, \"the pink side is pinker: {left:?} vs {right:?}\");\n assert!((left[0] - right[0]).abs() < 0.01, \"one lightness across the shape: {left:?} vs {right:?}\");\n assert!(edge[2] > 0.0, \"no blue from the next shape at the cut: {edge:?}\");\n }",
|
||
" assert!((left[0] - right[0]).abs() < 0.01, \"one lightness across the shape: {left:?} vs {right:?}\");\n assert!(edge[2] > 0.0, \"no blue from the next shape at the cut: {edge:?}\");\n }",
|
||
" assert!(edge[2] > 0.0, \"no blue from the next shape at the cut: {edge:?}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/regions.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "transposing_twice_gives_the_image_back",
|
||
"path": "crates/algo/src/cutout/util.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked transposing_twice_gives_the_image_back -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h) = (5usize, 3usize);\n let c: Vec<Px> = (0..w * h).map(|i| [i as f32, 0.0, 0.0]).collect();\n let t = transpose(&c, w, h);\n assert_eq!(t[1], c[w], \"the second value of the first column is the first of the second row\");\n assert_eq!(transpose(&t, h, w), c);\n let ids: Vec<u32> = (0..(w * h) as u32).collect();\n assert_eq!(transpose_u32(&ids, w, h), t.iter().map(|p| p[0] as u32).collect::<Vec<_>>());\n assert_eq!(transpose_u32(&transpose_u32(&ids, w, h), h, w), ids);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(t[1], c[w], \"the second value of the first column is the first of the second row\");\n assert_eq!(transpose(&t, h, w), c);\n let ids: Vec<u32> = (0..(w * h) as u32).collect();\n assert_eq!(transpose_u32(&ids, w, h), t.iter().map(|p| p[0] as u32).collect::<Vec<_>>());",
|
||
" assert_eq!(transpose(&t, h, w), c);\n let ids: Vec<u32> = (0..(w * h) as u32).collect();\n assert_eq!(transpose_u32(&ids, w, h), t.iter().map(|p| p[0] as u32).collect::<Vec<_>>());\n assert_eq!(transpose_u32(&transpose_u32(&ids, w, h), h, w), ids);",
|
||
" assert_eq!(transpose_u32(&ids, w, h), t.iter().map(|p| p[0] as u32).collect::<Vec<_>>());\n assert_eq!(transpose_u32(&transpose_u32(&ids, w, h), h, w), ids);\n }",
|
||
" assert_eq!(transpose_u32(&transpose_u32(&ids, w, h), h, w), ids);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/util.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "find_returns_the_root_and_shortens_the_path",
|
||
"path": "crates/algo/src/cutout/util.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked find_returns_the_root_and_shortens_the_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " // 4 -> 3 -> 2 -> 1 -> 0.\n let mut parent = vec![0, 0, 1, 2, 3];\n assert_eq!(find(&mut parent, 4), 0);\n assert_eq!(find(&mut parent, 0), 0);\n assert!(parent[4] < 3, \"the path was halved: {parent:?}\");\n assert!(parent.iter().all(|&p| p <= 2));\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(find(&mut parent, 4), 0);\n assert_eq!(find(&mut parent, 0), 0);\n assert!(parent[4] < 3, \"the path was halved: {parent:?}\");\n assert!(parent.iter().all(|&p| p <= 2));",
|
||
" assert_eq!(find(&mut parent, 0), 0);\n assert!(parent[4] < 3, \"the path was halved: {parent:?}\");\n assert!(parent.iter().all(|&p| p <= 2));\n }",
|
||
" assert!(parent[4] < 3, \"the path was halved: {parent:?}\");\n assert!(parent.iter().all(|&p| p <= 2));\n }",
|
||
" assert!(parent.iter().all(|&p| p <= 2));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5c30699087b02edcaa23397a0f7076bf503be048/crates/algo/src/cutout/util.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-8039",
|
||
"pr": 8039,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-compose --locked softer_outer_glow_keeps_a_fading_tail_past_its_size -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked softer_outer_glow_margin_includes_its_tail_support -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked softer_outer_glow_program_keeps_the_tent_and_adds_a_distance_tail -- --nocapture"
|
||
],
|
||
"expected": "softer outer glow keeps a fading tail past its size; softer outer glow margin includes its tail support; softer outer glow program keeps the tent and adds a distance tail",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-compose --locked softer_outer_glow_keeps_a_fading_tail_past_its_size -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked softer_outer_glow_margin_includes_its_tail_support -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked softer_outer_glow_program_keeps_the_tent_and_adds_a_distance_tail -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "softer_outer_glow_keeps_a_fading_tail_past_its_size",
|
||
"path": "crates/compose/src/effects.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked softer_outer_glow_keeps_a_fading_tail_past_its_size -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut shape = Map::new(220, 220, 0.0);\n for y in 0..shape.h {\n for x in 20..100 {\n shape.v[y * shape.w + x] = 1.0;\n }\n }\n let glow = Glow {\n common: photocraft_doc::FxCommon::new(BlendMode::Screen, 1.0),\n paint: FxPaint::Color(photocraft_color::Color::WHITE),\n technique: GlowTechnique::Softer,\n spread: 0.0,\n size: 60.0,",
|
||
"expected_assertions": [
|
||
" assert!(at(50) > 0.024, \"the softer shoulder should stay visible: {}\", at(50));\n assert!(at(60) > 1.0 / 255.0, \"the glow must retain a visible tail at its Size: {}\", at(60));\n assert!(at(62) > 0.5 / 255.0, \"the glow must extend beyond its Size: {}\", at(62));\n assert!(at(66) < 1e-6, \"the added tail should fade to zero: {}\", at(66));",
|
||
" assert!(at(60) > 1.0 / 255.0, \"the glow must retain a visible tail at its Size: {}\", at(60));\n assert!(at(62) > 0.5 / 255.0, \"the glow must extend beyond its Size: {}\", at(62));\n assert!(at(66) < 1e-6, \"the added tail should fade to zero: {}\", at(66));\n }",
|
||
" assert!(at(62) > 0.5 / 255.0, \"the glow must extend beyond its Size: {}\", at(62));\n assert!(at(66) < 1e-6, \"the added tail should fade to zero: {}\", at(66));\n }",
|
||
" assert!(at(66) < 1e-6, \"the added tail should fade to zero: {}\", at(66));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5579cf5439856fed93f41a669a3fc9b56d5813cf/crates/compose/src/effects.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "softer_outer_glow_margin_includes_its_tail_support",
|
||
"path": "crates/compose/src/effects.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked softer_outer_glow_margin_includes_its_tail_support -- --nocapture",
|
||
"fixture_and_action_excerpt": " let glow = Glow {\n common: photocraft_doc::FxCommon::new(BlendMode::Screen, 1.0),\n paint: FxPaint::Color(photocraft_color::Color::WHITE),\n technique: GlowTechnique::Softer,\n spread: 0.0,\n size: 60.0,\n contour: Contour::Linear,\n anti_alias: false,\n range: 0.5,\n jitter: 0.0,\n noise: 0.0,\n source: GlowSource::Edge,",
|
||
"expected_assertions": [
|
||
" assert_eq!(margin(&layer), 68);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5579cf5439856fed93f41a669a3fc9b56d5813cf/crates/compose/src/effects.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "softer_outer_glow_program_keeps_the_tent_and_adds_a_distance_tail",
|
||
"path": "crates/gpu/src/fx.rs",
|
||
"package": "photocraft-gpu",
|
||
"command": "cargo test -p photocraft-gpu --locked softer_outer_glow_program_keeps_the_tent_and_adds_a_distance_tail -- --nocapture",
|
||
"fixture_and_action_excerpt": " let effect = Effect::OuterGlow(photocraft_doc::Glow {\n common: FxCommon::new(BlendMode::Screen, 1.0),\n paint: photocraft_doc::FxPaint::Color(photocraft_color::Color::WHITE),\n technique: GlowTechnique::Softer,\n spread: 0.0,\n size: 60.0,\n contour: Contour::Linear,\n anti_alias: false,\n range: 0.5,\n jitter: 0.0,\n noise: 0.0,\n source: GlowSource::Edge,",
|
||
"expected_assertions": [
|
||
" assert_eq!(blur.len(), 2);\n for stage in blur {\n assert_eq!(stage.radius, kernel.0);\n assert_eq!(stage.lut.as_deref().unwrap(), kernel.1.as_slice());",
|
||
" assert_eq!(stage.radius, kernel.0);\n assert_eq!(stage.lut.as_deref().unwrap(), kernel.1.as_slice());\n }\n let tail = p.stages.iter().find(|s| s.kernel == Kernel::MGlow).unwrap();",
|
||
" assert_eq!(stage.lut.as_deref().unwrap(), kernel.1.as_slice());\n }\n let tail = p.stages.iter().find(|s| s.kernel == Kernel::MGlow).unwrap();\n assert_eq!(tail.a, Some(In::Field(FieldKind::Outside)));",
|
||
" assert_eq!(tail.a, Some(In::Field(FieldKind::Outside)));\n assert_eq!(tail.p0, [54.0, 6.0, 0.0025, 1.0]);\n assert!(p.stages.iter().any(|s| s.kernel == Kernel::MFinish && s.p0[0] == 2.0));\n assert!(p.fields.contains(&(FieldKind::Outside, reach_for(66.0))));",
|
||
" assert_eq!(tail.p0, [54.0, 6.0, 0.0025, 1.0]);\n assert!(p.stages.iter().any(|s| s.kernel == Kernel::MFinish && s.p0[0] == 2.0));\n assert!(p.fields.contains(&(FieldKind::Outside, reach_for(66.0))));\n }",
|
||
" assert!(p.stages.iter().any(|s| s.kernel == Kernel::MFinish && s.p0[0] == 2.0));\n assert!(p.fields.contains(&(FieldKind::Outside, reach_for(66.0))));\n }",
|
||
" assert!(p.fields.contains(&(FieldKind::Outside, reach_for(66.0))));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5579cf5439856fed93f41a669a3fc9b56d5813cf/crates/gpu/src/fx.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-8191",
|
||
"pr": 8191,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-algo --locked oklab_round_trips_and_marks_the_gamut -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked out_of_gamut_colours_lose_strength_not_hue -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked smoothing_flattens_noise_and_keeps_edges -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked the_palette_finds_the_pictures_own_colours -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_tone_of_two_different_hues_splits_in_two -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_empty_image_still_has_a_palette -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked transposing_twice_gives_the_image_back -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked find_returns_the_root_and_shortens_the_path -- --nocapture"
|
||
],
|
||
"expected": "oklab round trips and marks the gamut; out of gamut colours lose strength not hue; smoothing flattens noise and keeps edges; the palette finds the pictures own colours; a tone of two different hues splits in two; an empty image still has a palette; transposing twice gives the image back; find returns the root and shortens the path",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-algo --locked oklab_round_trips_and_marks_the_gamut -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked out_of_gamut_colours_lose_strength_not_hue -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked smoothing_flattens_noise_and_keeps_edges -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked the_palette_finds_the_pictures_own_colours -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_tone_of_two_different_hues_splits_in_two -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_empty_image_still_has_a_palette -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked transposing_twice_gives_the_image_back -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked find_returns_the_root_and_shortens_the_path -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "oklab_round_trips_and_marks_the_gamut",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked oklab_round_trips_and_marks_the_gamut -- --nocapture",
|
||
"fixture_and_action_excerpt": " let white = oklab([1.0, 1.0, 1.0]);\n assert!((white[0] - 1.0).abs() < 1e-3 && white[1].abs() < 1e-3 && white[2].abs() < 1e-3, \"{white:?}\");\n assert!(oklab([0.0, 0.0, 0.0])[0].abs() < 1e-6);\n for p in [[0.2, 0.5, 0.9], [0.95, 0.1, 0.3], [0.5, 0.5, 0.5], [0.0, 1.0, 0.0]] {\n let back = srgb(oklab(p)).unwrap_or([-1.0; 3]);\n assert!(dist2(back, p) < 1e-6, \"{p:?} came back as {back:?}\");\n }\n // Very light and very colourful: no sRGB colour is that.\n assert_eq!(srgb([0.95, 0.3, 0.0]), None);\n }",
|
||
"expected_assertions": [
|
||
" assert!((white[0] - 1.0).abs() < 1e-3 && white[1].abs() < 1e-3 && white[2].abs() < 1e-3, \"{white:?}\");\n assert!(oklab([0.0, 0.0, 0.0])[0].abs() < 1e-6);\n for p in [[0.2, 0.5, 0.9], [0.95, 0.1, 0.3], [0.5, 0.5, 0.5], [0.0, 1.0, 0.0]] {\n let back = srgb(oklab(p)).unwrap_or([-1.0; 3]);",
|
||
" assert!(oklab([0.0, 0.0, 0.0])[0].abs() < 1e-6);\n for p in [[0.2, 0.5, 0.9], [0.95, 0.1, 0.3], [0.5, 0.5, 0.5], [0.0, 1.0, 0.0]] {\n let back = srgb(oklab(p)).unwrap_or([-1.0; 3]);\n assert!(dist2(back, p) < 1e-6, \"{p:?} came back as {back:?}\");",
|
||
" assert!(dist2(back, p) < 1e-6, \"{p:?} came back as {back:?}\");\n }\n // Very light and very colourful: no sRGB colour is that.\n assert_eq!(srgb([0.95, 0.3, 0.0]), None);",
|
||
" assert_eq!(srgb([0.95, 0.3, 0.0]), None);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/91e4cec43525ca739c05cff614701fbd3576e389/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "out_of_gamut_colours_lose_strength_not_hue",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked out_of_gamut_colours_lose_strength_not_hue -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (l, a, b) = (0.95, 0.3, 0.1);\n let c = in_gamut(l, a, b);\n let lab = oklab(c);\n assert!((lab[0] - l).abs() < 0.01, \"lightness kept: {lab:?}\");\n let chroma = (lab[1] * lab[1] + lab[2] * lab[2]).sqrt();\n assert!(chroma > 0.01 && chroma < (a * a + b * b).sqrt(), \"weaker but still coloured: {chroma}\");\n assert!((lab[2] / lab[1] - b / a).abs() < 0.05, \"same hue: {lab:?}\");\n // In gamut it is just the conversion.\n assert_eq!(in_gamut(0.6, 0.02, -0.03), srgb([0.6, 0.02, -0.03]).unwrap_or_default());\n }",
|
||
"expected_assertions": [
|
||
" assert!((lab[0] - l).abs() < 0.01, \"lightness kept: {lab:?}\");\n let chroma = (lab[1] * lab[1] + lab[2] * lab[2]).sqrt();\n assert!(chroma > 0.01 && chroma < (a * a + b * b).sqrt(), \"weaker but still coloured: {chroma}\");\n assert!((lab[2] / lab[1] - b / a).abs() < 0.05, \"same hue: {lab:?}\");",
|
||
" assert!(chroma > 0.01 && chroma < (a * a + b * b).sqrt(), \"weaker but still coloured: {chroma}\");\n assert!((lab[2] / lab[1] - b / a).abs() < 0.05, \"same hue: {lab:?}\");\n // In gamut it is just the conversion.\n assert_eq!(in_gamut(0.6, 0.02, -0.03), srgb([0.6, 0.02, -0.03]).unwrap_or_default());",
|
||
" assert!((lab[2] / lab[1] - b / a).abs() < 0.05, \"same hue: {lab:?}\");\n // In gamut it is just the conversion.\n assert_eq!(in_gamut(0.6, 0.02, -0.03), srgb([0.6, 0.02, -0.03]).unwrap_or_default());\n }",
|
||
" assert_eq!(in_gamut(0.6, 0.02, -0.03), srgb([0.6, 0.02, -0.03]).unwrap_or_default());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/91e4cec43525ca739c05cff614701fbd3576e389/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "smoothing_flattens_noise_and_keeps_edges",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked smoothing_flattens_noise_and_keeps_edges -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h) = (40usize, 20usize);\n let lab = noisy(w, h, 0.02, |x| if x < 20 { [0.3, 0.0, 0.0] } else { [0.8, 0.0, 0.0] });\n let out = smooth(lab.clone(), w, h, 2);\n let spread = |v: &[Px], xs: std::ops::Range<usize>| {\n let l: Vec<f32> = (0..h).flat_map(|y| xs.clone().map(move |x| y * w + x)).map(|i| v[i][0]).collect();\n let mean = l.iter().sum::<f32>() / l.len() as f32;\n (l.iter().map(|v| (v - mean).powi(2)).sum::<f32>() / l.len() as f32).sqrt()\n };\n assert!(spread(&out, 2..16) < spread(&lab, 2..16) / 2.0, \"noise kept: {} vs {}\", spread(&out, 2..16), spread(&lab, 2..16));\n // The step stays a step: the pixels either side of it keep most of their difference.\n let step = (0..h).map(|y| out[y * w + 20][0] - out[y * w + 19][0]).sum::<f32>() / h as f32;\n assert!(step > 0.4, \"edge blurred to {step}\");",
|
||
"expected_assertions": [
|
||
" assert!(spread(&out, 2..16) < spread(&lab, 2..16) / 2.0, \"noise kept: {} vs {}\", spread(&out, 2..16), spread(&lab, 2..16));\n // The step stays a step: the pixels either side of it keep most of their difference.\n let step = (0..h).map(|y| out[y * w + 20][0] - out[y * w + 19][0]).sum::<f32>() / h as f32;\n assert!(step > 0.4, \"edge blurred to {step}\");",
|
||
" assert!(step > 0.4, \"edge blurred to {step}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/91e4cec43525ca739c05cff614701fbd3576e389/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_palette_finds_the_pictures_own_colours",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked the_palette_finds_the_pictures_own_colours -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h) = (60usize, 20usize);\n let (dark, light) = ([0.25, 0.02, -0.03], [0.75, -0.04, 0.05]);\n let lab = noisy(w, h, 0.01, |x| if x < 30 { dark } else { light });\n // Asked for up to six, it gives two: colours only noise apart are one.\n let p = palette(&lab, 6);\n assert_eq!(p.len(), 2, \"{p:?}\");\n for c in [dark, light] {\n assert!(p.iter().any(|q| dist2(*q, c).sqrt() < 0.02), \"{c:?} not in {p:?}\");\n }\n assert_eq!(nearest(&p, dark), nearest(&p, [0.27, 0.0, -0.02]));\n assert_ne!(nearest(&p, dark), nearest(&p, light));\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(p.len(), 2, \"{p:?}\");\n for c in [dark, light] {\n assert!(p.iter().any(|q| dist2(*q, c).sqrt() < 0.02), \"{c:?} not in {p:?}\");\n }",
|
||
" assert!(p.iter().any(|q| dist2(*q, c).sqrt() < 0.02), \"{c:?} not in {p:?}\");\n }\n assert_eq!(nearest(&p, dark), nearest(&p, [0.27, 0.0, -0.02]));\n assert_ne!(nearest(&p, dark), nearest(&p, light));",
|
||
" assert_eq!(nearest(&p, dark), nearest(&p, [0.27, 0.0, -0.02]));\n assert_ne!(nearest(&p, dark), nearest(&p, light));\n }",
|
||
" assert_ne!(nearest(&p, dark), nearest(&p, light));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/91e4cec43525ca739c05cff614701fbd3576e389/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_tone_of_two_different_hues_splits_in_two",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked a_tone_of_two_different_hues_splits_in_two -- --nocapture",
|
||
"fixture_and_action_excerpt": " // A dark tone and a light one, the light one half blue and half pink: two levels give\n // three colours, or the blue and pink areas would be one shape of their grey average.\n let (w, h) = (60usize, 20usize);\n let (dark, blue, pink) = ([0.2, 0.0, 0.0], [0.7, -0.03, -0.1], [0.7, 0.12, 0.0]);\n let lab = noisy(w, h, 0.005, |x| {\n if x < 30 {\n dark\n } else if x < 45 {\n blue\n } else {\n pink\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(p.len(), 3, \"{p:?}\");\n for c in [dark, blue, pink] {\n assert!(p.iter().any(|q| dist2(*q, c).sqrt() < 0.03), \"{c:?} not in {p:?}\");\n }",
|
||
" assert!(p.iter().any(|q| dist2(*q, c).sqrt() < 0.03), \"{c:?} not in {p:?}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/91e4cec43525ca739c05cff614701fbd3576e389/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "an_empty_image_still_has_a_palette",
|
||
"path": "crates/algo/src/cutout/colour.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked an_empty_image_still_has_a_palette -- --nocapture",
|
||
"fixture_and_action_excerpt": " assert_eq!(palette(&[], 4).len(), 1);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(palette(&[], 4).len(), 1);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/91e4cec43525ca739c05cff614701fbd3576e389/crates/algo/src/cutout/colour.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "transposing_twice_gives_the_image_back",
|
||
"path": "crates/algo/src/cutout/util.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked transposing_twice_gives_the_image_back -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h) = (5usize, 3usize);\n let c: Vec<Px> = (0..w * h).map(|i| [i as f32, 0.0, 0.0]).collect();\n let t = transpose(&c, w, h);\n assert_eq!(t[1], c[w], \"the second value of the first column is the first of the second row\");\n assert_eq!(transpose(&t, h, w), c);\n let ids: Vec<u32> = (0..(w * h) as u32).collect();\n assert_eq!(transpose_u32(&ids, w, h), t.iter().map(|p| p[0] as u32).collect::<Vec<_>>());\n assert_eq!(transpose_u32(&transpose_u32(&ids, w, h), h, w), ids);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(t[1], c[w], \"the second value of the first column is the first of the second row\");\n assert_eq!(transpose(&t, h, w), c);\n let ids: Vec<u32> = (0..(w * h) as u32).collect();\n assert_eq!(transpose_u32(&ids, w, h), t.iter().map(|p| p[0] as u32).collect::<Vec<_>>());",
|
||
" assert_eq!(transpose(&t, h, w), c);\n let ids: Vec<u32> = (0..(w * h) as u32).collect();\n assert_eq!(transpose_u32(&ids, w, h), t.iter().map(|p| p[0] as u32).collect::<Vec<_>>());\n assert_eq!(transpose_u32(&transpose_u32(&ids, w, h), h, w), ids);",
|
||
" assert_eq!(transpose_u32(&ids, w, h), t.iter().map(|p| p[0] as u32).collect::<Vec<_>>());\n assert_eq!(transpose_u32(&transpose_u32(&ids, w, h), h, w), ids);\n }",
|
||
" assert_eq!(transpose_u32(&transpose_u32(&ids, w, h), h, w), ids);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/91e4cec43525ca739c05cff614701fbd3576e389/crates/algo/src/cutout/util.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "find_returns_the_root_and_shortens_the_path",
|
||
"path": "crates/algo/src/cutout/util.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked find_returns_the_root_and_shortens_the_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " // 4 -> 3 -> 2 -> 1 -> 0.\n let mut parent = vec![0, 0, 1, 2, 3];\n assert_eq!(find(&mut parent, 4), 0);\n assert_eq!(find(&mut parent, 0), 0);\n assert!(parent[4] < 3, \"the path was halved: {parent:?}\");\n assert!(parent.iter().all(|&p| p <= 2));\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(find(&mut parent, 4), 0);\n assert_eq!(find(&mut parent, 0), 0);\n assert!(parent[4] < 3, \"the path was halved: {parent:?}\");\n assert!(parent.iter().all(|&p| p <= 2));",
|
||
" assert_eq!(find(&mut parent, 0), 0);\n assert!(parent[4] < 3, \"the path was halved: {parent:?}\");\n assert!(parent.iter().all(|&p| p <= 2));\n }",
|
||
" assert!(parent[4] < 3, \"the path was halved: {parent:?}\");\n assert!(parent.iter().all(|&p| p <= 2));\n }",
|
||
" assert!(parent.iter().all(|&p| p <= 2));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/91e4cec43525ca739c05cff614701fbd3576e389/crates/algo/src/cutout/util.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-8192",
|
||
"pr": 8192,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Synthetic label maps in cutout/regions.rs",
|
||
"action": [
|
||
"cargo test -p photocraft-algo --locked components_are_four_connected_and_numbered_in_raster_order -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked small_regions_merge_into_the_neighbour_they_share_most_border_with -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked slivers_merge_though_they_are_large -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked local_colour_drifts_within_a_shape_but_never_crosses_a_cut -- --nocapture"
|
||
],
|
||
"expected": "Four-connected components have deterministic raster numbering; small regions choose the shared-border neighbour; narrow slivers merge despite area; colour variation never crosses a cut.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "The earlier Oklab test is supporting coverage, not the regions-stage oracle.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-algo --locked components_are_four_connected_and_numbered_in_raster_order -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked small_regions_merge_into_the_neighbour_they_share_most_border_with -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked slivers_merge_though_they_are_large -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked local_colour_drifts_within_a_shape_but_never_crosses_a_cut -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-8193",
|
||
"pr": 8193,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Two-region boundaries, islands, antialiased edges, squares and open chains in cutout/edges.rs and curves.rs",
|
||
"action": [
|
||
"cargo test -p photocraft-algo --locked the_edge_between_two_regions_is_one_chain_between_junctions -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_island_is_one_closed_chain -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_anti_aliased_edge_is_placed_inside_its_pixel -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_square_keeps_its_four_corners_and_straight_sides -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_open_chain_ends_where_it_started_at_any_fidelity -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked fitting_keeps_small_islands_and_their_winding -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked cutout_makes_flat_shapes_with_clean_edges -- --nocapture"
|
||
],
|
||
"expected": "Shared boundaries are single chains; islands close; subpixel edge placement, square corners, open endpoints and winding survive fitting. Complete Cutout yields the asserted clean flat shapes.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Run after the complete #8191 → #8192 → #8193 → #7903 chain.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-algo --locked the_edge_between_two_regions_is_one_chain_between_junctions -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_island_is_one_closed_chain -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_anti_aliased_edge_is_placed_inside_its_pixel -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked a_square_keeps_its_four_corners_and_straight_sides -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_open_chain_ends_where_it_started_at_any_fidelity -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked fitting_keeps_small_islands_and_their_winding -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked cutout_makes_flat_shapes_with_clean_edges -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-8903",
|
||
"pr": 8903,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-compose --locked minified_pattern_is_filtered_not_aliased -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked pattern_fill_layers -- --nocapture"
|
||
],
|
||
"expected": "minified pattern is filtered not aliased; pattern fill layers",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-compose --locked minified_pattern_is_filtered_not_aliased -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked pattern_fill_layers -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "minified_pattern_is_filtered_not_aliased",
|
||
"path": "crates/compose/src/pattern.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked minified_pattern_is_filtered_not_aliased -- --nocapture",
|
||
"fixture_and_action_excerpt": " // 1-px dark / light stripes (mean 0.5), shown at 25 %: every pixel covers 4 tile pixels.\n // The 0.125 px phase puts each pixel centre on a light tile pixel's centre, so a single\n // bilinear tap would return pure white.\n let mut s = Surface::new(PixelFormat::RGBA8);\n s.fill_rect(Rect::new(0, 0, 8, 8), &[1.0, 1.0, 1.0, 1.0]);\n for x in (0..8).step_by(2) {\n s.fill_rect(Rect::new(x, 0, x + 1, 8), &[0.0, 0.0, 0.0, 1.0]);\n }\n let t = Tile::new(&Pattern::new(\"stripes\", s, 8, 8)).unwrap();\n let place = Placement::new(Rect::EMPTY, false, (0.125, 0.0), 0.25, 0.0);\n let (u, _) = place.map(0.5, 0.5);\n assert_eq!(t.sample(u, 0.5)[0], 1.0, \"the single tap lands on a light stripe\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(t.sample(u, 0.5)[0], 1.0, \"the single tap lands on a light stripe\");\n for p in render(&t, &place, Rect::new(0, 0, 8, 1)) {\n assert!((p[0] - 0.5).abs() < 0.05, \"{p:?}\");\n }",
|
||
" assert!((p[0] - 0.5).abs() < 0.05, \"{p:?}\");\n }\n // 100 % stays exact.\n let one = Placement::new(Rect::EMPTY, false, (0.0, 0.0), 1.0, 0.0);",
|
||
" assert_eq!((row[0][0], row[1][0]), (0.0, 1.0));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d387f52f1f2f5681b2c7d1c517aa5b5992c7bc88/crates/compose/src/pattern.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "pattern_fill_layers",
|
||
"path": "crates/gpu/tests/it/parity.rs",
|
||
"package": "photocraft-gpu",
|
||
"command": "cargo test -p photocraft-gpu --locked pattern_fill_layers -- --nocapture",
|
||
"fixture_and_action_excerpt": " let Some(mut g) = gpu() else { return };\n let pat = checker_pattern();\n for (link, scale, angle, masked) in [(true, 1.0, 0.0, false), (false, 0.7, 25.0, true), (true, 1.6, -40.0, false), (true, 0.3, 10.0, false)] {\n let mut d = base_doc(70, 50);\n d.patterns.push(pat.clone());\n let fill = Fill::Pattern { name: pat.name.clone(), id: pat.id.clone(), scale, angle, link, phase: (3.0, -2.0) };\n let mut l = Layer::new(\"pat\", LayerContent::Fill(fill));\n l.opacity = 0.85;\n l.blend = BlendMode::Overlay;\n if masked {\n l.mask = Some(mask(Rect::new(5, 5, 60, 45), 61, 0.0));\n }",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d387f52f1f2f5681b2c7d1c517aa5b5992c7bc88/crates/gpu/tests/it/parity.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9472",
|
||
"pr": 9472,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked displace_psd_filter_with_only_a_map_path_renders_after_replace_contents -- --nocapture",
|
||
"cargo test -p photocraft-io --locked a_map_named_only_by_its_path_imports_as_map_path -- --nocapture"
|
||
],
|
||
"expected": "displace psd filter with only a map path renders after replace contents; a map named only by its path imports as map path",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked displace_psd_filter_with_only_a_map_path_renders_after_replace_contents -- --nocapture",
|
||
"cargo test -p photocraft-io --locked a_map_named_only_by_its_path_imports_as_map_path -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "displace_psd_filter_with_only_a_map_path_renders_after_replace_contents",
|
||
"path": "crates/engine/tests/it/smart_psd.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked displace_psd_filter_with_only_a_map_path_renders_after_replace_contents -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_psd::descriptor::{Descriptor, Id, UnicodeString, Value};\n let dir = std::env::temp_dir().join(format!(\"pcraft-9162-{}\", std::process::id()));\n std::fs::create_dir_all(&dir).unwrap();\n let png = |name: &str, size: (u32, u32), c: [f32; 4]| {\n let d = Document::with_background(\n \"m\",\n photocraft_geom::Size::new(size.0, size.1),\n photocraft_color::ColorMode::Rgb,\n photocraft_color::SampleType::U8,\n photocraft_color::Color::rgba(c[0], c[1], c[2], c[3]),\n );\n let path = dir.join(name);",
|
||
"expected_assertions": [
|
||
" assert_eq!(out[\"warnings\"], json!([]), \"depth {depth}\");\n let cache = smart(&s2.active().unwrap().doc).1.cache.unwrap();\n // 10 % of 128 px at full map contrast: the design (x 8..80) moves 12.8 px left.\n let alpha = |x: i32| cache.pixel(x, 30)[3];",
|
||
" assert!(alpha(2) > 0.99 && alpha(75) < 0.01, \"depth {depth}: {} {}\", alpha(2), alpha(75));\n }\n std::fs::remove_dir_all(&dir).ok();\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/4bab657cd4fb4a91ced44d3721e63a002ca5068c/crates/engine/tests/it/smart_psd.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_map_named_only_by_its_path_imports_as_map_path",
|
||
"path": "crates/io/src/displace_map.rs",
|
||
"package": "photocraft-io",
|
||
"command": "cargo test -p photocraft-io --locked a_map_named_only_by_its_path_imports_as_map_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let with_file = |file: Value| {\n let mut i = item(Vec::new());\n let mut f = get_desc(&i, \"Fltr\").unwrap().clone();\n f.items.retain(|(k, _)| !k.is(MAP_KEY));\n set(&mut f, \"DspF\", file);\n set(&mut i, \"Fltr\", Value::Descriptor(f));\n i\n };\n let src = with_file(pth(\"C:\\\\maps\\\\repro-map.psd\"));\n let f = filter_from_item(&src);\n assert_eq!(f.command, COMMAND);\n assert_eq!(f.params[\"mapPath\"], json!(\"C:\\\\maps\\\\repro-map.psd\"));",
|
||
"expected_assertions": [
|
||
" assert_eq!(f.command, COMMAND);\n assert_eq!(f.params[\"mapPath\"], json!(\"C:\\\\maps\\\\repro-map.psd\"));\n assert!(embedded_map(&f.params).is_none());\n assert_eq!(item_for_filter(&f).unwrap(), src, \"written back as it was\");",
|
||
" assert_eq!(f.params[\"mapPath\"], json!(\"C:\\\\maps\\\\repro-map.psd\"));\n assert!(embedded_map(&f.params).is_none());\n assert_eq!(item_for_filter(&f).unwrap(), src, \"written back as it was\");\n let mut moved = f.clone();",
|
||
" assert!(embedded_map(&f.params).is_none());\n assert_eq!(item_for_filter(&f).unwrap(), src, \"written back as it was\");\n let mut moved = f.clone();\n moved.params[\"mapPath\"] = json!(\"/elsewhere/map.png\");",
|
||
" assert_eq!(item_for_filter(&f).unwrap(), src, \"written back as it was\");\n let mut moved = f.clone();\n moved.params[\"mapPath\"] = json!(\"/elsewhere/map.png\");\n assert!(item_for_filter(&moved).is_err(), \"another map path has no place in the template\");",
|
||
" assert!(item_for_filter(&moved).is_err(), \"another map path has no place in the template\");\n let mut no_path = f.clone();\n no_path.params.as_object_mut().unwrap().remove(\"mapPath\");\n assert!(item_for_filter(&no_path).is_err(), \"a path-only template needs its mapPath, or the PSD names a map the render never read\");",
|
||
" assert!(item_for_filter(&no_path).is_err(), \"a path-only template needs its mapPath, or the PSD names a map the render never read\");\n // A record whose size field disagrees with its units, or without the final NUL.\n let mut wrong_size = pth(\"map.psd\");\n if let Value::Path(b) = &mut wrong_size {",
|
||
" assert_eq!(filter_from_item(&src).command, UNSUPPORTED_FILTER);\n }\n // A damaged embedded map is never replaced by a readable path.\n let mut damaged = item(vec![0; 4]);",
|
||
" assert_eq!(filter_from_item(&damaged).command, UNSUPPORTED_FILTER);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/4bab657cd4fb4a91ced44d3721e63a002ca5068c/crates/io/src/displace_map.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9509",
|
||
"pr": 9509,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-compose --locked full_coverage_adjustment_keeps_its_result_over_huge_hdr_values -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked reused_render_matches_previous_allocating_stack -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked mixing_through_a_selection_matches_sampling_it_per_pixel -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked full_coverage_keeps_the_edit_over_huge_hdr_values -- --nocapture"
|
||
],
|
||
"expected": "full coverage adjustment keeps its result over huge hdr values; reused render matches previous allocating stack; mixing through a selection matches sampling it per pixel; full coverage keeps the edit over huge hdr values",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-compose --locked full_coverage_adjustment_keeps_its_result_over_huge_hdr_values -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked reused_render_matches_previous_allocating_stack -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked mixing_through_a_selection_matches_sampling_it_per_pixel -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked full_coverage_keeps_the_edit_over_huge_hdr_values -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "full_coverage_adjustment_keeps_its_result_over_huge_hdr_values",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked full_coverage_adjustment_keeps_its_result_over_huge_hdr_values -- --nocapture",
|
||
"fixture_and_action_excerpt": " for v in [1.0e6_f32, 1.0e8, -1.0e6] {\n let mut d = Document::new(\"hdr\", Size::new(2, 2), ColorMode::Rgb, SampleType::F32);\n let mut base = Layer::raster(\"b\", PixelFormat::RGBA32F);\n base.surface_mut().unwrap().fill_rect(Rect::new(0, 0, 2, 2), &[v, v, v, 1.0]);\n let look = Adjustment::ColorLookup { name: \"half\".into(), lut: Some(std::sync::Arc::new(vec![0.5; 24])), size: 2, tetrahedral: false, dither: false };\n d.layers = vec![base, Layer::new(\"look\", LayerContent::Adjustment(look))];\n let got = px(&d, 0, 0);\n for c in &got[..3] {\n assert!((c - 0.5).abs() < 1e-6, \"{v}: {got:?}\");\n }\n }\n}",
|
||
"expected_assertions": [
|
||
" assert!((c - 0.5).abs() < 1e-6, \"{v}: {got:?}\");\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d78d7493d3f0b6e760c88de969ac810e9bc5d910/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "reused_render_matches_previous_allocating_stack",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked reused_render_matches_previous_allocating_stack -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [SampleType::U8, SampleType::U16, SampleType::F32] {\n let mut doc = Document::new(\"equivalence\", Size::new(513, 7), ColorMode::Rgb, depth);\n let rect = doc.bounds();\n for (name, color) in [(\"bottom\", [0.2, 0.4, 0.8, 1.0]), (\"top\", [1.5, -0.25, 0.6, 0.5])] {\n let mut layer = Layer::raster(name, doc.pixel_format());\n layer.surface_mut().unwrap().fill_rect(rect, &color);\n doc.layers.push(layer);\n }\n let mut levels = Adjustment::identity_levels();\n if let Adjustment::Levels { master, .. } = &mut levels {\n master.gamma = 1.4;\n }",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d78d7493d3f0b6e760c88de969ac810e9bc5d910/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "mixing_through_a_selection_matches_sampling_it_per_pixel",
|
||
"path": "crates/engine/src/pixels_tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked mixing_through_a_selection_matches_sampling_it_per_pixel -- --nocapture",
|
||
"fixture_and_action_excerpt": " // A rectangle across tile edges (negative x included), a selection with fractional\n // coverage, untouched tiles (default coverage) and a 16-bit as well as an 8-bit layer.\n let r = Rect::new(-300, 200, 330, 290);\n let gray32 = PixelFormat { mode: ColorMode::Grayscale, sample: SampleType::F32, alpha: false };\n for sel_fmt in [PixelFormat::GRAY8, PixelFormat::GRAYA8, gray32] {\n let mut sel = Surface::new(sel_fmt);\n sel.fill_rect(Rect::new(-260, 210, 40, 280), &vec![0.6; sel_fmt.channels()]);\n for x in 0..120 {\n sel.write_pixel(x * 2, 230 + x % 40, &vec![x as f32 / 119.0; sel_fmt.channels()]);\n }\n for fmt in [PixelFormat::RGBA8, PixelFormat::RGBA16] {\n let n = (r.width() * r.height()) as usize;",
|
||
"expected_assertions": [
|
||
" assert_eq!(mix_through_selection(&fmt, r, &orig, &edited, Some(&sel)), expected, \"{sel_fmt:?} over {fmt:?}\");\n }\n }\n // Without a selection the edit is taken whole; an empty rectangle mixes nothing.",
|
||
" assert_eq!(mix_through_selection(&fmt, Rect::new(0, 0, 1, 1), &[[0.0; 4]], &px, None), enc[..m].to_vec());\n assert!(mix_through_selection(&fmt, Rect::EMPTY, &[], &[], None).is_empty());\n}",
|
||
" assert!(mix_through_selection(&fmt, Rect::EMPTY, &[], &[], None).is_empty());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d78d7493d3f0b6e760c88de969ac810e9bc5d910/crates/engine/src/pixels_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "full_coverage_keeps_the_edit_over_huge_hdr_values",
|
||
"path": "crates/engine/src/pixels_tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked full_coverage_keeps_the_edit_over_huge_hdr_values -- --nocapture",
|
||
"fixture_and_action_excerpt": " let fmt = PixelFormat::RGBA32F;\n for (o, a) in [(1.0e8_f32, 0.5_f32), (1.0e6, 0.1), (-1.0e6, 0.9)] {\n let out = mix_through_selection(&fmt, Rect::new(0, 0, 1, 1), &[[o, o, o, 1.0]], &[[a, a, a, 1.0]], None);\n assert_eq!(out[..3], [a, a, a], \"{a} over {o}\");\n }\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(out[..3], [a, a, a], \"{a} over {o}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d78d7493d3f0b6e760c88de969ac810e9bc5d910/crates/engine/src/pixels_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9512",
|
||
"pr": 9512,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-compose --locked adjustment_fill_changes_the_special_blend_modes -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked special_eight_fill_on_adjustment_layers_matches_cpu -- --nocapture"
|
||
],
|
||
"expected": "adjustment fill changes the special blend modes; special eight fill on adjustment layers matches cpu",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-compose --locked adjustment_fill_changes_the_special_blend_modes -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked special_eight_fill_on_adjustment_layers_matches_cpu -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "adjustment_fill_changes_the_special_blend_modes",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked adjustment_fill_changes_the_special_blend_modes -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (mode, want) in [(BlendMode::ColorDodge, [80, 160, 240]), (BlendMode::LinearBurn, [13, 77, 141])] {\n let mut d = Document::with_background(\"fill\", Size::new(1, 1), ColorMode::Rgb, SampleType::U8, Color::WHITE);\n let mut base = Layer::raster(\"b\", PixelFormat::RGBA8);\n base.surface_mut().unwrap().fill_rect(Rect::new(0, 0, 1, 1), &[64.0 / 255.0, 128.0 / 255.0, 192.0 / 255.0, 1.0]);\n let look = Adjustment::ColorLookup { name: \"half\".into(), lut: Some(std::sync::Arc::new(vec![0.5; 24])), size: 2, tetrahedral: false, dither: false };\n let mut adj = Layer::new(\"look\", LayerContent::Adjustment(look));\n adj.blend = mode;\n adj.fill_opacity = 0.4;\n d.layers.push(base);\n d.layers.push(adj);\n let got = px(&d, 0, 0);\n let got: Vec<i32> = got[..3].iter().map(|v| (v * 255.0).round() as i32).collect();",
|
||
"expected_assertions": [
|
||
" assert!(got.iter().zip(want).all(|(g, w)| (g - w).abs() <= 1), \"{mode:?}: {got:?} vs Photoshop {want:?}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/6c55561128caf5ac917eb3d174e8e7bb4bd48e23/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "special_eight_fill_on_adjustment_layers_matches_cpu",
|
||
"path": "crates/gpu/tests/it/parity.rs",
|
||
"package": "photocraft-gpu",
|
||
"command": "cargo test -p photocraft-gpu --locked special_eight_fill_on_adjustment_layers_matches_cpu -- --nocapture",
|
||
"fixture_and_action_excerpt": " let Some(mut g) = gpu() else { return };\n let special = [\n BlendMode::ColorBurn,\n BlendMode::LinearBurn,\n BlendMode::ColorDodge,\n BlendMode::LinearDodge,\n BlendMode::VividLight,\n BlendMode::LinearLight,\n BlendMode::HardMix,\n BlendMode::Difference,\n ];\n for mode in special {",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/6c55561128caf5ac917eb3d174e8e7bb4bd48e23/crates/gpu/tests/it/parity.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9584",
|
||
"pr": 9584,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-compose --locked blend_if_16_bit_cutoffs_follow_photoshops_steps -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked blend_if_gray_follows_photoshops_weights_and_rounding -- --nocapture"
|
||
],
|
||
"expected": "blend if 16 bit cutoffs follow photoshops steps; blend if gray follows photoshops weights and rounding",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-compose --locked blend_if_16_bit_cutoffs_follow_photoshops_steps -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked blend_if_gray_follows_photoshops_weights_and_rounding -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "blend_if_16_bit_cutoffs_follow_photoshops_steps",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked blend_if_16_bit_cutoffs_follow_photoshops_steps -- --nocapture",
|
||
"fixture_and_action_excerpt": " let shown = |v16: u16, black: u8, white: u8| {\n let v = f32::from(v16) / 65535.0;\n let mut d = Document::new(\"t\", Size::new(1, 1), ColorMode::Rgb, SampleType::U16);\n let layer16 = |name: &str, c: [f32; 4]| {\n let mut l = Layer::raster(name, PixelFormat::RGBA16);\n l.surface_mut().unwrap().fill_rect(Rect::new(0, 0, 1, 1), &c);\n l\n };\n d.layers.push(layer16(\"under\", [v, v, v, 1.0]));\n let mut l = layer16(\"top\", [1.0, 1.0, 1.0, 1.0]);\n l.blend_if.set(3, [FULL, range([black, black], [white, white])]);\n d.layers.push(l);",
|
||
"expected_assertions": [
|
||
" assert!(shown(at(step), c, 255), \"black {c}: step {step} shows\");\n assert!(!shown(at(step - 1), c, 255), \"black {c}: step {} hides\", step - 1);\n assert!(shown(at(step), 0, c), \"white {c}: step {step} shows\");\n assert!(!shown(at(step + 1), 0, c), \"white {c}: step {} hides\", step + 1);",
|
||
" assert!(!shown(at(step - 1), c, 255), \"black {c}: step {} hides\", step - 1);\n assert!(shown(at(step), 0, c), \"white {c}: step {step} shows\");\n assert!(!shown(at(step + 1), 0, c), \"white {c}: step {} hides\", step + 1);\n }",
|
||
" assert!(shown(at(step), 0, c), \"white {c}: step {step} shows\");\n assert!(!shown(at(step + 1), 0, c), \"white {c}: step {} hides\", step + 1);\n }\n assert!(shown(32895, 128, 255) && !shown(32894, 128, 255), \"the reporter's RGB16 boundary\");",
|
||
" assert!(!shown(at(step + 1), 0, c), \"white {c}: step {} hides\", step + 1);\n }\n assert!(shown(32895, 128, 255) && !shown(32894, 128, 255), \"the reporter's RGB16 boundary\");\n}",
|
||
" assert!(shown(32895, 128, 255) && !shown(32894, 128, 255), \"the reporter's RGB16 boundary\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/fc0f7b1132f799b5bba7be642c9047499d95a887/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "blend_if_gray_follows_photoshops_weights_and_rounding",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked blend_if_gray_follows_photoshops_weights_and_rounding -- --nocapture",
|
||
"fixture_and_action_excerpt": " let shown = |rgb: [u8; 3], black: u8, white: u8| {\n let mut d = Document::new(\"t\", Size::new(1, 1), ColorMode::Rgb, SampleType::U8);\n let c = rgb.map(|v| f32::from(v) / 255.0);\n d.layers.push(solid_layer(\"under\", Rect::new(0, 0, 1, 1), [c[0], c[1], c[2], 1.0]));\n let mut l = solid_layer(\"top\", Rect::new(0, 0, 1, 1), [1.0, 1.0, 1.0, 1.0]);\n l.blend_if.set(0, [FULL, range([black, black], [white, white])]);\n d.layers.push(l);\n px(&d, 0, 0)[0] > 0.999 && px(&d, 0, 0)[2] > 0.999\n };\n // (colour hidden by a black point at `cut`, the next colour shown), single channels.\n for (cut, below, at) in [\n (20, [65, 0, 0], [66, 0, 0]),",
|
||
"expected_assertions": [
|
||
" assert!(!shown(below, cut, 255), \"{below:?} hidden by black {cut}\");\n assert!(shown(at, cut, 255), \"{at:?} shown by black {cut}\");\n }\n // The reporter's mixed colours, and the white point's half-down rounding.",
|
||
" assert!(shown(at, cut, 255), \"{at:?} shown by black {cut}\");\n }\n // The reporter's mixed colours, and the white point's half-down rounding.\n assert!(shown([123, 126, 151], 128, 255), \"127.85 is 128\");",
|
||
" assert!(shown([123, 126, 151], 128, 255), \"127.85 is 128\");\n assert!(shown([120, 129, 149], 0, 128), \"128.5 is 128\");\n assert!(!shown([121, 129, 149], 0, 128), \"128.8 is 129\");\n}",
|
||
" assert!(shown([120, 129, 149], 0, 128), \"128.5 is 128\");\n assert!(!shown([121, 129, 149], 0, 128), \"128.8 is 129\");\n}",
|
||
" assert!(!shown([121, 129, 149], 0, 128), \"128.8 is 129\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/fc0f7b1132f799b5bba7be642c9047499d95a887/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9589",
|
||
"pr": 9589,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-compose --locked adjustment_blend_if_judges_the_result_before_opacity -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked blend_if -- --nocapture"
|
||
],
|
||
"expected": "adjustment blend if judges the result before opacity; blend if",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-compose --locked adjustment_blend_if_judges_the_result_before_opacity -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked blend_if -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "adjustment_blend_if_judges_the_result_before_opacity",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked adjustment_blend_if_judges_the_result_before_opacity -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (black, white, want) in [(150u8, 255u8, [115, 128, 140]), (0, 150, [64, 128, 192])] {\n let mut d = Document::with_background(\"bi\", Size::new(1, 1), ColorMode::Rgb, SampleType::U8, Color::WHITE);\n d.layers.push(solid_layer(\"base\", Rect::new(0, 0, 1, 1), [64.0 / 255.0, 128.0 / 255.0, 192.0 / 255.0, 1.0]));\n let mut inv = Layer::new(\"invert\", LayerContent::Adjustment(Adjustment::Invert));\n inv.opacity = 0.4;\n inv.blend_if.set(1, [range([black, black], [white, white]), FULL]);\n d.layers.push(inv);\n let got: Vec<i32> = px(&d, 0, 0)[..3].iter().map(|v| (v * 255.0).round() as i32).collect();\n assert!(got.iter().zip(want).all(|(g, w)| (g - w).abs() <= 1), \"black {black} white {white}: {got:?} vs Photoshop {want:?}\");\n }\n}",
|
||
"expected_assertions": [
|
||
" assert!(got.iter().zip(want).all(|(g, w)| (g - w).abs() <= 1), \"black {black} white {white}: {got:?} vs Photoshop {want:?}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/da157945077190e550b53a5e14b0536f62761292/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "blend_if",
|
||
"path": "crates/gpu/tests/it/parity.rs",
|
||
"package": "photocraft-gpu",
|
||
"command": "cargo test -p photocraft-gpu --locked blend_if -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_doc::BlendRange;\n let Some(mut g) = gpu() else { return };\n let r = |b0: u8, b1: u8, w0: u8, w1: u8| BlendRange { black: [b0, b1], white: [w0, w1] };\n // (name, entry, [this layer, underlying], has a hard point)\n let cases: [(&str, usize, [BlendRange; 2], bool); 7] = [\n (\"gray this hard\", 0, [r(90, 90, 255, 255), BlendRange::FULL], true),\n (\"gray under split\", 0, [BlendRange::FULL, r(30, 140, 150, 230)], false),\n (\"red both\", 1, [r(0, 60, 200, 200), r(20, 20, 180, 250)], true),\n (\"red both split\", 1, [r(0, 60, 190, 230), r(10, 50, 180, 250)], false),\n (\"green white split\", 2, [r(0, 0, 100, 220), BlendRange::FULL], false),\n (\"blue under hard\", 3, [BlendRange::FULL, r(128, 128, 255, 255)], true),\n (\"everything hidden\", 0, [r(255, 255, 0, 0), BlendRange::FULL], true),",
|
||
"expected_assertions": [
|
||
" assert!(hits.prefix_hits > 0, \"{depth:?} {name}: the edit above reuses the lower stack\");\n\n // Masked, with channel restrictions.\n let mut m = l.clone();"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/da157945077190e550b53a5e14b0536f62761292/crates/gpu/tests/it/parity.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9595",
|
||
"pr": 9595,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-compose --locked pass_through_group_with_blend_if_is_isolated -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked pass_through_group_with_blend_if_is_isolated -- --nocapture"
|
||
],
|
||
"expected": "pass through group with blend if is isolated; pass through group with blend if is isolated",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-compose --locked pass_through_group_with_blend_if_is_isolated -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked pass_through_group_with_blend_if_is_isolated -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "pass_through_group_with_blend_if_is_isolated",
|
||
"path": "crates/compose/src/tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked pass_through_group_with_blend_if_is_isolated -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (gated, want) in [(true, [64, 128, 192]), (false, [191, 127, 63])] {\n let mut d = Document::with_background(\"pt\", Size::new(1, 1), ColorMode::Rgb, SampleType::U8, Color::WHITE);\n d.layers.push(solid_layer(\"base\", Rect::new(0, 0, 1, 1), [64.0 / 255.0, 128.0 / 255.0, 192.0 / 255.0, 1.0]));\n let mut g = Layer::group(\"group\", vec![Layer::new(\"invert\", LayerContent::Adjustment(Adjustment::Invert))]);\n g.blend = BlendMode::PassThrough;\n if gated {\n g.blend_if.set(1, [FULL, range([0, 0], [110, 110])]);\n }\n d.layers.push(g);\n let got: Vec<i32> = px(&d, 0, 0)[..3].iter().map(|v| (v * 255.0).round() as i32).collect();\n assert!(got.iter().zip(want).all(|(g, w)| (g - w).abs() <= 1), \"Blend If {gated}: {got:?} vs Photoshop {want:?}\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(got.iter().zip(want).all(|(g, w)| (g - w).abs() <= 1), \"Blend If {gated}: {got:?} vs Photoshop {want:?}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/75fa71a4f55a098061b12d91508b514565ab8dcf/crates/compose/src/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "pass_through_group_with_blend_if_is_isolated",
|
||
"path": "crates/gpu/tests/it/parity.rs",
|
||
"package": "photocraft-gpu",
|
||
"command": "cargo test -p photocraft-gpu --locked pass_through_group_with_blend_if_is_isolated -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_doc::BlendRange;\n let Some(mut g) = gpu() else { return };\n for gated in [true, false] {\n let mut d = base_doc(64, 48);\n d.layers[0] = noise_layer(\"bg\", PixelFormat::RGBA8, Rect::from_xywh(0, 0, 64, 48), 5, 1.0);\n let mut grp = Layer::group(\"group\", vec![Layer::new(\"inv\", LayerContent::Adjustment(Adjustment::Invert))]);\n grp.blend = BlendMode::PassThrough;\n if gated {\n grp.blend_if.set(1, [BlendRange::FULL, BlendRange { black: [0, 0], white: [110, 110] }]);\n }\n d.layers.push(grp);\n check(&mut g, &d, &format!(\"pass-through group, Blend If {gated}\"));",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/75fa71a4f55a098061b12d91508b514565ab8dcf/crates/gpu/tests/it/parity.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9651",
|
||
"pr": 9651,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-algo --locked matches_scalar_sharpen_bit_for_bit_across_layouts_edges_and_hdr -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked empty_channel_layout_remains_empty -- --nocapture"
|
||
],
|
||
"expected": "matches scalar sharpen bit for bit across layouts edges and hdr; empty channel layout remains empty",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-algo --locked matches_scalar_sharpen_bit_for_bit_across_layouts_edges_and_hdr -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked empty_channel_layout_remains_empty -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "matches_scalar_sharpen_bit_for_bit_across_layouts_edges_and_hdr",
|
||
"path": "crates/algo/tests/it/retouch_sharpen_exact.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked matches_scalar_sharpen_bit_for_bit_across_layouts_edges_and_hdr -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (w, h) in [(1, 1), (3, 7), (37, 29)] {\n for ch in 1..=5 {\n for alpha in std::iter::once(None).chain((0..ch).map(Some)) {\n let data: Vec<f32> = (0..w * h * ch)\n .map(|i| if Some(i % ch) == alpha { [0.0, 1e-8, 0.25, 0.75, 1.0][(i / ch) % 5] } else { ((i * 73 + 19) % 113) as f32 / 17.0 - 2.0 })\n .collect();\n for win in [(0, 0, w, h), (w / 2, h / 2, w, h), (0, 0, 1, 1), (0, 0, 0, h)] {\n for amount in [0.0, 0.5, 1.0, 2.5] {\n for protect_detail in [false, true] {\n let expected = scalar_local_sharpen(&data, w, h, ch, alpha, win, amount, protect_detail);\n let actual = local_sharpen(&data, w, h, ch, alpha, win, amount, protect_detail);\n assert_eq!(actual.len(), expected.len());",
|
||
"expected_assertions": [
|
||
" assert_eq!(actual.len(), expected.len());\n for (i, (a, b)) in actual.iter().zip(&expected).enumerate() {\n assert_eq!(\n a.to_bits(),",
|
||
" assert_eq!(\n a.to_bits(),\n b.to_bits(),\n \"{w}x{h} ch={ch} alpha={alpha:?} win={win:?} amount={amount} protect={protect_detail} sample={i}\""
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/67666bdf72a58066df868868cef82e5b9cc838de/crates/algo/tests/it/retouch_sharpen_exact.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "empty_channel_layout_remains_empty",
|
||
"path": "crates/algo/tests/it/retouch_sharpen_exact.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked empty_channel_layout_remains_empty -- --nocapture",
|
||
"fixture_and_action_excerpt": " assert!(local_sharpen(&[], 5, 5, 0, None, (0, 0, 5, 5), 1.0, true).is_empty());\n}",
|
||
"expected_assertions": [
|
||
" assert!(local_sharpen(&[], 5, 5, 0, None, (0, 0, 5, 5), 1.0, true).is_empty());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/67666bdf72a58066df868868cef82e5b9cc838de/crates/algo/tests/it/retouch_sharpen_exact.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9703",
|
||
"pr": 9703,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked a_new_adjustment_or_fill_layer_shows_its_settings_until_the_mask_thumbnail_is_clicked -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked adjustment_names_target_contents_instead_of_masks -- --nocapture"
|
||
],
|
||
"expected": "a new adjustment or fill layer shows its settings until the mask thumbnail is clicked; adjustment names target contents instead of masks",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked a_new_adjustment_or_fill_layer_shows_its_settings_until_the_mask_thumbnail_is_clicked -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked adjustment_names_target_contents_instead_of_masks -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "a_new_adjustment_or_fill_layer_shows_its_settings_until_the_mask_thumbnail_is_clicked",
|
||
"path": "crates/ui-egui/src/mask_thumbs_ui/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked a_new_adjustment_or_fill_layer_shows_its_settings_until_the_mask_thumbnail_is_clicked -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (command, settings) in [(\"layer.newAdjustmentLayer.curves\", Some(\"Reset to defaults\")), (\"layer.newFillLayer.solidColor\", None)] {\n let mut s = photocraft_engine::Session::new();\n s.execute(\"file.new\", json!({\"width\": 200, \"height\": 100})).unwrap();\n s.execute(\"layer.new.layer\", json!({})).unwrap();\n let mut h = harness(s, 0, 1.0, 290.0);\n let ctx = h.ctx.clone();\n let (req, _rx) = crate::control::ControlRequest::new(\"ui.set\", json!({\"dock\": {\"collapsed\": [\"color\", \"history\", \"navigator\"]}}));\n crate::control::handle(h.state_mut(), &ctx, &req);\n h.state_mut().run(command, json!({})).unwrap();\n h.run_steps(6);\n let id = h.state().session.active().unwrap().active_layer.unwrap().0;\n assert!(h.state().ui.mask_target, \"{command}: the new mask is targeted\");",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.mask_target, \"{command}: the new mask is targeted\");\n assert_eq!(crate::canvas::paint_target(h.state()), json!(\"mask\"), \"{command}: painting edits the mask\");\n assert!(h.query_all_by_label(\"Density\").next().is_none(), \"{command}: Properties shows the layer, not its mask\");\n if let Some(label) = settings {",
|
||
" assert_eq!(crate::canvas::paint_target(h.state()), json!(\"mask\"), \"{command}: painting edits the mask\");\n assert!(h.query_all_by_label(\"Density\").next().is_none(), \"{command}: Properties shows the layer, not its mask\");\n if let Some(label) = settings {\n assert!(h.query_all_by_label(label).next().is_some(), \"{command}: its settings show\");",
|
||
" assert!(h.query_all_by_label(\"Density\").next().is_none(), \"{command}: Properties shows the layer, not its mask\");\n if let Some(label) = settings {\n assert!(h.query_all_by_label(label).next().is_some(), \"{command}: its settings show\");\n }",
|
||
" assert!(h.query_all_by_label(label).next().is_some(), \"{command}: its settings show\");\n }\n // Clicking the row (not a thumbnail) keeps the settings.\n let row = h.get_by_label(&layer(&h, id).name).rect().center();",
|
||
" assert_eq!(h.state().ui.mask_target, command.starts_with(\"layer.newFillLayer.\"));\n assert!(!h.state().ui.vector_mask_target);\n assert!(h.query_all_by_label(\"Density\").next().is_none(), \"{command}: a row click keeps the settings\");\n // The mask thumbnail switches Properties to the mask.",
|
||
" assert!(!h.state().ui.vector_mask_target);\n assert!(h.query_all_by_label(\"Density\").next().is_none(), \"{command}: a row click keeps the settings\");\n // The mask thumbnail switches Properties to the mask.\n let r = mask_rect(&h, id, MaskKind::Pixel);",
|
||
" assert!(h.query_all_by_label(\"Density\").next().is_none(), \"{command}: a row click keeps the settings\");\n // The mask thumbnail switches Properties to the mask.\n let r = mask_rect(&h, id, MaskKind::Pixel);\n click_with(&mut h, r.center(), Modifiers::NONE);",
|
||
" assert!(h.state().ui.mask_target);\n assert!(h.query_all_by_label(\"Density\").next().is_some(), \"{command}: the mask thumbnail shows the mask controls\");\n if let Some(label) = settings {\n assert!(h.query_all_by_label(label).next().is_none());",
|
||
" assert!(h.query_all_by_label(\"Density\").next().is_some(), \"{command}: the mask thumbnail shows the mask controls\");\n if let Some(label) = settings {\n assert!(h.query_all_by_label(label).next().is_none());\n }",
|
||
" assert!(h.query_all_by_label(label).next().is_none());\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3605d30c38294c4d970e52f4a02f44f97e8bc1a9/crates/ui-egui/src/mask_thumbs_ui/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "adjustment_names_target_contents_instead_of_masks",
|
||
"path": "crates/ui-egui/src/mask_thumbs_ui/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked adjustment_names_target_contents_instead_of_masks -- --nocapture",
|
||
"fixture_and_action_excerpt": " for command in [\"layer.newAdjustmentLayer.hueSaturation\", \"layer.newAdjustmentLayer.curves\"] {\n for ppp in [1.0, 2.0] {\n let (mut s, _, other) = session();\n s.execute(command, json!({})).unwrap();\n let id = s.active().unwrap().active_layer.unwrap().0;\n let path = json!({\"subpaths\": [{\"knots\": [[20, 10], [120, 10], [120, 90], [20, 90]]}]});\n s.execute(\"layer.vectorMask.add\", json!({\"layer\": id, \"path\": path})).unwrap();\n let mut h = harness(s, 0, ppp, 360.0);\n for kind in [MaskKind::Pixel, MaskKind::Vector] {\n let at = mask_rect(&h, id, kind).center();\n click_with(&mut h, at, Modifiers::NONE);\n assert_eq!(h.state().ui.mask_target, kind == MaskKind::Pixel);",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().ui.mask_target, kind == MaskKind::Pixel);\n assert_eq!(h.state().ui.vector_mask_target, kind == MaskKind::Vector);\n let name = crate::layer_row_ui::recorded(&h.ctx).into_iter().find(|r| r.layer == id).unwrap().name.unwrap().center();\n click_with(&mut h, name, Modifiers::NONE);",
|
||
" assert_eq!(h.state().ui.vector_mask_target, kind == MaskKind::Vector);\n let name = crate::layer_row_ui::recorded(&h.ctx).into_iter().find(|r| r.layer == id).unwrap().name.unwrap().center();\n click_with(&mut h, name, Modifiers::NONE);\n assert!(!h.state().ui.mask_target && !h.state().ui.vector_mask_target, \"{command} @{ppp}x after {kind:?}\");",
|
||
" assert!(!h.state().ui.mask_target && !h.state().ui.vector_mask_target, \"{command} @{ppp}x after {kind:?}\");\n let thumb = crate::layer_row_ui::recorded(&h.ctx).into_iter().find(|r| r.layer == id).unwrap().thumbnail.unwrap();\n assert!(near(super::brackets(&h.ctx).unwrap(), thumb.expand(3.0)), \"the content thumbnail is selected\");\n assert_eq!(h.state().session.active().unwrap().active_layer.unwrap().0, id);",
|
||
" assert!(near(super::brackets(&h.ctx).unwrap(), thumb.expand(3.0)), \"the content thumbnail is selected\");\n assert_eq!(h.state().session.active().unwrap().active_layer.unwrap().0, id);\n }\n let name = crate::layer_row_ui::recorded(&h.ctx).into_iter().find(|r| r.layer == other).unwrap().name.unwrap().center();",
|
||
" assert_eq!(h.state().session.active().unwrap().active_layer.unwrap().0, id);\n }\n let name = crate::layer_row_ui::recorded(&h.ctx).into_iter().find(|r| r.layer == other).unwrap().name.unwrap().center();\n click_with(&mut h, name, Modifiers::NONE);",
|
||
" assert_eq!(h.state().session.active().unwrap().active_layer.unwrap().0, id);\n assert!(!h.state().ui.mask_target && !h.state().ui.vector_mask_target, \"{command} @{ppp}x from another layer\");\n assert_eq!(crate::canvas::paint_target(h.state()), json!(\"mask\"));\n let content = layer(&h, id).content;",
|
||
" assert!(!h.state().ui.mask_target && !h.state().ui.vector_mask_target, \"{command} @{ppp}x from another layer\");\n assert_eq!(crate::canvas::paint_target(h.state()), json!(\"mask\"));\n let content = layer(&h, id).content;\n h.state_mut().run(\"edit.fill\", json!({\"contents\": \"black\"})).unwrap();",
|
||
" assert_eq!(crate::canvas::paint_target(h.state()), json!(\"mask\"));\n let content = layer(&h, id).content;\n h.state_mut().run(\"edit.fill\", json!({\"contents\": \"black\"})).unwrap();\n assert_eq!(layer(&h, id).content, content, \"filling must preserve the adjustment or fill content\");",
|
||
" assert_eq!(layer(&h, id).content, content, \"filling must preserve the adjustment or fill content\");\n assert_eq!(layer(&h, id).mask.unwrap().surface.sample_channel(50, 50, 0), 0.0, \"Fill edits the mask\");\n assert!(!h.state().ui.mask_target && !h.state().ui.vector_mask_target, \"painting leaves the content thumbnail selected\");\n }",
|
||
" assert_eq!(layer(&h, id).mask.unwrap().surface.sample_channel(50, 50, 0), 0.0, \"Fill edits the mask\");\n assert!(!h.state().ui.mask_target && !h.state().ui.vector_mask_target, \"painting leaves the content thumbnail selected\");\n }\n }",
|
||
" assert!(!h.state().ui.mask_target && !h.state().ui.vector_mask_target, \"painting leaves the content thumbnail selected\");\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/3605d30c38294c4d970e52f4a02f44f97e8bc1a9/crates/ui-egui/src/mask_thumbs_ui/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-1991",
|
||
"pr": 1991,
|
||
"subsystem": "Actions and automation",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-automation --locked automation_rejects_ambient_path_commands_and_preferences -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked json_actions_round_trip_preserves_metadata -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked reimport_after_changing_button_color_keeps_names_unique -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked parents_before_children_are_retargeted_and_reimport_is_idempotent -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked invalid_json_params_and_nested_indices_fail_atomically -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked long_unicode_collision_names_remain_portable_and_idempotent -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked loading_json_actions_uses_engine_import_and_selects_the_new_action -- --nocapture"
|
||
],
|
||
"expected": "automation rejects ambient path commands and preferences; json actions round trip preserves metadata; reimport after changing button color keeps names unique; parents before children are retargeted and reimport is idempotent; invalid json params and nested indices fail atomically; long unicode collision names remain portable and idempotent; loading json actions uses engine import and selects the new action",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-automation --locked automation_rejects_ambient_path_commands_and_preferences -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked json_actions_round_trip_preserves_metadata -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked reimport_after_changing_button_color_keeps_names_unique -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked parents_before_children_are_retargeted_and_reimport_is_idempotent -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked invalid_json_params_and_nested_indices_fail_atomically -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked long_unicode_collision_names_remain_portable_and_idempotent -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked loading_json_actions_uses_engine_import_and_selects_the_new_action -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "automation_rejects_ambient_path_commands_and_preferences",
|
||
"path": "crates/automation/src/workspace.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked automation_rejects_ambient_path_commands_and_preferences -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (id, params) in [\n (\"brush.presets.importAbr\", serde_json::json!({\"path\": \"/outside/set.abr\"})),\n (\"brush.presets.importImage\", serde_json::json!({\"path\": \"/outside/tip.png\"})),\n (\"gradient.presets.importGrd\", serde_json::json!({\"path\": \"/outside/set.grd\"})),\n (\"plugin.install\", serde_json::json!({\"path\": \"/outside/plugin.wasm\"})),\n (\"plugin.reload\", serde_json::json!({\"path\": \"/outside/plugins\"})),\n (\"plugin.reload\", serde_json::json!({})),\n (\"plugin.install\", serde_json::json!({\"path\": \" \"})),\n (\"swatches.import\", serde_json::json!({\"path\": \"/outside/set.aco\"})),\n (\"swatches.export\", serde_json::json!({\"path\": \"/outside/set.ase\"})),\n (\"actions.load\", serde_json::json!({\"path\": \"/outside/set.atn\"})),\n (\"actions.save\", serde_json::json!({\"path\": \"/outside/set.atn\"})),",
|
||
"expected_assertions": [
|
||
" assert!(authorize_engine_command(id, ¶ms).is_err(), \"{id}: {params}\");\n }\n for (id, params) in [\n (\"brush.presets.importAbr\", serde_json::json!({\"data\": \"QUJD\"})),",
|
||
" assert!(authorize_engine_command(id, ¶ms).is_ok(), \"{id}: {params}\");\n }\n for path in [\n \"\",",
|
||
" assert!(authorize_engine_command(\"prefs.set\", &serde_json::json!({\"path\": path, \"value\": {}})).is_err(), \"{path}\");\n }\n assert!(\n authorize_engine_command(\"prefs.set\", &serde_json::json!({\"values\": {\"interface.language\": \"fr\", \"historyLog.filePath\": \"/outside/log\"}})).is_err()",
|
||
" assert!(\n authorize_engine_command(\"prefs.set\", &serde_json::json!({\"values\": {\"interface.language\": \"fr\", \"historyLog.filePath\": \"/outside/log\"}})).is_err()\n );\n assert!(authorize_engine_command(\"prefs.set\", &serde_json::json!({\"path\": \"interface.language\", \"value\": \"fr\"})).is_ok());",
|
||
" assert!(authorize_engine_command(\"prefs.set\", &serde_json::json!({\"path\": \"interface.language\", \"value\": \"fr\"})).is_ok());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/202266b90613280e16ae285b53dd4e10d5f0c7ac/crates/automation/src/workspace.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "json_actions_round_trip_preserves_metadata",
|
||
"path": "crates/engine/src/actions_cmds/json_file.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked json_actions_round_trip_preserves_metadata -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n let mut action = Action::new(\"Draw\", vec![(\"layer.new.layer\".into(), json!({}))]);\n action.disabled.insert(0);\n action.dialogs.insert(0);\n action.set = Some(\"Painting\".into());\n s.actions.list.push(action.clone());\n let exported = s.execute(\"actions.export\", json!({})).unwrap();\n s.actions.list.clear();\n let result = s.execute(\"actions.import\", json!({\"data\": exported[\"data\"]})).unwrap();\n assert_eq!(result[\"imported\"], 1);\n assert_eq!(s.actions.list, [action]);\n let rev = s.actions.rev;",
|
||
"expected_assertions": [
|
||
" assert_eq!(result[\"imported\"], 1);\n assert_eq!(s.actions.list, [action]);\n let rev = s.actions.rev;\n assert_eq!(s.execute(\"actions.import\", json!({\"data\": exported[\"data\"]})).unwrap()[\"imported\"], 0);",
|
||
" assert_eq!(s.actions.list, [action]);\n let rev = s.actions.rev;\n assert_eq!(s.execute(\"actions.import\", json!({\"data\": exported[\"data\"]})).unwrap()[\"imported\"], 0);\n assert_eq!(s.actions.rev, rev);",
|
||
" assert_eq!(s.execute(\"actions.import\", json!({\"data\": exported[\"data\"]})).unwrap()[\"imported\"], 0);\n assert_eq!(s.actions.rev, rev);\n }",
|
||
" assert_eq!(s.actions.rev, rev);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/202266b90613280e16ae285b53dd4e10d5f0c7ac/crates/engine/src/actions_cmds/json_file.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "reimport_after_changing_button_color_keeps_names_unique",
|
||
"path": "crates/engine/src/actions_cmds/json_file.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked reimport_after_changing_button_color_keeps_names_unique -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.actions.list.push(Action::new(\"Draw\", vec![]));\n let data = s.execute(\"actions.export\", json!({})).unwrap()[\"data\"].clone();\n s.execute(\"actions.setColor\", json!({\"action\": \"Draw\", \"color\": \"red\"})).unwrap();\n let params = json!({\"data\": data});\n assert_eq!(s.execute(\"actions.import\", params.clone()).unwrap()[\"imported\"], 1);\n assert_eq!(s.actions.list[0].name, \"Draw\");\n assert_eq!(s.actions.list[0].color, \"red\");\n assert_eq!(s.actions.list[1].name, \"Draw (Imported 2)\");\n assert!(s.actions.list[1].color.is_empty());\n let before = s.actions.clone();\n assert_eq!(s.execute(\"actions.import\", params).unwrap()[\"imported\"], 0);",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.execute(\"actions.import\", params.clone()).unwrap()[\"imported\"], 1);\n assert_eq!(s.actions.list[0].name, \"Draw\");\n assert_eq!(s.actions.list[0].color, \"red\");\n assert_eq!(s.actions.list[1].name, \"Draw (Imported 2)\");",
|
||
" assert_eq!(s.actions.list[0].name, \"Draw\");\n assert_eq!(s.actions.list[0].color, \"red\");\n assert_eq!(s.actions.list[1].name, \"Draw (Imported 2)\");\n assert!(s.actions.list[1].color.is_empty());",
|
||
" assert_eq!(s.actions.list[0].color, \"red\");\n assert_eq!(s.actions.list[1].name, \"Draw (Imported 2)\");\n assert!(s.actions.list[1].color.is_empty());\n let before = s.actions.clone();",
|
||
" assert_eq!(s.actions.list[1].name, \"Draw (Imported 2)\");\n assert!(s.actions.list[1].color.is_empty());\n let before = s.actions.clone();\n assert_eq!(s.execute(\"actions.import\", params).unwrap()[\"imported\"], 0);",
|
||
" assert!(s.actions.list[1].color.is_empty());\n let before = s.actions.clone();\n assert_eq!(s.execute(\"actions.import\", params).unwrap()[\"imported\"], 0);\n assert_eq!(s.actions, before);",
|
||
" assert_eq!(s.execute(\"actions.import\", params).unwrap()[\"imported\"], 0);\n assert_eq!(s.actions, before);\n }",
|
||
" assert_eq!(s.actions, before);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/202266b90613280e16ae285b53dd4e10d5f0c7ac/crates/engine/src/actions_cmds/json_file.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "parents_before_children_are_retargeted_and_reimport_is_idempotent",
|
||
"path": "crates/engine/src/actions_cmds/json_file.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked parents_before_children_are_retargeted_and_reimport_is_idempotent -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.actions.list.push(Action::new(\"Child\", vec![]));\n let file = ActionsFile {\n version: 1,\n actions: vec![\n Action::new(\"Parent\", vec![(\"actions.play\".into(), json!({\"action\": 1}))]),\n Action::new(\"Child\", vec![(\"layer.new.layer\".into(), json!({}))]),\n Action::new(\"Named\", vec![(\"actions.play\".into(), json!({\"action\": \"Child\"}))]),\n ],\n };\n let params = json!({\"data\": serde_json::to_string(&file).unwrap()});\n assert_eq!(s.execute(\"actions.import\", params.clone()).unwrap()[\"imported\"], 3);",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.execute(\"actions.import\", params.clone()).unwrap()[\"imported\"], 3);\n assert_eq!(s.actions.list[1].steps[0].1[\"action\"], \"Child (Imported 2)\");\n assert_eq!(s.actions.list[2].name, \"Child (Imported 2)\");\n assert_eq!(s.actions.list[3].steps[0].1[\"action\"], \"Child (Imported 2)\");",
|
||
" assert_eq!(s.actions.list[1].steps[0].1[\"action\"], \"Child (Imported 2)\");\n assert_eq!(s.actions.list[2].name, \"Child (Imported 2)\");\n assert_eq!(s.actions.list[3].steps[0].1[\"action\"], \"Child (Imported 2)\");\n let before = s.actions.clone();",
|
||
" assert_eq!(s.actions.list[2].name, \"Child (Imported 2)\");\n assert_eq!(s.actions.list[3].steps[0].1[\"action\"], \"Child (Imported 2)\");\n let before = s.actions.clone();\n assert_eq!(s.execute(\"actions.import\", params).unwrap()[\"imported\"], 0);",
|
||
" assert_eq!(s.actions.list[3].steps[0].1[\"action\"], \"Child (Imported 2)\");\n let before = s.actions.clone();\n assert_eq!(s.execute(\"actions.import\", params).unwrap()[\"imported\"], 0);\n assert_eq!(s.actions, before);",
|
||
" assert_eq!(s.execute(\"actions.import\", params).unwrap()[\"imported\"], 0);\n assert_eq!(s.actions, before);\n }",
|
||
" assert_eq!(s.actions, before);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/202266b90613280e16ae285b53dd4e10d5f0c7ac/crates/engine/src/actions_cmds/json_file.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "invalid_json_params_and_nested_indices_fail_atomically",
|
||
"path": "crates/engine/src/actions_cmds/json_file.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked invalid_json_params_and_nested_indices_fail_atomically -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.actions.list.push(Action::new(\"Keep\", vec![]));\n let before = s.actions.clone();\n for p in [Value::Null, json!([]), json!({\"data\": true}), json!({\"data\": \"invalid\"}), json!({\"data\": \"{\\\"version\\\":2,\\\"actions\\\":[]}\"})] {\n assert!(s.execute(\"actions.import\", p).is_err());\n assert_eq!(s.actions, before);\n }\n for target in [json!(-1), json!(0.5), json!(1), Value::Null] {\n let file = ActionsFile { version: 1, actions: vec![Action::new(\"A\", vec![(\"actions.play\".into(), json!({\"action\": target}))])] };\n assert!(s.execute(\"actions.import\", json!({\"data\": serde_json::to_string(&file).unwrap()})).is_err());\n assert_eq!(s.actions, before);\n }",
|
||
"expected_assertions": [
|
||
" assert!(s.execute(\"actions.import\", p).is_err());\n assert_eq!(s.actions, before);\n }\n for target in [json!(-1), json!(0.5), json!(1), Value::Null] {",
|
||
" assert_eq!(s.actions, before);\n }\n for target in [json!(-1), json!(0.5), json!(1), Value::Null] {\n let file = ActionsFile { version: 1, actions: vec![Action::new(\"A\", vec![(\"actions.play\".into(), json!({\"action\": target}))])] };",
|
||
" assert!(s.execute(\"actions.import\", json!({\"data\": serde_json::to_string(&file).unwrap()})).is_err());\n assert_eq!(s.actions, before);\n }\n assert!(s.execute(\"actions.export\", json!({\"path\": 1})).is_err());",
|
||
" assert_eq!(s.actions, before);\n }\n assert!(s.execute(\"actions.export\", json!({\"path\": 1})).is_err());\n s.actions.recording = Some((0, 0));",
|
||
" assert!(s.execute(\"actions.export\", json!({\"path\": 1})).is_err());\n s.actions.recording = Some((0, 0));\n assert!(s.execute(\"actions.import\", json!({\"data\": \"{}\"})).is_err());\n assert!(s.execute(\"actions.export\", json!({})).is_err());",
|
||
" assert!(s.execute(\"actions.import\", json!({\"data\": \"{}\"})).is_err());\n assert!(s.execute(\"actions.export\", json!({})).is_err());\n assert_eq!(s.actions.list, before.list);\n }",
|
||
" assert!(s.execute(\"actions.export\", json!({})).is_err());\n assert_eq!(s.actions.list, before.list);\n }",
|
||
" assert_eq!(s.actions.list, before.list);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/202266b90613280e16ae285b53dd4e10d5f0c7ac/crates/engine/src/actions_cmds/json_file.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "long_unicode_collision_names_remain_portable_and_idempotent",
|
||
"path": "crates/engine/src/actions_cmds/json_file.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked long_unicode_collision_names_remain_portable_and_idempotent -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n let name = \"界\".repeat(85);\n s.actions.list.push(Action::new(&name, vec![]));\n let file = ActionsFile { version: 1, actions: vec![Action::new(&name, vec![(\"select.all\".into(), json!({}))])] };\n let params = json!({\"data\": serde_json::to_string(&file).unwrap()});\n assert_eq!(s.execute(\"actions.import\", params.clone()).unwrap()[\"imported\"], 1);\n assert!(s.actions.list[1].name.len() <= MAX_NAME_BYTES);\n assert_eq!(s.execute(\"actions.import\", params).unwrap()[\"imported\"], 0);\n assert!(s.execute(\"actions.export\", json!({})).is_ok());\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.execute(\"actions.import\", params.clone()).unwrap()[\"imported\"], 1);\n assert!(s.actions.list[1].name.len() <= MAX_NAME_BYTES);\n assert_eq!(s.execute(\"actions.import\", params).unwrap()[\"imported\"], 0);\n assert!(s.execute(\"actions.export\", json!({})).is_ok());",
|
||
" assert!(s.actions.list[1].name.len() <= MAX_NAME_BYTES);\n assert_eq!(s.execute(\"actions.import\", params).unwrap()[\"imported\"], 0);\n assert!(s.execute(\"actions.export\", json!({})).is_ok());\n }",
|
||
" assert_eq!(s.execute(\"actions.import\", params).unwrap()[\"imported\"], 0);\n assert!(s.execute(\"actions.export\", json!({})).is_ok());\n }",
|
||
" assert!(s.execute(\"actions.export\", json!({})).is_ok());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/202266b90613280e16ae285b53dd4e10d5f0c7ac/crates/engine/src/actions_cmds/json_file.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "loading_json_actions_uses_engine_import_and_selects_the_new_action",
|
||
"path": "crates/ui-egui/src/actions.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked loading_json_actions_uses_engine_import_and_selects_the_new_action -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n let action = Action::new(\"Portable\", vec![(\"select.all\".into(), json!({}))]);\n let file = actions_cmds::ActionsFile { version: 1, actions: vec![action.clone()] };\n let bytes = serde_json::to_vec(&file).unwrap();\n assert_eq!(load_bytes(&mut app, \"Actions.JSON\", &bytes).unwrap()[\"imported\"], 1);\n assert_eq!(app.session.actions.list, [action]);\n assert_eq!(app.ui.actions.selected, Some(0));\n assert_eq!(app.ui.actions.selected_step, None);\n assert!(app.ui.actions.expanded[0]);\n assert!(!app.ui.status_error);\n let before = app.session.actions.clone();\n assert_eq!(load_bytes(&mut app, \"Actions.json\", &bytes).unwrap()[\"imported\"], 0);",
|
||
"expected_assertions": [
|
||
" assert_eq!(load_bytes(&mut app, \"Actions.JSON\", &bytes).unwrap()[\"imported\"], 1);\n assert_eq!(app.session.actions.list, [action]);\n assert_eq!(app.ui.actions.selected, Some(0));\n assert_eq!(app.ui.actions.selected_step, None);",
|
||
" assert_eq!(app.session.actions.list, [action]);\n assert_eq!(app.ui.actions.selected, Some(0));\n assert_eq!(app.ui.actions.selected_step, None);\n assert!(app.ui.actions.expanded[0]);",
|
||
" assert_eq!(app.ui.actions.selected, Some(0));\n assert_eq!(app.ui.actions.selected_step, None);\n assert!(app.ui.actions.expanded[0]);\n assert!(!app.ui.status_error);",
|
||
" assert_eq!(app.ui.actions.selected_step, None);\n assert!(app.ui.actions.expanded[0]);\n assert!(!app.ui.status_error);\n let before = app.session.actions.clone();",
|
||
" assert!(app.ui.actions.expanded[0]);\n assert!(!app.ui.status_error);\n let before = app.session.actions.clone();\n assert_eq!(load_bytes(&mut app, \"Actions.json\", &bytes).unwrap()[\"imported\"], 0);",
|
||
" assert!(!app.ui.status_error);\n let before = app.session.actions.clone();\n assert_eq!(load_bytes(&mut app, \"Actions.json\", &bytes).unwrap()[\"imported\"], 0);\n assert_eq!(app.session.actions, before);",
|
||
" assert_eq!(load_bytes(&mut app, \"Actions.json\", &bytes).unwrap()[\"imported\"], 0);\n assert_eq!(app.session.actions, before);\n }",
|
||
" assert_eq!(app.session.actions, before);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/202266b90613280e16ae285b53dd4e10d5f0c7ac/crates/ui-egui/src/actions.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-3142",
|
||
"pr": 3142,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-raw --locked measured_image_areas_crop_the_borders_without_touching_the_rest -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked encrypted_applied_white_balance_and_black_reach_the_developer -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked plain_levels_win_and_invalid_encrypted_levels_are_ignored -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked hostile_private_metadata_is_bounded_and_optional -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked measured_keystream_recurrence_and_unencrypted_tail -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked decode_matches_the_measured_oracles -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked developing_produces_the_crop_in_16bit_rgb -- --nocapture"
|
||
],
|
||
"expected": "measured image areas crop the borders without touching the rest; encrypted applied white balance and black reach the developer; plain levels win and invalid encrypted levels are ignored; hostile private metadata is bounded and optional; measured keystream recurrence and unencrypted tail; decode matches the measured oracles; developing produces the crop in 16bit rgb",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-raw --locked measured_image_areas_crop_the_borders_without_touching_the_rest -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked encrypted_applied_white_balance_and_black_reach_the_developer -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked plain_levels_win_and_invalid_encrypted_levels_are_ignored -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked hostile_private_metadata_is_bounded_and_optional -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked measured_keystream_recurrence_and_unencrypted_tail -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked decode_matches_the_measured_oracles -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked developing_produces_the_crop_in_16bit_rgb -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "measured_image_areas_crop_the_borders_without_touching_the_rest",
|
||
"path": "crates/raw/src/cameras.rs",
|
||
"package": "photocraft-raw",
|
||
"command": "cargo test -p photocraft-raw --locked measured_image_areas_crop_the_borders_without_touching_the_rest -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = nef(\"NIKON D800E\", 7424, 4924);\n apply(&mut s);\n assert_eq!(s.crop, Rect::new(8, 6, 7360, 4912));\n // Only the image area is measured: levels, colour and tone stay untouched.\n assert!(s.color.calibrations.is_empty() && s.tone_curve.is_empty());\n assert_eq!(s.white, [16383.0; 3]);\n\n let mut s = sensor(\"SONY\", \"ILCE-7\", 6048, 4024);\n apply(&mut s);\n assert_eq!(s.crop, Rect::new(12, 12, 6000, 4000));\n\n let mut s = sensor(\"SONY\", \"ILCE-6000\", 6048, 4024);",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.crop, Rect::new(8, 6, 7360, 4912));\n // Only the image area is measured: levels, colour and tone stay untouched.\n assert!(s.color.calibrations.is_empty() && s.tone_curve.is_empty());\n assert_eq!(s.white, [16383.0; 3]);",
|
||
" assert!(s.color.calibrations.is_empty() && s.tone_curve.is_empty());\n assert_eq!(s.white, [16383.0; 3]);\n\n let mut s = sensor(\"SONY\", \"ILCE-7\", 6048, 4024);",
|
||
" assert_eq!(s.white, [16383.0; 3]);\n\n let mut s = sensor(\"SONY\", \"ILCE-7\", 6048, 4024);\n apply(&mut s);",
|
||
" assert_eq!(s.crop, Rect::new(12, 12, 6000, 4000));\n\n let mut s = sensor(\"SONY\", \"ILCE-6000\", 6048, 4024);\n apply(&mut s);",
|
||
" assert_eq!(s.crop, Rect::new(12, 12, 6000, 4000));\n assert!(s.color.calibrations.is_empty() && s.tone_curve.is_empty());\n // A file's explicit crop wins, including a different in-camera aspect ratio.\n s.crop = Rect::new(12, 324, 6000, 3376);",
|
||
" assert!(s.color.calibrations.is_empty() && s.tone_curve.is_empty());\n // A file's explicit crop wins, including a different in-camera aspect ratio.\n s.crop = Rect::new(12, 324, 6000, 3376);\n apply(&mut s);",
|
||
" assert_eq!(s.crop, Rect::new(12, 324, 6000, 3376));\n\n let mut s = sensor(\"SONY\", \"ILCE-6000\", 3024, 2012);\n apply(&mut s);",
|
||
" assert_eq!(s.crop, Rect::new(0, 0, 3024, 2012));\n\n // Another size or model of the same maker is left alone.\n let mut s = nef(\"NIKON D800E\", 2496, 1646);",
|
||
" assert_eq!(s.crop, Rect::new(0, 0, 2496, 1646));\n let mut s = nef(\"NIKON D800\", 7424, 4924);\n apply(&mut s);\n assert_eq!(s.crop, Rect::new(0, 0, 7424, 4924));",
|
||
" assert_eq!(s.crop, Rect::new(0, 0, 7424, 4924));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2ed234e654e574109ffcdb9756f8e8d1b8a00b2/crates/raw/src/cameras.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "encrypted_applied_white_balance_and_black_reach_the_developer",
|
||
"path": "crates/raw/src/sony_metadata.rs",
|
||
"package": "photocraft-raw",
|
||
"command": "cargo test -p photocraft-raw --locked encrypted_applied_white_balance_and_black_reach_the_developer -- --nocapture",
|
||
"fixture_and_action_excerpt": " for be in [false, true] {\n let bytes = fixture(be, false, [512, 513, 514, 515], [3072, 1024, 1024, 2048]);\n let s = decode(&bytes, &Limits::default()).unwrap();\n assert_eq!(s.format, RawFormat::Arw);\n assert_eq!(s.camera_wb, Some([3.0, 1.0, 2.0]));\n assert_eq!(s.black.values, vec![512.0, 513.0, 514.0, 515.0]);\n let dev = develop_sensor(&s, &DevelopOptions::default()).unwrap();\n assert_eq!(dev.info.wb_multipliers, [3.0, 1.0, 2.0]);\n assert!(!dev.warnings.iter().any(|w| w.contains(\"grey world\") || w.contains(\"assumed 0\")));\n let explicit = develop_sensor(&s, &DevelopOptions { white_balance: WhiteBalance::Multipliers([3.0, 1.0, 2.0]), ..Default::default() }).unwrap();\n assert_eq!(dev.rgb, explicit.rgb);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.format, RawFormat::Arw);\n assert_eq!(s.camera_wb, Some([3.0, 1.0, 2.0]));\n assert_eq!(s.black.values, vec![512.0, 513.0, 514.0, 515.0]);\n let dev = develop_sensor(&s, &DevelopOptions::default()).unwrap();",
|
||
" assert_eq!(s.camera_wb, Some([3.0, 1.0, 2.0]));\n assert_eq!(s.black.values, vec![512.0, 513.0, 514.0, 515.0]);\n let dev = develop_sensor(&s, &DevelopOptions::default()).unwrap();\n assert_eq!(dev.info.wb_multipliers, [3.0, 1.0, 2.0]);",
|
||
" assert_eq!(s.black.values, vec![512.0, 513.0, 514.0, 515.0]);\n let dev = develop_sensor(&s, &DevelopOptions::default()).unwrap();\n assert_eq!(dev.info.wb_multipliers, [3.0, 1.0, 2.0]);\n assert!(!dev.warnings.iter().any(|w| w.contains(\"grey world\") || w.contains(\"assumed 0\")));",
|
||
" assert_eq!(dev.info.wb_multipliers, [3.0, 1.0, 2.0]);\n assert!(!dev.warnings.iter().any(|w| w.contains(\"grey world\") || w.contains(\"assumed 0\")));\n let explicit = develop_sensor(&s, &DevelopOptions { white_balance: WhiteBalance::Multipliers([3.0, 1.0, 2.0]), ..Default::default() }).unwrap();\n assert_eq!(dev.rgb, explicit.rgb);",
|
||
" assert!(!dev.warnings.iter().any(|w| w.contains(\"grey world\") || w.contains(\"assumed 0\")));\n let explicit = develop_sensor(&s, &DevelopOptions { white_balance: WhiteBalance::Multipliers([3.0, 1.0, 2.0]), ..Default::default() }).unwrap();\n assert_eq!(dev.rgb, explicit.rgb);\n }",
|
||
" assert_eq!(dev.rgb, explicit.rgb);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2ed234e654e574109ffcdb9756f8e8d1b8a00b2/crates/raw/src/sony_metadata.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "plain_levels_win_and_invalid_encrypted_levels_are_ignored",
|
||
"path": "crates/raw/src/sony_metadata.rs",
|
||
"package": "photocraft-raw",
|
||
"command": "cargo test -p photocraft-raw --locked plain_levels_win_and_invalid_encrypted_levels_are_ignored -- --nocapture",
|
||
"fixture_and_action_excerpt": " let s = decode(&fixture(false, true, [800; 4], [3072, 1024, 1024, 2048]), &Limits::default()).unwrap();\n assert_eq!(s.camera_wb, Some([2.0, 1.0, 1.5]));\n assert_eq!(s.black.values, vec![600.0; 4]);\n let mut broken_plain = fixture(false, true, [800; 4], [3072, 1024, 1024, 2048]);\n let t = Tiff::new(&broken_plain).unwrap();\n let raw = t.all_ifds().into_iter().find(|i| i.has(0x7313)).unwrap();\n let at = raw.get(0x7313).unwrap().at;\n broken_plain[at..at + 8].fill(0);\n let s = decode(&broken_plain, &Limits::default()).unwrap();\n assert_eq!(s.camera_wb, Some([3.0, 1.0, 2.0]));\n assert_eq!(s.black.values, vec![600.0; 4]);\n for wb in [[0, 0, 0, 0], [65535, 1024, 1024, 2048], [30000, 1024, 1024, 2048], [3072, 0, 0, 2048]] {",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.camera_wb, Some([2.0, 1.0, 1.5]));\n assert_eq!(s.black.values, vec![600.0; 4]);\n let mut broken_plain = fixture(false, true, [800; 4], [3072, 1024, 1024, 2048]);\n let t = Tiff::new(&broken_plain).unwrap();",
|
||
" assert_eq!(s.black.values, vec![600.0; 4]);\n let mut broken_plain = fixture(false, true, [800; 4], [3072, 1024, 1024, 2048]);\n let t = Tiff::new(&broken_plain).unwrap();\n let raw = t.all_ifds().into_iter().find(|i| i.has(0x7313)).unwrap();",
|
||
" assert_eq!(s.camera_wb, Some([3.0, 1.0, 2.0]));\n assert_eq!(s.black.values, vec![600.0; 4]);\n for wb in [[0, 0, 0, 0], [65535, 1024, 1024, 2048], [30000, 1024, 1024, 2048], [3072, 0, 0, 2048]] {\n let s = decode(&fixture(false, false, [65535; 4], wb), &Limits::default()).unwrap();",
|
||
" assert_eq!(s.black.values, vec![600.0; 4]);\n for wb in [[0, 0, 0, 0], [65535, 1024, 1024, 2048], [30000, 1024, 1024, 2048], [3072, 0, 0, 2048]] {\n let s = decode(&fixture(false, false, [65535; 4], wb), &Limits::default()).unwrap();\n assert_eq!(s.camera_wb, None);",
|
||
" assert_eq!(s.camera_wb, None);\n assert_eq!(s.black.values, vec![0.0]);\n }\n }",
|
||
" assert_eq!(s.black.values, vec![0.0]);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2ed234e654e574109ffcdb9756f8e8d1b8a00b2/crates/raw/src/sony_metadata.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "hostile_private_metadata_is_bounded_and_optional",
|
||
"path": "crates/raw/src/sony_metadata.rs",
|
||
"package": "photocraft-raw",
|
||
"command": "cargo test -p photocraft-raw --locked hostile_private_metadata_is_bounded_and_optional -- --nocapture",
|
||
"fixture_and_action_excerpt": " let bytes = fixture(false, false, [512; 4], [3072, 1024, 1024, 2048]);\n for n in 0..bytes.len() {\n if let Some(t) = Tiff::new(&bytes[..n]) {\n let _ = read(&t, &Limits::default());\n }\n }\n let t = Tiff::new(&bytes).unwrap();\n assert!(read(&t, &Limits { max_alloc: 2000, ..Default::default() }).is_none());\n let root = t.ifd_at(t.first_ifd, 0).unwrap();\n let private = t.ifd_at(t.u32_at(root.get(PRIVATE_DATA).unwrap().at).unwrap() as usize, 0).unwrap();\n for (at, value) in [(private.get(KEY).unwrap().at, 0), (private.get(LENGTH).unwrap().at, u32::MAX), (private.get(OFFSET).unwrap().at, u32::MAX)] {\n let mut corrupt = bytes.clone();",
|
||
"expected_assertions": [
|
||
" assert!(read(&t, &Limits { max_alloc: 2000, ..Default::default() }).is_none());\n let root = t.ifd_at(t.first_ifd, 0).unwrap();\n let private = t.ifd_at(t.u32_at(root.get(PRIVATE_DATA).unwrap().at).unwrap() as usize, 0).unwrap();\n for (at, value) in [(private.get(KEY).unwrap().at, 0), (private.get(LENGTH).unwrap().at, u32::MAX), (private.get(OFFSET).unwrap().at, u32::MAX)] {",
|
||
" assert!(read(&Tiff::new(&corrupt).unwrap(), &Limits::default()).is_none());\n let s = decode(&corrupt, &Limits::default()).unwrap();\n assert_eq!(s.camera_wb, None);\n }",
|
||
" assert_eq!(s.camera_wb, None);\n }\n let start = t.tag_uint(&private, OFFSET).unwrap() as usize;\n let len = t.tag_uint(&private, LENGTH).unwrap() as usize;",
|
||
" assert!(read(&Tiff::new(&corrupt).unwrap(), &Limits::default()).unwrap().wb.is_none());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2ed234e654e574109ffcdb9756f8e8d1b8a00b2/crates/raw/src/sony_metadata.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "measured_keystream_recurrence_and_unencrypted_tail",
|
||
"path": "crates/raw/src/sony_metadata.rs",
|
||
"package": "photocraft-raw",
|
||
"command": "cargo test -p photocraft-raw --locked measured_keystream_recurrence_and_unencrypted_tail -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut zero = vec![0; 14239 * 4 + 2];\n decipher(&mut zero);\n assert_eq!(&zero[..4], &[0x54, 0xc2, 0xc4, 0xd6]);\n // Words recovered independently from all three oracle dumps, including ring wrap\n // and the final complete word of a real metadata block.\n assert_eq!(&zero[127 * 4..128 * 4], &[0x86, 0xbe, 0x2e, 0x12]);\n assert_eq!(&zero[255 * 4..256 * 4], &[0xc9, 0x1a, 0x54, 0xc4]);\n assert_eq!(&zero[14238 * 4..14239 * 4], &[0xb9, 0xd3, 0x6e, 0xab]);\n assert_eq!(&zero[14239 * 4..], &[0, 0]);\n decipher(&mut zero);\n assert!(zero.iter().all(|&b| b == 0));\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(&zero[..4], &[0x54, 0xc2, 0xc4, 0xd6]);\n // Words recovered independently from all three oracle dumps, including ring wrap\n // and the final complete word of a real metadata block.\n assert_eq!(&zero[127 * 4..128 * 4], &[0x86, 0xbe, 0x2e, 0x12]);",
|
||
" assert_eq!(&zero[127 * 4..128 * 4], &[0x86, 0xbe, 0x2e, 0x12]);\n assert_eq!(&zero[255 * 4..256 * 4], &[0xc9, 0x1a, 0x54, 0xc4]);\n assert_eq!(&zero[14238 * 4..14239 * 4], &[0xb9, 0xd3, 0x6e, 0xab]);\n assert_eq!(&zero[14239 * 4..], &[0, 0]);",
|
||
" assert_eq!(&zero[255 * 4..256 * 4], &[0xc9, 0x1a, 0x54, 0xc4]);\n assert_eq!(&zero[14238 * 4..14239 * 4], &[0xb9, 0xd3, 0x6e, 0xab]);\n assert_eq!(&zero[14239 * 4..], &[0, 0]);\n decipher(&mut zero);",
|
||
" assert_eq!(&zero[14238 * 4..14239 * 4], &[0xb9, 0xd3, 0x6e, 0xab]);\n assert_eq!(&zero[14239 * 4..], &[0, 0]);\n decipher(&mut zero);\n assert!(zero.iter().all(|&b| b == 0));",
|
||
" assert_eq!(&zero[14239 * 4..], &[0, 0]);\n decipher(&mut zero);\n assert!(zero.iter().all(|&b| b == 0));\n }",
|
||
" assert!(zero.iter().all(|&b| b == 0));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2ed234e654e574109ffcdb9756f8e8d1b8a00b2/crates/raw/src/sony_metadata.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "decode_matches_the_measured_oracles",
|
||
"path": "crates/raw/tests/raw_corpus.rs",
|
||
"package": "photocraft-raw",
|
||
"command": "cargo test -p photocraft-raw --locked decode_matches_the_measured_oracles -- --nocapture",
|
||
"fixture_and_action_excerpt": " for w in WANTS {\n let bytes = std::fs::read(pixls(w.file)).unwrap_or_else(|e| panic!(\"{}: {e}\", w.file));\n let s = photocraft_raw::decode(&bytes, &Limits::default()).unwrap_or_else(|e| panic!(\"{}: {e}\", w.file));\n assert_eq!(s.format, w.format, \"{}\", w.file);\n assert_eq!(s.make.as_deref(), Some(w.make), \"{}\", w.file);\n assert_eq!(s.model.as_deref(), Some(w.model), \"{}\", w.file);\n assert_eq!((s.width, s.height), w.size, \"{}\", w.file);\n let cfa = s.cfa.as_ref().unwrap_or_else(|| panic!(\"{}: no CFA\", w.file));\n assert_eq!(cfa.colors, w.cfa, \"{}\", w.file);\n assert_eq!(s.black.values, w.black, \"{}\", w.file);\n if w.file == \"DSC00009.ARW\" {\n assert_eq!(s.camera_wb, Some([2056.0 / 1024.0, 1.0, 1908.0 / 1024.0]));",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.format, w.format, \"{}\", w.file);\n assert_eq!(s.make.as_deref(), Some(w.make), \"{}\", w.file);\n assert_eq!(s.model.as_deref(), Some(w.model), \"{}\", w.file);\n assert_eq!((s.width, s.height), w.size, \"{}\", w.file);",
|
||
" assert_eq!(s.make.as_deref(), Some(w.make), \"{}\", w.file);\n assert_eq!(s.model.as_deref(), Some(w.model), \"{}\", w.file);\n assert_eq!((s.width, s.height), w.size, \"{}\", w.file);\n let cfa = s.cfa.as_ref().unwrap_or_else(|| panic!(\"{}: no CFA\", w.file));",
|
||
" assert_eq!(s.model.as_deref(), Some(w.model), \"{}\", w.file);\n assert_eq!((s.width, s.height), w.size, \"{}\", w.file);\n let cfa = s.cfa.as_ref().unwrap_or_else(|| panic!(\"{}: no CFA\", w.file));\n assert_eq!(cfa.colors, w.cfa, \"{}\", w.file);",
|
||
" assert_eq!((s.width, s.height), w.size, \"{}\", w.file);\n let cfa = s.cfa.as_ref().unwrap_or_else(|| panic!(\"{}: no CFA\", w.file));\n assert_eq!(cfa.colors, w.cfa, \"{}\", w.file);\n assert_eq!(s.black.values, w.black, \"{}\", w.file);",
|
||
" assert_eq!(cfa.colors, w.cfa, \"{}\", w.file);\n assert_eq!(s.black.values, w.black, \"{}\", w.file);\n if w.file == \"DSC00009.ARW\" {\n assert_eq!(s.camera_wb, Some([2056.0 / 1024.0, 1.0, 1908.0 / 1024.0]));",
|
||
" assert_eq!(s.black.values, w.black, \"{}\", w.file);\n if w.file == \"DSC00009.ARW\" {\n assert_eq!(s.camera_wb, Some([2056.0 / 1024.0, 1.0, 1908.0 / 1024.0]));\n }",
|
||
" assert_eq!(s.camera_wb, Some([2056.0 / 1024.0, 1.0, 1908.0 / 1024.0]));\n }\n for ch in 0..3 {\n assert!((s.white[ch] - w.white[ch]).abs() < 0.5, \"{} white[{ch}] = {}\", w.file, s.white[ch]);",
|
||
" assert!((s.white[ch] - w.white[ch]).abs() < 0.5, \"{} white[{ch}] = {}\", w.file, s.white[ch]);\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2ed234e654e574109ffcdb9756f8e8d1b8a00b2/crates/raw/tests/raw_corpus.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "developing_produces_the_crop_in_16bit_rgb",
|
||
"path": "crates/raw/tests/raw_corpus.rs",
|
||
"package": "photocraft-raw",
|
||
"command": "cargo test -p photocraft-raw --locked developing_produces_the_crop_in_16bit_rgb -- --nocapture",
|
||
"fixture_and_action_excerpt": " for w in WANTS {\n let bytes = std::fs::read(pixls(w.file)).unwrap_or_else(|e| panic!(\"{}: {e}\", w.file));\n let s = photocraft_raw::decode(&bytes, &Limits::default()).unwrap_or_else(|e| panic!(\"{}: {e}\", w.file));\n let d = photocraft_raw::develop_sensor(&s, &photocraft_raw::DevelopOptions::default()).unwrap_or_else(|e| panic!(\"{}: {e}\", w.file));\n assert_eq!((d.width as usize, d.height as usize), (s.crop.width, s.crop.height), \"{}\", w.file);\n assert_eq!(d.rgb.len(), d.width as usize * d.height as usize * 3, \"{}\", w.file);\n // A real exposure covers a sane share of the range and never leaves it.\n let (mut lo, mut hi) = (u16::MAX, 0u16);\n for v in &d.rgb {\n lo = (*v).min(lo);\n hi = (*v).max(hi);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!((d.width as usize, d.height as usize), (s.crop.width, s.crop.height), \"{}\", w.file);\n assert_eq!(d.rgb.len(), d.width as usize * d.height as usize * 3, \"{}\", w.file);\n // A real exposure covers a sane share of the range and never leaves it.\n let (mut lo, mut hi) = (u16::MAX, 0u16);",
|
||
" assert_eq!(d.rgb.len(), d.width as usize * d.height as usize * 3, \"{}\", w.file);\n // A real exposure covers a sane share of the range and never leaves it.\n let (mut lo, mut hi) = (u16::MAX, 0u16);\n for v in &d.rgb {",
|
||
" assert!(lo < black_cap, \"{}: developed blacks at {lo}\", w.file);\n assert!(hi > u16::MAX / 4, \"{}: developed highlights at {hi}\", w.file);\n // Deterministic: a second develop of the same sensor gives the same pixels.\n let d2 = photocraft_raw::develop_sensor(&s, &photocraft_raw::DevelopOptions::default()).unwrap();",
|
||
" assert!(hi > u16::MAX / 4, \"{}: developed highlights at {hi}\", w.file);\n // Deterministic: a second develop of the same sensor gives the same pixels.\n let d2 = photocraft_raw::develop_sensor(&s, &photocraft_raw::DevelopOptions::default()).unwrap();\n assert_eq!(d.rgb, d2.rgb, \"{}\", w.file);",
|
||
" assert_eq!(d.rgb, d2.rgb, \"{}\", w.file);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2ed234e654e574109ffcdb9756f8e8d1b8a00b2/crates/raw/tests/raw_corpus.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-3387",
|
||
"pr": 3387,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Native 7×5 Gray/GrayA/RGB/RGBA U8/U16 fixtures plus 2/513/8193-pixel-wide alpha samples in codecs/tests/jxl_export.rs",
|
||
"action": [
|
||
"cargo test -p photocraft-codecs --locked jpeg_xl_decodes_losslessly_with_independent_decoder -- --nocapture",
|
||
"cargo test -p photocraft-codecs --locked jpeg_xl_preserves_sixteen_bit_alpha_across_dimension_header_sizes -- --nocapture",
|
||
"cargo test -p photocraft-codecs --locked jpeg_xl_encoding_is_deterministic_and_converts_float_to_integer -- --nocapture",
|
||
"cargo test -p photocraft-codecs --locked jpeg_xl_is_export_only_and_detects_both_signatures -- --nocapture",
|
||
"cargo test -p photocraft-codecs --locked jpeg_xl_rejects_one_pixel_images_without_panicking -- --nocapture"
|
||
],
|
||
"expected": "Independent jxl_oxide decoding equals original integer samples exactly, including alpha and GrayA widening. Dimensions/channels and deterministic output are correct; capabilities remain export-only; 1×1 refuses without panic.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "These native independent-decoder checks cannot be established by wasm or malformed-header rejection alone.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-codecs --locked jpeg_xl_decodes_losslessly_with_independent_decoder -- --nocapture",
|
||
"cargo test -p photocraft-codecs --locked jpeg_xl_preserves_sixteen_bit_alpha_across_dimension_header_sizes -- --nocapture",
|
||
"cargo test -p photocraft-codecs --locked jpeg_xl_encoding_is_deterministic_and_converts_float_to_integer -- --nocapture",
|
||
"cargo test -p photocraft-codecs --locked jpeg_xl_is_export_only_and_detects_both_signatures -- --nocapture",
|
||
"cargo test -p photocraft-codecs --locked jpeg_xl_rejects_one_pixel_images_without_panicking -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-3464",
|
||
"pr": 3464,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked appended_work_and_saved_components_preserve_existing_geometry_and_undo -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked appending_valid_components_cannot_exceed_total_path_budget -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked invalid_path_coordinates_leave_work_and_saved_paths_unchanged -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked large_straight_work_and_saved_paths_append_and_undo_without_shape_coordinate_limits -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shape_layer_paths_are_edited_and_a_direct_selection_is_cleared -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked add_and_delete_anchor_tools_edit_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked command_with_freeform_and_curvature_edits_the_selected_saved_path_after_modifier_release -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked command_cannot_edit_an_existing_path_when_the_freeform_trace_failed_to_finish -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked dragging_an_anchor_moves_it_in_one_undoable_step -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked arrow_keys_nudge_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked selected_saved_and_work_paths_win_overlapping_shape_hits -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked direct_selection_cannot_apply_to_another_document_or_a_reopened_identity -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked external_revision_cancels_preview_and_preserves_the_new_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_path_and_tool_changes_cancel_the_owned_edit -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked closing_a_document_and_changing_marquee_target_discard_old_events -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked serialized_anchor_selection_has_no_runtime_ownership_and_is_not_restored -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked command_drag_after_failed_pen_commit_preserves_draft_and_existing_work_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked switching_between_selection_and_convert_tools_cancels_an_in_flight_drag -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_convert_point_tool_edits_selected_saved_paths_without_changing_the_work_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked changing_the_channel_vector_mask_target_cancels_an_owned_edit -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked esc_ends_a_pen_path_and_keeps_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pen_shows_the_close_path_pointer_over_the_first_anchor -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked real_freeform_freehand_and_alt_straight_segments_append_to_the_owned_saved_path_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked real_freeform_stale_target_source_revision_and_document_cancel_without_finishing_elsewhere -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked another_freeform_trace_cannot_replace_a_failed_owned_draft_or_retry_it_automatically -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_alt_release_in_the_next_press_keeps_the_failed_fit -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked clicking_the_vector_mask_targets_it_for_the_path_tools -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked cmd_enter_while_drawing_finishes_the_path_and_loads_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_and_path_selection_releases_cannot_edit_a_different_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_release_cancels_after_revision_or_target_change -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_valid_release_is_one_undoable_path_edit -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked frame_cancellation_consumes_old_events_after_switching_tools -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked selected_work_and_saved_paths_append_pen_and_curvature_components_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked deselected_work_path_is_replaced_without_touching_saved_paths -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked captured_path_and_shape_mode_do_not_follow_later_ui_selection -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked captured_pen_paint_preserves_float_colour_and_alpha_after_toolbar_changes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked stale_drafts_are_cancelled_before_tool_switch_or_pointer_input -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked sync_views_and_input_apis_discard_unowned_or_closed_document_drafts -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked same_named_saved_paths_do_not_share_selection_or_drafts_across_tabs -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked reopened_same_id_and_revision_do_not_reuse_the_saved_path_selection -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ordinary_path_edits_undo_and_redo_preserve_the_explicit_saved_path_selection -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked failed_pen_and_curvature_commits_keep_the_exact_draft_and_do_not_retry_each_frame -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ordinary_tool_switch_commits_the_owned_draft_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked selected_saved_paths_move_and_free_transform_without_changing_work_or_shape -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked explicit_work_path_precedes_vector_mask_and_deselection_restores_mask_fallback -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pen_keeps_its_captured_vector_mask_when_another_path_is_selected -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_finish_uses_its_captured_saved_path_and_rejects_foreign_documents -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked saved_path_drag_visual_fixture -- --nocapture --ignored",
|
||
"cargo test -p photocraft-ui-egui --locked enter_selects_a_stroke_style_and_escape_closes_its_popups_without_committing_pen -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked transparent_and_absent_paints_remain_distinct_and_open_pen_keeps_foreground -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked all_shape_tools_and_open_pen_use_the_complete_stroke_defaults -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_straight_segments_keep_the_captured_saved_path_and_reject_a_foreign_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked failed_freeform_straight_segment_commit_keeps_its_owned_fitted_draft -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked show_target_path_and_extras_hide_the_path_outlines -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pen_last_anchor_hit_tolerance_tracks_zoom_and_draft_round_trips -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked general_paths_keep_large_straight_coordinates_and_shape_limits_stay_put -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked general_paths_reject_coordinates_that_overflow_the_ui_or_segment_arithmetic -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked general_paths_bound_total_knots_subpaths_and_combined_tessellation -- --nocapture"
|
||
],
|
||
"expected": "appended work and saved components preserve existing geometry and undo; appending valid components cannot exceed total path budget; invalid path coordinates leave work and saved paths unchanged; large straight work and saved paths append and undo without shape coordinate limits; shape layer paths are edited and a direct selection is cleared; add and delete anchor tools edit the selected saved path; command with freeform and curvature edits the selected saved path after modifier release; command cannot edit an existing path when the freeform trace failed to finish; dragging an anchor moves it in one undoable step; arrow keys nudge the selected saved path; selected saved and work paths win overlapping shape hits; direct selection cannot apply to another document or a reopened identity; external revision cancels preview and preserves the new path; layer path and tool changes cancel the owned edit; closing a document and changing marquee target discard old events; serialized anchor selection has no runtime ownership and is not restored; command drag after failed pen commit preserves draft and existing work path; switching between selection and convert tools cancels an in flight drag; the convert point tool edits selected saved paths without changing the work path; changing the channel vector mask target cancels an owned edit; esc ends a pen path and keeps it; pen shows the close path pointer over the first anchor; real freeform freehand and alt straight segments append to the owned saved path once; real freeform stale target source revision and document cancel without finishing elsewhere; another freeform trace cannot replace a failed owned draft or retry it automatically; freeform alt release in the next press keeps the failed fit; clicking the vector mask targets it for the path tools; cmd enter while drawing finishes the path and loads it; freeform and path selection releases cannot edit a different document; freeform release cancels after revision or target change; freeform valid release is one undoable path edit; frame cancellation consumes old events after switching tools; selected work and saved paths append pen and curvature components once; deselected work path is replaced without touching saved paths; captured path and shape mode do not follow later ui selection; captured pen paint preserves float colour and alpha after toolbar changes; stale drafts are cancelled before tool switch or pointer input; sync views and input apis discard unowned or closed document drafts; same named saved paths do not share selection or drafts across tabs; reopened same id and revision do not reuse the saved path selection; ordinary path edits undo and redo preserve the explicit saved path selection; failed pen and curvature commits keep the exact draft and do not retry each frame; ordinary tool switch commits the owned draft once; selected saved paths move and free transform without changing work or shape; explicit work path precedes vector mask and deselection restores mask fallback; pen keeps its captured vector mask when another path is selected; freeform finish uses its captured saved path and rejects foreign documents; saved path drag visual fixture; enter selects a stroke style and escape closes its popups without committing pen; transparent and absent paints remain distinct and open pen keeps foreground; all shape tools and open pen use the complete stroke defaults; freeform straight segments keep the captured saved path and reject a foreign document; failed freeform straight segment commit keeps its owned fitted draft; show target path and extras hide the path outlines; pen last anchor hit tolerance tracks zoom and draft round trips; general paths keep large straight coordinates and shape limits stay put; general paths reject coordinates that overflow the ui or segment arithmetic; general paths bound total knots subpaths and combined tessellation",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked appended_work_and_saved_components_preserve_existing_geometry_and_undo -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked appending_valid_components_cannot_exceed_total_path_budget -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked invalid_path_coordinates_leave_work_and_saved_paths_unchanged -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked large_straight_work_and_saved_paths_append_and_undo_without_shape_coordinate_limits -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shape_layer_paths_are_edited_and_a_direct_selection_is_cleared -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked add_and_delete_anchor_tools_edit_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked command_with_freeform_and_curvature_edits_the_selected_saved_path_after_modifier_release -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked command_cannot_edit_an_existing_path_when_the_freeform_trace_failed_to_finish -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked dragging_an_anchor_moves_it_in_one_undoable_step -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked arrow_keys_nudge_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked selected_saved_and_work_paths_win_overlapping_shape_hits -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked direct_selection_cannot_apply_to_another_document_or_a_reopened_identity -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked external_revision_cancels_preview_and_preserves_the_new_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_path_and_tool_changes_cancel_the_owned_edit -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked closing_a_document_and_changing_marquee_target_discard_old_events -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked serialized_anchor_selection_has_no_runtime_ownership_and_is_not_restored -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked command_drag_after_failed_pen_commit_preserves_draft_and_existing_work_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked switching_between_selection_and_convert_tools_cancels_an_in_flight_drag -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_convert_point_tool_edits_selected_saved_paths_without_changing_the_work_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked changing_the_channel_vector_mask_target_cancels_an_owned_edit -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked esc_ends_a_pen_path_and_keeps_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pen_shows_the_close_path_pointer_over_the_first_anchor -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked real_freeform_freehand_and_alt_straight_segments_append_to_the_owned_saved_path_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked real_freeform_stale_target_source_revision_and_document_cancel_without_finishing_elsewhere -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked another_freeform_trace_cannot_replace_a_failed_owned_draft_or_retry_it_automatically -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_alt_release_in_the_next_press_keeps_the_failed_fit -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked clicking_the_vector_mask_targets_it_for_the_path_tools -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked cmd_enter_while_drawing_finishes_the_path_and_loads_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_and_path_selection_releases_cannot_edit_a_different_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_release_cancels_after_revision_or_target_change -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_valid_release_is_one_undoable_path_edit -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked frame_cancellation_consumes_old_events_after_switching_tools -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked selected_work_and_saved_paths_append_pen_and_curvature_components_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked deselected_work_path_is_replaced_without_touching_saved_paths -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked captured_path_and_shape_mode_do_not_follow_later_ui_selection -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked captured_pen_paint_preserves_float_colour_and_alpha_after_toolbar_changes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked stale_drafts_are_cancelled_before_tool_switch_or_pointer_input -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked sync_views_and_input_apis_discard_unowned_or_closed_document_drafts -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked same_named_saved_paths_do_not_share_selection_or_drafts_across_tabs -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked reopened_same_id_and_revision_do_not_reuse_the_saved_path_selection -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ordinary_path_edits_undo_and_redo_preserve_the_explicit_saved_path_selection -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked failed_pen_and_curvature_commits_keep_the_exact_draft_and_do_not_retry_each_frame -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ordinary_tool_switch_commits_the_owned_draft_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked selected_saved_paths_move_and_free_transform_without_changing_work_or_shape -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked explicit_work_path_precedes_vector_mask_and_deselection_restores_mask_fallback -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pen_keeps_its_captured_vector_mask_when_another_path_is_selected -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_finish_uses_its_captured_saved_path_and_rejects_foreign_documents -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked saved_path_drag_visual_fixture -- --nocapture --ignored",
|
||
"cargo test -p photocraft-ui-egui --locked enter_selects_a_stroke_style_and_escape_closes_its_popups_without_committing_pen -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked transparent_and_absent_paints_remain_distinct_and_open_pen_keeps_foreground -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked all_shape_tools_and_open_pen_use_the_complete_stroke_defaults -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_straight_segments_keep_the_captured_saved_path_and_reject_a_foreign_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked failed_freeform_straight_segment_commit_keeps_its_owned_fitted_draft -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked show_target_path_and_extras_hide_the_path_outlines -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pen_last_anchor_hit_tolerance_tracks_zoom_and_draft_round_trips -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked general_paths_keep_large_straight_coordinates_and_shape_limits_stay_put -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked general_paths_reject_coordinates_that_overflow_the_ui_or_segment_arithmetic -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked general_paths_bound_total_knots_subpaths_and_combined_tessellation -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "appended_work_and_saved_components_preserve_existing_geometry_and_undo",
|
||
"path": "crates/engine/tests/pen_path_append.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked appended_work_and_saved_components_preserve_existing_geometry_and_undo -- --nocapture",
|
||
"fixture_and_action_excerpt": " for name in [\"work\", \"Saved drawing\"] {\n let mut session = session();\n let first = json!({\"subpaths\": [{\"closed\": false, \"knots\": [[20, 20], [80, 20]]}]});\n let second = json!({\"subpaths\": [{\"closed\": false, \"knots\": [[30, 60], [90, 60]]}]});\n session.execute(\"path.set\", json!({\"name\": name, \"path\": first})).unwrap();\n let before = session.execute(\"path.info\", json!({\"name\": name})).unwrap();\n session.execute(\"path.set\", json!({\"name\": name, \"path\": second, \"op\": \"combine\"})).unwrap();\n let after = session.execute(\"path.info\", json!({\"name\": name})).unwrap();\n assert_eq!(after[\"path\"][\"subpaths\"].as_array().unwrap().len(), 2);\n assert_eq!(after[\"path\"][\"subpaths\"][0], before[\"path\"][\"subpaths\"][0]);\n session.execute(\"edit.undo\", json!({})).unwrap();\n assert_eq!(session.execute(\"path.info\", json!({\"name\": name})).unwrap(), before);",
|
||
"expected_assertions": [
|
||
" assert_eq!(after[\"path\"][\"subpaths\"].as_array().unwrap().len(), 2);\n assert_eq!(after[\"path\"][\"subpaths\"][0], before[\"path\"][\"subpaths\"][0]);\n session.execute(\"edit.undo\", json!({})).unwrap();\n assert_eq!(session.execute(\"path.info\", json!({\"name\": name})).unwrap(), before);",
|
||
" assert_eq!(after[\"path\"][\"subpaths\"][0], before[\"path\"][\"subpaths\"][0]);\n session.execute(\"edit.undo\", json!({})).unwrap();\n assert_eq!(session.execute(\"path.info\", json!({\"name\": name})).unwrap(), before);\n session.execute(\"edit.redo\", json!({})).unwrap();",
|
||
" assert_eq!(session.execute(\"path.info\", json!({\"name\": name})).unwrap(), before);\n session.execute(\"edit.redo\", json!({})).unwrap();\n assert_eq!(session.execute(\"path.info\", json!({\"name\": name})).unwrap(), after);\n }",
|
||
" assert_eq!(session.execute(\"path.info\", json!({\"name\": name})).unwrap(), after);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/engine/tests/pen_path_append.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "appending_valid_components_cannot_exceed_total_path_budget",
|
||
"path": "crates/engine/tests/pen_path_append.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked appending_valid_components_cannot_exceed_total_path_budget -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut session = session();\n let subpath = json!({\"closed\": false, \"knots\": []});\n session.execute(\"path.set\", json!({\"path\": {\"subpaths\": vec![subpath.clone(); 2_049]}})).unwrap();\n let before = session.active().unwrap().doc.work_path.clone();\n let history = session.active().unwrap().history.entries().len();\n let error = session.execute(\"path.set\", json!({\"path\": {\"subpaths\": vec![subpath; 2_048]}, \"op\": \"combine\"})).unwrap_err();\n assert!(error.to_string().contains(\"4096\"));\n assert_eq!(session.active().unwrap().doc.work_path, before);\n assert_eq!(session.active().unwrap().history.entries().len(), history);\n}",
|
||
"expected_assertions": [
|
||
" assert!(error.to_string().contains(\"4096\"));\n assert_eq!(session.active().unwrap().doc.work_path, before);\n assert_eq!(session.active().unwrap().history.entries().len(), history);\n}",
|
||
" assert_eq!(session.active().unwrap().doc.work_path, before);\n assert_eq!(session.active().unwrap().history.entries().len(), history);\n}",
|
||
" assert_eq!(session.active().unwrap().history.entries().len(), history);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/engine/tests/pen_path_append.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "invalid_path_coordinates_leave_work_and_saved_paths_unchanged",
|
||
"path": "crates/engine/tests/pen_path_append.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked invalid_path_coordinates_leave_work_and_saved_paths_unchanged -- --nocapture",
|
||
"fixture_and_action_excerpt": " for name in [\"work\", \"Saved drawing\"] {\n let mut session = session();\n session.execute(\"path.set\", json!({\"name\": name, \"path\": {\"subpaths\": [{\"knots\": [[10, 10], [20, 20]]}]}})).unwrap();\n let before = session.execute(\"path.info\", json!({\"name\": name})).unwrap();\n let history = session.active().unwrap().history.entries().len();\n assert!(\n session.execute(\"path.set\", json!({\"name\": name, \"op\": \"combine\", \"path\": {\"subpaths\": [{\"knots\": [[-1.0e308, 10], [1.0e308, 20]]}]}})).is_err()\n );\n assert_eq!(session.execute(\"path.info\", json!({\"name\": name})).unwrap(), before);\n assert_eq!(session.active().unwrap().history.entries().len(), history);\n }\n}",
|
||
"expected_assertions": [
|
||
" assert!(\n session.execute(\"path.set\", json!({\"name\": name, \"op\": \"combine\", \"path\": {\"subpaths\": [{\"knots\": [[-1.0e308, 10], [1.0e308, 20]]}]}})).is_err()\n );\n assert_eq!(session.execute(\"path.info\", json!({\"name\": name})).unwrap(), before);",
|
||
" assert_eq!(session.execute(\"path.info\", json!({\"name\": name})).unwrap(), before);\n assert_eq!(session.active().unwrap().history.entries().len(), history);\n }\n}",
|
||
" assert_eq!(session.active().unwrap().history.entries().len(), history);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/engine/tests/pen_path_append.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "large_straight_work_and_saved_paths_append_and_undo_without_shape_coordinate_limits",
|
||
"path": "crates/engine/tests/pen_path_append.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked large_straight_work_and_saved_paths_append_and_undo_without_shape_coordinate_limits -- --nocapture",
|
||
"fixture_and_action_excerpt": " for name in [\"work\", \"Saved drawing\"] {\n let mut session = session();\n let large = json!({\"subpaths\": [{\"closed\": true, \"knots\": [[0.0, 0.0], [3.0e9, 0.0], [3.0e9, 1.0e9]]}]});\n let before = session.active().unwrap().doc.clone();\n let history = session.active().unwrap().history.entries().len();\n session.execute(\"path.set\", json!({\"name\":name,\"path\":large})).unwrap();\n let first = session.execute(\"path.info\", json!({\"name\":name})).unwrap();\n assert_eq!(first[\"path\"][\"subpaths\"][0][\"knots\"][1][\"anchor\"], json!([3.0e9, 0.0]));\n assert_eq!(session.active().unwrap().history.entries().len(), history + 1);\n session.execute(\"path.set\", json!({\"name\":name,\"op\":\"combine\",\"path\":{\"subpaths\":[{\"knots\":[[10,20],[80,20]]}]}})).unwrap();\n let appended = session.execute(\"path.info\", json!({\"name\":name})).unwrap();\n assert_eq!(appended[\"path\"][\"subpaths\"].as_array().unwrap().len(), 2);",
|
||
"expected_assertions": [
|
||
" assert_eq!(first[\"path\"][\"subpaths\"][0][\"knots\"][1][\"anchor\"], json!([3.0e9, 0.0]));\n assert_eq!(session.active().unwrap().history.entries().len(), history + 1);\n session.execute(\"path.set\", json!({\"name\":name,\"op\":\"combine\",\"path\":{\"subpaths\":[{\"knots\":[[10,20],[80,20]]}]}})).unwrap();\n let appended = session.execute(\"path.info\", json!({\"name\":name})).unwrap();",
|
||
" assert_eq!(session.active().unwrap().history.entries().len(), history + 1);\n session.execute(\"path.set\", json!({\"name\":name,\"op\":\"combine\",\"path\":{\"subpaths\":[{\"knots\":[[10,20],[80,20]]}]}})).unwrap();\n let appended = session.execute(\"path.info\", json!({\"name\":name})).unwrap();\n assert_eq!(appended[\"path\"][\"subpaths\"].as_array().unwrap().len(), 2);",
|
||
" assert_eq!(appended[\"path\"][\"subpaths\"].as_array().unwrap().len(), 2);\n assert_eq!(appended[\"path\"][\"subpaths\"][0], first[\"path\"][\"subpaths\"][0]);\n session.execute(\"edit.undo\", json!({})).unwrap();\n assert_eq!(session.execute(\"path.info\", json!({\"name\":name})).unwrap(), first);",
|
||
" assert_eq!(appended[\"path\"][\"subpaths\"][0], first[\"path\"][\"subpaths\"][0]);\n session.execute(\"edit.undo\", json!({})).unwrap();\n assert_eq!(session.execute(\"path.info\", json!({\"name\":name})).unwrap(), first);\n session.execute(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(session.execute(\"path.info\", json!({\"name\":name})).unwrap(), first);\n session.execute(\"edit.undo\", json!({})).unwrap();\n assert_eq!(session.active().unwrap().doc.work_path, before.work_path);\n assert_eq!(session.active().unwrap().doc.paths, before.paths);",
|
||
" assert_eq!(session.active().unwrap().doc.work_path, before.work_path);\n assert_eq!(session.active().unwrap().doc.paths, before.paths);\n session.execute(\"edit.redo\", json!({})).unwrap();\n assert_eq!(session.execute(\"path.info\", json!({\"name\":name})).unwrap(), first);",
|
||
" assert_eq!(session.active().unwrap().doc.paths, before.paths);\n session.execute(\"edit.redo\", json!({})).unwrap();\n assert_eq!(session.execute(\"path.info\", json!({\"name\":name})).unwrap(), first);\n }",
|
||
" assert_eq!(session.execute(\"path.info\", json!({\"name\":name})).unwrap(), first);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/engine/tests/pen_path_append.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "shape_layer_paths_are_edited_and_a_direct_selection_is_cleared",
|
||
"path": "crates/ui-egui/src/anchor_tools_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked shape_layer_paths_are_edited_and_a_direct_selection_is_cleared -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::DirectSelection);\n let id = app.run(\"shape.create\", json!({\"kind\": \"rect\", \"rect\": [20, 20, 60, 60], \"fill\": \"#3070c0\"})).unwrap()[\"layer\"].as_u64().unwrap();\n click(&mut app, [80.0, 80.0], Modifiers::NONE);\n assert_eq!((app.ui.direct_selection.target.clone(), app.ui.direct_selection.anchors.clone()), (Some(PathRef::Layer(id)), vec![[0, 2]]));\n app.ui.tool = Tool::AddAnchorPoint;\n click(&mut app, [50.0, 20.0], Modifiers::NONE);\n let info = app.run(\"shape.info\", json!({\"layer\": id})).unwrap();\n assert_eq!(info[\"path\"][\"subpaths\"][0][\"knots\"].as_array().unwrap().len(), 5);\n assert!(app.ui.direct_selection.anchors.is_empty(), \"the selection no longer points at a shifted anchor\");\n app.ui.tool = Tool::DeleteAnchorPoint;\n click(&mut app, [20.0, 80.0], Modifiers::NONE);\n let info = app.run(\"shape.info\", json!({\"layer\": id})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!((app.ui.direct_selection.target.clone(), app.ui.direct_selection.anchors.clone()), (Some(PathRef::Layer(id)), vec![[0, 2]]));\n app.ui.tool = Tool::AddAnchorPoint;\n click(&mut app, [50.0, 20.0], Modifiers::NONE);\n let info = app.run(\"shape.info\", json!({\"layer\": id})).unwrap();",
|
||
" assert_eq!(info[\"path\"][\"subpaths\"][0][\"knots\"].as_array().unwrap().len(), 5);\n assert!(app.ui.direct_selection.anchors.is_empty(), \"the selection no longer points at a shifted anchor\");\n app.ui.tool = Tool::DeleteAnchorPoint;\n click(&mut app, [20.0, 80.0], Modifiers::NONE);",
|
||
" assert!(app.ui.direct_selection.anchors.is_empty(), \"the selection no longer points at a shifted anchor\");\n app.ui.tool = Tool::DeleteAnchorPoint;\n click(&mut app, [20.0, 80.0], Modifiers::NONE);\n let info = app.run(\"shape.info\", json!({\"layer\": id})).unwrap();",
|
||
" assert_eq!(info[\"path\"][\"subpaths\"][0][\"knots\"].as_array().unwrap().len(), 4);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/anchor_tools_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "add_and_delete_anchor_tools_edit_the_selected_saved_path",
|
||
"path": "crates/ui-egui/src/anchor_tools_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked add_and_delete_anchor_tools_edit_the_selected_saved_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::AddAnchorPoint);\n with_path(&mut app);\n let before_work = work(&app);\n let path = photocraft_engine::vector_cmds::path_json(&before_work);\n app.run(\"path.set\", json!({\"name\":\"Saved\", \"path\":path})).unwrap();\n app.ui.selected_path = Some(\"Saved\".into());\n let n = steps(&app);\n click(&mut app, [80.0, 120.0], Modifiers::NONE);\n let saved = || app.session.active().unwrap().doc.paths.iter().find(|path| path.name == \"Saved\").unwrap().path.clone();\n let added = saved();\n assert_eq!(added.subpaths[0].knots.len(), 5);\n assert_eq!(work(&app), before_work);",
|
||
"expected_assertions": [
|
||
" assert_eq!(added.subpaths[0].knots.len(), 5);\n assert_eq!(work(&app), before_work);\n assert_eq!(steps(&app), n + 1);\n app.ui.tool = Tool::DeleteAnchorPoint;",
|
||
" assert_eq!(work(&app), before_work);\n assert_eq!(steps(&app), n + 1);\n app.ui.tool = Tool::DeleteAnchorPoint;\n let anchor = added.subpaths[0].knots[3].anchor;",
|
||
" assert_eq!(steps(&app), n + 1);\n app.ui.tool = Tool::DeleteAnchorPoint;\n let anchor = added.subpaths[0].knots[3].anchor;\n click(&mut app, [anchor.x, anchor.y], Modifiers::NONE);",
|
||
" assert_eq!(deleted.subpaths[0].knots.len(), 4);\n assert_eq!(work(&app), before_work);\n assert_eq!(steps(&app), n + 2);\n assert!(app.session.undo());",
|
||
" assert_eq!(work(&app), before_work);\n assert_eq!(steps(&app), n + 2);\n assert!(app.session.undo());\n assert_eq!(app.session.active().unwrap().doc.paths.iter().find(|path| path.name == \"Saved\").unwrap().path, added);",
|
||
" assert_eq!(steps(&app), n + 2);\n assert!(app.session.undo());\n assert_eq!(app.session.active().unwrap().doc.paths.iter().find(|path| path.name == \"Saved\").unwrap().path, added);\n}",
|
||
" assert!(app.session.undo());\n assert_eq!(app.session.active().unwrap().doc.paths.iter().find(|path| path.name == \"Saved\").unwrap().path, added);\n}",
|
||
" assert_eq!(app.session.active().unwrap().doc.paths.iter().find(|path| path.name == \"Saved\").unwrap().path, added);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/anchor_tools_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "command_with_freeform_and_curvature_edits_the_selected_saved_path_after_modifier_release",
|
||
"path": "crates/ui-egui/src/direct_select.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked command_with_freeform_and_curvature_edits_the_selected_saved_path_after_modifier_release -- --nocapture",
|
||
"fixture_and_action_excerpt": " for tool in [Tool::FreeformPen, Tool::CurvaturePen] {\n let mut app = app(tool);\n let original = app.session.active().unwrap().doc.clone();\n let n = app.session.active().unwrap().history.past_len();\n let command = Modifiers { command: true, ctrl: true, ..Default::default() };\n assert!(pointer(&mut app, ToolEvent::Down { x: 20.0, y: 20.0, pressure: 1.0 }, command));\n assert_eq!(app.ui.direct_selection.target, Some(PathRef::Saved(\"Saved drawing\".into())));\n assert!(captured_drag(&app));\n assert!(pointer(&mut app, ToolEvent::Move { x: 30.0, y: 40.0, pressure: 1.0 }, Modifiers::NONE));\n assert!(pointer(&mut app, ToolEvent::Up { x: 30.0, y: 40.0 }, Modifiers::NONE));\n let st = app.session.active().unwrap();\n assert_eq!(st.doc.work_path, original.work_path);",
|
||
"expected_assertions": [
|
||
" assert!(pointer(&mut app, ToolEvent::Down { x: 20.0, y: 20.0, pressure: 1.0 }, command));\n assert_eq!(app.ui.direct_selection.target, Some(PathRef::Saved(\"Saved drawing\".into())));\n assert!(captured_drag(&app));\n assert!(pointer(&mut app, ToolEvent::Move { x: 30.0, y: 40.0, pressure: 1.0 }, Modifiers::NONE));",
|
||
" assert_eq!(app.ui.direct_selection.target, Some(PathRef::Saved(\"Saved drawing\".into())));\n assert!(captured_drag(&app));\n assert!(pointer(&mut app, ToolEvent::Move { x: 30.0, y: 40.0, pressure: 1.0 }, Modifiers::NONE));\n assert!(pointer(&mut app, ToolEvent::Up { x: 30.0, y: 40.0 }, Modifiers::NONE));",
|
||
" assert!(captured_drag(&app));\n assert!(pointer(&mut app, ToolEvent::Move { x: 30.0, y: 40.0, pressure: 1.0 }, Modifiers::NONE));\n assert!(pointer(&mut app, ToolEvent::Up { x: 30.0, y: 40.0 }, Modifiers::NONE));\n let st = app.session.active().unwrap();",
|
||
" assert!(pointer(&mut app, ToolEvent::Move { x: 30.0, y: 40.0, pressure: 1.0 }, Modifiers::NONE));\n assert!(pointer(&mut app, ToolEvent::Up { x: 30.0, y: 40.0 }, Modifiers::NONE));\n let st = app.session.active().unwrap();\n assert_eq!(st.doc.work_path, original.work_path);",
|
||
" assert!(pointer(&mut app, ToolEvent::Up { x: 30.0, y: 40.0 }, Modifiers::NONE));\n let st = app.session.active().unwrap();\n assert_eq!(st.doc.work_path, original.work_path);\n assert_eq!(st.doc.paths[0].path.subpaths[0].knots[0].anchor, Point::new(30.0, 40.0));",
|
||
" assert_eq!(st.doc.work_path, original.work_path);\n assert_eq!(st.doc.paths[0].path.subpaths[0].knots[0].anchor, Point::new(30.0, 40.0));\n assert_eq!(st.history.past_len(), n + 1);\n assert!(app.ui.direct_selection.owner.as_ref().unwrap().valid(&app));",
|
||
" assert_eq!(st.doc.paths[0].path.subpaths[0].knots[0].anchor, Point::new(30.0, 40.0));\n assert_eq!(st.history.past_len(), n + 1);\n assert!(app.ui.direct_selection.owner.as_ref().unwrap().valid(&app));\n assert!(!captured_drag(&app));",
|
||
" assert_eq!(st.history.past_len(), n + 1);\n assert!(app.ui.direct_selection.owner.as_ref().unwrap().valid(&app));\n assert!(!captured_drag(&app));\n assert!(app.session.undo());",
|
||
" assert!(app.ui.direct_selection.owner.as_ref().unwrap().valid(&app));\n assert!(!captured_drag(&app));\n assert!(app.session.undo());\n assert_eq!(app.session.active().unwrap().doc.paths, original.paths);",
|
||
" assert!(!captured_drag(&app));\n assert!(app.session.undo());\n assert_eq!(app.session.active().unwrap().doc.paths, original.paths);\n }",
|
||
" assert!(app.session.undo());\n assert_eq!(app.session.active().unwrap().doc.paths, original.paths);\n }\n }",
|
||
" assert_eq!(app.session.active().unwrap().doc.paths, original.paths);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "command_cannot_edit_an_existing_path_when_the_freeform_trace_failed_to_finish",
|
||
"path": "crates/ui-egui/src/direct_select.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked command_cannot_edit_an_existing_path_when_the_freeform_trace_failed_to_finish -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::FreeformPen);\n let original = app.session.active().unwrap().doc.clone();\n let n = app.session.active().unwrap().history.past_len();\n for [x, y] in [[40.0, 60.0], [1e40, 60.0], [140.0, 80.0]] {\n assert!(crate::lasso_ui::pointer(&mut app, ToolEvent::Down { x, y, pressure: 1.0 }, Modifiers::ALT));\n assert!(crate::lasso_ui::pointer(&mut app, ToolEvent::Up { x, y }, Modifiers::ALT));\n }\n let command = Modifiers { command: true, ctrl: true, ..Default::default() };\n assert!(pointer(&mut app, ToolEvent::Down { x: 20.0, y: 20.0, pressure: 1.0 }, command));\n let pen = app.ui.pen.as_ref().expect(\"failed Freeform commit must preserve its fitted draft\");\n assert!(pen.commit_failed && pen.owner.is_some());\n assert!(app.ui.direct_selection.drag.is_none());",
|
||
"expected_assertions": [
|
||
" assert!(crate::lasso_ui::pointer(&mut app, ToolEvent::Down { x, y, pressure: 1.0 }, Modifiers::ALT));\n assert!(crate::lasso_ui::pointer(&mut app, ToolEvent::Up { x, y }, Modifiers::ALT));\n }\n let command = Modifiers { command: true, ctrl: true, ..Default::default() };",
|
||
" assert!(crate::lasso_ui::pointer(&mut app, ToolEvent::Up { x, y }, Modifiers::ALT));\n }\n let command = Modifiers { command: true, ctrl: true, ..Default::default() };\n assert!(pointer(&mut app, ToolEvent::Down { x: 20.0, y: 20.0, pressure: 1.0 }, command));",
|
||
" assert!(pointer(&mut app, ToolEvent::Down { x: 20.0, y: 20.0, pressure: 1.0 }, command));\n let pen = app.ui.pen.as_ref().expect(\"failed Freeform commit must preserve its fitted draft\");\n assert!(pen.commit_failed && pen.owner.is_some());\n assert!(app.ui.direct_selection.drag.is_none());",
|
||
" assert!(pen.commit_failed && pen.owner.is_some());\n assert!(app.ui.direct_selection.drag.is_none());\n assert!(app.ui.direct_selection.cancelled_drag);\n assert!(pointer(&mut app, ToolEvent::Up { x: 30.0, y: 40.0 }, command));",
|
||
" assert!(app.ui.direct_selection.drag.is_none());\n assert!(app.ui.direct_selection.cancelled_drag);\n assert!(pointer(&mut app, ToolEvent::Up { x: 30.0, y: 40.0 }, command));\n assert!(app.ui.direct_selection.drag.is_none());",
|
||
" assert!(app.ui.direct_selection.cancelled_drag);\n assert!(pointer(&mut app, ToolEvent::Up { x: 30.0, y: 40.0 }, command));\n assert!(app.ui.direct_selection.drag.is_none());\n assert_eq!(app.session.active().unwrap().doc.paths, original.paths);",
|
||
" assert!(pointer(&mut app, ToolEvent::Up { x: 30.0, y: 40.0 }, command));\n assert!(app.ui.direct_selection.drag.is_none());\n assert_eq!(app.session.active().unwrap().doc.paths, original.paths);\n assert_eq!(app.session.active().unwrap().doc.work_path, original.work_path);",
|
||
" assert!(app.ui.direct_selection.drag.is_none());\n assert_eq!(app.session.active().unwrap().doc.paths, original.paths);\n assert_eq!(app.session.active().unwrap().doc.work_path, original.work_path);\n assert_eq!(app.session.active().unwrap().history.past_len(), n);",
|
||
" assert_eq!(app.session.active().unwrap().doc.paths, original.paths);\n assert_eq!(app.session.active().unwrap().doc.work_path, original.work_path);\n assert_eq!(app.session.active().unwrap().history.past_len(), n);\n }",
|
||
" assert_eq!(app.session.active().unwrap().doc.work_path, original.work_path);\n assert_eq!(app.session.active().unwrap().history.past_len(), n);\n }",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), n);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "dragging_an_anchor_moves_it_in_one_undoable_step",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked dragging_an_anchor_moves_it_in_one_undoable_step -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::DirectSelection);\n with_path(&mut app);\n let (before, n) = (work(&app), steps(&app));\n drag(&mut app, [40.5, 120.5], [50.5, 130.5], Modifiers::NONE);\n assert_eq!(anchor(&app, 3), Point::new(50.0, 130.0));\n assert_eq!(anchor(&app, 0), Point::new(40.0, 40.0), \"only the dragged anchor moved\");\n assert_eq!(steps(&app), n + 1, \"one history step for the whole drag\");\n assert_eq!((app.ui.direct_selection.target.clone(), app.ui.direct_selection.anchors.clone()), (Some(PathRef::Work), vec![[0, 3]]));\n assert!(app.session.undo());\n assert_eq!(work(&app), before);\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(anchor(&app, 3), Point::new(50.0, 130.0));\n assert_eq!(anchor(&app, 0), Point::new(40.0, 40.0), \"only the dragged anchor moved\");\n assert_eq!(steps(&app), n + 1, \"one history step for the whole drag\");\n assert_eq!((app.ui.direct_selection.target.clone(), app.ui.direct_selection.anchors.clone()), (Some(PathRef::Work), vec![[0, 3]]));",
|
||
" assert_eq!(anchor(&app, 0), Point::new(40.0, 40.0), \"only the dragged anchor moved\");\n assert_eq!(steps(&app), n + 1, \"one history step for the whole drag\");\n assert_eq!((app.ui.direct_selection.target.clone(), app.ui.direct_selection.anchors.clone()), (Some(PathRef::Work), vec![[0, 3]]));\n assert!(app.session.undo());",
|
||
" assert_eq!(steps(&app), n + 1, \"one history step for the whole drag\");\n assert_eq!((app.ui.direct_selection.target.clone(), app.ui.direct_selection.anchors.clone()), (Some(PathRef::Work), vec![[0, 3]]));\n assert!(app.session.undo());\n assert_eq!(work(&app), before);",
|
||
" assert_eq!((app.ui.direct_selection.target.clone(), app.ui.direct_selection.anchors.clone()), (Some(PathRef::Work), vec![[0, 3]]));\n assert!(app.session.undo());\n assert_eq!(work(&app), before);\n}",
|
||
" assert!(app.session.undo());\n assert_eq!(work(&app), before);\n}",
|
||
" assert_eq!(work(&app), before);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "arrow_keys_nudge_the_selected_saved_path",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked arrow_keys_nudge_the_selected_saved_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::DirectSelection);\n with_path(&mut app);\n save_path(&mut app);\n app.ui.selected_path = Some(\"Saved\".into());\n click(&mut app, [40.0, 120.0], Modifiers::NONE);\n assert_eq!(app.ui.direct_selection.target, Some(PathRef::Saved(\"Saved\".into())));\n let (work_before, n) = (work(&app), steps(&app));\n assert!(press(&mut app, egui::Key::ArrowRight, Modifiers::NONE));\n assert!(press(&mut app, egui::Key::ArrowRight, Modifiers::NONE));\n assert_eq!(saved(&app).subpaths[0].knots[3].anchor, Point::new(42.0, 120.0));\n assert_eq!(work(&app), work_before);\n assert_eq!(steps(&app), n + 2);",
|
||
"expected_assertions": [
|
||
" assert_eq!(app.ui.direct_selection.target, Some(PathRef::Saved(\"Saved\".into())));\n let (work_before, n) = (work(&app), steps(&app));\n assert!(press(&mut app, egui::Key::ArrowRight, Modifiers::NONE));\n assert!(press(&mut app, egui::Key::ArrowRight, Modifiers::NONE));",
|
||
" assert!(press(&mut app, egui::Key::ArrowRight, Modifiers::NONE));\n assert!(press(&mut app, egui::Key::ArrowRight, Modifiers::NONE));\n assert_eq!(saved(&app).subpaths[0].knots[3].anchor, Point::new(42.0, 120.0));\n assert_eq!(work(&app), work_before);",
|
||
" assert!(press(&mut app, egui::Key::ArrowRight, Modifiers::NONE));\n assert_eq!(saved(&app).subpaths[0].knots[3].anchor, Point::new(42.0, 120.0));\n assert_eq!(work(&app), work_before);\n assert_eq!(steps(&app), n + 2);",
|
||
" assert_eq!(saved(&app).subpaths[0].knots[3].anchor, Point::new(42.0, 120.0));\n assert_eq!(work(&app), work_before);\n assert_eq!(steps(&app), n + 2);\n}",
|
||
" assert_eq!(work(&app), work_before);\n assert_eq!(steps(&app), n + 2);\n}",
|
||
" assert_eq!(steps(&app), n + 2);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "selected_saved_and_work_paths_win_overlapping_shape_hits",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked selected_saved_and_work_paths_win_overlapping_shape_hits -- --nocapture",
|
||
"fixture_and_action_excerpt": " for name in [\"Saved\", \"work\"] {\n let mut app = app(Tool::DirectSelection);\n let id = app.run(\"shape.create\", json!({\"kind\":\"rect\", \"rect\":[40,40,80,80]})).unwrap()[\"layer\"].as_u64().unwrap();\n with_path(&mut app);\n save_path(&mut app);\n app.ui.selected_path = Some(name.into());\n let (before_work, before_saved, n) = (work(&app), saved(&app), steps(&app));\n let before_shape = app.run(\"shape.info\", json!({\"layer\":id})).unwrap()[\"path\"].clone();\n drag(&mut app, [40.0, 120.0], [55.0, 130.0], Modifiers::NONE);\n let (actual, unchanged, target) =\n if name == \"Saved\" { (saved(&app), work(&app), PathRef::Saved(\"Saved\".into())) } else { (work(&app), saved(&app), PathRef::Work) };\n assert_eq!(actual.subpaths[0].knots[3].anchor, Point::new(55.0, 130.0));",
|
||
"expected_assertions": [
|
||
" assert_eq!(actual.subpaths[0].knots[3].anchor, Point::new(55.0, 130.0));\n assert_eq!(unchanged, if name == \"Saved\" { before_work.clone() } else { before_saved.clone() });\n assert_eq!(app.ui.direct_selection.target.as_ref(), Some(&target));\n assert_eq!(steps(&app), n + 1);",
|
||
" assert_eq!(unchanged, if name == \"Saved\" { before_work.clone() } else { before_saved.clone() });\n assert_eq!(app.ui.direct_selection.target.as_ref(), Some(&target));\n assert_eq!(steps(&app), n + 1);\n assert_eq!(app.run(\"shape.info\", json!({\"layer\":id})).unwrap()[\"path\"], before_shape);",
|
||
" assert_eq!(app.ui.direct_selection.target.as_ref(), Some(&target));\n assert_eq!(steps(&app), n + 1);\n assert_eq!(app.run(\"shape.info\", json!({\"layer\":id})).unwrap()[\"path\"], before_shape);\n assert!(app.session.undo());",
|
||
" assert_eq!(steps(&app), n + 1);\n assert_eq!(app.run(\"shape.info\", json!({\"layer\":id})).unwrap()[\"path\"], before_shape);\n assert!(app.session.undo());\n assert_eq!(work(&app), before_work);",
|
||
" assert_eq!(app.run(\"shape.info\", json!({\"layer\":id})).unwrap()[\"path\"], before_shape);\n assert!(app.session.undo());\n assert_eq!(work(&app), before_work);\n assert_eq!(saved(&app), before_saved);",
|
||
" assert!(app.session.undo());\n assert_eq!(work(&app), before_work);\n assert_eq!(saved(&app), before_saved);\n app.sync_views();",
|
||
" assert_eq!(work(&app), before_work);\n assert_eq!(saved(&app), before_saved);\n app.sync_views();\n assert!(app.ui.direct_selection.anchors.is_empty(), \"undo invalidates runtime anchor ownership\");",
|
||
" assert_eq!(saved(&app), before_saved);\n app.sync_views();\n assert!(app.ui.direct_selection.anchors.is_empty(), \"undo invalidates runtime anchor ownership\");\n }",
|
||
" assert!(app.ui.direct_selection.anchors.is_empty(), \"undo invalidates runtime anchor ownership\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "direct_selection_cannot_apply_to_another_document_or_a_reopened_identity",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked direct_selection_cannot_apply_to_another_document_or_a_reopened_identity -- --nocapture",
|
||
"fixture_and_action_excerpt": " for reopen in [false, true] {\n let mut app = app(Tool::Pen);\n with_path(&mut app);\n let source = app.session.active().unwrap().doc.clone();\n let revision = app.session.active().unwrap().revision;\n start_command_drag(&mut app);\n if reopen {\n app.session.close(0).unwrap();\n }\n app.session.add_document((*source).clone(), None);\n app.session.active_mut().unwrap().revision = revision;\n let (before, n) = (work(&app), steps(&app));",
|
||
"expected_assertions": [
|
||
" assert_ne!(source.id, app.session.active().unwrap().doc.id);\n } else {\n assert_eq!(source.id, app.session.active().unwrap().doc.id, \"a reopened document may preserve its ID\");\n }",
|
||
" assert_eq!(source.id, app.session.active().unwrap().doc.id, \"a reopened document may preserve its ID\");\n }\n // The frame hook may cancel before the old pointer event arrives.\n app.sync_views();",
|
||
" assert_eq!(work(&app), before);\n assert_eq!(steps(&app), n);\n assert!(app.ui.pen.is_none(), \"an old release must not start a new Pen draft\");\n if !reopen {",
|
||
" assert_eq!(steps(&app), n);\n assert!(app.ui.pen.is_none(), \"an old release must not start a new Pen draft\");\n if !reopen {\n assert_eq!(app.session.documents()[0].doc.work_path.as_ref(), source.work_path.as_ref());",
|
||
" assert!(app.ui.pen.is_none(), \"an old release must not start a new Pen draft\");\n if !reopen {\n assert_eq!(app.session.documents()[0].doc.work_path.as_ref(), source.work_path.as_ref());\n }",
|
||
" assert_eq!(app.session.documents()[0].doc.work_path.as_ref(), source.work_path.as_ref());\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "external_revision_cancels_preview_and_preserves_the_new_path",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked external_revision_cancels_preview_and_preserves_the_new_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::Pen);\n with_path(&mut app);\n start_command_drag(&mut app);\n assert!(super::pointer(&mut app, ToolEvent::Move { x: 50.0, y: 130.0, pressure: 1.0 }, Modifiers::COMMAND));\n app.session.execute(\"path.moveAnchors\", json!({\"name\":\"work\", \"anchors\":[[0,0]], \"move\":[-5,7]})).unwrap();\n let (before, n) = (work(&app), steps(&app));\n consume_stale_drag(&mut app);\n assert_eq!(work(&app), before);\n assert_eq!(steps(&app), n);\n assert!(app.ui.pen.is_none());\n}",
|
||
"expected_assertions": [
|
||
" assert!(super::pointer(&mut app, ToolEvent::Move { x: 50.0, y: 130.0, pressure: 1.0 }, Modifiers::COMMAND));\n app.session.execute(\"path.moveAnchors\", json!({\"name\":\"work\", \"anchors\":[[0,0]], \"move\":[-5,7]})).unwrap();\n let (before, n) = (work(&app), steps(&app));\n consume_stale_drag(&mut app);",
|
||
" assert_eq!(work(&app), before);\n assert_eq!(steps(&app), n);\n assert!(app.ui.pen.is_none());\n}",
|
||
" assert_eq!(steps(&app), n);\n assert!(app.ui.pen.is_none());\n}",
|
||
" assert!(app.ui.pen.is_none());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_path_and_tool_changes_cancel_the_owned_edit",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_path_and_tool_changes_cancel_the_owned_edit -- --nocapture",
|
||
"fixture_and_action_excerpt": " for change in [\"layer\", \"path\", \"vectorMask\", \"tool\"] {\n let mut app = app(Tool::Pen);\n with_path(&mut app);\n save_path(&mut app);\n let first = app.session.active().unwrap().active_layer.unwrap();\n app.run(\"layer.new.layer\", json!({})).unwrap();\n let second = app.session.active().unwrap().active_layer.unwrap();\n app.run(\"layer.select\", json!({\"layer\":first.0})).unwrap();\n start_command_drag(&mut app);\n match change {\n \"layer\" => {\n app.session.execute(\"layer.select\", json!({\"layer\":second.0})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(work(&app), before_work, \"{change}\");\n assert_eq!(saved(&app), before_saved, \"{change}\");\n assert_eq!(steps(&app), n, \"{change}\");\n assert!(app.ui.pen.is_none());",
|
||
" assert_eq!(saved(&app), before_saved, \"{change}\");\n assert_eq!(steps(&app), n, \"{change}\");\n assert!(app.ui.pen.is_none());\n }",
|
||
" assert_eq!(steps(&app), n, \"{change}\");\n assert!(app.ui.pen.is_none());\n }\n}",
|
||
" assert!(app.ui.pen.is_none());\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "closing_a_document_and_changing_marquee_target_discard_old_events",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked closing_a_document_and_changing_marquee_target_discard_old_events -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::Pen);\n with_path(&mut app);\n start_command_drag(&mut app);\n let closed = app.session.close(0).unwrap();\n app.sync_views();\n consume_stale_drag(&mut app);\n assert_eq!(closed.doc.work_path.as_ref().unwrap().subpaths[0].knots[3].anchor, Point::new(40.0, 120.0));\n\n app.session.add_document((*closed.doc).clone(), None);\n app.sync_views();\n save_path(&mut app);\n app.ui.tool = Tool::DirectSelection;",
|
||
"expected_assertions": [
|
||
" assert_eq!(closed.doc.work_path.as_ref().unwrap().subpaths[0].knots[3].anchor, Point::new(40.0, 120.0));\n\n app.session.add_document((*closed.doc).clone(), None);\n app.sync_views();",
|
||
" assert!(super::pointer(&mut app, ToolEvent::Down { x: 30.0, y: 110.0, pressure: 1.0 }, Modifiers::NONE));\n assert!(matches!(app.ui.direct_selection.drag, Some(Drag::Marquee { .. })));\n app.ui.selected_path = Some(\"Saved\".into());\n let n = steps(&app);",
|
||
" assert!(matches!(app.ui.direct_selection.drag, Some(Drag::Marquee { .. })));\n app.ui.selected_path = Some(\"Saved\".into());\n let n = steps(&app);\n consume_stale_drag(&mut app);",
|
||
" assert_eq!(steps(&app), n);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "serialized_anchor_selection_has_no_runtime_ownership_and_is_not_restored",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked serialized_anchor_selection_has_no_runtime_ownership_and_is_not_restored -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::DirectSelection);\n with_path(&mut app);\n click(&mut app, [40.0, 120.0], Modifiers::NONE);\n let serialized = serde_json::to_value(&app.ui.direct_selection).unwrap();\n assert!(serialized.get(\"owner\").is_none());\n assert!(serialized.get(\"drag\").is_none());\n assert!(serialized.get(\"cancelled_drag\").is_none());\n app.ui.direct_selection = serde_json::from_value(serialized).unwrap();\n assert!(app.ui.direct_selection.owner.is_none());\n super::cancel_stale(&mut app);\n assert!(app.ui.direct_selection.anchors.is_empty());\n assert!(app.ui.direct_selection.target.is_none());",
|
||
"expected_assertions": [
|
||
" assert!(serialized.get(\"owner\").is_none());\n assert!(serialized.get(\"drag\").is_none());\n assert!(serialized.get(\"cancelled_drag\").is_none());\n app.ui.direct_selection = serde_json::from_value(serialized).unwrap();",
|
||
" assert!(serialized.get(\"drag\").is_none());\n assert!(serialized.get(\"cancelled_drag\").is_none());\n app.ui.direct_selection = serde_json::from_value(serialized).unwrap();\n assert!(app.ui.direct_selection.owner.is_none());",
|
||
" assert!(serialized.get(\"cancelled_drag\").is_none());\n app.ui.direct_selection = serde_json::from_value(serialized).unwrap();\n assert!(app.ui.direct_selection.owner.is_none());\n super::cancel_stale(&mut app);",
|
||
" assert!(app.ui.direct_selection.owner.is_none());\n super::cancel_stale(&mut app);\n assert!(app.ui.direct_selection.anchors.is_empty());\n assert!(app.ui.direct_selection.target.is_none());",
|
||
" assert!(app.ui.direct_selection.anchors.is_empty());\n assert!(app.ui.direct_selection.target.is_none());\n}",
|
||
" assert!(app.ui.direct_selection.target.is_none());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "command_drag_after_failed_pen_commit_preserves_draft_and_existing_work_path",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked command_drag_after_failed_pen_commit_preserves_draft_and_existing_work_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::Pen);\n with_path(&mut app);\n app.ui.extras.snap = false;\n for [x, y] in [[1e40, 0.0], [40.0, 120.0]] {\n tool_event(&mut app, ToolEvent::Down { x, y, pressure: 1.0 }, Modifiers::NONE);\n tool_event(&mut app, ToolEvent::Up { x, y }, Modifiers::NONE);\n }\n let before_draft = app.ui.pen.as_ref().unwrap().knots.clone();\n let (before_work, n, revision) = (work(&app), steps(&app), app.session.active().unwrap().revision);\n // ⌘ off the draft ends it (a press on it would edit it in place, #4022); here that fails.\n tool_event(&mut app, ToolEvent::Down { x: 40.0, y: 40.0, pressure: 1.0 }, Modifiers::COMMAND);\n assert!(app.ui.pen.as_ref().unwrap().commit_failed);",
|
||
"expected_assertions": [
|
||
" assert!(app.ui.pen.as_ref().unwrap().commit_failed);\n assert!(app.ui.direct_selection.drag.is_none(), \"the press must not go on to edit the old work path\");\n assert!(app.ui.direct_selection.cancelled_drag);\n tool_event(&mut app, ToolEvent::Move { x: 60.0, y: 140.0, pressure: 1.0 }, Modifiers::COMMAND);",
|
||
" assert!(app.ui.direct_selection.drag.is_none(), \"the press must not go on to edit the old work path\");\n assert!(app.ui.direct_selection.cancelled_drag);\n tool_event(&mut app, ToolEvent::Move { x: 60.0, y: 140.0, pressure: 1.0 }, Modifiers::COMMAND);\n tool_event(&mut app, ToolEvent::Up { x: 60.0, y: 140.0 }, Modifiers::COMMAND);",
|
||
" assert!(app.ui.direct_selection.cancelled_drag);\n tool_event(&mut app, ToolEvent::Move { x: 60.0, y: 140.0, pressure: 1.0 }, Modifiers::COMMAND);\n tool_event(&mut app, ToolEvent::Up { x: 60.0, y: 140.0 }, Modifiers::COMMAND);\n assert_eq!(app.ui.pen.as_ref().unwrap().knots, before_draft);",
|
||
" assert_eq!(app.ui.pen.as_ref().unwrap().knots, before_draft);\n assert_eq!(work(&app), before_work);\n assert_eq!(steps(&app), n);\n assert_eq!(app.session.active().unwrap().revision, revision);",
|
||
" assert_eq!(work(&app), before_work);\n assert_eq!(steps(&app), n);\n assert_eq!(app.session.active().unwrap().revision, revision);\n assert!(app.ui.status_error);",
|
||
" assert_eq!(steps(&app), n);\n assert_eq!(app.session.active().unwrap().revision, revision);\n assert!(app.ui.status_error);\n assert!(!app.ui.direct_selection.cancelled_drag);",
|
||
" assert_eq!(app.session.active().unwrap().revision, revision);\n assert!(app.ui.status_error);\n assert!(!app.ui.direct_selection.cancelled_drag);\n}",
|
||
" assert!(app.ui.status_error);\n assert!(!app.ui.direct_selection.cancelled_drag);\n}",
|
||
" assert!(!app.ui.direct_selection.cancelled_drag);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "switching_between_selection_and_convert_tools_cancels_an_in_flight_drag",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked switching_between_selection_and_convert_tools_cancels_an_in_flight_drag -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (from, to) in [(Tool::DirectSelection, Tool::ConvertPoint), (Tool::ConvertPoint, Tool::DirectSelection)] {\n let mut app = app(from);\n with_path(&mut app);\n let (before, n) = (work(&app), steps(&app));\n tool_event(&mut app, ToolEvent::Down { x: 40.0, y: 120.0, pressure: 1.0 }, Modifiers::NONE);\n assert!(app.ui.direct_selection.drag.is_some());\n app.ui.tool = to;\n app.sync_views();\n consume_stale_drag(&mut app);\n assert_eq!((work(&app), steps(&app)), (before, n));\n }\n}",
|
||
"expected_assertions": [
|
||
" assert!(app.ui.direct_selection.drag.is_some());\n app.ui.tool = to;\n app.sync_views();\n consume_stale_drag(&mut app);",
|
||
" assert_eq!((work(&app), steps(&app)), (before, n));\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_convert_point_tool_edits_selected_saved_paths_without_changing_the_work_path",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_convert_point_tool_edits_selected_saved_paths_without_changing_the_work_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::ConvertPoint);\n with_path(&mut app);\n save_path(&mut app);\n app.ui.selected_path = Some(\"Saved\".into());\n let (before_work, before_saved, n) = (work(&app), saved(&app), steps(&app));\n click(&mut app, [120.0, 40.0], Modifiers::NONE);\n assert_eq!(saved(&app).subpaths[0].knots[1], photocraft_doc::Knot::corner(120.0, 40.0));\n assert_eq!(work(&app), before_work);\n assert_eq!(steps(&app), n + 1);\n assert_eq!(app.ui.direct_selection.target, Some(PathRef::Saved(\"Saved\".into())));\n assert!(app.session.undo());\n assert_eq!(saved(&app), before_saved);",
|
||
"expected_assertions": [
|
||
" assert_eq!(saved(&app).subpaths[0].knots[1], photocraft_doc::Knot::corner(120.0, 40.0));\n assert_eq!(work(&app), before_work);\n assert_eq!(steps(&app), n + 1);\n assert_eq!(app.ui.direct_selection.target, Some(PathRef::Saved(\"Saved\".into())));",
|
||
" assert_eq!(work(&app), before_work);\n assert_eq!(steps(&app), n + 1);\n assert_eq!(app.ui.direct_selection.target, Some(PathRef::Saved(\"Saved\".into())));\n assert!(app.session.undo());",
|
||
" assert_eq!(steps(&app), n + 1);\n assert_eq!(app.ui.direct_selection.target, Some(PathRef::Saved(\"Saved\".into())));\n assert!(app.session.undo());\n assert_eq!(saved(&app), before_saved);",
|
||
" assert_eq!(app.ui.direct_selection.target, Some(PathRef::Saved(\"Saved\".into())));\n assert!(app.session.undo());\n assert_eq!(saved(&app), before_saved);\n}",
|
||
" assert!(app.session.undo());\n assert_eq!(saved(&app), before_saved);\n}",
|
||
" assert_eq!(saved(&app), before_saved);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "changing_the_channel_vector_mask_target_cancels_an_owned_edit",
|
||
"path": "crates/ui-egui/src/direct_select_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked changing_the_channel_vector_mask_target_cancels_an_owned_edit -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::DirectSelection);\n with_path(&mut app);\n tool_event(&mut app, ToolEvent::Down { x: 40.0, y: 120.0, pressure: 1.0 }, Modifiers::NONE);\n assert!(app.ui.direct_selection.drag.is_some());\n let (before, n) = (work(&app), steps(&app));\n app.session.active_mut().unwrap().channel_view.target = photocraft_engine::channel_cmds::ChannelTarget::VectorMask;\n assert!(!app.ui.vector_mask_target, \"the channel target can change before the UI syncs its mask flag\");\n consume_stale_drag(&mut app);\n assert_eq!((work(&app), steps(&app)), (before, n));\n}",
|
||
"expected_assertions": [
|
||
" assert!(app.ui.direct_selection.drag.is_some());\n let (before, n) = (work(&app), steps(&app));\n app.session.active_mut().unwrap().channel_view.target = photocraft_engine::channel_cmds::ChannelTarget::VectorMask;\n assert!(!app.ui.vector_mask_target, \"the channel target can change before the UI syncs its mask flag\");",
|
||
" assert!(!app.ui.vector_mask_target, \"the channel target can change before the UI syncs its mask flag\");\n consume_stale_drag(&mut app);\n assert_eq!((work(&app), steps(&app)), (before, n));\n}",
|
||
" assert_eq!((work(&app), steps(&app)), (before, n));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/direct_select_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "esc_ends_a_pen_path_and_keeps_it",
|
||
"path": "crates/ui-egui/src/input_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked esc_ends_a_pen_path_and_keeps_it -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n h.state_mut().ui.tool = crate::state::Tool::Pen;\n let owner = crate::vector_ui::capture_pen_owner(h.state());\n h.state_mut().ui.pen =\n Some(crate::vector_ui::PenPath { knots: vec![[[50.0, 50.0]; 3], [[150.0, 50.0]; 3], [[150.0, 120.0]; 3]], owner, ..Default::default() });\n h.key_press(Key::Escape);\n h.run_steps(2);\n assert!(h.state().ui.pen.is_none(), \"the Pen leaves drawing state\");\n let doc = &h.state().session.active().unwrap().doc;\n let path = doc.work_path.as_ref().expect(\"the path is kept as the work path\");\n assert_eq!(path.subpaths.len(), 1);\n assert!(!path.subpaths[0].closed, \"left open\");",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.pen.is_none(), \"the Pen leaves drawing state\");\n let doc = &h.state().session.active().unwrap().doc;\n let path = doc.work_path.as_ref().expect(\"the path is kept as the work path\");\n assert_eq!(path.subpaths.len(), 1);",
|
||
" assert_eq!(path.subpaths.len(), 1);\n assert!(!path.subpaths[0].closed, \"left open\");\n assert_eq!(path.subpaths[0].knots.len(), 3);\n assert_eq!(h.state().ui.selected_path.as_deref(), Some(\"work\"));",
|
||
" assert!(!path.subpaths[0].closed, \"left open\");\n assert_eq!(path.subpaths[0].knots.len(), 3);\n assert_eq!(h.state().ui.selected_path.as_deref(), Some(\"work\"));\n}",
|
||
" assert_eq!(path.subpaths[0].knots.len(), 3);\n assert_eq!(h.state().ui.selected_path.as_deref(), Some(\"work\"));\n}",
|
||
" assert_eq!(h.state().ui.selected_path.as_deref(), Some(\"work\"));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/input_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "pen_shows_the_close_path_pointer_over_the_first_anchor",
|
||
"path": "crates/ui-egui/src/input_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked pen_shows_the_close_path_pointer_over_the_first_anchor -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n h.state_mut().ui.tool = crate::state::Tool::Pen;\n let owner = crate::vector_ui::capture_pen_owner(h.state());\n h.state_mut().ui.pen = Some(crate::vector_ui::PenPath { knots: vec![[[50.0, 50.0]; 3], [[150.0, 50.0]; 3]], owner, ..Default::default() });\n let screen = |h: &Harness<'static, PhotocraftApp>, x: f32, y: f32| {\n let v = &h.state().ui.views[0];\n let c = h.state().last_canvas_rect.center();\n pos2(c.x + (x - v.center[0]) * v.zoom, c.y + (y - v.center[1]) * v.zoom)\n };\n let pointer = |h: &mut Harness<'static, PhotocraftApp>, x: f32, y: f32| {\n let p = screen(h, x, y);\n h.hover_at(p);",
|
||
"expected_assertions": [
|
||
" assert_eq!(close.0, egui::CursorIcon::Crosshair, \"the fallback under the bitmap\");\n assert!(close.1.is_some(), \"a bitmap\");\n let elsewhere = pointer(&mut h, 200.0, 200.0);\n assert_ne!(elsewhere.1, close.1, \"empty canvas: the plain Pen pointer\");",
|
||
" assert!(close.1.is_some(), \"a bitmap\");\n let elsewhere = pointer(&mut h, 200.0, 200.0);\n assert_ne!(elsewhere.1, close.1, \"empty canvas: the plain Pen pointer\");\n assert_ne!(pointer(&mut h, 150.0, 50.0).1, close.1, \"the last anchor doesn't close\");",
|
||
" assert_ne!(elsewhere.1, close.1, \"empty canvas: the plain Pen pointer\");\n assert_ne!(pointer(&mut h, 150.0, 50.0).1, close.1, \"the last anchor doesn't close\");\n assert_eq!(pointer(&mut h, 50.0, 50.0), close, \"back on the first anchor\");\n}",
|
||
" assert_ne!(pointer(&mut h, 150.0, 50.0).1, close.1, \"the last anchor doesn't close\");\n assert_eq!(pointer(&mut h, 50.0, 50.0), close, \"back on the first anchor\");\n}",
|
||
" assert_eq!(pointer(&mut h, 50.0, 50.0), close, \"back on the first anchor\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/input_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "real_freeform_freehand_and_alt_straight_segments_append_to_the_owned_saved_path_once",
|
||
"path": "crates/ui-egui/src/lasso_ui/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked real_freeform_freehand_and_alt_straight_segments_append_to_the_owned_saved_path_once -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = freeform_harness();\n let original = h.state().session.active().unwrap().doc.clone();\n let n = h.state().session.active().unwrap().history.past_len();\n freeform_run_and_straight_click(&mut h);\n h.event(Event::ModifiersChanged(Modifiers::NONE));\n h.run_steps(3);\n let app = h.state();\n assert!(!active(app) && app.ui.pen.is_none());\n let st = app.session.active().unwrap();\n assert_eq!(st.doc.work_path, original.work_path);\n let path = &st.doc.paths[0].path;\n assert_eq!(path.subpaths.len(), 2);",
|
||
"expected_assertions": [
|
||
" assert!(!active(app) && app.ui.pen.is_none());\n let st = app.session.active().unwrap();\n assert_eq!(st.doc.work_path, original.work_path);\n let path = &st.doc.paths[0].path;",
|
||
" assert_eq!(st.doc.work_path, original.work_path);\n let path = &st.doc.paths[0].path;\n assert_eq!(path.subpaths.len(), 2);\n assert_eq!(path.subpaths[0], original.paths[0].path.subpaths[0]);",
|
||
" assert_eq!(path.subpaths.len(), 2);\n assert_eq!(path.subpaths[0], original.paths[0].path.subpaths[0]);\n let knots = &path.subpaths[1].knots;\n assert_eq!(knots.last().unwrap().anchor, photocraft_geom::Point::new(180.0, 100.0));",
|
||
" assert_eq!(path.subpaths[0], original.paths[0].path.subpaths[0]);\n let knots = &path.subpaths[1].knots;\n assert_eq!(knots.last().unwrap().anchor, photocraft_geom::Point::new(180.0, 100.0));\n assert_eq!(knots.last().unwrap().in_ctrl, knots.last().unwrap().anchor);",
|
||
" assert_eq!(knots.last().unwrap().anchor, photocraft_geom::Point::new(180.0, 100.0));\n assert_eq!(knots.last().unwrap().in_ctrl, knots.last().unwrap().anchor);\n assert_eq!(knots[knots.len() - 2].out_ctrl, knots[knots.len() - 2].anchor);\n assert_eq!(st.history.past_len(), n + 1);",
|
||
" assert_eq!(knots.last().unwrap().in_ctrl, knots.last().unwrap().anchor);\n assert_eq!(knots[knots.len() - 2].out_ctrl, knots[knots.len() - 2].anchor);\n assert_eq!(st.history.past_len(), n + 1);\n assert!(h.state_mut().session.undo());",
|
||
" assert_eq!(knots[knots.len() - 2].out_ctrl, knots[knots.len() - 2].anchor);\n assert_eq!(st.history.past_len(), n + 1);\n assert!(h.state_mut().session.undo());\n assert_eq!(h.state().session.active().unwrap().doc.paths, original.paths);",
|
||
" assert_eq!(st.history.past_len(), n + 1);\n assert!(h.state_mut().session.undo());\n assert_eq!(h.state().session.active().unwrap().doc.paths, original.paths);\n}",
|
||
" assert!(h.state_mut().session.undo());\n assert_eq!(h.state().session.active().unwrap().doc.paths, original.paths);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().doc.paths, original.paths);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/lasso_ui/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "real_freeform_stale_target_source_revision_and_document_cancel_without_finishing_elsewhere",
|
||
"path": "crates/ui-egui/src/lasso_ui/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked real_freeform_stale_target_source_revision_and_document_cancel_without_finishing_elsewhere -- --nocapture",
|
||
"fixture_and_action_excerpt": " for change in [\"target\", \"source\", \"revision\", \"document\"] {\n let mut h = freeform_harness();\n freeform_run_and_straight_click(&mut h);\n let app = h.state_mut();\n match change {\n \"target\" => app.ui.selected_path = Some(\"work\".into()),\n \"source\" => {\n let st = app.session.active_mut().unwrap();\n st.doc = std::sync::Arc::new((*st.doc).clone());\n }\n \"revision\" => app.session.active_mut().unwrap().revision += 1,\n \"document\" => {",
|
||
"expected_assertions": [
|
||
" assert!(!active(app) && app.ui.pen.is_none(), \"{change}: no stale trace remains\");\n assert!(std::sync::Arc::ptr_eq(&source, &app.session.active().unwrap().doc), \"{change}: late input changed document pixels or paths\");\n assert_eq!(app.session.active().unwrap().history.past_len(), n, \"{change}\");\n }",
|
||
" assert!(std::sync::Arc::ptr_eq(&source, &app.session.active().unwrap().doc), \"{change}: late input changed document pixels or paths\");\n assert_eq!(app.session.active().unwrap().history.past_len(), n, \"{change}\");\n }\n}",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), n, \"{change}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/lasso_ui/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "another_freeform_trace_cannot_replace_a_failed_owned_draft_or_retry_it_automatically",
|
||
"path": "crates/ui-egui/src/lasso_ui/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked another_freeform_trace_cannot_replace_a_failed_owned_draft_or_retry_it_automatically -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n app.ui.tool = Tool::FreeformPen;\n app.ui.extras.snap = false;\n for [x, y] in [[40.0, 60.0], [1e40, 60.0], [140.0, 80.0]] {\n event(&mut app, \"down\", x, y, Modifiers::ALT);\n event(&mut app, \"up\", x, y, Modifiers::ALT);\n }\n modifiers(&mut app, Modifiers::NONE);\n let failed = app.ui.pen.clone().expect(\"invalid fitted trace must remain available\");\n assert!(failed.commit_failed && failed.owner.is_some());\n assert!(!active(&app));\n let source = app.session.active().unwrap().doc.clone();",
|
||
"expected_assertions": [
|
||
" assert!(failed.commit_failed && failed.owner.is_some());\n assert!(!active(&app));\n let source = app.session.active().unwrap().doc.clone();\n let n = app.session.active().unwrap().history.past_len();",
|
||
" assert!(!active(&app));\n let source = app.session.active().unwrap().doc.clone();\n let n = app.session.active().unwrap().history.past_len();\n let journal = app.session.journal.len();",
|
||
" assert!(!active(&app), \"pending fitted draft owns the next drawing attempt\");\n }\n modifiers(&mut app, Modifiers::NONE);\n assert_eq!(app.ui.pen.as_ref(), Some(&failed));",
|
||
" assert_eq!(app.ui.pen.as_ref(), Some(&failed));\n assert!(std::sync::Arc::ptr_eq(&source, &app.session.active().unwrap().doc));\n assert_eq!(app.session.active().unwrap().history.past_len(), n);\n assert_eq!(app.session.journal.len(), journal, \"drawing must not retry the failed engine command\");",
|
||
" assert!(std::sync::Arc::ptr_eq(&source, &app.session.active().unwrap().doc));\n assert_eq!(app.session.active().unwrap().history.past_len(), n);\n assert_eq!(app.session.journal.len(), journal, \"drawing must not retry the failed engine command\");\n }",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), n);\n assert_eq!(app.session.journal.len(), journal, \"drawing must not retry the failed engine command\");\n }\n}",
|
||
" assert_eq!(app.session.journal.len(), journal, \"drawing must not retry the failed engine command\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/lasso_ui/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "freeform_alt_release_in_the_next_press_keeps_the_failed_fit",
|
||
"path": "crates/ui-egui/src/lasso_ui/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked freeform_alt_release_in_the_next_press_keeps_the_failed_fit -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n app.ui.tool = Tool::FreeformPen;\n for [x, y] in [[40.0, 60.0], [1e40, 60.0], [140.0, 80.0]] {\n event(&mut app, \"down\", x, y, Modifiers::ALT);\n event(&mut app, \"up\", x, y, Modifiers::ALT);\n }\n assert!(active(&app));\n let source = app.session.active().unwrap().doc.clone();\n let n = app.session.active().unwrap().history.past_len();\n // No separate modifier-change event: this press both releases Alt and tries a new trace.\n event(&mut app, \"down\", 200.0, 100.0, Modifiers::NONE);\n let failed = app.ui.pen.clone().expect(\"failed fit must survive the press that finished it\");",
|
||
"expected_assertions": [
|
||
" assert!(active(&app));\n let source = app.session.active().unwrap().doc.clone();\n let n = app.session.active().unwrap().history.past_len();\n // No separate modifier-change event: this press both releases Alt and tries a new trace.",
|
||
" assert!(failed.commit_failed && failed.owner.is_some());\n assert!(!active(&app));\n let journal = app.session.journal.len();\n event(&mut app, \"move\", 240.0, 120.0, Modifiers::NONE);",
|
||
" assert!(!active(&app));\n let journal = app.session.journal.len();\n event(&mut app, \"move\", 240.0, 120.0, Modifiers::NONE);\n event(&mut app, \"up\", 240.0, 120.0, Modifiers::NONE);",
|
||
" assert_eq!(app.ui.pen.as_ref(), Some(&failed));\n assert_eq!(app.session.journal.len(), journal);\n assert!(std::sync::Arc::ptr_eq(&source, &app.session.active().unwrap().doc));\n assert_eq!(app.session.active().unwrap().history.past_len(), n);",
|
||
" assert_eq!(app.session.journal.len(), journal);\n assert!(std::sync::Arc::ptr_eq(&source, &app.session.active().unwrap().doc));\n assert_eq!(app.session.active().unwrap().history.past_len(), n);\n}",
|
||
" assert!(std::sync::Arc::ptr_eq(&source, &app.session.active().unwrap().doc));\n assert_eq!(app.session.active().unwrap().history.past_len(), n);\n}",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), n);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/lasso_ui/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "clicking_the_vector_mask_targets_it_for_the_path_tools",
|
||
"path": "crates/ui-egui/src/mask_thumbs_ui/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked clicking_the_vector_mask_targets_it_for_the_path_tools -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (s, masked, _) = session();\n let mut h = harness(s, 0, 1.0, 290.0);\n let r = mask_rect(&h, masked, MaskKind::Vector);\n click_with(&mut h, r.center(), Modifiers::NONE);\n assert!(h.state().ui.vector_mask_target && !h.state().ui.mask_target);\n assert_eq!(h.state().ui.selected_path.as_deref(), Some(\"layer\"), \"the Paths panel selects its path\");\n assert!(near(super::brackets(&h.ctx).unwrap(), r.expand(3.0)), \"brackets on the vector mask\");\n assert_eq!(crate::canvas::paint_target(h.state()), json!(\"pixels\"));\n // Path Selection moves the vector mask.\n crate::vector_ui::path_selection_finish(h.state_mut(), [30.0, 30.0], [35.0, 32.0]);\n let k = layer(&h, masked).vector_mask.unwrap().path.subpaths[0].knots[0].anchor;\n assert_eq!((k.x, k.y), (25.0, 12.0));",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.vector_mask_target && !h.state().ui.mask_target);\n assert_eq!(h.state().ui.selected_path.as_deref(), Some(\"layer\"), \"the Paths panel selects its path\");\n assert!(near(super::brackets(&h.ctx).unwrap(), r.expand(3.0)), \"brackets on the vector mask\");\n assert_eq!(crate::canvas::paint_target(h.state()), json!(\"pixels\"));",
|
||
" assert_eq!(h.state().ui.selected_path.as_deref(), Some(\"layer\"), \"the Paths panel selects its path\");\n assert!(near(super::brackets(&h.ctx).unwrap(), r.expand(3.0)), \"brackets on the vector mask\");\n assert_eq!(crate::canvas::paint_target(h.state()), json!(\"pixels\"));\n // Path Selection moves the vector mask.",
|
||
" assert!(near(super::brackets(&h.ctx).unwrap(), r.expand(3.0)), \"brackets on the vector mask\");\n assert_eq!(crate::canvas::paint_target(h.state()), json!(\"pixels\"));\n // Path Selection moves the vector mask.\n crate::vector_ui::path_selection_finish(h.state_mut(), [30.0, 30.0], [35.0, 32.0]);",
|
||
" assert_eq!(crate::canvas::paint_target(h.state()), json!(\"pixels\"));\n // Path Selection moves the vector mask.\n crate::vector_ui::path_selection_finish(h.state_mut(), [30.0, 30.0], [35.0, 32.0]);\n let k = layer(&h, masked).vector_mask.unwrap().path.subpaths[0].knots[0].anchor;",
|
||
" assert_eq!((k.x, k.y), (25.0, 12.0));\n // The Pen adds a subpath to it.\n let owner = crate::vector_ui::capture_pen_owner(h.state());\n h.state_mut().ui.pen =",
|
||
" assert_eq!(layer(&h, masked).vector_mask.unwrap().path.subpaths.len(), 2);\n assert!(h.state().session.active().unwrap().doc.work_path.is_none(), \"not a work path\");\n h.run_steps(2);\n // The pixel mask and the layer thumbnail take the brackets back.",
|
||
" assert!(h.state().session.active().unwrap().doc.work_path.is_none(), \"not a work path\");\n h.run_steps(2);\n // The pixel mask and the layer thumbnail take the brackets back.\n let m = mask_rect(&h, masked, MaskKind::Pixel);",
|
||
" assert!(h.state().ui.mask_target && !h.state().ui.vector_mask_target);\n assert!(near(super::brackets(&h.ctx).unwrap(), m.expand(3.0)));\n click_with(&mut h, r.center(), Modifiers::NONE);\n let p = layer_thumb_center(&h, masked);",
|
||
" assert!(near(super::brackets(&h.ctx).unwrap(), m.expand(3.0)));\n click_with(&mut h, r.center(), Modifiers::NONE);\n let p = layer_thumb_center(&h, masked);\n click_with(&mut h, p, Modifiers::NONE);",
|
||
" assert!(!h.state().ui.mask_target && !h.state().ui.vector_mask_target);\n // Deleting the vector mask drops the target.\n click_with(&mut h, r.center(), Modifiers::NONE);\n assert!(h.state().ui.vector_mask_target);",
|
||
" assert!(h.state().ui.vector_mask_target);\n h.state_mut().run(\"layer.vectorMask.delete\", json!({\"layer\": masked})).unwrap();\n h.run_steps(2);\n assert!(!h.state().ui.vector_mask_target);",
|
||
" assert!(!h.state().ui.vector_mask_target);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/mask_thumbs_ui/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "cmd_enter_while_drawing_finishes_the_path_and_loads_it",
|
||
"path": "crates/ui-egui/src/path_selection_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked cmd_enter_while_drawing_finishes_the_path_and_loads_it -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n h.state_mut().ui.tool = Tool::Pen;\n let p = |x: f64, y: f64| [[x, y], [x, y], [x, y]];\n let owner = crate::vector_ui::capture_pen_owner(h.state());\n h.state_mut().ui.pen = Some(PenPath { knots: vec![p(20.0, 20.0), p(120.0, 20.0), p(120.0, 80.0)], owner, ..Default::default() });\n h.run_steps(2);\n press(&mut h, Key::Enter, command());\n let app = h.state();\n assert!(app.ui.pen.is_none(), \"the pen path was finished\");\n assert!(app.session.active().unwrap().doc.work_path.is_some(), \"into the work path\");\n assert!(app.session.active().unwrap().doc.selection.is_some(), \"and loaded as a selection: {}\", app.ui.status);\n // Plain ↩ still only finishes a path.",
|
||
"expected_assertions": [
|
||
" assert!(app.ui.pen.is_none(), \"the pen path was finished\");\n assert!(app.session.active().unwrap().doc.work_path.is_some(), \"into the work path\");\n assert!(app.session.active().unwrap().doc.selection.is_some(), \"and loaded as a selection: {}\", app.ui.status);\n // Plain ↩ still only finishes a path.",
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_some(), \"into the work path\");\n assert!(app.session.active().unwrap().doc.selection.is_some(), \"and loaded as a selection: {}\", app.ui.status);\n // Plain ↩ still only finishes a path.\n let mut h = harness();",
|
||
" assert!(app.session.active().unwrap().doc.selection.is_some(), \"and loaded as a selection: {}\", app.ui.status);\n // Plain ↩ still only finishes a path.\n let mut h = harness();\n h.state_mut().ui.tool = Tool::Pen;",
|
||
" assert!(h.state().session.active().unwrap().doc.work_path.is_some());\n assert!(h.state().session.active().unwrap().doc.selection.is_none());\n}",
|
||
" assert!(h.state().session.active().unwrap().doc.selection.is_none());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/path_selection_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "freeform_and_path_selection_releases_cannot_edit_a_different_document",
|
||
"path": "crates/ui-egui/src/pen_gesture_owner_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked freeform_and_path_selection_releases_cannot_edit_a_different_document -- --nocapture",
|
||
"fixture_and_action_excerpt": " for tool in [Tool::FreeformPen, Tool::PathSelection] {\n let mut app = app(tool);\n app.run(\"path.set\", json!({\"path\": {\"subpaths\": [{\"knots\": [[20, 20], [50, 35], [90, 80]]}]}})).unwrap();\n let original = app.session.active().unwrap().doc.work_path.clone();\n down(&mut app);\n app.session.execute(\"file.new\", json!({\"width\": 200, \"height\": 200})).unwrap();\n app.sync_views();\n let revision = app.session.active().unwrap().revision;\n tool_event(&mut app, ToolEvent::Up { x: 100.0, y: 100.0 }, Modifiers::NONE);\n assert!(app.drag.is_none());\n assert!(app.session.active().unwrap().doc.work_path.is_none());\n assert_eq!(app.session.active().unwrap().revision, revision);",
|
||
"expected_assertions": [
|
||
" assert!(app.drag.is_none());\n assert!(app.session.active().unwrap().doc.work_path.is_none());\n assert_eq!(app.session.active().unwrap().revision, revision);\n assert_eq!(app.session.documents()[0].doc.work_path, original);",
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_none());\n assert_eq!(app.session.active().unwrap().revision, revision);\n assert_eq!(app.session.documents()[0].doc.work_path, original);\n }",
|
||
" assert_eq!(app.session.active().unwrap().revision, revision);\n assert_eq!(app.session.documents()[0].doc.work_path, original);\n }\n}",
|
||
" assert_eq!(app.session.documents()[0].doc.work_path, original);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_gesture_owner_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "freeform_release_cancels_after_revision_or_target_change",
|
||
"path": "crates/ui-egui/src/pen_gesture_owner_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked freeform_release_cancels_after_revision_or_target_change -- --nocapture",
|
||
"fixture_and_action_excerpt": " for change in [\"revision\", \"selected\", \"mode\"] {\n let mut app = app(Tool::FreeformPen);\n down(&mut app);\n match change {\n \"revision\" => {\n app.run(\"path.set\", json!({\"path\": {\"subpaths\": [{\"knots\": [[10, 10], [15, 15]]}]}})).unwrap();\n }\n \"selected\" => app.ui.selected_path = Some(\"Another path\".into()),\n _ => app.ui.tool_options.vector_mode = \"shape\".into(),\n }\n let before = app.session.active().unwrap().doc.clone();\n let revision = app.session.active().unwrap().revision;",
|
||
"expected_assertions": [
|
||
" assert!(app.drag.is_none());\n assert_eq!(app.session.active().unwrap().doc.work_path, before.work_path);\n assert_eq!(app.session.active().unwrap().doc.layers, before.layers);\n assert_eq!(app.session.active().unwrap().revision, revision);",
|
||
" assert_eq!(app.session.active().unwrap().doc.work_path, before.work_path);\n assert_eq!(app.session.active().unwrap().doc.layers, before.layers);\n assert_eq!(app.session.active().unwrap().revision, revision);\n }",
|
||
" assert_eq!(app.session.active().unwrap().doc.layers, before.layers);\n assert_eq!(app.session.active().unwrap().revision, revision);\n }\n}",
|
||
" assert_eq!(app.session.active().unwrap().revision, revision);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_gesture_owner_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "freeform_valid_release_is_one_undoable_path_edit",
|
||
"path": "crates/ui-egui/src/pen_gesture_owner_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked freeform_valid_release_is_one_undoable_path_edit -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::FreeformPen);\n let history = app.session.active().unwrap().history.entries().len();\n down(&mut app);\n tool_event(&mut app, ToolEvent::Up { x: 100.0, y: 100.0 }, Modifiers::NONE);\n assert!(app.session.active().unwrap().doc.work_path.is_some());\n assert_eq!(app.session.active().unwrap().history.entries().len(), history + 1);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert!(app.session.active().unwrap().doc.work_path.is_none());\n app.run(\"edit.redo\", json!({})).unwrap();\n assert!(app.session.active().unwrap().doc.work_path.is_some());\n}",
|
||
"expected_assertions": [
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_some());\n assert_eq!(app.session.active().unwrap().history.entries().len(), history + 1);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert!(app.session.active().unwrap().doc.work_path.is_none());",
|
||
" assert_eq!(app.session.active().unwrap().history.entries().len(), history + 1);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert!(app.session.active().unwrap().doc.work_path.is_none());\n app.run(\"edit.redo\", json!({})).unwrap();",
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_none());\n app.run(\"edit.redo\", json!({})).unwrap();\n assert!(app.session.active().unwrap().doc.work_path.is_some());\n}",
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_some());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_gesture_owner_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "frame_cancellation_consumes_old_events_after_switching_tools",
|
||
"path": "crates/ui-egui/src/pen_gesture_owner_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked frame_cancellation_consumes_old_events_after_switching_tools -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::FreeformPen);\n down(&mut app);\n app.ui.tool = Tool::PolygonLasso;\n app.ui.polygon = vec![[10.0, 10.0], [20.0, 20.0]];\n let polygon = app.ui.polygon.clone();\n app.sync_views();\n assert!(app.drag.is_none());\n let modifiers = Modifiers { alt: true, ..Modifiers::NONE };\n tool_event(&mut app, ToolEvent::Move { x: 100.0, y: 100.0, pressure: 1.0 }, modifiers);\n tool_event(&mut app, ToolEvent::Up { x: 100.0, y: 100.0 }, modifiers);\n assert_eq!(app.ui.polygon, polygon, \"old pointer events must not become a Polygonal Lasso gesture\");\n assert!(!app.cancelled_vector_drag);",
|
||
"expected_assertions": [
|
||
" assert!(app.drag.is_none());\n let modifiers = Modifiers { alt: true, ..Modifiers::NONE };\n tool_event(&mut app, ToolEvent::Move { x: 100.0, y: 100.0, pressure: 1.0 }, modifiers);\n tool_event(&mut app, ToolEvent::Up { x: 100.0, y: 100.0 }, modifiers);",
|
||
" assert_eq!(app.ui.polygon, polygon, \"old pointer events must not become a Polygonal Lasso gesture\");\n assert!(!app.cancelled_vector_drag);\n}",
|
||
" assert!(!app.cancelled_vector_drag);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_gesture_owner_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "selected_work_and_saved_paths_append_pen_and_curvature_components_once",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked selected_work_and_saved_paths_append_pen_and_curvature_components_once -- --nocapture",
|
||
"fixture_and_action_excerpt": " for tool in [Tool::Pen, Tool::CurvaturePen] {\n for name in [\"work\", \"Saved drawing\"] {\n let mut app = app(tool);\n seed(&mut app, \"work\", 20.0);\n seed(&mut app, \"Saved drawing\", 40.0);\n app.ui.selected_path = Some(name.into());\n let (original, other) = (path(&app, name), path(&app, if name == \"work\" { \"Saved drawing\" } else { \"work\" }));\n let n = steps(&app);\n draft(&mut app);\n assert_eq!(steps(&app), n, \"placing anchors is not a history step\");\n vector_ui::pen_commit(&mut app, false);\n let after = path(&app, name);",
|
||
"expected_assertions": [
|
||
" assert_eq!(steps(&app), n, \"placing anchors is not a history step\");\n vector_ui::pen_commit(&mut app, false);\n let after = path(&app, name);\n assert_eq!(after.subpaths.len(), 2, \"{tool:?}: {name}\");",
|
||
" assert_eq!(after.subpaths.len(), 2, \"{tool:?}: {name}\");\n assert_eq!(after.subpaths[0], original.subpaths[0]);\n let anchors: Vec<_> = after.subpaths[1].knots.iter().map(|k| [k.anchor.x, k.anchor.y]).collect();\n assert_eq!(anchors, [[30.0, 60.0], [130.0, 60.0]]);",
|
||
" assert_eq!(after.subpaths[0], original.subpaths[0]);\n let anchors: Vec<_> = after.subpaths[1].knots.iter().map(|k| [k.anchor.x, k.anchor.y]).collect();\n assert_eq!(anchors, [[30.0, 60.0], [130.0, 60.0]]);\n assert_eq!(path(&app, if name == \"work\" { \"Saved drawing\" } else { \"work\" }), other);",
|
||
" assert_eq!(anchors, [[30.0, 60.0], [130.0, 60.0]]);\n assert_eq!(path(&app, if name == \"work\" { \"Saved drawing\" } else { \"work\" }), other);\n assert_eq!(app.ui.selected_path.as_deref(), Some(name));\n assert_eq!(steps(&app), n + 1);",
|
||
" assert_eq!(path(&app, if name == \"work\" { \"Saved drawing\" } else { \"work\" }), other);\n assert_eq!(app.ui.selected_path.as_deref(), Some(name));\n assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(app.ui.selected_path.as_deref(), Some(name));\n assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(path(&app, name), original);",
|
||
" assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(path(&app, name), original);\n app.run(\"edit.redo\", json!({})).unwrap();",
|
||
" assert_eq!(path(&app, name), original);\n app.run(\"edit.redo\", json!({})).unwrap();\n assert_eq!(path(&app, name), after);\n }",
|
||
" assert_eq!(path(&app, name), after);\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "deselected_work_path_is_replaced_without_touching_saved_paths",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked deselected_work_path_is_replaced_without_touching_saved_paths -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::Pen);\n seed(&mut app, \"work\", 20.0);\n seed(&mut app, \"Saved drawing\", 40.0);\n app.ui.selected_path = None;\n let (before, saved, n) = (path(&app, \"work\"), path(&app, \"Saved drawing\"), steps(&app));\n draft(&mut app);\n vector_ui::pen_commit(&mut app, false);\n let after = path(&app, \"work\");\n assert_eq!(after.subpaths.len(), 1);\n assert_eq!(after.subpaths[0].knots[0].anchor.y, 60.0);\n assert_eq!(path(&app, \"Saved drawing\"), saved);\n assert_eq!(steps(&app), n + 1);",
|
||
"expected_assertions": [
|
||
" assert_eq!(after.subpaths.len(), 1);\n assert_eq!(after.subpaths[0].knots[0].anchor.y, 60.0);\n assert_eq!(path(&app, \"Saved drawing\"), saved);\n assert_eq!(steps(&app), n + 1);",
|
||
" assert_eq!(after.subpaths[0].knots[0].anchor.y, 60.0);\n assert_eq!(path(&app, \"Saved drawing\"), saved);\n assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(path(&app, \"Saved drawing\"), saved);\n assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(path(&app, \"work\"), before);",
|
||
" assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(path(&app, \"work\"), before);\n}",
|
||
" assert_eq!(path(&app, \"work\"), before);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "captured_path_and_shape_mode_do_not_follow_later_ui_selection",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked captured_path_and_shape_mode_do_not_follow_later_ui_selection -- --nocapture",
|
||
"fixture_and_action_excerpt": " for shape in [false, true] {\n let mut app = app(Tool::Pen);\n seed(&mut app, \"work\", 20.0);\n seed(&mut app, \"Saved drawing\", 40.0);\n app.ui.selected_path = Some(\"Saved drawing\".into());\n app.ui.tool_options.vector_mode = if shape { \"shape\" } else { \"path\" }.into();\n let (work, saved, n) = (path(&app, \"work\"), path(&app, \"Saved drawing\"), steps(&app));\n click(&mut app, 30.0, 60.0);\n app.ui.selected_path = Some(\"work\".into());\n app.ui.tool_options.vector_mode = if shape { \"path\" } else { \"shape\" }.into();\n app.ui.vector_mask_target = true;\n click(&mut app, 130.0, 60.0);",
|
||
"expected_assertions": [
|
||
" assert_eq!(path(&app, \"work\"), work);\n if shape {\n let st = app.session.active().unwrap();\n assert!(matches!(st.doc.layer(st.active_layer.unwrap()).unwrap().content, LayerContent::Shape(_)));",
|
||
" assert!(matches!(st.doc.layer(st.active_layer.unwrap()).unwrap().content, LayerContent::Shape(_)));\n assert_eq!(path(&app, \"Saved drawing\"), saved);\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"layer\"));\n } else {",
|
||
" assert_eq!(path(&app, \"Saved drawing\"), saved);\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"layer\"));\n } else {\n assert_eq!(path(&app, \"Saved drawing\").subpaths.len(), 2);",
|
||
" assert_eq!(app.ui.selected_path.as_deref(), Some(\"layer\"));\n } else {\n assert_eq!(path(&app, \"Saved drawing\").subpaths.len(), 2);\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));",
|
||
" assert_eq!(path(&app, \"Saved drawing\").subpaths.len(), 2);\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));\n }\n assert_eq!(steps(&app), n + 1);",
|
||
" assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));\n }\n assert_eq!(steps(&app), n + 1);\n }",
|
||
" assert_eq!(steps(&app), n + 1);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "captured_pen_paint_preserves_float_colour_and_alpha_after_toolbar_changes",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked captured_pen_paint_preserves_float_colour_and_alpha_after_toolbar_changes -- --nocapture",
|
||
"fixture_and_action_excerpt": " for closed in [false, true] {\n let mut app = app(Tool::Pen);\n app.ui.tool_options.vector_mode = \"shape\".into();\n app.ui.tool_options.shape_fill = true;\n app.ui.tool_options.stroke_width = 3.0;\n let foreground = [0.12345, 0.34567, 0.56789, 0.375];\n let background = [0.76543, 0.54321, 0.32109, 0.625];\n app.session.tools.foreground = foreground;\n app.session.tools.background = background;\n click(&mut app, 30.0, 60.0);\n app.session.tools.foreground = [1.0; 4];\n app.session.tools.background = [0.0; 4];",
|
||
"expected_assertions": [
|
||
" assert_eq!(shape.fill, closed.then(|| paint(foreground)));\n assert_eq!(shape.stroke.as_ref().unwrap().paint, paint(if closed { background } else { foreground }));\n }\n}",
|
||
" assert_eq!(shape.stroke.as_ref().unwrap().paint, paint(if closed { background } else { foreground }));\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "stale_drafts_are_cancelled_before_tool_switch_or_pointer_input",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked stale_drafts_are_cancelled_before_tool_switch_or_pointer_input -- --nocapture",
|
||
"fixture_and_action_excerpt": " for tool in [Tool::Pen, Tool::CurvaturePen] {\n for change in [\"document\", \"revision\", \"reopen\"] {\n let mut app = app(tool);\n seed(&mut app, \"Saved drawing\", 20.0);\n app.ui.selected_path = Some(\"Saved drawing\".into());\n draft(&mut app);\n let source = app.session.active().unwrap().doc.clone();\n let revision = app.session.active().unwrap().revision;\n match change {\n \"document\" => {\n app.session.execute(\"file.new\", json!({\"width\": 200, \"height\": 200})).unwrap();\n app.session.execute(\"path.set\", json!({\"name\":\"Saved drawing\", \"path\": {\"subpaths\": [{\"knots\": [[50, 50], [80, 80]]}]}})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(app.ui.pen.is_none(), \"{tool:?}: {change}\");\n vector_ui::pen_move(&mut app, 160.0, 80.0);\n vector_ui::curvature_move(&mut app, 160.0, 80.0);\n vector_ui::pen_up(&mut app);",
|
||
" assert!(std::sync::Arc::ptr_eq(&app.session.active().unwrap().doc, ¤t));\n assert_eq!(steps(&app), n);\n assert_eq!(source.paths[0].path.subpaths.len(), 1);\n }",
|
||
" assert_eq!(steps(&app), n);\n assert_eq!(source.paths[0].path.subpaths.len(), 1);\n }\n }",
|
||
" assert_eq!(source.paths[0].path.subpaths.len(), 1);\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "sync_views_and_input_apis_discard_unowned_or_closed_document_drafts",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked sync_views_and_input_apis_discard_unowned_or_closed_document_drafts -- --nocapture",
|
||
"fixture_and_action_excerpt": " for entry in [\"sync\", \"move\", \"up\", \"commit\", \"undo\", \"toggle\", \"down\"] {\n let mut app = app(Tool::CurvaturePen);\n draft(&mut app);\n app.session.close(0).unwrap();\n match entry {\n \"sync\" => app.sync_views(),\n \"move\" => vector_ui::curvature_move(&mut app, 160.0, 80.0),\n \"up\" => vector_ui::curvature_up(&mut app),\n \"commit\" => vector_ui::pen_commit(&mut app, false),\n \"undo\" => {\n assert!(vector_ui::pen_undo_last_point(&mut app));\n }",
|
||
"expected_assertions": [
|
||
" assert!(vector_ui::pen_undo_last_point(&mut app));\n }\n \"toggle\" => vector_ui::curvature_toggle(&mut app, 30.0, 60.0),\n \"down\" => vector_ui::curvature_down(&mut app, 160.0, 80.0),",
|
||
" assert!(app.ui.pen.is_none(), \"{entry}\");\n }\n let mut app = app(Tool::Pen);\n draft(&mut app);",
|
||
" assert!(app.ui.pen.is_none());\n assert!(app.session.active().unwrap().doc.work_path.is_none());\n assert_eq!(steps(&app), n);\n}",
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_none());\n assert_eq!(steps(&app), n);\n}",
|
||
" assert_eq!(steps(&app), n);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "same_named_saved_paths_do_not_share_selection_or_drafts_across_tabs",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked same_named_saved_paths_do_not_share_selection_or_drafts_across_tabs -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::Pen);\n seed(&mut app, \"Saved drawing\", 20.0);\n let first = path(&app, \"Saved drawing\");\n app.run(\"file.new\", json!({\"width\":200,\"height\":200})).unwrap();\n seed(&mut app, \"Saved drawing\", 90.0);\n let second = path(&app, \"Saved drawing\");\n assert!(app.session.set_active(0));\n app.sync_views();\n app.ui.selected_path = Some(\"Saved drawing\".into());\n draft(&mut app);\n assert!(app.session.set_active(1));\n app.sync_views();",
|
||
"expected_assertions": [
|
||
" assert!(app.session.set_active(0));\n app.sync_views();\n app.ui.selected_path = Some(\"Saved drawing\".into());\n draft(&mut app);",
|
||
" assert!(app.session.set_active(1));\n app.sync_views();\n assert!(app.ui.selected_path.is_none());\n assert!(app.ui.pen.is_none());",
|
||
" assert!(app.ui.selected_path.is_none());\n assert!(app.ui.pen.is_none());\n let n = steps(&app);\n vector_ui::pen_commit(&mut app, false);",
|
||
" assert!(app.ui.pen.is_none());\n let n = steps(&app);\n vector_ui::pen_commit(&mut app, false);\n assert_eq!(path(&app, \"Saved drawing\"), second);",
|
||
" assert_eq!(path(&app, \"Saved drawing\"), second);\n assert_eq!(steps(&app), n);\n // A fresh drawing without explicitly selecting B's saved path creates a work path.\n draft(&mut app);",
|
||
" assert_eq!(steps(&app), n);\n // A fresh drawing without explicitly selecting B's saved path creates a work path.\n draft(&mut app);\n vector_ui::pen_commit(&mut app, false);",
|
||
" assert_eq!(path(&app, \"Saved drawing\"), second);\n assert_eq!(path(&app, \"work\").subpaths[0].knots[0].anchor.y, 60.0);\n assert!(app.session.set_active(0));\n app.sync_views();",
|
||
" assert_eq!(path(&app, \"work\").subpaths[0].knots[0].anchor.y, 60.0);\n assert!(app.session.set_active(0));\n app.sync_views();\n assert!(app.ui.selected_path.is_none());",
|
||
" assert!(app.session.set_active(0));\n app.sync_views();\n assert!(app.ui.selected_path.is_none());\n assert_eq!(path(&app, \"Saved drawing\"), first);",
|
||
" assert!(app.ui.selected_path.is_none());\n assert_eq!(path(&app, \"Saved drawing\"), first);\n}",
|
||
" assert_eq!(path(&app, \"Saved drawing\"), first);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "reopened_same_id_and_revision_do_not_reuse_the_saved_path_selection",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked reopened_same_id_and_revision_do_not_reuse_the_saved_path_selection -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::Pen);\n seed(&mut app, \"Saved drawing\", 20.0);\n app.ui.selected_path = Some(\"Saved drawing\".into());\n let original = path(&app, \"Saved drawing\");\n draft(&mut app);\n let closed = app.session.close(0).unwrap();\n // Recovery can preserve both the document ID and revision before another frame is drawn.\n app.session.add_document((*closed.doc).clone(), None);\n app.session.active_mut().unwrap().revision = closed.revision;\n assert_eq!(app.session.active().unwrap().doc.id, closed.doc.id);\n app.sync_views();\n assert!(app.ui.selected_path.is_none());",
|
||
"expected_assertions": [
|
||
" assert_eq!(app.session.active().unwrap().doc.id, closed.doc.id);\n app.sync_views();\n assert!(app.ui.selected_path.is_none());\n assert!(app.ui.pen.is_none());",
|
||
" assert!(app.ui.selected_path.is_none());\n assert!(app.ui.pen.is_none());\n draft(&mut app);\n vector_ui::pen_commit(&mut app, false);",
|
||
" assert!(app.ui.pen.is_none());\n draft(&mut app);\n vector_ui::pen_commit(&mut app, false);\n assert_eq!(path(&app, \"Saved drawing\"), original);",
|
||
" assert_eq!(path(&app, \"Saved drawing\"), original);\n assert_eq!(path(&app, \"work\").subpaths[0].knots[0].anchor.y, 60.0);\n}",
|
||
" assert_eq!(path(&app, \"work\").subpaths[0].knots[0].anchor.y, 60.0);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "ordinary_path_edits_undo_and_redo_preserve_the_explicit_saved_path_selection",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked ordinary_path_edits_undo_and_redo_preserve_the_explicit_saved_path_selection -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::Pen);\n seed(&mut app, \"Saved drawing\", 20.0);\n app.ui.selected_path = Some(\"Saved drawing\".into());\n let original = path(&app, \"Saved drawing\");\n let revision = app.session.active().unwrap().revision;\n seed(&mut app, \"Saved drawing\", 90.0);\n assert!(app.session.active().unwrap().revision > revision);\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));\n let changed = path(&app, \"Saved drawing\");\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(path(&app, \"Saved drawing\"), original);\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));",
|
||
"expected_assertions": [
|
||
" assert!(app.session.active().unwrap().revision > revision);\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));\n let changed = path(&app, \"Saved drawing\");\n app.run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));\n let changed = path(&app, \"Saved drawing\");\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(path(&app, \"Saved drawing\"), original);",
|
||
" assert_eq!(path(&app, \"Saved drawing\"), original);\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));\n app.run(\"edit.redo\", json!({})).unwrap();\n assert_eq!(path(&app, \"Saved drawing\"), changed);",
|
||
" assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));\n app.run(\"edit.redo\", json!({})).unwrap();\n assert_eq!(path(&app, \"Saved drawing\"), changed);\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));",
|
||
" assert_eq!(path(&app, \"Saved drawing\"), changed);\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));\n app.sync_views();\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));",
|
||
" assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));\n app.sync_views();\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));\n}",
|
||
" assert_eq!(app.ui.selected_path.as_deref(), Some(\"Saved drawing\"));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "failed_pen_and_curvature_commits_keep_the_exact_draft_and_do_not_retry_each_frame",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked failed_pen_and_curvature_commits_keep_the_exact_draft_and_do_not_retry_each_frame -- --nocapture",
|
||
"fixture_and_action_excerpt": " for tool in [Tool::Pen, Tool::CurvaturePen] {\n let mut app = app(tool);\n click(&mut app, 30.0, 60.0);\n click(&mut app, 1e40, 60.0);\n let (before, original, n) = (app.session.active().unwrap().doc.clone(), app.ui.pen.clone().unwrap(), steps(&app));\n vector_ui::pen_commit(&mut app, false);\n let failed = app.ui.pen.as_ref().expect(\"invalid geometry leaves an editable draft\");\n assert_eq!(failed.knots, original.knots);\n assert_eq!(failed.unlinked, original.unlinked);\n assert_eq!(failed.owner, original.owner);\n assert!(failed.commit_failed && app.ui.status_error);\n assert!(std::sync::Arc::ptr_eq(&before, &app.session.active().unwrap().doc));",
|
||
"expected_assertions": [
|
||
" assert_eq!(failed.knots, original.knots);\n assert_eq!(failed.unlinked, original.unlinked);\n assert_eq!(failed.owner, original.owner);\n assert!(failed.commit_failed && app.ui.status_error);",
|
||
" assert_eq!(failed.unlinked, original.unlinked);\n assert_eq!(failed.owner, original.owner);\n assert!(failed.commit_failed && app.ui.status_error);\n assert!(std::sync::Arc::ptr_eq(&before, &app.session.active().unwrap().doc));",
|
||
" assert_eq!(failed.owner, original.owner);\n assert!(failed.commit_failed && app.ui.status_error);\n assert!(std::sync::Arc::ptr_eq(&before, &app.session.active().unwrap().doc));\n assert_eq!(steps(&app), n);",
|
||
" assert!(failed.commit_failed && app.ui.status_error);\n assert!(std::sync::Arc::ptr_eq(&before, &app.session.active().unwrap().doc));\n assert_eq!(steps(&app), n);\n app.ui.tool = Tool::Brush;",
|
||
" assert!(std::sync::Arc::ptr_eq(&before, &app.session.active().unwrap().doc));\n assert_eq!(steps(&app), n);\n app.ui.tool = Tool::Brush;\n let journal = app.session.journal.len();",
|
||
" assert_eq!(steps(&app), n);\n app.ui.tool = Tool::Brush;\n let journal = app.session.journal.len();\n vector_ui::finish_pen_if_left(&mut app);",
|
||
" assert_eq!(app.session.journal.len(), journal, \"tool switch must not continually retry a failing commit\");\n assert!(vector_ui::path_to_selection(&mut app, Value::Null).is_err(), \"a failed draft cannot select an unrelated path\");\n app.ui.pen.as_mut().unwrap().knots[1] = [[130.0, 60.0]; 3];\n vector_ui::pen_commit(&mut app, false);",
|
||
" assert!(vector_ui::path_to_selection(&mut app, Value::Null).is_err(), \"a failed draft cannot select an unrelated path\");\n app.ui.pen.as_mut().unwrap().knots[1] = [[130.0, 60.0]; 3];\n vector_ui::pen_commit(&mut app, false);\n assert!(app.ui.pen.is_none());",
|
||
" assert!(app.ui.pen.is_none());\n assert_eq!(path(&app, \"work\").subpaths[0].knots[1].anchor.x, 130.0);\n assert_eq!(steps(&app), n + 1);\n }",
|
||
" assert_eq!(path(&app, \"work\").subpaths[0].knots[1].anchor.x, 130.0);\n assert_eq!(steps(&app), n + 1);\n }\n}",
|
||
" assert_eq!(steps(&app), n + 1);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "ordinary_tool_switch_commits_the_owned_draft_once",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked ordinary_tool_switch_commits_the_owned_draft_once -- --nocapture",
|
||
"fixture_and_action_excerpt": " for tool in [Tool::Pen, Tool::CurvaturePen] {\n let mut app = app(tool);\n draft(&mut app);\n let n = steps(&app);\n app.ui.tool = Tool::Brush;\n vector_ui::finish_pen_if_left(&mut app);\n vector_ui::finish_pen_if_left(&mut app);\n assert_eq!(path(&app, \"work\").subpaths[0].knots.len(), 2);\n assert_eq!(steps(&app), n + 1);\n assert!(app.ui.pen.is_none());\n }\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(path(&app, \"work\").subpaths[0].knots.len(), 2);\n assert_eq!(steps(&app), n + 1);\n assert!(app.ui.pen.is_none());\n }",
|
||
" assert_eq!(steps(&app), n + 1);\n assert!(app.ui.pen.is_none());\n }\n}",
|
||
" assert!(app.ui.pen.is_none());\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "selected_saved_paths_move_and_free_transform_without_changing_work_or_shape",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked selected_saved_paths_move_and_free_transform_without_changing_work_or_shape -- --nocapture",
|
||
"fixture_and_action_excerpt": " for tool in [Tool::PathSelection, Tool::DirectSelection] {\n let mut app = app(tool);\n app.run(\"shape.create\", json!({\"kind\": \"rect\", \"rect\": [110, 110, 50, 40]})).unwrap();\n let shape = app.run(\"shape.info\", json!({})).unwrap();\n seed(&mut app, \"work\", 20.0);\n seed(&mut app, \"Saved drawing\", 40.0);\n app.ui.selected_path = Some(\"Saved drawing\".into());\n let (original, work, n) = (path(&app, \"Saved drawing\"), path(&app, \"work\"), steps(&app));\n let (params, selected) = vector_ui::free_transform_path(&app).unwrap();\n assert_eq!(params, json!({\"name\":\"Saved drawing\"}));\n assert_eq!(selected, original);\n vector_ui::path_selection_finish(&mut app, [0.0, 0.0], [10.4, -4.6]);",
|
||
"expected_assertions": [
|
||
" assert_eq!(params, json!({\"name\":\"Saved drawing\"}));\n assert_eq!(selected, original);\n vector_ui::path_selection_finish(&mut app, [0.0, 0.0], [10.4, -4.6]);\n let moved = path(&app, \"Saved drawing\");",
|
||
" assert_eq!(selected, original);\n vector_ui::path_selection_finish(&mut app, [0.0, 0.0], [10.4, -4.6]);\n let moved = path(&app, \"Saved drawing\");\n for (a, b) in original.subpaths[0].knots.iter().zip(&moved.subpaths[0].knots) {",
|
||
" assert_eq!(b.anchor.x, a.anchor.x + 10.0);\n assert_eq!(b.anchor.y, a.anchor.y - 5.0);\n assert_eq!(b.in_ctrl.x, a.in_ctrl.x + 10.0);\n assert_eq!(b.out_ctrl.y, a.out_ctrl.y - 5.0);",
|
||
" assert_eq!(b.anchor.y, a.anchor.y - 5.0);\n assert_eq!(b.in_ctrl.x, a.in_ctrl.x + 10.0);\n assert_eq!(b.out_ctrl.y, a.out_ctrl.y - 5.0);\n }",
|
||
" assert_eq!(b.in_ctrl.x, a.in_ctrl.x + 10.0);\n assert_eq!(b.out_ctrl.y, a.out_ctrl.y - 5.0);\n }\n assert_eq!(path(&app, \"work\"), work);",
|
||
" assert_eq!(b.out_ctrl.y, a.out_ctrl.y - 5.0);\n }\n assert_eq!(path(&app, \"work\"), work);\n assert_eq!(app.run(\"shape.info\", json!({})).unwrap(), shape);",
|
||
" assert_eq!(path(&app, \"work\"), work);\n assert_eq!(app.run(\"shape.info\", json!({})).unwrap(), shape);\n assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(app.run(\"shape.info\", json!({})).unwrap(), shape);\n assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(path(&app, \"Saved drawing\"), original);",
|
||
" assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(path(&app, \"Saved drawing\"), original);\n let mut params = params;",
|
||
" assert_eq!(path(&app, \"Saved drawing\"), original);\n let mut params = params;\n params[\"matrix\"] = json!([1, 0, 0, 1, 7, 9]);\n app.run(\"path.transform\", params).unwrap();",
|
||
" assert_eq!(path(&app, \"Saved drawing\").subpaths[0].knots[0].anchor.x, 17.0);\n assert_eq!(path(&app, \"work\"), work);\n assert_eq!(app.run(\"shape.info\", json!({})).unwrap(), shape);\n app.run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(path(&app, \"work\"), work);\n assert_eq!(app.run(\"shape.info\", json!({})).unwrap(), shape);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(path(&app, \"Saved drawing\"), original);",
|
||
" assert_eq!(app.run(\"shape.info\", json!({})).unwrap(), shape);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(path(&app, \"Saved drawing\"), original);\n app.ui.selected_path = None;",
|
||
" assert_eq!(path(&app, \"Saved drawing\"), original);\n app.ui.selected_path = None;\n assert_eq!(vector_ui::free_transform_path(&app).unwrap().0[\"name\"], \"layer\", \"deselection restores the shape fallback\");\n }",
|
||
" assert_eq!(vector_ui::free_transform_path(&app).unwrap().0[\"name\"], \"layer\", \"deselection restores the shape fallback\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "explicit_work_path_precedes_vector_mask_and_deselection_restores_mask_fallback",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked explicit_work_path_precedes_vector_mask_and_deselection_restores_mask_fallback -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::PathSelection);\n seed(&mut app, \"work\", 20.0);\n let layer = app.session.active().unwrap().active_layer.unwrap();\n app.run(\"layer.vectorMask.add\", json!({\"layer\":layer.0,\"path\":{\"subpaths\":[{\"knots\":[[30,40],[80,40]]}]}})).unwrap();\n app.ui.vector_mask_target = true;\n app.ui.selected_path = Some(\"work\".into());\n assert_eq!(vector_ui::free_transform_path(&app).unwrap().0, json!({\"name\":\"work\"}));\n app.ui.selected_path = None;\n assert_eq!(vector_ui::free_transform_path(&app).unwrap().0, json!({\"name\":\"layer\",\"layer\":layer.0}));\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(vector_ui::free_transform_path(&app).unwrap().0, json!({\"name\":\"work\"}));\n app.ui.selected_path = None;\n assert_eq!(vector_ui::free_transform_path(&app).unwrap().0, json!({\"name\":\"layer\",\"layer\":layer.0}));\n}",
|
||
" assert_eq!(vector_ui::free_transform_path(&app).unwrap().0, json!({\"name\":\"layer\",\"layer\":layer.0}));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "pen_keeps_its_captured_vector_mask_when_another_path_is_selected",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked pen_keeps_its_captured_vector_mask_when_another_path_is_selected -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::Pen);\n seed(&mut app, \"Saved drawing\", 20.0);\n let layer = app.session.active().unwrap().active_layer.unwrap();\n app.run(\"layer.vectorMask.add\", json!({\"layer\":layer.0,\"path\":{\"subpaths\":[{\"knots\":[[30,40],[80,40]]}]}})).unwrap();\n app.ui.selected_path = None;\n app.ui.vector_mask_target = true;\n let (saved, original, n) = (path(&app, \"Saved drawing\"), app.session.active().unwrap().doc.layer(layer).unwrap().vector_mask.clone().unwrap(), steps(&app));\n click(&mut app, 30.0, 60.0);\n app.ui.vector_mask_target = false;\n app.ui.selected_path = Some(\"Saved drawing\".into());\n click(&mut app, 130.0, 60.0);\n vector_ui::pen_commit(&mut app, false);",
|
||
"expected_assertions": [
|
||
" assert_eq!(mask.path.subpaths.len(), 2);\n assert_eq!(mask.path.subpaths[0], original.path.subpaths[0]);\n assert_eq!(mask.path.subpaths[1].knots[0].anchor.y, 60.0);\n assert_eq!(path(&app, \"Saved drawing\"), saved);",
|
||
" assert_eq!(mask.path.subpaths[0], original.path.subpaths[0]);\n assert_eq!(mask.path.subpaths[1].knots[0].anchor.y, 60.0);\n assert_eq!(path(&app, \"Saved drawing\"), saved);\n assert!(app.session.active().unwrap().doc.work_path.is_none());",
|
||
" assert_eq!(mask.path.subpaths[1].knots[0].anchor.y, 60.0);\n assert_eq!(path(&app, \"Saved drawing\"), saved);\n assert!(app.session.active().unwrap().doc.work_path.is_none());\n assert_eq!(steps(&app), n + 1);",
|
||
" assert_eq!(path(&app, \"Saved drawing\"), saved);\n assert!(app.session.active().unwrap().doc.work_path.is_none());\n assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_none());\n assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(app.session.active().unwrap().doc.layer(layer).unwrap().vector_mask.as_ref(), Some(&original));",
|
||
" assert_eq!(steps(&app), n + 1);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(app.session.active().unwrap().doc.layer(layer).unwrap().vector_mask.as_ref(), Some(&original));\n}",
|
||
" assert_eq!(app.session.active().unwrap().doc.layer(layer).unwrap().vector_mask.as_ref(), Some(&original));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "freeform_finish_uses_its_captured_saved_path_and_rejects_foreign_documents",
|
||
"path": "crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked freeform_finish_uses_its_captured_saved_path_and_rejects_foreign_documents -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::FreeformPen);\n seed(&mut app, \"work\", 20.0);\n seed(&mut app, \"Saved drawing\", 40.0);\n app.ui.selected_path = Some(\"Saved drawing\".into());\n let owner = vector_ui::capture_pen_owner(&app).unwrap();\n let points = [[30.0, 60.0, 1.0], [80.0, 60.0, 1.0], [130.0, 60.0, 1.0]];\n let (original, work, n) = (path(&app, \"Saved drawing\"), path(&app, \"work\"), steps(&app));\n app.ui.selected_path = Some(\"work\".into());\n app.ui.tool_options.vector_mode = \"shape\".into();\n vector_ui::freeform_finish_owned(&mut app, &points, &[], owner);\n assert_eq!(path(&app, \"Saved drawing\").subpaths.len(), 2);\n assert_eq!(path(&app, \"Saved drawing\").subpaths[0], original.subpaths[0]);",
|
||
"expected_assertions": [
|
||
" assert_eq!(path(&app, \"Saved drawing\").subpaths.len(), 2);\n assert_eq!(path(&app, \"Saved drawing\").subpaths[0], original.subpaths[0]);\n assert_eq!(path(&app, \"work\"), work);\n assert_eq!(steps(&app), n + 1);",
|
||
" assert_eq!(path(&app, \"Saved drawing\").subpaths[0], original.subpaths[0]);\n assert_eq!(path(&app, \"work\"), work);\n assert_eq!(steps(&app), n + 1);\n app.ui.tool_options.vector_mode = \"path\".into();",
|
||
" assert_eq!(path(&app, \"work\"), work);\n assert_eq!(steps(&app), n + 1);\n app.ui.tool_options.vector_mode = \"path\".into();\n let owner = vector_ui::capture_pen_owner(&app).unwrap();",
|
||
" assert_eq!(steps(&app), n + 1);\n app.ui.tool_options.vector_mode = \"path\".into();\n let owner = vector_ui::capture_pen_owner(&app).unwrap();\n app.session.execute(\"file.new\", json!({\"width\":200,\"height\":200})).unwrap();",
|
||
" assert!(std::sync::Arc::ptr_eq(&source, &app.session.active().unwrap().doc));\n assert_eq!(steps(&app), n);\n}",
|
||
" assert_eq!(steps(&app), n);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_ownership_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "saved_path_drag_visual_fixture",
|
||
"path": "crates/ui-egui/src/pen_path_visual_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked saved_path_drag_visual_fixture -- --nocapture --ignored",
|
||
"fixture_and_action_excerpt": " let baseline = std::env::var(\"PHOTOCRAFT_PEN_VISUAL_BASELINE\").is_ok_and(|v| v == \"1\");\n let output = std::env::var_os(\"PHOTOCRAFT_PEN_VISUAL_DIR\").map(std::path::PathBuf::from).unwrap_or_else(|| \"log/pen-path-visual\".into());\n std::fs::create_dir_all(&output).expect(\"create synthetic screenshot directory\");\n let mut h = egui_kittest::Harness::builder().with_size(vec2(1280.0, 800.0)).with_max_steps(64).wgpu().build_eframe(|cc| {\n PhotocraftApp::setup_context(&cc.egui_ctx, Default::default());\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.session.edit_prefs(|p| p.interface.language = \"en\".into());\n if let Some(rs) = cc.wgpu_render_state.as_ref() {\n app.set_wgpu(rs.clone());\n }\n app.run(\"file.new\", json!({\"name\": \"Saved path targeting\", \"width\": 400, \"height\": 260, \"background\": \"white\"})).unwrap();\n app.run(\"path.set\", json!({\"name\": \"work\", \"path\": {\"subpaths\": [{\"closed\": true, \"knots\": [[40, 80], [140, 80], [90, 180]]}]}})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().ui.selected_path.as_deref(), Some(\"Saved drawing\"), \"the Paths panel row selects the saved path\");\n let (work, saved) = (path(h.state(), \"work\"), path(h.state(), \"Saved drawing\"));\n let history = h.state().session.active().unwrap().history.past_len();\n let mode = if baseline { \"baseline\" } else { \"fixed\" };",
|
||
" assert!(xf.rect.contains(start) && xf.rect.contains(end));\n h.event(Event::PointerMoved(start));\n h.event(button(start, true));\n h.step();",
|
||
" assert!(h.state().drag.is_some(), \"native movement past the drag threshold starts a path gesture\");\n h.event(button(end, false));\n h.step();\n h.run_steps(12);",
|
||
" assert!(h.state().drag.is_none());\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 1, \"one native drag is one Undo step\");\n if baseline {\n assert_eq!(path(h.state(), \"Saved drawing\"), saved, \"baseline incorrectly leaves the selected saved path untouched\");",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 1, \"one native drag is one Undo step\");\n if baseline {\n assert_eq!(path(h.state(), \"Saved drawing\"), saved, \"baseline incorrectly leaves the selected saved path untouched\");\n assert_eq!(path(h.state(), \"work\"), translated(work, 25.0, -20.0), \"baseline incorrectly moves the Work Path\");",
|
||
" assert_eq!(path(h.state(), \"Saved drawing\"), saved, \"baseline incorrectly leaves the selected saved path untouched\");\n assert_eq!(path(h.state(), \"work\"), translated(work, 25.0, -20.0), \"baseline incorrectly moves the Work Path\");\n } else {\n assert_eq!(path(h.state(), \"work\"), work, \"editing a saved path preserves the Work Path\");",
|
||
" assert_eq!(path(h.state(), \"work\"), translated(work, 25.0, -20.0), \"baseline incorrectly moves the Work Path\");\n } else {\n assert_eq!(path(h.state(), \"work\"), work, \"editing a saved path preserves the Work Path\");\n assert_eq!(path(h.state(), \"Saved drawing\"), translated(saved, 25.0, -20.0), \"the selected saved path and its curve handles move together\");",
|
||
" assert_eq!(path(h.state(), \"work\"), work, \"editing a saved path preserves the Work Path\");\n assert_eq!(path(h.state(), \"Saved drawing\"), translated(saved, 25.0, -20.0), \"the selected saved path and its curve handles move together\");\n }\n let after = output.join(format!(\"{mode}-after.png\"));",
|
||
" assert_eq!(path(h.state(), \"Saved drawing\"), translated(saved, 25.0, -20.0), \"the selected saved path and its curve handles move together\");\n }\n let after = output.join(format!(\"{mode}-after.png\"));\n h.render().expect(\"render completed drag\").save(&after).expect(\"save completed drag\");"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/pen_path_visual_tests.rs",
|
||
"ignored_requires_explicit_execution": true
|
||
},
|
||
{
|
||
"name": "enter_selects_a_stroke_style_and_escape_closes_its_popups_without_committing_pen",
|
||
"path": "crates/ui-egui/src/shape_stroke_ui/shortcut_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked enter_selects_a_stroke_style_and_escape_closes_its_popups_without_committing_pen -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::Pen);\n let owner = crate::vector_ui::capture_pen_owner(&app);\n app.ui.pen = Some(crate::vector_ui::PenPath { knots: vec![[[12.0, 12.0]; 3], [[60.0, 40.0]; 3]], owner, ..Default::default() });\n let pen = app.ui.pen.clone();\n let original = app.session.active().unwrap().doc.clone();\n let history = app.session.active().unwrap().history.past_len();\n let mut h = harness(app, false);\n open(&mut h);\n h.get_by_role_and_label(egui::accesskit::Role::RadioButton, \"Dotted\").focus();\n h.run_steps(2);\n h.key_press(Key::Enter);\n h.run_steps(3);",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().ui.tool_options.shape_stroke.dashes, [0.0, 2.0]);\n assert_eq!(h.state().ui.pen, pen, \"Enter belongs to the focused style target\");\n h.get_by_role_and_label(egui::accesskit::Role::ComboBox, \"Caps\").click();\n h.run_steps(3);",
|
||
" assert_eq!(h.state().ui.pen, pen, \"Enter belongs to the focused style target\");\n h.get_by_role_and_label(egui::accesskit::Role::ComboBox, \"Caps\").click();\n h.run_steps(3);\n assert!(egui::Popup::is_any_open(&h.ctx));",
|
||
" assert!(egui::Popup::is_any_open(&h.ctx));\n h.key_press(Key::Escape);\n h.run_steps(3);\n assert!(!egui::Popup::is_any_open(&h.ctx));",
|
||
" assert!(!egui::Popup::is_any_open(&h.ctx));\n assert!(h.state().ui.stroke_editor.is_some());\n assert_eq!(h.state().ui.pen, pen);\n h.key_press(Key::Escape);",
|
||
" assert!(h.state().ui.stroke_editor.is_some());\n assert_eq!(h.state().ui.pen, pen);\n h.key_press(Key::Escape);\n h.run_steps(3);",
|
||
" assert_eq!(h.state().ui.pen, pen);\n h.key_press(Key::Escape);\n h.run_steps(3);\n assert!(h.state().ui.stroke_editor.is_none());",
|
||
" assert!(h.state().ui.stroke_editor.is_none());\n assert_eq!(h.state().ui.pen, pen, \"dismissing Stroke Options leaves the Pen gesture intact\");\n assert_eq!(h.state().session.active().unwrap().doc, original);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);",
|
||
" assert_eq!(h.state().ui.pen, pen, \"dismissing Stroke Options leaves the Pen gesture intact\");\n assert_eq!(h.state().session.active().unwrap().doc, original);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().doc, original);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/shape_stroke_ui/shortcut_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "transparent_and_absent_paints_remain_distinct_and_open_pen_keeps_foreground",
|
||
"path": "crates/ui-egui/src/vector_paint_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked transparent_and_absent_paints_remain_distinct_and_open_pen_keeps_foreground -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(\"rgb\", 32);\n let transparent = [0.124578, 0.564321, 0.765432, 0.0];\n set_tool_paint(&mut app, false, PaintChange::Color(transparent)).unwrap();\n set_tool_paint(&mut app, true, PaintChange::Color(transparent)).unwrap();\n let preview = shape_preview(&app, Tool::Rectangle, [20.0, 20.0], [80.0, 70.0], Modifiers::NONE).unwrap();\n assert_eq!(preview.fill, Some(solid_paint(transparent)));\n assert_eq!(preview.stroke.as_ref().unwrap().paint, solid_paint(transparent));\n finish_shape(&mut app, Tool::Rectangle, [20.0, 20.0], [80.0, 70.0], Modifiers::NONE);\n assert_eq!(shape(&app).fill, preview.fill);\n assert_eq!(shape(&app).stroke, preview.stroke);\n assert_eq!(shape(&app).cache.as_ref().unwrap().pixel(40, 40), vec![0.0; 4]);\n set_tool_paint(&mut app, false, PaintChange::None).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(preview.fill, Some(solid_paint(transparent)));\n assert_eq!(preview.stroke.as_ref().unwrap().paint, solid_paint(transparent));\n finish_shape(&mut app, Tool::Rectangle, [20.0, 20.0], [80.0, 70.0], Modifiers::NONE);\n assert_eq!(shape(&app).fill, preview.fill);",
|
||
" assert_eq!(preview.stroke.as_ref().unwrap().paint, solid_paint(transparent));\n finish_shape(&mut app, Tool::Rectangle, [20.0, 20.0], [80.0, 70.0], Modifiers::NONE);\n assert_eq!(shape(&app).fill, preview.fill);\n assert_eq!(shape(&app).stroke, preview.stroke);",
|
||
" assert_eq!(shape(&app).fill, preview.fill);\n assert_eq!(shape(&app).stroke, preview.stroke);\n assert_eq!(shape(&app).cache.as_ref().unwrap().pixel(40, 40), vec![0.0; 4]);\n set_tool_paint(&mut app, false, PaintChange::None).unwrap();",
|
||
" assert_eq!(shape(&app).stroke, preview.stroke);\n assert_eq!(shape(&app).cache.as_ref().unwrap().pixel(40, 40), vec![0.0; 4]);\n set_tool_paint(&mut app, false, PaintChange::None).unwrap();\n set_tool_paint(&mut app, true, PaintChange::None).unwrap();",
|
||
" assert_eq!(shape(&app).cache.as_ref().unwrap().pixel(40, 40), vec![0.0; 4]);\n set_tool_paint(&mut app, false, PaintChange::None).unwrap();\n set_tool_paint(&mut app, true, PaintChange::None).unwrap();\n finish_shape(&mut app, Tool::Triangle, [20.0, 20.0], [80.0, 70.0], Modifiers::NONE);",
|
||
" assert!(shape(&app).fill.is_none() && shape(&app).stroke.is_none());\n let foreground = [0.836521, 0.125468, 0.745632, 0.438271];\n app.run(\"tools.setColors\", json!({\"foreground\": foreground, \"background\": [0.0, 1.0, 0.0, 1.0]})).unwrap();\n app.ui.tool_options.vector_mode = \"shape\".into();",
|
||
" assert!(shape(&app).fill.is_none());\n assert!(!shape(&app).path.subpaths[0].closed);\n assert_eq!(shape(&app).stroke.as_ref().unwrap().paint, solid_paint(foreground));\n}",
|
||
" assert!(!shape(&app).path.subpaths[0].closed);\n assert_eq!(shape(&app).stroke.as_ref().unwrap().paint, solid_paint(foreground));\n}",
|
||
" assert_eq!(shape(&app).stroke.as_ref().unwrap().paint, solid_paint(foreground));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/vector_paint_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "all_shape_tools_and_open_pen_use_the_complete_stroke_defaults",
|
||
"path": "crates/ui-egui/src/vector_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked all_shape_tools_and_open_pen_use_the_complete_stroke_defaults -- --nocapture",
|
||
"fixture_and_action_excerpt": " for tool in [Tool::Rectangle, Tool::EllipseShape, Tool::Triangle, Tool::Polygon, Tool::Line, Tool::CustomShape] {\n let mut a = app();\n a.ui.tool_options.stroke_width = 5.0;\n a.ui.tool_options.shape_stroke = crate::shape_stroke_ui::StrokeOptions {\n cap: photocraft_doc::LineCap::Square,\n join: photocraft_doc::LineJoin::Bevel,\n dashes: vec![4.0, 2.0, 1.0, 3.0],\n dash_offset: -0.5,\n opacity: 0.4,\n ..Default::default()\n };\n let history = a.session.active().unwrap().history.past_len();",
|
||
"expected_assertions": [
|
||
" assert_eq!(info[\"stroke\"][\"dashes\"], json!([4.0, 2.0, 1.0, 3.0]));\n assert_eq!(info[\"stroke\"][\"cap\"], \"square\");\n assert_eq!(info[\"stroke\"][\"width\"], 5.0);\n assert_eq!(a.session.active().unwrap().history.past_len(), history + 1);",
|
||
" assert_eq!(info[\"stroke\"][\"cap\"], \"square\");\n assert_eq!(info[\"stroke\"][\"width\"], 5.0);\n assert_eq!(a.session.active().unwrap().history.past_len(), history + 1);\n a.run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(info[\"stroke\"][\"width\"], 5.0);\n assert_eq!(a.session.active().unwrap().history.past_len(), history + 1);\n a.run(\"edit.undo\", json!({})).unwrap();\n a.run(\"edit.redo\", json!({})).unwrap();",
|
||
" assert_eq!(a.session.active().unwrap().history.past_len(), history + 1);\n a.run(\"edit.undo\", json!({})).unwrap();\n a.run(\"edit.redo\", json!({})).unwrap();\n assert_eq!(a.run(\"shape.info\", json!({})).unwrap(), info);",
|
||
" assert_eq!(a.run(\"shape.info\", json!({})).unwrap(), info);\n a.ui.tool_options.vector_mode = \"shape\".into();\n a.ui.pen = Some(PenPath { knots: vec![[[30.0, 40.0]; 3], [[80.0, 40.0]; 3]], owner: capture_pen_owner(&a), ..Default::default() });\n pen_commit(&mut a, false);",
|
||
" assert_eq!(open[\"stroke\"][\"dashes\"], info[\"stroke\"][\"dashes\"]);\n assert_eq!(open[\"path\"][\"subpaths\"][0][\"closed\"], false);\n }\n }",
|
||
" assert_eq!(open[\"path\"][\"subpaths\"][0][\"closed\"], false);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/vector_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "freeform_straight_segments_keep_the_captured_saved_path_and_reject_a_foreign_document",
|
||
"path": "crates/ui-egui/src/vector_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked freeform_straight_segments_keep_the_captured_saved_path_and_reject_a_foreign_document -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n app.ui.tool = Tool::FreeformPen;\n let seed = json!({\"subpaths\":[{\"knots\":[[20,20],[120,20]]}]});\n for name in [\"work\", \"Saved drawing\"] {\n app.run(\"path.set\", json!({\"name\": name, \"path\": seed})).unwrap();\n }\n app.ui.selected_path = Some(\"Saved drawing\".into());\n let owner = capture_pen_owner(&app).unwrap();\n let original = app.session.active().unwrap().doc.clone();\n let n = app.session.active().unwrap().history.past_len();\n let points = [[20.0, 60.0, 1.0], [60.0, 60.0, 1.0], [100.0, 80.0, 1.0], [140.0, 80.0, 1.0]];\n app.ui.selected_path = Some(\"work\".into());",
|
||
"expected_assertions": [
|
||
" assert_eq!(st.doc.work_path, original.work_path);\n let saved = &st.doc.paths.iter().find(|p| p.name == \"Saved drawing\").unwrap().path;\n assert_eq!(saved.subpaths[0], original.paths[0].path.subpaths[0]);\n assert_eq!(saved.subpaths.len(), 2);",
|
||
" assert_eq!(saved.subpaths[0], original.paths[0].path.subpaths[0]);\n assert_eq!(saved.subpaths.len(), 2);\n let knots = &saved.subpaths[1].knots;\n assert_eq!(knots.len(), 4);",
|
||
" assert_eq!(saved.subpaths.len(), 2);\n let knots = &saved.subpaths[1].knots;\n assert_eq!(knots.len(), 4);\n for (a, b) in [(0, 1), (2, 3)] {",
|
||
" assert_eq!(knots.len(), 4);\n for (a, b) in [(0, 1), (2, 3)] {\n assert_eq!(knots[a].out_ctrl, knots[a].anchor, \"straight segment starts at its anchor\");\n assert_eq!(knots[b].in_ctrl, knots[b].anchor, \"straight segment ends at its anchor\");",
|
||
" assert_eq!(knots[a].out_ctrl, knots[a].anchor, \"straight segment starts at its anchor\");\n assert_eq!(knots[b].in_ctrl, knots[b].anchor, \"straight segment ends at its anchor\");\n }\n assert_eq!(st.history.past_len(), n + 1);",
|
||
" assert_eq!(knots[b].in_ctrl, knots[b].anchor, \"straight segment ends at its anchor\");\n }\n assert_eq!(st.history.past_len(), n + 1);\n assert!(app.ui.pen.is_none());",
|
||
" assert_eq!(st.history.past_len(), n + 1);\n assert!(app.ui.pen.is_none());\n app.ui.tool_options.vector_mode = \"path\".into();\n let owner = capture_pen_owner(&app).unwrap();",
|
||
" assert!(app.ui.pen.is_none());\n app.ui.tool_options.vector_mode = \"path\".into();\n let owner = capture_pen_owner(&app).unwrap();\n app.run(\"file.new\", json!({\"width\": 200, \"height\": 200})).unwrap();",
|
||
" assert!(Arc::ptr_eq(&source, &app.session.active().unwrap().doc));\n assert_eq!(app.session.active().unwrap().history.past_len(), n);\n }",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), n);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/vector_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "failed_freeform_straight_segment_commit_keeps_its_owned_fitted_draft",
|
||
"path": "crates/ui-egui/src/vector_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked failed_freeform_straight_segment_commit_keeps_its_owned_fitted_draft -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n app.ui.tool = Tool::FreeformPen;\n let owner = capture_pen_owner(&app).unwrap();\n let (source, n) = (app.session.active().unwrap().doc.clone(), app.session.active().unwrap().history.past_len());\n let points = [[20.0, 60.0, 1.0], [1e40, 60.0, 1.0], [140.0, 80.0, 1.0]];\n freeform_finish_owned(&mut app, &points, &[1, 2], owner.clone());\n let pen = app.ui.pen.as_ref().expect(\"invalid fitted geometry must remain available after its failed commit\");\n assert!(pen.commit_failed);\n assert_eq!(pen.owner.as_ref(), Some(&owner));\n assert!(owner.valid(&app));\n assert_eq!(pen.knots.len(), 3);\n assert_eq!(pen.knots[1], [[1e40, 60.0]; 3]);",
|
||
"expected_assertions": [
|
||
" assert!(pen.commit_failed);\n assert_eq!(pen.owner.as_ref(), Some(&owner));\n assert!(owner.valid(&app));\n assert_eq!(pen.knots.len(), 3);",
|
||
" assert_eq!(pen.owner.as_ref(), Some(&owner));\n assert!(owner.valid(&app));\n assert_eq!(pen.knots.len(), 3);\n assert_eq!(pen.knots[1], [[1e40, 60.0]; 3]);",
|
||
" assert!(owner.valid(&app));\n assert_eq!(pen.knots.len(), 3);\n assert_eq!(pen.knots[1], [[1e40, 60.0]; 3]);\n assert!(Arc::ptr_eq(&source, &app.session.active().unwrap().doc));",
|
||
" assert_eq!(pen.knots.len(), 3);\n assert_eq!(pen.knots[1], [[1e40, 60.0]; 3]);\n assert!(Arc::ptr_eq(&source, &app.session.active().unwrap().doc));\n assert_eq!(app.session.active().unwrap().history.past_len(), n);",
|
||
" assert_eq!(pen.knots[1], [[1e40, 60.0]; 3]);\n assert!(Arc::ptr_eq(&source, &app.session.active().unwrap().doc));\n assert_eq!(app.session.active().unwrap().history.past_len(), n);\n }",
|
||
" assert!(Arc::ptr_eq(&source, &app.session.active().unwrap().doc));\n assert_eq!(app.session.active().unwrap().history.past_len(), n);\n }",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), n);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/vector_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "show_target_path_and_extras_hide_the_path_outlines",
|
||
"path": "crates/ui-egui/src/vector_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked show_target_path_and_extras_hide_the_path_outlines -- --nocapture",
|
||
"fixture_and_action_excerpt": " // #1119: View › Show › Target Path only flipped its checkmark; the canvas kept drawing the\n // work path and the active shape's path.\n let ctx = egui::Context::default();\n let mut app = app();\n let path = json!({\"subpaths\": [{\"closed\": true, \"knots\": [\n {\"anchor\": [10, 10], \"in\": [10, 10], \"out\": [10, 10]},\n {\"anchor\": [80, 10], \"in\": [80, 10], \"out\": [80, 10]},\n {\"anchor\": [80, 80], \"in\": [80, 80], \"out\": [80, 80]}\n ]}]});\n app.run(\"path.set\", json!({\"path\": path})).unwrap();\n assert!(app.session.active().unwrap().doc.work_path.is_some());\n finish_shape(&mut app, Tool::Rectangle, [100.0, 100.0], [160.0, 150.0], egui::Modifiers::NONE);",
|
||
"expected_assertions": [
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_some());\n finish_shape(&mut app, Tool::Rectangle, [100.0, 100.0], [160.0, 150.0], egui::Modifiers::NONE);\n let toggle = |app: &mut PhotocraftApp, id: &str| crate::menus::invoke(app, &ctx, id, Value::Null).unwrap();\n for tool in [Tool::Pen, Tool::PathSelection, Tool::DirectSelection, Tool::Rectangle] {",
|
||
" assert!(app.ui.view.show.target_path && app.ui.view.extras);\n assert!(overlay_shapes(&app, &ctx) > 0, \"{tool:?}: the paths are drawn by default\");\n toggle(&mut app, \"view.show.targetPath\");\n assert!(!app.ui.view.show.target_path);",
|
||
" assert!(overlay_shapes(&app, &ctx) > 0, \"{tool:?}: the paths are drawn by default\");\n toggle(&mut app, \"view.show.targetPath\");\n assert!(!app.ui.view.show.target_path);\n assert_eq!(overlay_shapes(&app, &ctx), 0, \"{tool:?}: Target Path off\");",
|
||
" assert!(!app.ui.view.show.target_path);\n assert_eq!(overlay_shapes(&app, &ctx), 0, \"{tool:?}: Target Path off\");\n toggle(&mut app, \"view.show.targetPath\");\n toggle(&mut app, \"view.extras\");",
|
||
" assert_eq!(overlay_shapes(&app, &ctx), 0, \"{tool:?}: Target Path off\");\n toggle(&mut app, \"view.show.targetPath\");\n toggle(&mut app, \"view.extras\");\n assert!(!app.ui.view.extras);",
|
||
" assert!(!app.ui.view.extras);\n assert_eq!(overlay_shapes(&app, &ctx), 0, \"{tool:?}: Extras off\");\n toggle(&mut app, \"view.extras\");\n assert!(overlay_shapes(&app, &ctx) > 0, \"{tool:?}: shown again\");",
|
||
" assert_eq!(overlay_shapes(&app, &ctx), 0, \"{tool:?}: Extras off\");\n toggle(&mut app, \"view.extras\");\n assert!(overlay_shapes(&app, &ctx) > 0, \"{tool:?}: shown again\");\n }",
|
||
" assert!(overlay_shapes(&app, &ctx) > 0, \"{tool:?}: shown again\");\n }\n // The Pen's path in progress is a gesture, not the target path: it stays visible.\n app.ui.tool = Tool::Pen;",
|
||
" assert!(overlay_shapes(&app, &ctx) > 0, \"the pen path in progress is still drawn\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/vector_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "pen_last_anchor_hit_tolerance_tracks_zoom_and_draft_round_trips",
|
||
"path": "crates/ui-egui/src/vector_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked pen_last_anchor_hit_tolerance_tracks_zoom_and_draft_round_trips -- --nocapture",
|
||
"fixture_and_action_excerpt": " for zoom in [0.25, 1.0, 4.0] {\n let mut app = app();\n app.ui.views[0].zoom = zoom;\n pen_down(&mut app, 20.0, 20.0);\n pen_up(&mut app);\n pen_down(&mut app, 100.0, 100.0);\n pen_move(&mut app, 110.0, 120.0);\n pen_up(&mut app);\n let incoming = app.ui.pen.as_ref().unwrap().knots[1][1];\n pen_down(&mut app, 100.0 + 5.0 / f64::from(zoom), 100.0);\n pen_up(&mut app);\n let pen = app.ui.pen.as_ref().unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(pen.knots.len(), 2);\n assert_eq!(pen.knots[1][1], incoming);\n assert_eq!(pen.knots[1][2], pen.knots[1][0]);\n let saved = serde_json::to_value(pen).unwrap();",
|
||
" assert_eq!(pen.knots[1][1], incoming);\n assert_eq!(pen.knots[1][2], pen.knots[1][0]);\n let saved = serde_json::to_value(pen).unwrap();\n let restored: PenPath = serde_json::from_value(saved).unwrap();",
|
||
" assert_eq!(pen.knots[1][2], pen.knots[1][0]);\n let saved = serde_json::to_value(pen).unwrap();\n let restored: PenPath = serde_json::from_value(saved).unwrap();\n // The runtime owner isn't saved: a restored draft belongs to no document.",
|
||
" assert_eq!(restored, PenPath { owner: None, ..pen.clone() });\n assert_eq!(pen_to_json(&restored, false)[\"subpaths\"][0][\"knots\"][1][\"smooth\"], false);\n pen_down(&mut app, 100.0 + 7.0 / f64::from(zoom), 100.0);\n assert_eq!(app.ui.pen.as_ref().unwrap().knots.len(), 3);",
|
||
" assert_eq!(pen_to_json(&restored, false)[\"subpaths\"][0][\"knots\"][1][\"smooth\"], false);\n pen_down(&mut app, 100.0 + 7.0 / f64::from(zoom), 100.0);\n assert_eq!(app.ui.pen.as_ref().unwrap().knots.len(), 3);\n }",
|
||
" assert_eq!(app.ui.pen.as_ref().unwrap().knots.len(), 3);\n }\n let legacy: PenPath = serde_json::from_value(json!({\"knots\": [[[10, 10], [10, 10], [10, 10]]]})).unwrap();\n assert!(legacy.unlinked.is_empty());",
|
||
" assert!(legacy.unlinked.is_empty());\n assert!(!legacy.dragging && !legacy.adjusting_last);\n }",
|
||
" assert!(!legacy.dragging && !legacy.adjusting_last);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/ui-egui/src/vector_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "general_paths_keep_large_straight_coordinates_and_shape_limits_stay_put",
|
||
"path": "crates/vector/src/flatten.rs",
|
||
"package": "photocraft-vector",
|
||
"command": "cargo test -p photocraft-vector --locked general_paths_keep_large_straight_coordinates_and_shape_limits_stay_put -- --nocapture",
|
||
"fixture_and_action_excerpt": " let at_shape_limit = Path { subpaths: vec![Subpath::polygon(&[(0.0, 0.0), (1_000_000.0, 0.0)])], ..Default::default() };\n assert!(validate_shape(&at_shape_limit, None).is_ok());\n let outside_shape = Path { subpaths: vec![Subpath::polygon(&[(0.0, 0.0), (1_000_001.0, 0.0)])], ..Default::default() };\n assert_eq!(validate_shape(&outside_shape, None), Err(\"shape coordinates must be finite and within ±1000000 px\"));\n assert!(validate_path(&outside_shape).is_ok());\n for extent in [3.0e9, f64::from(f32::MAX)] {\n let path = Path { subpaths: vec![Subpath::polygon(&[(0.0, 0.0), (extent, 0.0), (extent, extent)])], ..Default::default() };\n assert!(validate_path(&path).is_ok());\n let line = flatten_subpath(&path.subpaths[0], crate::DEFAULT_TOLERANCE);\n assert_eq!(line.pts, [(0.0, 0.0), (extent, 0.0), (extent, extent)]);\n assert!(line.pts.iter().all(|(x, y)| (*x as f32).is_finite() && (*y as f32).is_finite()));\n assert!(validate_shape(&path, None).is_err());",
|
||
"expected_assertions": [
|
||
" assert!(validate_shape(&at_shape_limit, None).is_ok());\n let outside_shape = Path { subpaths: vec![Subpath::polygon(&[(0.0, 0.0), (1_000_001.0, 0.0)])], ..Default::default() };\n assert_eq!(validate_shape(&outside_shape, None), Err(\"shape coordinates must be finite and within ±1000000 px\"));\n assert!(validate_path(&outside_shape).is_ok());",
|
||
" assert_eq!(validate_shape(&outside_shape, None), Err(\"shape coordinates must be finite and within ±1000000 px\"));\n assert!(validate_path(&outside_shape).is_ok());\n for extent in [3.0e9, f64::from(f32::MAX)] {\n let path = Path { subpaths: vec![Subpath::polygon(&[(0.0, 0.0), (extent, 0.0), (extent, extent)])], ..Default::default() };",
|
||
" assert!(validate_path(&outside_shape).is_ok());\n for extent in [3.0e9, f64::from(f32::MAX)] {\n let path = Path { subpaths: vec![Subpath::polygon(&[(0.0, 0.0), (extent, 0.0), (extent, extent)])], ..Default::default() };\n assert!(validate_path(&path).is_ok());",
|
||
" assert!(validate_path(&path).is_ok());\n let line = flatten_subpath(&path.subpaths[0], crate::DEFAULT_TOLERANCE);\n assert_eq!(line.pts, [(0.0, 0.0), (extent, 0.0), (extent, extent)]);\n assert!(line.pts.iter().all(|(x, y)| (*x as f32).is_finite() && (*y as f32).is_finite()));",
|
||
" assert_eq!(line.pts, [(0.0, 0.0), (extent, 0.0), (extent, extent)]);\n assert!(line.pts.iter().all(|(x, y)| (*x as f32).is_finite() && (*y as f32).is_finite()));\n assert!(validate_shape(&path, None).is_err());\n }",
|
||
" assert!(line.pts.iter().all(|(x, y)| (*x as f32).is_finite() && (*y as f32).is_finite()));\n assert!(validate_shape(&path, None).is_err());\n }\n }",
|
||
" assert!(validate_shape(&path, None).is_err());\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/vector/src/flatten.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "general_paths_reject_coordinates_that_overflow_the_ui_or_segment_arithmetic",
|
||
"path": "crates/vector/src/flatten.rs",
|
||
"package": "photocraft-vector",
|
||
"command": "cargo test -p photocraft-vector --locked general_paths_reject_coordinates_that_overflow_the_ui_or_segment_arithmetic -- --nocapture",
|
||
"fixture_and_action_excerpt": " for extent in [f64::from(f32::MAX) * 2.0, 1.0e308, f64::INFINITY, f64::NAN] {\n let path = Path { subpaths: vec![Subpath::polygon(&[(-extent, 0.0), (extent, 0.0)])], ..Default::default() };\n assert_eq!(validate_path(&path), Err(\"path coordinates must be finite and representable as f32\"));\n }\n // The shared arithmetic guard also rejects overflow independently of coordinate policy.\n let overflowing_difference = Path { subpaths: vec![Subpath::polygon(&[(-1.0e308, 0.0), (1.0e308, 0.0)])], ..Default::default() };\n assert_eq!(validate_workload(&overflowing_difference, None, f64::MAX, \"coordinates\"), Err(\"path geometry arithmetic must be finite\"));\n let overflowing_length = Path { subpaths: vec![Subpath::polygon(&[(0.0, 0.0), (f64::MAX, f64::MAX)])], ..Default::default() };\n assert_eq!(validate_workload(&overflowing_length, None, f64::MAX, \"coordinates\"), Err(\"path geometry arithmetic must be finite\"));\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(validate_path(&path), Err(\"path coordinates must be finite and representable as f32\"));\n }\n // The shared arithmetic guard also rejects overflow independently of coordinate policy.\n let overflowing_difference = Path { subpaths: vec![Subpath::polygon(&[(-1.0e308, 0.0), (1.0e308, 0.0)])], ..Default::default() };",
|
||
" assert_eq!(validate_workload(&overflowing_difference, None, f64::MAX, \"coordinates\"), Err(\"path geometry arithmetic must be finite\"));\n let overflowing_length = Path { subpaths: vec![Subpath::polygon(&[(0.0, 0.0), (f64::MAX, f64::MAX)])], ..Default::default() };\n assert_eq!(validate_workload(&overflowing_length, None, f64::MAX, \"coordinates\"), Err(\"path geometry arithmetic must be finite\"));\n }",
|
||
" assert_eq!(validate_workload(&overflowing_length, None, f64::MAX, \"coordinates\"), Err(\"path geometry arithmetic must be finite\"));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/vector/src/flatten.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "general_paths_bound_total_knots_subpaths_and_combined_tessellation",
|
||
"path": "crates/vector/src/flatten.rs",
|
||
"package": "photocraft-vector",
|
||
"command": "cargo test -p photocraft-vector --locked general_paths_bound_total_knots_subpaths_and_combined_tessellation -- --nocapture",
|
||
"fixture_and_action_excerpt": " let line = Subpath::polygon(&[(0.0, 0.0)]);\n let mut paths = Path { subpaths: vec![line.clone(); 4096], ..Default::default() };\n assert!(validate_path(&paths).is_ok());\n paths.subpaths.push(line);\n assert_eq!(validate_path(&paths), Err(\"path exceeds 4096 knots/subpaths\"));\n let knots = Path { subpaths: vec![Subpath::polygon(&vec![(0.0, 0.0); 4097])], ..Default::default() };\n assert_eq!(validate_path(&knots), Err(\"path exceeds 4096 knots/subpaths\"));\n\n let curve = shapes::ellipse(0.0, 0.0, 1000.0, 1000.0).subpaths.remove(0);\n let points = 1 + curve.segments().iter().map(|s| if is_line(s) { 1 } else { pieces(s, crate::DEFAULT_TOLERANCE) }).sum::<usize>();\n let half = 100_000 / points / 2 + 1;\n let mut combined = Path { subpaths: vec![curve.clone(); half], ..Default::default() };",
|
||
"expected_assertions": [
|
||
" assert!(validate_path(&paths).is_ok());\n paths.subpaths.push(line);\n assert_eq!(validate_path(&paths), Err(\"path exceeds 4096 knots/subpaths\"));\n let knots = Path { subpaths: vec![Subpath::polygon(&vec![(0.0, 0.0); 4097])], ..Default::default() };",
|
||
" assert_eq!(validate_path(&paths), Err(\"path exceeds 4096 knots/subpaths\"));\n let knots = Path { subpaths: vec![Subpath::polygon(&vec![(0.0, 0.0); 4097])], ..Default::default() };\n assert_eq!(validate_path(&knots), Err(\"path exceeds 4096 knots/subpaths\"));\n",
|
||
" assert_eq!(validate_path(&knots), Err(\"path exceeds 4096 knots/subpaths\"));\n\n let curve = shapes::ellipse(0.0, 0.0, 1000.0, 1000.0).subpaths.remove(0);\n let points = 1 + curve.segments().iter().map(|s| if is_line(s) { 1 } else { pieces(s, crate::DEFAULT_TOLERANCE) }).sum::<usize>();",
|
||
" assert!(validate_path(&combined).is_ok());\n assert!(validate_shape(&combined, None).is_ok());\n combined.subpaths.extend(vec![curve; half]);\n assert!(combined.subpaths.len() < 4096 && combined.subpaths.iter().map(|s| s.knots.len()).sum::<usize>() < 4096);",
|
||
" assert!(validate_shape(&combined, None).is_ok());\n combined.subpaths.extend(vec![curve; half]);\n assert!(combined.subpaths.len() < 4096 && combined.subpaths.iter().map(|s| s.knots.len()).sum::<usize>() < 4096);\n assert_eq!(validate_path(&combined), Err(\"path tessellation exceeds 100000 points\"));",
|
||
" assert!(combined.subpaths.len() < 4096 && combined.subpaths.iter().map(|s| s.knots.len()).sum::<usize>() < 4096);\n assert_eq!(validate_path(&combined), Err(\"path tessellation exceeds 100000 points\"));\n assert_eq!(validate_shape(&combined, None), Err(\"path tessellation exceeds 100000 points\"));\n }",
|
||
" assert_eq!(validate_path(&combined), Err(\"path tessellation exceeds 100000 points\"));\n assert_eq!(validate_shape(&combined, None), Err(\"path tessellation exceeds 100000 points\"));\n }",
|
||
" assert_eq!(validate_shape(&combined, None), Err(\"path tessellation exceeds 100000 points\"));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1eecd00b2dff4ae4c642269cec211cd06ce1c3aa/crates/vector/src/flatten.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-3519",
|
||
"pr": 3519,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked layers_to_files_can_trim_transparent_margins_without_changing_the_document -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked streamed_layer_export_respects_trim -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked trimming_an_empty_layer_keeps_a_valid_nonzero_canvas -- --nocapture"
|
||
],
|
||
"expected": "layers to files can trim transparent margins without changing the document; streamed layer export respects trim; trimming an empty layer keeps a valid nonzero canvas",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked layers_to_files_can_trim_transparent_margins_without_changing_the_document -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked streamed_layer_export_respects_trim -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked trimming_an_empty_layer_keeps_a_valid_nonzero_canvas -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "layers_to_files_can_trim_transparent_margins_without_changing_the_document",
|
||
"path": "crates/engine/src/file_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked layers_to_files_can_trim_transparent_margins_without_changing_the_document -- --nocapture",
|
||
"fixture_and_action_excerpt": " let dir = tmp(\"layers-trim\");\n for depth in [8, 16, 32] {\n let mut s = session(12, 11, depth);\n s.execute(\"layer.new.layer\", json!({\"name\": \"Ink\"})).unwrap();\n s.execute(\"select.rect\", json!({\"x\": 3, \"y\": 2, \"width\": 4, \"height\": 5})).unwrap();\n s.execute(\"edit.fill\", json!({\"color\": \"#ff0000\"})).unwrap();\n s.execute(\"select.deselect\", json!({})).unwrap();\n\n let before = doc(&s).clone();\n let regular = s.execute(\"file.export.layersToFiles\", json!({\"dir\": dir, \"prefix\": format!(\"full-{depth}\"), \"format\": \"png\"})).unwrap();\n let full = std::fs::read(regular[\"files\"][0].as_str().unwrap()).unwrap();\n let full = photocraft_io::import(\"full.png\", &full).unwrap().document;",
|
||
"expected_assertions": [
|
||
" assert_eq!((full.size.width, full.size.height), (12, 11), \"default is unchanged\");\n\n let trimmed = s.execute(\"file.export.layersToFiles\", json!({\"dir\": dir, \"prefix\": format!(\"trim-{depth}\"), \"format\": \"png\", \"trim\": true})).unwrap();\n let image = std::fs::read(trimmed[\"files\"][0].as_str().unwrap()).unwrap();",
|
||
" assert_eq!((cropped.size.width, cropped.size.height), (4, 5), \"depth {depth}\");\n let px = photocraft_compose::render(&cropped, Rect::new(0, 0, 1, 1)).px[0];\n assert!(px[0] > 0.95 && px[1] < 0.05 && px[2] < 0.05, \"depth {depth}: {px:?}\");\n assert_eq!(*doc(&s), before, \"export must not crop the original document\");",
|
||
" assert!(px[0] > 0.95 && px[1] < 0.05 && px[2] < 0.05, \"depth {depth}: {px:?}\");\n assert_eq!(*doc(&s), before, \"export must not crop the original document\");\n }\n}",
|
||
" assert_eq!(*doc(&s), before, \"export must not crop the original document\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/807de6c043a512cb947d86b944c758b3db1277c7/crates/engine/src/file_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "streamed_layer_export_respects_trim",
|
||
"path": "crates/engine/src/file_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked streamed_layer_export_respects_trim -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session(12, 11, 8);\n s.execute(\"layer.new.layer\", json!({\"name\": \"Ink\"})).unwrap();\n s.execute(\"select.rect\", json!({\"x\": 3, \"y\": 2, \"width\": 4, \"height\": 5})).unwrap();\n s.execute(\"edit.fill\", json!({\"color\": \"#ff0000\"})).unwrap();\n s.execute(\"select.deselect\", json!({})).unwrap();\n let mut encoded = Vec::new();\n let names = super::export_layers_with(&s, &json!({\"trim\": true, \"format\": \"png\"}), |name, bytes| {\n encoded.push((name.to_string(), bytes.to_vec()));\n Ok(())\n })\n .unwrap();\n assert_eq!(names.len(), encoded.len());",
|
||
"expected_assertions": [
|
||
" assert_eq!(names.len(), encoded.len());\n let cropped = photocraft_io::import(&encoded[0].0, &encoded[0].1).unwrap().document;\n assert_eq!((cropped.size.width, cropped.size.height), (4, 5));\n}",
|
||
" assert_eq!((cropped.size.width, cropped.size.height), (4, 5));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/807de6c043a512cb947d86b944c758b3db1277c7/crates/engine/src/file_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "trimming_an_empty_layer_keeps_a_valid_nonzero_canvas",
|
||
"path": "crates/engine/src/file_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked trimming_an_empty_layer_keeps_a_valid_nonzero_canvas -- --nocapture",
|
||
"fixture_and_action_excerpt": " let dir = tmp(\"layers-trim-empty\");\n let mut s = session(6, 7, 8);\n s.execute(\"layer.new.layer\", json!({\"name\": \"Empty\"})).unwrap();\n let result = s.execute(\"file.export.layersToFiles\", json!({\"dir\": dir, \"format\": \"png\", \"trim\": true})).unwrap();\n let bytes = std::fs::read(result[\"files\"][0].as_str().unwrap()).unwrap();\n let back = photocraft_io::import(\"empty.png\", &bytes).unwrap().document;\n assert_eq!((back.size.width, back.size.height), (6, 7));\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!((back.size.width, back.size.height), (6, 7));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/807de6c043a512cb947d86b944c758b3db1277c7/crates/engine/src/file_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-5870",
|
||
"pr": 5870,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-format --locked duplicate_layer_ids_are_rejected_across_the_whole_tree -- --nocapture",
|
||
"cargo test -p photocraft-format --locked duplicate_extreme_layer_ids_are_not_silently_remapped -- --nocapture",
|
||
"cargo test -p photocraft-format --locked duplicate_layer_ids_are_rejected_before_fetching_payloads -- --nocapture",
|
||
"cargo test -p photocraft-format --locked unique_nested_layer_ids_preserve_comp_targets_in_both_load_modes -- --nocapture",
|
||
"cargo test -p photocraft-format --locked layer_identity_validation_keeps_smart_document_and_contents_scopes_independent -- --nocapture",
|
||
"cargo test -p photocraft-format --locked an_empty_layer_tree_loads_in_both_modes -- --nocapture"
|
||
],
|
||
"expected": "duplicate layer ids are rejected across the whole tree; duplicate extreme layer ids are not silently remapped; duplicate layer ids are rejected before fetching payloads; unique nested layer ids preserve comp targets in both load modes; layer identity validation keeps smart document and contents scopes independent; an empty layer tree loads in both modes",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-format --locked duplicate_layer_ids_are_rejected_across_the_whole_tree -- --nocapture",
|
||
"cargo test -p photocraft-format --locked duplicate_extreme_layer_ids_are_not_silently_remapped -- --nocapture",
|
||
"cargo test -p photocraft-format --locked duplicate_layer_ids_are_rejected_before_fetching_payloads -- --nocapture",
|
||
"cargo test -p photocraft-format --locked unique_nested_layer_ids_preserve_comp_targets_in_both_load_modes -- --nocapture",
|
||
"cargo test -p photocraft-format --locked layer_identity_validation_keeps_smart_document_and_contents_scopes_independent -- --nocapture",
|
||
"cargo test -p photocraft-format --locked an_empty_layer_tree_loads_in_both_modes -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "duplicate_layer_ids_are_rejected_across_the_whole_tree",
|
||
"path": "crates/format/tests/layer_identities.rs",
|
||
"package": "photocraft-format",
|
||
"command": "cargo test -p photocraft-format --locked duplicate_layer_ids_are_rejected_across_the_whole_tree -- --nocapture",
|
||
"fixture_and_action_excerpt": " let doc = sample();\n let bytes = save_to_bytes(&doc, &SaveOptions::default()).unwrap();\n // Top-level siblings, ancestor/descendant, nested siblings, and unrelated groups must all\n // share one identity namespace. Reidentifying cannot recover an ambiguous comp target.\n for (source, target) in [\n (\"/document/layers/1/id\", \"/document/layers/2/id\"),\n (\"/document/layers/1/id\", \"/document/layers/1/content/children/1/content/children/0/id\"),\n (\"/document/layers/1/content/children/0/id\", \"/document/layers/1/content/children/1/id\"),\n (\"/document/layers/1/content/children/0/id\", \"/document/layers/2/content/children/0/id\"),\n (\"/document/layers/0/id\", \"/document/layers/1/content/children/1/content/children/0/id\"),\n ] {\n let mut duplicate = 0;",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/f9de0a6abc78aa405b1ef46f5da6cba424106204/crates/format/tests/layer_identities.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "duplicate_extreme_layer_ids_are_not_silently_remapped",
|
||
"path": "crates/format/tests/layer_identities.rs",
|
||
"package": "photocraft-format",
|
||
"command": "cargo test -p photocraft-format --locked duplicate_extreme_layer_ids_are_not_silently_remapped -- --nocapture",
|
||
"fixture_and_action_excerpt": " let bytes = save_to_bytes(&sample(), &SaveOptions::default()).unwrap();\n let damaged = rewrite_manifest(&bytes, |m| {\n m[\"document\"][\"layers\"][0][\"id\"] = u64::MAX.into();\n m[\"document\"][\"layers\"][2][\"id\"] = u64::MAX.into();\n });\n for preserve_ids in [true, false] {\n let error = load_from_bytes_with(&damaged, &LoadOptions { preserve_ids, ..Default::default() }).unwrap_err();\n assert_duplicate(error, u64::MAX);\n }\n}",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/f9de0a6abc78aa405b1ef46f5da6cba424106204/crates/format/tests/layer_identities.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "duplicate_layer_ids_are_rejected_before_fetching_payloads",
|
||
"path": "crates/format/tests/layer_identities.rs",
|
||
"package": "photocraft-format",
|
||
"command": "cargo test -p photocraft-format --locked duplicate_layer_ids_are_rejected_before_fetching_payloads -- --nocapture",
|
||
"fixture_and_action_excerpt": " struct ManifestOnly {\n json: Vec<u8>,\n payload_reads: Cell<usize>,\n }\n impl ByteSource for ManifestOnly {\n fn get(&self, path: &str, _max: usize) -> photocraft_format::Result<Vec<u8>> {\n if path == \"manifest.json\" {\n return Ok(self.json.clone());\n }\n self.payload_reads.set(self.payload_reads.get() + 1);\n Err(FormatError::Corrupt(\"payload fetched before validating layer ids\".into()))\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(src.payload_reads.get(), 0);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/f9de0a6abc78aa405b1ef46f5da6cba424106204/crates/format/tests/layer_identities.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "unique_nested_layer_ids_preserve_comp_targets_in_both_load_modes",
|
||
"path": "crates/format/tests/layer_identities.rs",
|
||
"package": "photocraft-format",
|
||
"command": "cargo test -p photocraft-format --locked unique_nested_layer_ids_preserve_comp_targets_in_both_load_modes -- --nocapture",
|
||
"fixture_and_action_excerpt": " let doc = sample();\n let bytes = save_to_bytes(&doc, &SaveOptions::default()).unwrap();\n let original_ids: HashSet<_> = doc.walk().into_iter().map(|(_, _, l)| l.id).collect();\n for preserve_ids in [true, false] {\n let loaded = load_from_bytes_with(&bytes, &LoadOptions { preserve_ids, ..Default::default() }).unwrap();\n let walk = loaded.walk();\n let ids: HashSet<_> = walk.iter().map(|(_, _, l)| l.id).collect();\n assert_eq!(ids.len(), walk.len());\n for ((_, _, layer), state) in walk.iter().zip(&loaded.layer_comps[0].states) {\n assert_eq!(state.layer, layer.id);\n assert_eq!(loaded.layer(state.layer), Some(*layer));\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(ids.len(), walk.len());\n for ((_, _, layer), state) in walk.iter().zip(&loaded.layer_comps[0].states) {\n assert_eq!(state.layer, layer.id);\n assert_eq!(loaded.layer(state.layer), Some(*layer));",
|
||
" assert_eq!(state.layer, layer.id);\n assert_eq!(loaded.layer(state.layer), Some(*layer));\n }\n if preserve_ids {",
|
||
" assert_eq!(loaded.layer(state.layer), Some(*layer));\n }\n if preserve_ids {\n assert_eq!(loaded, doc);",
|
||
" assert_eq!(loaded, doc);\n } else {\n assert!(ids.is_disjoint(&original_ids));\n }",
|
||
" assert!(ids.is_disjoint(&original_ids));\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/f9de0a6abc78aa405b1ef46f5da6cba424106204/crates/format/tests/layer_identities.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_identity_validation_keeps_smart_document_and_contents_scopes_independent",
|
||
"path": "crates/format/tests/layer_identities.rs",
|
||
"package": "photocraft-format",
|
||
"command": "cargo test -p photocraft-format --locked layer_identity_validation_keeps_smart_document_and_contents_scopes_independent -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut doc = sample();\n let mut inner = Document::new(\"inside\", doc.size, doc.mode, doc.depth);\n inner.layers.push(doc.layers[0].clone());\n let bytes = Arc::new(save_to_bytes(&inner, &SaveOptions::default()).unwrap());\n let mut smart = SmartObject::new(SmartSource::Embedded { file_name: \"inside.pcraft\".into(), bytes: bytes.clone() }, Affine::IDENTITY, None);\n // These typed identities may have the same number without identifying the same thing.\n smart.contents_id = SmartContentsId(doc.layers[0].id.0);\n doc.id = DocId(doc.layers[0].id.0);\n let first = Layer::new(\"instance\", LayerContent::Smart(smart));\n let second = first.duplicate();\n doc.layers.extend([first, second]);\n let outer = save_to_bytes(&doc, &SaveOptions::default()).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(instances.len(), 2);\n assert_eq!(instances[0].contents_id, instances[1].contents_id);\n for instance in instances {\n let SmartSource::Embedded { bytes: stored, .. } = &instance.source else { panic!(\"embedded source expected\") };",
|
||
" assert_eq!(instances[0].contents_id, instances[1].contents_id);\n for instance in instances {\n let SmartSource::Embedded { bytes: stored, .. } = &instance.source else { panic!(\"embedded source expected\") };\n assert_eq!(stored, &bytes);",
|
||
" assert_eq!(stored, &bytes);\n let restored = load_from_bytes_with(stored, &opts).unwrap();\n assert_eq!(restored.layers.len(), 1);\n if preserve_ids {",
|
||
" assert_eq!(restored.layers.len(), 1);\n if preserve_ids {\n assert_eq!(restored, inner);\n assert_eq!(restored.layers[0].id, loaded.layers[0].id);",
|
||
" assert_eq!(restored, inner);\n assert_eq!(restored.layers[0].id, loaded.layers[0].id);\n }\n }",
|
||
" assert_eq!(restored.layers[0].id, loaded.layers[0].id);\n }\n }\n if preserve_ids {",
|
||
" assert_eq!(loaded, doc);\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/f9de0a6abc78aa405b1ef46f5da6cba424106204/crates/format/tests/layer_identities.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "an_empty_layer_tree_loads_in_both_modes",
|
||
"path": "crates/format/tests/layer_identities.rs",
|
||
"package": "photocraft-format",
|
||
"command": "cargo test -p photocraft-format --locked an_empty_layer_tree_loads_in_both_modes -- --nocapture",
|
||
"fixture_and_action_excerpt": " let doc = Document::new(\"empty\", Size::new(1, 1), ColorMode::Rgb, SampleType::U8);\n let bytes = save_to_bytes(&doc, &SaveOptions::default()).unwrap();\n for preserve_ids in [true, false] {\n let loaded = load_from_bytes_with(&bytes, &LoadOptions { preserve_ids, ..Default::default() }).unwrap();\n assert!(loaded.layers.is_empty());\n }\n}",
|
||
"expected_assertions": [
|
||
" assert!(loaded.layers.is_empty());\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/f9de0a6abc78aa405b1ef46f5da6cba424106204/crates/format/tests/layer_identities.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-6383",
|
||
"pr": 6383,
|
||
"subsystem": "Platform and reliability",
|
||
"fixture_setup": "Portable/executable artifact and symbols ZIP from the SAME immutable final-SHA build run, per claimed architecture",
|
||
"action": [
|
||
"Manual artifact/identity inspection described below"
|
||
],
|
||
"expected": "ZIP has photocraft.pdb, photocraft_cli.pdb and symbols.txt. Each PDB GUID/age matches its same-run executable; debugger/profiler resolves a PhotoCraft function. Portable/MSI launches without optional symbols.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Inspect PE CodeView/PDB identity, record run/job/artifact IDs and hashes. Same SHA rebuilt is not the same PDB identity. Source lines are not required because release omits line tables. Missing packaging artifacts/identity evidence is BLOCKED; do not publish a release just for fixtures.",
|
||
"tested_sha": "",
|
||
"test_commands": []
|
||
},
|
||
{
|
||
"id": "PR-8892",
|
||
"pr": 8892,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Open a layered synthetic document in Move tool and Save for Web; capture initial dialog geometry.",
|
||
"action": "Inspect alignment and overflow controls; enter an invalid Matte value and compare dialog width before/after.",
|
||
"expected": "Alignment and overflow controls keep the reviewed larger dimensions, and invalid Matte input does not change Save for Web width.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": ""
|
||
},
|
||
{
|
||
"id": "PR-8897",
|
||
"pr": 8897,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Unix test-owned FIFO linked by synthetic 8×6 document; bounded-reader synthetic fixtures",
|
||
"action": [
|
||
"cargo test -p photocraft-io --locked a_linked_fifo_is_not_read -- --nocapture",
|
||
"cargo test -p photocraft-format --locked reads_stop_at_the_total_limit -- --nocapture",
|
||
"cargo test -p photocraft-format --locked an_exact_hint_is_not_over_allocated -- --nocapture"
|
||
],
|
||
"expected": "FIFO export completes within 30 seconds without a writer, exports cached pixels and warns of fallback/not-regular-file. Exact-limit read succeeds, over-limit/never-ending reads fail FileTooLarge; size hints do not overallocate.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Use only owned temporary FIFO, never a real device. Non-Unix exclusion is BLOCKED for FIFO qualification, not PASSED.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-io --locked a_linked_fifo_is_not_read -- --nocapture",
|
||
"cargo test -p photocraft-format --locked reads_stop_at_the_total_limit -- --nocapture",
|
||
"cargo test -p photocraft-format --locked an_exact_hint_is_not_over_allocated -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-8986",
|
||
"pr": 8986,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked direct_selection_drags_an_anchor_of_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked direct_selection_marquee_selects_and_arrow_params_name_the_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_saved_path_is_only_edited_while_the_paths_panel_selects_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_selected_saved_path_comes_before_the_work_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked path_selection_moves_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked free_transform_path_names_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked add_and_delete_anchor_point_edit_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_saved_path_read_from_a_psd_is_editable -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked arrows_leave_a_saved_path_the_paths_panel_no_longer_selects -- --nocapture"
|
||
],
|
||
"expected": "direct selection drags an anchor of the selected saved path; direct selection marquee selects and arrow params name the saved path; the saved path is only edited while the paths panel selects it; the selected saved path comes before the work path; path selection moves the selected saved path; free transform path names the selected saved path; add and delete anchor point edit the selected saved path; a saved path read from a psd is editable; arrows leave a saved path the paths panel no longer selects",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked direct_selection_drags_an_anchor_of_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked direct_selection_marquee_selects_and_arrow_params_name_the_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_saved_path_is_only_edited_while_the_paths_panel_selects_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_selected_saved_path_comes_before_the_work_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked path_selection_moves_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked free_transform_path_names_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked add_and_delete_anchor_point_edit_the_selected_saved_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_saved_path_read_from_a_psd_is_editable -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked arrows_leave_a_saved_path_the_paths_panel_no_longer_selects -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "direct_selection_drags_an_anchor_of_the_selected_saved_path",
|
||
"path": "crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked direct_selection_drags_an_anchor_of_the_selected_saved_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::DirectSelection);\n with_saved_path(&mut app);\n let (before, n) = (saved(&app), steps(&app));\n drag(&mut app, [120.5, 120.5], [130.5, 135.5], Modifiers::NONE);\n let after = saved(&app);\n assert_eq!(after.subpaths[0].knots[2].anchor, Point::new(130.0, 135.0), \"the dragged anchor moved\");\n assert_eq!(after.subpaths[0].knots[0].anchor, Point::new(40.0, 40.0), \"the others stay\");\n assert_eq!(steps(&app), n + 1, \"one history step\");\n assert_eq!((app.ui.direct_selection.target, app.ui.direct_selection.anchors.clone()), (Some(PathRef::Saved(0)), vec![[0, 2]]));\n assert!(app.session.active().unwrap().doc.work_path.is_none(), \"no work path was made\");\n assert!(app.session.undo());\n assert_eq!(saved(&app), before);",
|
||
"expected_assertions": [
|
||
" assert_eq!(after.subpaths[0].knots[2].anchor, Point::new(130.0, 135.0), \"the dragged anchor moved\");\n assert_eq!(after.subpaths[0].knots[0].anchor, Point::new(40.0, 40.0), \"the others stay\");\n assert_eq!(steps(&app), n + 1, \"one history step\");\n assert_eq!((app.ui.direct_selection.target, app.ui.direct_selection.anchors.clone()), (Some(PathRef::Saved(0)), vec![[0, 2]]));",
|
||
" assert_eq!(after.subpaths[0].knots[0].anchor, Point::new(40.0, 40.0), \"the others stay\");\n assert_eq!(steps(&app), n + 1, \"one history step\");\n assert_eq!((app.ui.direct_selection.target, app.ui.direct_selection.anchors.clone()), (Some(PathRef::Saved(0)), vec![[0, 2]]));\n assert!(app.session.active().unwrap().doc.work_path.is_none(), \"no work path was made\");",
|
||
" assert_eq!(steps(&app), n + 1, \"one history step\");\n assert_eq!((app.ui.direct_selection.target, app.ui.direct_selection.anchors.clone()), (Some(PathRef::Saved(0)), vec![[0, 2]]));\n assert!(app.session.active().unwrap().doc.work_path.is_none(), \"no work path was made\");\n assert!(app.session.undo());",
|
||
" assert_eq!((app.ui.direct_selection.target, app.ui.direct_selection.anchors.clone()), (Some(PathRef::Saved(0)), vec![[0, 2]]));\n assert!(app.session.active().unwrap().doc.work_path.is_none(), \"no work path was made\");\n assert!(app.session.undo());\n assert_eq!(saved(&app), before);",
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_none(), \"no work path was made\");\n assert!(app.session.undo());\n assert_eq!(saved(&app), before);\n}",
|
||
" assert!(app.session.undo());\n assert_eq!(saved(&app), before);\n}",
|
||
" assert_eq!(saved(&app), before);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/390dfbbcb026b33d46c52c62360b65deca00f258/crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "direct_selection_marquee_selects_and_arrow_params_name_the_saved_path",
|
||
"path": "crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked direct_selection_marquee_selects_and_arrow_params_name_the_saved_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::DirectSelection);\n with_saved_path(&mut app);\n drag(&mut app, [30.0, 30.0], [50.0, 50.0], Modifiers::NONE);\n assert_eq!((app.ui.direct_selection.target, app.ui.direct_selection.anchors.clone()), (Some(PathRef::Saved(0)), vec![[0, 0]]));\n assert_eq!(PathRef::Saved(0).params(&app), json!({\"name\": NAME}));\n // A path that is gone gets no name, which the engine refuses instead of editing another one.\n assert_eq!(PathRef::Saved(7).params(&app), json!({\"name\": \"\"}));\n assert!(app.run(\"path.moveAnchors\", json!({\"name\": \"\", \"anchors\": [[0, 0]], \"move\": [1, 1]})).is_err());\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!((app.ui.direct_selection.target, app.ui.direct_selection.anchors.clone()), (Some(PathRef::Saved(0)), vec![[0, 0]]));\n assert_eq!(PathRef::Saved(0).params(&app), json!({\"name\": NAME}));\n // A path that is gone gets no name, which the engine refuses instead of editing another one.\n assert_eq!(PathRef::Saved(7).params(&app), json!({\"name\": \"\"}));",
|
||
" assert_eq!(PathRef::Saved(0).params(&app), json!({\"name\": NAME}));\n // A path that is gone gets no name, which the engine refuses instead of editing another one.\n assert_eq!(PathRef::Saved(7).params(&app), json!({\"name\": \"\"}));\n assert!(app.run(\"path.moveAnchors\", json!({\"name\": \"\", \"anchors\": [[0, 0]], \"move\": [1, 1]})).is_err());",
|
||
" assert_eq!(PathRef::Saved(7).params(&app), json!({\"name\": \"\"}));\n assert!(app.run(\"path.moveAnchors\", json!({\"name\": \"\", \"anchors\": [[0, 0]], \"move\": [1, 1]})).is_err());\n}",
|
||
" assert!(app.run(\"path.moveAnchors\", json!({\"name\": \"\", \"anchors\": [[0, 0]], \"move\": [1, 1]})).is_err());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/390dfbbcb026b33d46c52c62360b65deca00f258/crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_saved_path_is_only_edited_while_the_paths_panel_selects_it",
|
||
"path": "crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_saved_path_is_only_edited_while_the_paths_panel_selects_it -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::DirectSelection);\n with_saved_path(&mut app);\n app.ui.selected_path = None;\n let before = saved(&app);\n drag(&mut app, [120.5, 120.5], [130.5, 135.5], Modifiers::NONE);\n assert_eq!(saved(&app), before, \"an unselected saved path is not the target path\");\n assert!(!crate::direct_select::active_paths(&app).iter().any(|(r, _)| matches!(r, PathRef::Saved(_))));\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(saved(&app), before, \"an unselected saved path is not the target path\");\n assert!(!crate::direct_select::active_paths(&app).iter().any(|(r, _)| matches!(r, PathRef::Saved(_))));\n}",
|
||
" assert!(!crate::direct_select::active_paths(&app).iter().any(|(r, _)| matches!(r, PathRef::Saved(_))));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/390dfbbcb026b33d46c52c62360b65deca00f258/crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_selected_saved_path_comes_before_the_work_path",
|
||
"path": "crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_selected_saved_path_comes_before_the_work_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::DirectSelection);\n with_saved_path(&mut app);\n // A work path on top of the same square: the saved path the panel selects wins.\n app.run(\"path.set\", json!({\"name\": \"work\", \"path\": square(40.0, 40.0, 80.0)})).unwrap();\n let work = app.session.active().unwrap().doc.work_path.clone().unwrap();\n let refs: Vec<PathRef> = crate::direct_select::active_paths(&app).into_iter().map(|(r, _)| r).collect();\n assert_eq!(refs, vec![PathRef::Saved(0), PathRef::Work]);\n drag(&mut app, [40.5, 40.5], [20.5, 30.5], Modifiers::NONE);\n assert_eq!(saved(&app).subpaths[0].knots[0].anchor, Point::new(20.0, 30.0));\n assert_eq!(app.session.active().unwrap().doc.work_path.clone().unwrap(), work, \"the work path is untouched\");\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(refs, vec![PathRef::Saved(0), PathRef::Work]);\n drag(&mut app, [40.5, 40.5], [20.5, 30.5], Modifiers::NONE);\n assert_eq!(saved(&app).subpaths[0].knots[0].anchor, Point::new(20.0, 30.0));\n assert_eq!(app.session.active().unwrap().doc.work_path.clone().unwrap(), work, \"the work path is untouched\");",
|
||
" assert_eq!(saved(&app).subpaths[0].knots[0].anchor, Point::new(20.0, 30.0));\n assert_eq!(app.session.active().unwrap().doc.work_path.clone().unwrap(), work, \"the work path is untouched\");\n}",
|
||
" assert_eq!(app.session.active().unwrap().doc.work_path.clone().unwrap(), work, \"the work path is untouched\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/390dfbbcb026b33d46c52c62360b65deca00f258/crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "path_selection_moves_the_selected_saved_path",
|
||
"path": "crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked path_selection_moves_the_selected_saved_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::PathSelection);\n with_saved_path(&mut app);\n let n = steps(&app);\n drag(&mut app, [80.0, 40.0], [90.0, 55.0], Modifiers::NONE);\n assert_eq!(\n anchors(&saved(&app)),\n vec![Point::new(50.0, 55.0), Point::new(130.0, 55.0), Point::new(130.0, 135.0), Point::new(50.0, 135.0)],\n \"the whole path moved by (10, 15)\"\n );\n assert_eq!(steps(&app), n + 1);\n assert!(app.session.active().unwrap().doc.work_path.is_none());\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(\n anchors(&saved(&app)),\n vec![Point::new(50.0, 55.0), Point::new(130.0, 55.0), Point::new(130.0, 135.0), Point::new(50.0, 135.0)],\n \"the whole path moved by (10, 15)\"",
|
||
" assert_eq!(steps(&app), n + 1);\n assert!(app.session.active().unwrap().doc.work_path.is_none());\n}",
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_none());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/390dfbbcb026b33d46c52c62360b65deca00f258/crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "free_transform_path_names_the_selected_saved_path",
|
||
"path": "crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked free_transform_path_names_the_selected_saved_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::PathSelection);\n with_saved_path(&mut app);\n let (params, path) = crate::vector_ui::free_transform_path(&app).expect(\"the saved path is transformable\");\n assert_eq!(params, json!({\"name\": NAME}));\n assert_eq!(path, saved(&app));\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(params, json!({\"name\": NAME}));\n assert_eq!(path, saved(&app));\n}",
|
||
" assert_eq!(path, saved(&app));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/390dfbbcb026b33d46c52c62360b65deca00f258/crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "add_and_delete_anchor_point_edit_the_selected_saved_path",
|
||
"path": "crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked add_and_delete_anchor_point_edit_the_selected_saved_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::AddAnchorPoint);\n with_saved_path(&mut app);\n tool_event(&mut app, ToolEvent::Down { x: 80.0, y: 40.0, pressure: 1.0 }, Modifiers::NONE);\n tool_event(&mut app, ToolEvent::Up { x: 80.0, y: 40.0 }, Modifiers::NONE);\n assert_eq!(anchors(&saved(&app)).len(), 5, \"an anchor was added on the top segment\");\n app.ui.tool = Tool::DeleteAnchorPoint;\n tool_event(&mut app, ToolEvent::Down { x: 120.0, y: 120.0, pressure: 1.0 }, Modifiers::NONE);\n tool_event(&mut app, ToolEvent::Up { x: 120.0, y: 120.0 }, Modifiers::NONE);\n assert!(!anchors(&saved(&app)).contains(&Point::new(120.0, 120.0)), \"the corner anchor was deleted\");\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(anchors(&saved(&app)).len(), 5, \"an anchor was added on the top segment\");\n app.ui.tool = Tool::DeleteAnchorPoint;\n tool_event(&mut app, ToolEvent::Down { x: 120.0, y: 120.0, pressure: 1.0 }, Modifiers::NONE);\n tool_event(&mut app, ToolEvent::Up { x: 120.0, y: 120.0 }, Modifiers::NONE);",
|
||
" assert!(!anchors(&saved(&app)).contains(&Point::new(120.0, 120.0)), \"the corner anchor was deleted\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/390dfbbcb026b33d46c52c62360b65deca00f258/crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_saved_path_read_from_a_psd_is_editable",
|
||
"path": "crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked a_saved_path_read_from_a_psd_is_editable -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut src = app(Tool::DirectSelection);\n with_saved_path(&mut src);\n let doc = src.session.active().unwrap().doc.clone();\n let bytes = photocraft_io::export(&doc, \"psd\", &Default::default()).unwrap().bytes;\n let mut app = app(Tool::DirectSelection);\n photocraft_engine::file_cmds::open_bytes_as(&mut app.session, \"paths.psd\", &bytes, None, None).unwrap();\n app.sync_views();\n assert!(app.session.active().unwrap().doc.paths.iter().any(|p| p.name == NAME), \"the PSD keeps its saved path\");\n app.ui.selected_path = Some(NAME.into());\n let n = steps(&app);\n drag(&mut app, [120.5, 120.5], [130.5, 135.5], Modifiers::NONE);\n // PSD stores path points as 8.24 fixed-point fractions of the canvas: compare loosely.",
|
||
"expected_assertions": [
|
||
" assert!(app.session.active().unwrap().doc.paths.iter().any(|p| p.name == NAME), \"the PSD keeps its saved path\");\n app.ui.selected_path = Some(NAME.into());\n let n = steps(&app);\n drag(&mut app, [120.5, 120.5], [130.5, 135.5], Modifiers::NONE);",
|
||
" assert!((a.x - 130.0).abs() < 1e-3 && (a.y - 135.0).abs() < 1e-3, \"the anchor moved to (130, 135): {a:?}\");\n assert_eq!(steps(&app), n + 1);\n}",
|
||
" assert_eq!(steps(&app), n + 1);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/390dfbbcb026b33d46c52c62360b65deca00f258/crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "arrows_leave_a_saved_path_the_paths_panel_no_longer_selects",
|
||
"path": "crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked arrows_leave_a_saved_path_the_paths_panel_no_longer_selects -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(Tool::DirectSelection);\n with_saved_path(&mut app);\n app.run(\"path.set\", json!({\"name\": \"Path 2\", \"path\": square(10.0, 10.0, 20.0)})).unwrap();\n drag(&mut app, [30.0, 30.0], [50.0, 50.0], Modifiers::NONE);\n assert_eq!((app.ui.direct_selection.target, app.ui.direct_selection.anchors.clone()), (Some(PathRef::Saved(0)), vec![[0, 0]]));\n // One → press through the canvas arrow keys, as egui delivers it.\n let arrow = |app: &mut PhotocraftApp| {\n let ctx = egui::Context::default();\n ctx.input_mut(|i| {\n i.events.push(egui::Event::Key { key: egui::Key::ArrowRight, physical_key: None, pressed: true, repeat: false, modifiers: Modifiers::NONE })\n });\n crate::direct_select::arrow_keys(app, &ctx)",
|
||
"expected_assertions": [
|
||
" assert_eq!((app.ui.direct_selection.target, app.ui.direct_selection.anchors.clone()), (Some(PathRef::Saved(0)), vec![[0, 0]]));\n // One → press through the canvas arrow keys, as egui delivers it.\n let arrow = |app: &mut PhotocraftApp| {\n let ctx = egui::Context::default();",
|
||
" assert!(arrow(&mut app), \"the selected path's anchor is nudged\");\n assert_eq!(saved(&app).subpaths[0].knots[0].anchor, Point::new(41.0, 40.0));\n app.ui.selected_path = Some(\"Path 2\".into());\n let (one, two) = (saved(&app), app.session.active().unwrap().doc.paths[1].path.clone());",
|
||
" assert_eq!(saved(&app).subpaths[0].knots[0].anchor, Point::new(41.0, 40.0));\n app.ui.selected_path = Some(\"Path 2\".into());\n let (one, two) = (saved(&app), app.session.active().unwrap().doc.paths[1].path.clone());\n assert!(!arrow(&mut app), \"no key is used for a path that is not the target\");",
|
||
" assert!(!arrow(&mut app), \"no key is used for a path that is not the target\");\n assert_eq!(saved(&app), one, \"Path 1 stays\");\n assert_eq!(app.session.active().unwrap().doc.paths[1].path, two, \"Path 2 stays\");\n assert_eq!(app.ui.direct_selection.target, None, \"the stale anchor selection is dropped\");",
|
||
" assert_eq!(saved(&app), one, \"Path 1 stays\");\n assert_eq!(app.session.active().unwrap().doc.paths[1].path, two, \"Path 2 stays\");\n assert_eq!(app.ui.direct_selection.target, None, \"the stale anchor selection is dropped\");\n}",
|
||
" assert_eq!(app.session.active().unwrap().doc.paths[1].path, two, \"Path 2 stays\");\n assert_eq!(app.ui.direct_selection.target, None, \"the stale anchor selection is dropped\");\n}",
|
||
" assert_eq!(app.ui.direct_selection.target, None, \"the stale anchor selection is dropped\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/390dfbbcb026b33d46c52c62360b65deca00f258/crates/ui-egui/src/saved_path_edit_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9339",
|
||
"pr": 9339,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked ico_export_is_available_and_rejects_oversize_output -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked nearest_neighbor_doubles_each_pixel_into_an_exact_block -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked resample_choices_are_checked -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked export_document_scales_height_when_rounded_width_is_unchanged -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked export_document_proxy_limits_both_dimensions_before_rounding -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_estimate_is_the_exported_files_size -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked export_as_downscales_stroke_only_shapes_and_preview -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked export_document_scales_and_flattens -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked export_document_scales_when_only_the_height_changes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layered_preview_runs_outside_the_ui_frame -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked exact_pixels_lock_aspect_and_leave_the_source -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked untagged_srgb_export_tags_without_rewriting_pixels -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked untagged_srgb_export_24mp_keeps_pixel_tiles -- --nocapture --ignored",
|
||
"cargo test -p photocraft-ui-egui --locked untagged_jpeg_export_embeds_the_requested_srgb_profile -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preview_cache_tracks_working_profiles_but_prefers_embedded_profiles -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preview_workers_keep_the_captured_source_profile -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked replay_converts_untagged_pixels_from_the_original_working_profile -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked profile_and_metadata_follow_the_existing_exporter -- --nocapture"
|
||
],
|
||
"expected": "ico export is available and rejects oversize output; nearest neighbor doubles each pixel into an exact block; resample choices are checked; export document scales height when rounded width is unchanged; export document proxy limits both dimensions before rounding; the estimate is the exported files size; export as downscales stroke only shapes and preview; export document scales and flattens; export document scales when only the height changes; layered preview runs outside the ui frame; exact pixels lock aspect and leave the source; untagged srgb export tags without rewriting pixels; untagged srgb export 24mp keeps pixel tiles; untagged jpeg export embeds the requested srgb profile; preview cache tracks working profiles but prefers embedded profiles; preview workers keep the captured source profile; replay converts untagged pixels from the original working profile; profile and metadata follow the existing exporter",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked ico_export_is_available_and_rejects_oversize_output -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked nearest_neighbor_doubles_each_pixel_into_an_exact_block -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked resample_choices_are_checked -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked export_document_scales_height_when_rounded_width_is_unchanged -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked export_document_proxy_limits_both_dimensions_before_rounding -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_estimate_is_the_exported_files_size -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked export_as_downscales_stroke_only_shapes_and_preview -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked export_document_scales_and_flattens -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked export_document_scales_when_only_the_height_changes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layered_preview_runs_outside_the_ui_frame -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked exact_pixels_lock_aspect_and_leave_the_source -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked untagged_srgb_export_tags_without_rewriting_pixels -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked untagged_srgb_export_24mp_keeps_pixel_tiles -- --nocapture --ignored",
|
||
"cargo test -p photocraft-ui-egui --locked untagged_jpeg_export_embeds_the_requested_srgb_profile -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preview_cache_tracks_working_profiles_but_prefers_embedded_profiles -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preview_workers_keep_the_captured_source_profile -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked replay_converts_untagged_pixels_from_the_original_working_profile -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked profile_and_metadata_follow_the_existing_exporter -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "ico_export_is_available_and_rejects_oversize_output",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked ico_export_is_available_and_rejects_oversize_output -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 300, \"height\": 200})).unwrap();\n let mut f = Map::new();\n f.insert(\"format\".into(), json!(\"ico\"));\n f.insert(\"scale\".into(), json!(100));\n assert!(FORMATS.iter().any(|(ext, _)| *ext == \"ico\"));\n assert!(default_export_document(&app.session.active().unwrap().doc, &f, None).err().is_some_and(|e| e.contains(\"256\")));\n f.insert(\"scale\".into(), json!(50));\n let resized = default_export_document(&app.session.active().unwrap().doc, &f, None).unwrap();\n assert_eq!((resized.size.width, resized.size.height), (150, 100));\n }",
|
||
"expected_assertions": [
|
||
" assert!(FORMATS.iter().any(|(ext, _)| *ext == \"ico\"));\n assert!(default_export_document(&app.session.active().unwrap().doc, &f, None).err().is_some_and(|e| e.contains(\"256\")));\n f.insert(\"scale\".into(), json!(50));\n let resized = default_export_document(&app.session.active().unwrap().doc, &f, None).unwrap();",
|
||
" assert!(default_export_document(&app.session.active().unwrap().doc, &f, None).err().is_some_and(|e| e.contains(\"256\")));\n f.insert(\"scale\".into(), json!(50));\n let resized = default_export_document(&app.session.active().unwrap().doc, &f, None).unwrap();\n assert_eq!((resized.size.width, resized.size.height), (150, 100));",
|
||
" assert_eq!((resized.size.width, resized.size.height), (150, 100));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "nearest_neighbor_doubles_each_pixel_into_an_exact_block",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked nearest_neighbor_doubles_each_pixel_into_an_exact_block -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_doc::SampleType;\n for depth in [SampleType::U8, SampleType::U16] {\n let doc = checker_doc(depth);\n let before = doc.clone();\n let mut f = Map::new();\n f.insert(\"format\".into(), json!(\"png\"));\n f.insert(\"scale\".into(), json!(200));\n f.insert(\"resample\".into(), json!(\"nearest\"));\n let out = default_export_document(&doc, &f, None).unwrap();\n assert_eq!((out.size.width, out.size.height), (10, 6));\n assert_eq!(out.depth, depth);\n let surf = out.layers[0].surface().unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!((out.size.width, out.size.height), (10, 6));\n assert_eq!(out.depth, depth);\n let surf = out.layers[0].surface().unwrap();\n for y in 0..6 {",
|
||
" assert_eq!(out.depth, depth);\n let surf = out.layers[0].surface().unwrap();\n for y in 0..6 {\n for x in 0..10 {",
|
||
" assert_eq!(surf.rgba(x, y), checker(x / 2, y / 2), \"{depth:?} pixel {x},{y}\");\n }\n }\n assert_eq!(doc, before, \"{depth:?}: export leaves the source document unchanged\");",
|
||
" assert_eq!(doc, before, \"{depth:?}: export leaves the source document unchanged\");\n\n // The preview proxy keeps Nearest Neighbor's hard edges too.\n let proxy = default_export_document(&doc, &f, Some(512)).unwrap();",
|
||
" assert_eq!(proxy.layers[0].surface().unwrap().rgba(1, 1), checker(0, 0), \"{depth:?}: preview proxy is nearest as well\");\n assert_eq!(preview_filter(&f), egui::TextureOptions::NEAREST);\n\n f.insert(\"resample\".into(), json!(DEFAULT_RESAMPLE));",
|
||
" assert_eq!(preview_filter(&f), egui::TextureOptions::NEAREST);\n\n f.insert(\"resample\".into(), json!(DEFAULT_RESAMPLE));\n let smooth = default_export_document(&doc, &f, None).unwrap();",
|
||
" assert!(blended, \"{depth:?}: Bicubic Automatic blends neighbouring squares\");\n assert_eq!(preview_filter(&f), egui::TextureOptions::LINEAR);\n }\n }",
|
||
" assert_eq!(preview_filter(&f), egui::TextureOptions::LINEAR);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "resample_choices_are_checked",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked resample_choices_are_checked -- --nocapture",
|
||
"fixture_and_action_excerpt": " let doc = checker_doc(photocraft_doc::SampleType::U8);\n let mut f = Map::new();\n f.insert(\"scale\".into(), json!(300));\n for (method, _) in RESAMPLE {\n f.insert(\"resample\".into(), json!(method));\n let out = default_export_document(&doc, &f, None).unwrap();\n assert_eq!((out.size.width, out.size.height), (15, 9), \"{method}\");\n }\n for bad in [json!(\"lanczos\"), json!(\"NEAREST\"), json!(\"\"), json!(1), json!({\"m\": \"nearest\"})] {\n f.insert(\"resample\".into(), bad.clone());\n let err = default_export_document(&doc, &f, None).unwrap_err();\n assert!(err.contains(\"resample must be\"), \"{bad}: {err}\");",
|
||
"expected_assertions": [
|
||
" assert_eq!((out.size.width, out.size.height), (15, 9), \"{method}\");\n }\n for bad in [json!(\"lanczos\"), json!(\"NEAREST\"), json!(\"\"), json!(1), json!({\"m\": \"nearest\"})] {\n f.insert(\"resample\".into(), bad.clone());",
|
||
" assert!(err.contains(\"resample must be\"), \"{bad}: {err}\");\n assert!(default_export_document(&doc, &f, Some(512)).is_err(), \"{bad}: the preview reports it too\");\n }\n f.remove(\"resample\");",
|
||
" assert!(default_export_document(&doc, &f, Some(512)).is_err(), \"{bad}: the preview reports it too\");\n }\n f.remove(\"resample\");\n assert_eq!(resample_method(&f, None).unwrap(), \"bicubicAutomatic\");",
|
||
" assert_eq!(resample_method(&f, None).unwrap(), \"bicubicAutomatic\");\n assert_eq!(resample_method(&f, Some(512)).unwrap(), \"bilinear\", \"the preview stays on the fast path\");\n }",
|
||
" assert_eq!(resample_method(&f, Some(512)).unwrap(), \"bilinear\", \"the preview stays on the fast path\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "export_document_scales_height_when_rounded_width_is_unchanged",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked export_document_scales_height_when_rounded_width_is_unchanged -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_doc::{Color, ColorMode, SampleType, Size};\n\n for depth in [SampleType::U8, SampleType::U16, SampleType::F32] {\n for (width, height, scale, expected) in [\n (1, 100, 50, (1, 50)),\n (1, 200, 50, (1, 100)),\n (10, 100, 99, (10, 99)),\n (10, 100, 101, (10, 101)),\n (400, 300, 50, (200, 150)),\n (400, 300, 100, (400, 300)),\n ] {\n let doc = Document::with_background(\"x\", Size::new(width, height), ColorMode::Rgb, depth, Color::WHITE);",
|
||
"expected_assertions": [
|
||
" assert_eq!((out.size.width, out.size.height), expected, \"{width} × {height} at {scale}%, {depth:?}\");\n assert_eq!(out.depth, depth, \"export preserves the document's depth\");\n assert_eq!(doc, before, \"export leaves the source document unchanged\");\n }",
|
||
" assert_eq!(out.depth, depth, \"export preserves the document's depth\");\n assert_eq!(doc, before, \"export leaves the source document unchanged\");\n }\n }",
|
||
" assert_eq!(doc, before, \"export leaves the source document unchanged\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "export_document_proxy_limits_both_dimensions_before_rounding",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked export_document_proxy_limits_both_dimensions_before_rounding -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_doc::{Color, ColorMode, SampleType, Size};\n\n for (width, height, scale, max_side, expected) in\n [(1, 1000, 100, 360, (1, 360)), (1, 1000, 50, 360, (1, 360)), (1, 1000, 25, 360, (1, 250)), (13, 20, 50, 8, (5, 8)), (20, 13, 50, 8, (8, 5))]\n {\n let doc = Document::with_background(\"x\", Size::new(width, height), ColorMode::Rgb, SampleType::U8, Color::WHITE);\n let before = doc.clone();\n let mut f = Map::new();\n f.insert(\"format\".into(), json!(\"png\"));\n f.insert(\"scale\".into(), json!(scale));\n let out = default_export_document(&doc, &f, Some(max_side)).unwrap();\n assert_eq!((out.size.width, out.size.height), expected, \"{width} × {height} at {scale}%, proxy limit {max_side}\");",
|
||
"expected_assertions": [
|
||
" assert_eq!((out.size.width, out.size.height), expected, \"{width} × {height} at {scale}%, proxy limit {max_side}\");\n assert!(out.size.width.max(out.size.height) <= max_side, \"proxy respects its longest-side limit\");\n assert_eq!(doc, before, \"preview leaves the source document unchanged\");\n }",
|
||
" assert!(out.size.width.max(out.size.height) <= max_side, \"proxy respects its longest-side limit\");\n assert_eq!(doc, before, \"preview leaves the source document unchanged\");\n }\n }",
|
||
" assert_eq!(doc, before, \"preview leaves the source document unchanged\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_estimate_is_the_exported_files_size",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_estimate_is_the_exported_files_size -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut doc = Document::with_background(\n \"x\",\n photocraft_doc::Size::new(900, 300),\n photocraft_doc::ColorMode::Rgb,\n photocraft_doc::SampleType::U8,\n photocraft_doc::Color::WHITE,\n );\n let id = doc.layers[0].id;\n let surf = doc.layer_mut(id).unwrap().surface_mut().unwrap();\n let mut seed = 12345u32;\n for y in (0..300).step_by(2) {\n for x in (0..900).step_by(2) {",
|
||
"expected_assertions": [
|
||
" assert!((old as f64 / actual as f64 - 1.0).abs() > 0.1, \"the proxy estimate was off: {old} vs {actual}\");\n\n let ctx = egui::Context::default();\n let key = egui::Id::new(\"exact-estimate-test\");",
|
||
" assert!(std::time::Instant::now() < deadline, \"the exact estimate did not arrive\");\n std::thread::sleep(std::time::Duration::from_millis(10));\n };\n assert_eq!(size, Some(actual));",
|
||
" assert_eq!(size, Some(actual));\n // Over the limit there is no exact size; the proxy estimate stays.\n let huge = Map::from_iter([\n (\"format\".into(), json!(\"jpg\")),",
|
||
" assert_eq!(default_exact_estimate(&doc, &huge), None);\n // In scale mode the size comes from the scale, as the export's does, not from stale pixels.\n let big = Arc::new(Document::with_background(\n \"big\",",
|
||
" assert_eq!(default_exact_estimate(&big, &stale), None, \"10000 × 10000 at 1000 %, over the limit\");\n let small = Map::from_iter([\n (\"format\".into(), json!(\"png\")),\n (\"sizing\".into(), json!(\"scale\")),",
|
||
" assert_eq!(default_exact_estimate(&big, &small), Some(at_10), \"100 × 100 at 10 %, within it\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "export_as_downscales_stroke_only_shapes_and_preview",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked export_as_downscales_stroke_only_shapes_and_preview -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [8, 16, 32] {\n let mut session = photocraft_engine::Session::new();\n session.execute(\"file.new\", json!({\"width\": 1024, \"height\": 1024, \"depth\": depth, \"background\": \"transparent\"})).unwrap();\n let id = session.execute(\"shape.create\", json!({\"rect\": [256, 256, 512, 512], \"fill\": null, \"stroke\": {\"width\": 32}})).unwrap()[\"layer\"]\n .as_u64()\n .unwrap();\n let doc = session.active().unwrap().doc.clone();\n let fields = Map::from_iter([(\"format\".into(), json!(\"png\")), (\"scale\".into(), json!(25))]);\n for limit in [None, Some(128)] {\n let out = default_export_document(&doc, &fields, limit).unwrap();\n let side = if limit.is_some() { 128 } else { 256 };\n assert_eq!((out.size.width, out.size.height), (side, side));",
|
||
"expected_assertions": [
|
||
" assert_eq!((out.size.width, out.size.height), (side, side));\n let shape = out.layer(photocraft_doc::LayerId(id)).unwrap();\n let photocraft_doc::LayerContent::Shape(shape) = &shape.content else {\n panic!(\"shape lost\");",
|
||
" assert_eq!(shape.stroke.as_ref().unwrap().width, side as f32 / 32.0);\n let pixels = photocraft_compose::flatten(&out);\n let row = (side / 2 * side) as usize;\n assert!(pixels.px[row + (side / 4) as usize][3] > 0.99);",
|
||
" assert!(pixels.px[row + (side / 4) as usize][3] > 0.99);\n assert!(pixels.px[row + (side / 4 - side / 32) as usize][3] < 0.01);\n assert!(pixels.px[row + (side / 2) as usize][3] < 0.01);\n }",
|
||
" assert!(pixels.px[row + (side / 4 - side / 32) as usize][3] < 0.01);\n assert!(pixels.px[row + (side / 2) as usize][3] < 0.01);\n }\n assert_eq!(session.active().unwrap().doc, doc, \"export leaves the source unchanged\");",
|
||
" assert!(pixels.px[row + (side / 2) as usize][3] < 0.01);\n }\n assert_eq!(session.active().unwrap().doc, doc, \"export leaves the source unchanged\");\n }",
|
||
" assert_eq!(session.active().unwrap().doc, doc, \"export leaves the source unchanged\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "export_document_scales_and_flattens",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked export_document_scales_and_flattens -- --nocapture",
|
||
"fixture_and_action_excerpt": " let doc = Document::with_background(\n \"x\",\n photocraft_doc::Size::new(200, 100),\n photocraft_doc::ColorMode::Rgb,\n photocraft_doc::SampleType::U8,\n photocraft_doc::Color::WHITE,\n );\n let mut f = Map::new();\n f.insert(\"format\".into(), json!(\"jpg\"));\n f.insert(\"scale\".into(), json!(50));\n let out = default_export_document(&doc, &f, None).unwrap();\n assert_eq!((out.size.width, out.size.height), (100, 50));",
|
||
"expected_assertions": [
|
||
" assert_eq!((out.size.width, out.size.height), (100, 50));\n assert_eq!(out.layers.len(), 1);\n let proxy = default_export_document(&doc, &f, Some(40)).unwrap();\n assert_eq!(proxy.size.width, 40);",
|
||
" assert_eq!(out.layers.len(), 1);\n let proxy = default_export_document(&doc, &f, Some(40)).unwrap();\n assert_eq!(proxy.size.width, 40);\n assert_eq!(settings(&f).jpeg_quality, Some(85));",
|
||
" assert_eq!(proxy.size.width, 40);\n assert_eq!(settings(&f).jpeg_quality, Some(85));\n }",
|
||
" assert_eq!(settings(&f).jpeg_quality, Some(85));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "export_document_scales_when_only_the_height_changes",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked export_document_scales_when_only_the_height_changes -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut f = Map::new();\n f.insert(\"format\".into(), json!(\"png\"));\n f.insert(\"scale\".into(), json!(50));\n for (src_h, want_h) in [(100u32, 50u32), (200, 100)] {\n let doc = Document::with_background(\n \"x\",\n photocraft_doc::Size::new(1, src_h),\n photocraft_doc::ColorMode::Rgb,\n photocraft_doc::SampleType::U8,\n photocraft_doc::Color::WHITE,\n );\n let out = default_export_document(&doc, &f, None).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!((out.size.width, out.size.height), (1, want_h), \"1 × {src_h} at 50%\");\n // The preview proxy takes the same path.\n let proxy = default_export_document(&doc, &f, Some(40)).unwrap();\n assert_eq!((proxy.size.width, proxy.size.height), (1, 40), \"proxy of 1 × {src_h}\");",
|
||
" assert_eq!((proxy.size.width, proxy.size.height), (1, 40), \"proxy of 1 × {src_h}\");\n }\n // The label and the export agree, and neither side drops below 1 px.\n assert_eq!(scaled_size(1.0, 100.0, 0.5), (1.0, 50.0));",
|
||
" assert_eq!(scaled_size(1.0, 100.0, 0.5), (1.0, 50.0));\n assert_eq!(scaled_size(10.0, 300.0, 0.01), (1.0, 3.0));\n }",
|
||
" assert_eq!(scaled_size(10.0, 300.0, 0.01), (1.0, 3.0));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layered_preview_runs_outside_the_ui_frame",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layered_preview_runs_outside_the_ui_frame -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 32, \"height\": 16})).unwrap();\n for _ in 0..33 {\n app.run(\"layer.new.layer\", json!({})).unwrap();\n }\n let doc = app.session.active().unwrap().doc.clone();\n assert!(background_preview_needed(&doc));\n let fields = Map::from_iter([(\"format\".into(), json!(\"png\")), (\"scale\".into(), json!(100))]);\n let ctx = egui::Context::default();\n let key = egui::Id::new(\"layered-preview-test\");\n let mut result = None;\n let mut output = ctx.run_ui(Default::default(), |ctx| {",
|
||
"expected_assertions": [
|
||
" assert!(background_preview_needed(&doc));\n let fields = Map::from_iter([(\"format\".into(), json!(\"png\")), (\"scale\".into(), json!(100))]);\n let ctx = egui::Context::default();\n let key = egui::Id::new(\"layered-preview-test\");",
|
||
" assert!(result.is_none(), \"the first UI frame must only start the worker\");\n\n let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5);\n loop {",
|
||
" assert_eq!((preview.width, preview.height), (32, 16));\n assert_eq!(preview.rgba.len(), 32 * 16 * 4);\n assert!(preview.estimate.is_some_and(|bytes| bytes > 0));\n break;",
|
||
" assert_eq!(preview.rgba.len(), 32 * 16 * 4);\n assert!(preview.estimate.is_some_and(|bytes| bytes > 0));\n break;\n }",
|
||
" assert!(preview.estimate.is_some_and(|bytes| bytes > 0));\n break;\n }\n assert!(std::time::Instant::now() < deadline, \"background preview did not complete\");",
|
||
" assert!(std::time::Instant::now() < deadline, \"background preview did not complete\");\n std::thread::sleep(std::time::Duration::from_millis(10));\n }\n",
|
||
" assert_eq!(estimate_native(&doc, &proxy, &tiff_fields), Some(scaled_estimate(actual_bytes, &doc, &proxy, &tiff_fields)));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "exact_pixels_lock_aspect_and_leave_the_source",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked exact_pixels_lock_aspect_and_leave_the_source -- --nocapture",
|
||
"fixture_and_action_excerpt": " let linked = resize_from_scale(400.0, 200.0, 50.0).unwrap();\n assert_eq!((linked.width, linked.height, linked.scale), (200.0, 100.0, 50.0));\n let from_width = resize_from_side(400.0, 200.0, 100.0, 200.0, true, true).unwrap();\n assert_eq!((from_width.width, from_width.height), (100.0, 50.0));\n let from_height = resize_from_side(400.0, 200.0, 100.0, 40.0, true, false).unwrap();\n assert_eq!((from_height.width, from_height.height), (80.0, 40.0));\n let free = resize_from_side(400.0, 200.0, 100.0, 80.0, false, true).unwrap();\n assert_eq!((free.width, free.height), (100.0, 80.0));\n assert!(resize_from_scale(400.0, 200.0, 0.0).is_err());\n assert!(resize_from_side(400.0, 200.0, 0.0, 10.0, false, true).is_err());\n assert!(resize_from_side(10.0, 10.0, 400_000.0, 10.0, false, true).is_err());\n",
|
||
"expected_assertions": [
|
||
" assert_eq!((linked.width, linked.height, linked.scale), (200.0, 100.0, 50.0));\n let from_width = resize_from_side(400.0, 200.0, 100.0, 200.0, true, true).unwrap();\n assert_eq!((from_width.width, from_width.height), (100.0, 50.0));\n let from_height = resize_from_side(400.0, 200.0, 100.0, 40.0, true, false).unwrap();",
|
||
" assert_eq!((from_width.width, from_width.height), (100.0, 50.0));\n let from_height = resize_from_side(400.0, 200.0, 100.0, 40.0, true, false).unwrap();\n assert_eq!((from_height.width, from_height.height), (80.0, 40.0));\n let free = resize_from_side(400.0, 200.0, 100.0, 80.0, false, true).unwrap();",
|
||
" assert_eq!((from_height.width, from_height.height), (80.0, 40.0));\n let free = resize_from_side(400.0, 200.0, 100.0, 80.0, false, true).unwrap();\n assert_eq!((free.width, free.height), (100.0, 80.0));\n assert!(resize_from_scale(400.0, 200.0, 0.0).is_err());",
|
||
" assert_eq!((free.width, free.height), (100.0, 80.0));\n assert!(resize_from_scale(400.0, 200.0, 0.0).is_err());\n assert!(resize_from_side(400.0, 200.0, 0.0, 10.0, false, true).is_err());\n assert!(resize_from_side(10.0, 10.0, 400_000.0, 10.0, false, true).is_err());",
|
||
" assert!(resize_from_scale(400.0, 200.0, 0.0).is_err());\n assert!(resize_from_side(400.0, 200.0, 0.0, 10.0, false, true).is_err());\n assert!(resize_from_side(10.0, 10.0, 400_000.0, 10.0, false, true).is_err());\n",
|
||
" assert!(resize_from_side(400.0, 200.0, 0.0, 10.0, false, true).is_err());\n assert!(resize_from_side(10.0, 10.0, 400_000.0, 10.0, false, true).is_err());\n\n let doc = Document::with_background(",
|
||
" assert!(resize_from_side(10.0, 10.0, 400_000.0, 10.0, false, true).is_err());\n\n let doc = Document::with_background(\n \"x\",",
|
||
" assert_eq!((out.size.width, out.size.height), (120, 40), \"explicit pixels win over the percent scale\");\n let proxy = default_export_document(&doc, &f, Some(20)).unwrap();\n assert_eq!((proxy.size.width, proxy.size.height), (20, 7));\n assert_eq!(doc, before, \"export leaves the source document unchanged\");",
|
||
" assert_eq!((proxy.size.width, proxy.size.height), (20, 7));\n assert_eq!(doc, before, \"export leaves the source document unchanged\");\n }",
|
||
" assert_eq!(doc, before, \"export leaves the source document unchanged\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "untagged_srgb_export_tags_without_rewriting_pixels",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked untagged_srgb_export_tags_without_rewriting_pixels -- --nocapture",
|
||
"fixture_and_action_excerpt": " check_profile_only_export(8, 8);\n }",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "untagged_srgb_export_24mp_keeps_pixel_tiles",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked untagged_srgb_export_24mp_keeps_pixel_tiles -- --nocapture --ignored",
|
||
"fixture_and_action_excerpt": " let elapsed = check_profile_only_export(6000, 4000);\n println!(\"24 MP sRGB profile preparation (optimized test build): {elapsed:?}; all pixel tiles shared\");\n }",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": true
|
||
},
|
||
{
|
||
"name": "untagged_jpeg_export_embeds_the_requested_srgb_profile",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked untagged_jpeg_export_embeds_the_requested_srgb_profile -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_doc::{Color, ColorMode, SampleType, Size};\n for (mode, depth) in [\n (ColorMode::Rgb, SampleType::U8),\n (ColorMode::Rgb, SampleType::U16),\n (ColorMode::Rgb, SampleType::F32),\n (ColorMode::Grayscale, SampleType::U8),\n (ColorMode::Cmyk, SampleType::U8),\n ] {\n let doc = Document::with_background(\"untagged\", Size::new(8, 8), mode, depth, Color::WHITE);\n assert!(doc.icc_profile.is_none());\n let before = doc.clone();\n let mut fields =",
|
||
"expected_assertions": [
|
||
" assert!(doc.icc_profile.is_none());\n let before = doc.clone();\n let mut fields =\n json!({\"format\": \"jpg\", \"profile\": \"srgb\", \"embedProfile\": true, \"metadata\": \"none\", \"width\": 8, \"height\": 8}).as_object().unwrap().clone();",
|
||
" assert!(profile.same_colors(photocraft_cms::Builtin::Srgb.profile()), \"{depth:?}\");\n fields.insert(\"embedProfile\".into(), json!(false));\n let bytes = photocraft_io::export(&converted, \"out.jpg\", &settings(&fields).io_options()).unwrap().bytes;\n assert!(photocraft_io::import(\"out.jpg\", &bytes).unwrap().document.icc_profile.is_none(), \"embedding remains optional\");",
|
||
" assert!(photocraft_io::import(\"out.jpg\", &bytes).unwrap().document.icc_profile.is_none(), \"embedding remains optional\");\n fields.insert(\"profile\".into(), json!(\"document\"));\n fields.insert(\"embedProfile\".into(), json!(true));\n let unchanged = default_export_document(&doc, &fields, None).unwrap();",
|
||
" assert!(unchanged.icc_profile.is_none(), \"Document Profile preserves an untagged source\");\n assert_eq!(doc, before, \"export must not tag or convert the source document\");\n }\n }",
|
||
" assert_eq!(doc, before, \"export must not tag or convert the source document\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "preview_cache_tracks_working_profiles_but_prefers_embedded_profiles",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked preview_cache_tracks_working_profiles_but_prefers_embedded_profiles -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_cms::Builtin;\n use photocraft_doc::{Color, SampleType, Size};\n for embedded in [false, true] {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.session.execute(\"edit.colorSettings\", json!({\"workingRgb\": \"display-p3\", \"policyRgb\": \"off\"})).unwrap();\n let mut doc = Document::with_background(\"colour\", Size::new(8, 8), ColorMode::Rgb, SampleType::U8, Color::rgba(0.35, 0.65, 0.45, 1.0));\n if embedded {\n doc.icc_profile = Some(Builtin::DisplayP3.profile().to_bytes());\n }\n app.session.open_document(doc, None);\n let id = open(&mut app).unwrap();\n let mut fields = app.ui.dialog_mut(id).unwrap().fields.clone();",
|
||
"expected_assertions": [
|
||
" assert_eq!(app.session.active().unwrap().revision, revision);\n let after = draw(&mut app, &mut fields);\n assert_eq!(settings_of(&fields), settings);\n assert_eq!(before.signature != after.signature, !embedded);",
|
||
" assert_eq!(settings_of(&fields), settings);\n assert_eq!(before.signature != after.signature, !embedded);\n assert_eq!(before.texture.unwrap().id() != after.texture.unwrap().id(), !embedded);\n }",
|
||
" assert_eq!(before.signature != after.signature, !embedded);\n assert_eq!(before.texture.unwrap().id() != after.texture.unwrap().id(), !embedded);\n }\n }",
|
||
" assert_eq!(before.texture.unwrap().id() != after.texture.unwrap().id(), !embedded);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "preview_workers_keep_the_captured_source_profile",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked preview_workers_keep_the_captured_source_profile -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.session.execute(\"edit.colorSettings\", json!({\"workingRgb\": \"display-p3\", \"policyRgb\": \"off\"})).unwrap();\n let doc = Document::with_background(\n \"colour\",\n photocraft_doc::Size::new(8, 8),\n ColorMode::Rgb,\n photocraft_doc::SampleType::U8,\n photocraft_doc::Color::rgba(0.35, 0.65, 0.45, 1.0),\n );\n app.session.open_document(doc, None);\n let doc = app.session.active().unwrap().doc.clone();\n let profile = effective_source_profile(&app, &doc);",
|
||
"expected_assertions": [
|
||
" assert!(std::time::Instant::now() < deadline, \"profile-aware preview workers must finish\");\n std::thread::sleep(std::time::Duration::from_millis(10));\n }\n assert_eq!(preview.unwrap().unwrap().rgba, expected.rgba);",
|
||
" assert_eq!(preview.unwrap().unwrap().rgba, expected.rgba);\n assert_eq!(size.unwrap(), Some(expected_size));\n }",
|
||
" assert_eq!(size.unwrap(), Some(expected_size));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "replay_converts_untagged_pixels_from_the_original_working_profile",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked replay_converts_untagged_pixels_from_the_original_working_profile -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_cms::{Builtin, Intent};\n use photocraft_doc::{Color, ColorMode, SampleType, Size};\n for working in [Builtin::DisplayP3, Builtin::AdobeRgbCompat] {\n for depth in [SampleType::U8, SampleType::U16, SampleType::F32] {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.session.execute(\"edit.colorSettings\", json!({\"workingRgb\": working.id(), \"policyRgb\": \"off\"})).unwrap();\n let doc = Document::with_background(\"untagged\", Size::new(8, 8), ColorMode::Rgb, depth, Color::rgba(0.35, 0.65, 0.45, 1.0));\n app.session.open_document(doc, None);\n let source = app.session.active().unwrap().doc.clone();\n assert!(source.icc_profile.is_none());\n let mut expected = (*source).clone();\n expected.icc_profile = Some(working.profile().to_bytes());",
|
||
"expected_assertions": [
|
||
" assert!(source.icc_profile.is_none());\n let mut expected = (*source).clone();\n expected.icc_profile = Some(working.profile().to_bytes());\n photocraft_engine::color_cmds::convert_document(&mut expected, Builtin::Srgb.profile(), Intent::Perceptual, true).unwrap();",
|
||
" assert_ne!(original_pixel, expected_pixel, \"the control must require a pixel conversion\");\n let captured = Arc::new(std::sync::Mutex::new(None));\n let output = captured.clone();\n app.services.export = Some(Box::new(move |doc, _, _| {",
|
||
" assert_eq!(actual.layers[0].surface().unwrap().pixel(0, 0), expected_pixel, \"{working:?} {depth:?}\");\n let profile = photocraft_cms::Profile::parse(actual.icc_profile.as_deref().unwrap()).unwrap();\n assert!(profile.same_bytes(Builtin::Srgb.profile()));\n assert_eq!(app.session.active().unwrap().doc, source);",
|
||
" assert!(profile.same_bytes(Builtin::Srgb.profile()));\n assert_eq!(app.session.active().unwrap().doc, source);\n }\n }",
|
||
" assert_eq!(app.session.active().unwrap().doc, source);\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "profile_and_metadata_follow_the_existing_exporter",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked profile_and_metadata_follow_the_existing_exporter -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_cms::Builtin;\n\n let mut f = Map::new();\n f.insert(\"format\".into(), json!(\"jpg\"));\n assert!(settings(&f).embed_metadata, \"a missing metadata choice keeps EXIF and resolution\");\n assert!(settings(&f).embed_icc);\n f.insert(\"metadata\".into(), json!(\"none\"));\n f.insert(\"embedProfile\".into(), json!(false));\n let none = settings(&f);\n assert!(!none.xmp_all && !none.embed_metadata && !none.embed_icc);\n f.insert(\"metadata\".into(), json!(\"exif\"));\n let exif = settings(&f);",
|
||
"expected_assertions": [
|
||
" assert!(settings(&f).embed_metadata, \"a missing metadata choice keeps EXIF and resolution\");\n assert!(settings(&f).embed_icc);\n f.insert(\"metadata\".into(), json!(\"none\"));\n f.insert(\"embedProfile\".into(), json!(false));",
|
||
" assert!(settings(&f).embed_icc);\n f.insert(\"metadata\".into(), json!(\"none\"));\n f.insert(\"embedProfile\".into(), json!(false));\n let none = settings(&f);",
|
||
" assert!(!none.xmp_all && !none.embed_metadata && !none.embed_icc);\n f.insert(\"metadata\".into(), json!(\"exif\"));\n let exif = settings(&f);\n assert!(!exif.xmp_all && exif.embed_metadata);",
|
||
" assert!(!exif.xmp_all && exif.embed_metadata);\n f.insert(\"metadata\".into(), json!(\"all\"));\n f.insert(\"embedProfile\".into(), json!(true));\n let all = settings(&f);",
|
||
" assert!(all.xmp_all && all.embed_metadata && all.embed_icc);\n\n let mut doc = Document::with_background(\n \"x\",",
|
||
" assert!(parsed.same_colors(Builtin::Srgb.profile()), \"Convert to sRGB replaces the document profile\");\n let stripped = photocraft_io::export(&converted, \"out.jpg\", &settings(&f).io_options()).unwrap().bytes;\n assert!(!stripped.windows(b\"ICC_PROFILE\".len()).any(|w| w == b\"ICC_PROFILE\"));\n assert!(!stripped.windows(b\"secret\".len()).any(|w| w == b\"secret\"));",
|
||
" assert!(!stripped.windows(b\"ICC_PROFILE\".len()).any(|w| w == b\"ICC_PROFILE\"));\n assert!(!stripped.windows(b\"secret\".len()).any(|w| w == b\"secret\"));\n f.insert(\"metadata\".into(), json!(\"all\"));\n f.insert(\"embedProfile\".into(), json!(true));",
|
||
" assert!(!stripped.windows(b\"secret\".len()).any(|w| w == b\"secret\"));\n f.insert(\"metadata\".into(), json!(\"all\"));\n f.insert(\"embedProfile\".into(), json!(true));\n let kept = photocraft_io::export(&converted, \"out.jpg\", &settings(&f).io_options()).unwrap().bytes;",
|
||
" assert!(kept.windows(b\"ICC_PROFILE\".len()).any(|w| w == b\"ICC_PROFILE\"));\n assert!(kept.windows(b\"secret\".len()).any(|w| w == b\"secret\"));\n assert_eq!(doc, before);\n }",
|
||
" assert!(kept.windows(b\"secret\".len()).any(|w| w == b\"secret\"));\n assert_eq!(doc, before);\n }",
|
||
" assert_eq!(doc, before);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/393645ab91460af2e37cc3ba8f6921e7551f676e/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9342",
|
||
"pr": 9342,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-automation --locked doc_save_rejects_a_bad_quality_instead_of_ignoring_or_clamping_it -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked exif_srgb_jpeg_round_trip -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked embed_color_profile_tags_an_untagged_document_srgb -- --nocapture",
|
||
"cargo test -p photocraft-io --locked untagged_documents_embed_the_profile_they_are_assumed_to_be_in -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_estimate_is_the_exported_files_size -- --nocapture"
|
||
],
|
||
"expected": "doc save rejects a bad quality instead of ignoring or clamping it; exif srgb jpeg round trip; embed color profile tags an untagged document srgb; untagged documents embed the profile they are assumed to be in; the estimate is the exported files size",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-automation --locked doc_save_rejects_a_bad_quality_instead_of_ignoring_or_clamping_it -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked exif_srgb_jpeg_round_trip -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked embed_color_profile_tags_an_untagged_document_srgb -- --nocapture",
|
||
"cargo test -p photocraft-io --locked untagged_documents_embed_the_profile_they_are_assumed_to_be_in -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_estimate_is_the_exported_files_size -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "doc_save_rejects_a_bad_quality_instead_of_ignoring_or_clamping_it",
|
||
"path": "crates/automation/src/rpc.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked doc_save_rejects_a_bad_quality_instead_of_ignoring_or_clamping_it -- --nocapture",
|
||
"fixture_and_action_excerpt": " let dir = std::env::temp_dir().join(format!(\"pc-rpc-save-quality-{}\", std::process::id()));\n std::fs::create_dir_all(&dir).unwrap();\n let path = dir.join(\"x.webp\");\n let mut h = Headless::trusted_local();\n h.handle(\"doc.new\", json!({\"width\": 16, \"height\": 16})).unwrap();\n for q in [json!(85.0), json!(\"85\"), json!(0), json!(500), json!(-5), json!(true)] {\n let err = h.handle(\"doc.save\", json!({\"path\": path.to_string_lossy(), \"quality\": q})).unwrap_err().to_string();\n assert!(err.contains(\"quality\"), \"{q}: {err}\");\n assert!(!path.exists(), \"{q} wrote a file\");\n }\n h.handle(\"doc.save\", json!({\"path\": path.to_string_lossy(), \"quality\": 85})).unwrap();\n let bytes = std::fs::read(&path).unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(err.contains(\"quality\"), \"{q}: {err}\");\n assert!(!path.exists(), \"{q} wrote a file\");\n }\n h.handle(\"doc.save\", json!({\"path\": path.to_string_lossy(), \"quality\": 85})).unwrap();",
|
||
" assert!(!path.exists(), \"{q} wrote a file\");\n }\n h.handle(\"doc.save\", json!({\"path\": path.to_string_lossy(), \"quality\": 85})).unwrap();\n let bytes = std::fs::read(&path).unwrap();",
|
||
" assert!(bytes.windows(4).any(|c| c == b\"VP8 \") && !bytes.windows(4).any(|c| c == b\"VP8L\"), \"a WebP saved with a quality is lossy\");\n std::fs::remove_dir_all(dir).unwrap();\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c46a74621d36adae9707ab8f3eb39cf6b4c302b9/crates/automation/src/rpc.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "exif_srgb_jpeg_round_trip",
|
||
"path": "crates/engine/src/color_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked exif_srgb_jpeg_round_trip -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.execute(\"edit.colorSettings\", json!({\"workingRgb\": \"display-p3\"})).unwrap();\n // Embed Color Profile off: an untagged document is otherwise tagged sRGB on export (#9325).\n let mut opts = photocraft_io::ExportOptions::default();\n opts.encode.embed_icc = false;\n let r = photocraft_io::export(&untagged_camera_file(Some(1)), \"x.jpg\", &opts).unwrap();\n let back = photocraft_io::import(\"x.jpg\", &r.bytes).unwrap().document;\n assert!(back.icc_profile.is_none(), \"no ICC profile in the file\");\n let (_, r) = s.open_document(back, None);\n assert_eq!((r[\"action\"].as_str(), r[\"exif\"].as_bool()), (Some(\"kept\"), Some(true)));\n assert!(desc(&s.active().unwrap().doc).unwrap().starts_with(\"sRGB\"));\n }",
|
||
"expected_assertions": [
|
||
" assert!(back.icc_profile.is_none(), \"no ICC profile in the file\");\n let (_, r) = s.open_document(back, None);\n assert_eq!((r[\"action\"].as_str(), r[\"exif\"].as_bool()), (Some(\"kept\"), Some(true)));\n assert!(desc(&s.active().unwrap().doc).unwrap().starts_with(\"sRGB\"));",
|
||
" assert_eq!((r[\"action\"].as_str(), r[\"exif\"].as_bool()), (Some(\"kept\"), Some(true)));\n assert!(desc(&s.active().unwrap().doc).unwrap().starts_with(\"sRGB\"));\n }",
|
||
" assert!(desc(&s.active().unwrap().doc).unwrap().starts_with(\"sRGB\"));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c46a74621d36adae9707ab8f3eb39cf6b4c302b9/crates/engine/src/color_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "embed_color_profile_tags_an_untagged_document_srgb",
|
||
"path": "crates/engine/src/web_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked embed_color_profile_tags_an_untagged_document_srgb -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session(8);\n assert!(s.active().unwrap().doc.icc_profile.is_none(), \"a new document is untagged\");\n let dir = tmp(\"assumed-icc\");\n let profile = |path: &str| decode(path).icc.map(|b| photocraft_cms::Profile::parse(&b).unwrap().description);\n for (format, ext) in [(\"jpeg\", \"jpg\"), (\"png24\", \"png\")] {\n let on = format!(\"{dir}/on.{ext}\");\n s.execute(\"file.export.saveForWebLegacy\", json!({\"format\": format, \"embedIcc\": true, \"path\": on})).unwrap();\n assert_eq!(profile(&on).as_deref(), Some(photocraft_cms::Builtin::Srgb.description()), \"{format}\");\n let off = format!(\"{dir}/off.{ext}\");\n s.execute(\"file.export.saveForWebLegacy\", json!({\"format\": format, \"embedIcc\": false, \"path\": off})).unwrap();\n assert_eq!(profile(&off), None, \"{format}\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(s.active().unwrap().doc.icc_profile.is_none(), \"a new document is untagged\");\n let dir = tmp(\"assumed-icc\");\n let profile = |path: &str| decode(path).icc.map(|b| photocraft_cms::Profile::parse(&b).unwrap().description);\n for (format, ext) in [(\"jpeg\", \"jpg\"), (\"png24\", \"png\")] {",
|
||
" assert_eq!(profile(&on).as_deref(), Some(photocraft_cms::Builtin::Srgb.description()), \"{format}\");\n let off = format!(\"{dir}/off.{ext}\");\n s.execute(\"file.export.saveForWebLegacy\", json!({\"format\": format, \"embedIcc\": false, \"path\": off})).unwrap();\n assert_eq!(profile(&off), None, \"{format}\");",
|
||
" assert_eq!(profile(&off), None, \"{format}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c46a74621d36adae9707ab8f3eb39cf6b4c302b9/crates/engine/src/web_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "untagged_documents_embed_the_profile_they_are_assumed_to_be_in",
|
||
"path": "crates/io/src/flat.rs",
|
||
"package": "photocraft-io",
|
||
"command": "cargo test -p photocraft-io --locked untagged_documents_embed_the_profile_they_are_assumed_to_be_in -- --nocapture",
|
||
"fixture_and_action_excerpt": " let opts = ExportOptions::default();\n assert!(opts.encode.embed_icc);\n for ext in [\"jpg\", \"png\", \"tif\", \"webp\"] {\n let r = crate::export(&doc(ColorMode::Rgb), ext, &opts).unwrap();\n assert_eq!(embedded(&r).as_deref(), Some(Builtin::Srgb.description()), \"{ext}\");\n }\n // #9342 review: an untagged gray document shows through the default working gray (Dot\n // Gain 20 %-compatible), so that is the profile its samples are tagged with, not sGray\n // (which would show them darker than the canvas).\n let r = crate::export(&doc(ColorMode::Grayscale), \"png\", &opts).unwrap();\n assert_eq!(embedded(&r).as_deref(), Some(Builtin::DotGain20Compat.description()));\n // Embed Color Profile off: still none.",
|
||
"expected_assertions": [
|
||
" assert!(opts.encode.embed_icc);\n for ext in [\"jpg\", \"png\", \"tif\", \"webp\"] {\n let r = crate::export(&doc(ColorMode::Rgb), ext, &opts).unwrap();\n assert_eq!(embedded(&r).as_deref(), Some(Builtin::Srgb.description()), \"{ext}\");",
|
||
" assert_eq!(embedded(&r).as_deref(), Some(Builtin::Srgb.description()), \"{ext}\");\n }\n // #9342 review: an untagged gray document shows through the default working gray (Dot\n // Gain 20 %-compatible), so that is the profile its samples are tagged with, not sGray",
|
||
" assert_eq!(embedded(&r).as_deref(), Some(Builtin::DotGain20Compat.description()));\n // Embed Color Profile off: still none.\n let mut off = ExportOptions::default();\n off.encode.embed_icc = false;",
|
||
" assert_eq!(embedded(&crate::export(&doc(ColorMode::Rgb), \"jpg\", &off).unwrap()), None);\n // A format without profiles gets no warning about one.\n let r = crate::export(&doc(ColorMode::Rgb), \"bmp\", &opts).unwrap();\n assert!(!r.warnings.iter().any(|w| w.contains(\"profile\")), \"{:?}\", r.warnings);",
|
||
" assert!(!r.warnings.iter().any(|w| w.contains(\"profile\")), \"{:?}\", r.warnings);\n // A tagged document keeps its own profile.\n let mut p3 = doc(ColorMode::Rgb);\n p3.icc_profile = Some(Arc::new(Builtin::DisplayP3.profile().to_bytes().to_vec()));",
|
||
" assert_eq!(embedded(&crate::export(&p3, \"jpg\", &opts).unwrap()).as_deref(), Some(Builtin::DisplayP3.description()));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c46a74621d36adae9707ab8f3eb39cf6b4c302b9/crates/io/src/flat.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_estimate_is_the_exported_files_size",
|
||
"path": "crates/ui-egui/src/export_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_estimate_is_the_exported_files_size -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut doc = Document::with_background(\n \"x\",\n photocraft_doc::Size::new(900, 300),\n photocraft_doc::ColorMode::Rgb,\n photocraft_doc::SampleType::U8,\n photocraft_doc::Color::WHITE,\n );\n let id = doc.layers[0].id;\n let surf = doc.layer_mut(id).unwrap().surface_mut().unwrap();\n let mut seed = 12345u32;\n for y in (0..300).step_by(2) {\n for x in (0..900).step_by(2) {",
|
||
"expected_assertions": [
|
||
" assert!((old as f64 / actual as f64 - 1.0).abs() > 0.1, \"the proxy estimate was off: {old} vs {actual}\");\n\n let ctx = egui::Context::default();\n let key = egui::Id::new(\"exact-estimate-test\");",
|
||
" assert!(std::time::Instant::now() < deadline, \"the exact estimate did not arrive\");\n std::thread::sleep(std::time::Duration::from_millis(10));\n };\n assert_eq!(size, Some(actual));",
|
||
" assert_eq!(size, Some(actual));\n // Over the limit there is no exact size; the proxy estimate stays.\n let huge = Map::from_iter([\n (\"format\".into(), json!(\"jpg\")),",
|
||
" assert_eq!(exact_estimate(&doc, &huge), None);\n // In scale mode the size comes from the scale, as the export's does, not from stale pixels.\n let big = Arc::new(Document::with_background(\n \"big\",",
|
||
" assert_eq!(exact_estimate(&big, &stale), None, \"10000 × 10000 at 1000 %, over the limit\");\n let small = Map::from_iter([\n (\"format\".into(), json!(\"png\")),\n (\"sizing\".into(), json!(\"scale\")),",
|
||
" assert_eq!(exact_estimate(&big, &small), Some(at_10), \"100 × 100 at 10 %, within it\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/c46a74621d36adae9707ab8f3eb39cf6b4c302b9/crates/ui-egui/src/export_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9401",
|
||
"pr": 9401,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-automation --locked write_keeps_the_replaced_files_creation_time -- --nocapture",
|
||
"cargo test -p photocraft-format --locked keeps_the_original_creation_time -- --nocapture",
|
||
"cargo test -p photocraft-format --locked keeps_the_creation_time_under_a_deny_write_acl -- --nocapture"
|
||
],
|
||
"expected": "write keeps the replaced files creation time; keeps the original creation time; keeps the creation time under a deny write acl",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-automation --locked write_keeps_the_replaced_files_creation_time -- --nocapture",
|
||
"cargo test -p photocraft-format --locked keeps_the_original_creation_time -- --nocapture",
|
||
"cargo test -p photocraft-format --locked keeps_the_creation_time_under_a_deny_write_acl -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "write_keeps_the_replaced_files_creation_time",
|
||
"path": "crates/automation/src/workspace.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked write_keeps_the_replaced_files_creation_time -- --nocapture",
|
||
"fixture_and_action_excerpt": " use std::os::macos::fs::FileTimesExt;\n let (inside, _, workspace) = roots(\"created\");\n let path = inside.join(\"doc.psd\");\n workspace.write(\"doc.psd\", b\"original\").unwrap();\n let born = std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_600_000_000);\n std::fs::OpenOptions::new().write(true).open(&path).unwrap().set_times(std::fs::FileTimes::new().set_created(born)).unwrap();\n workspace.write(\"doc.psd\", b\"replacement\").unwrap();\n assert_eq!(std::fs::read(&path).unwrap(), b\"replacement\");\n assert_eq!(std::fs::metadata(&path).unwrap().created().unwrap(), born, \"the creation time survives the automation write\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(std::fs::read(&path).unwrap(), b\"replacement\");\n assert_eq!(std::fs::metadata(&path).unwrap().created().unwrap(), born, \"the creation time survives the automation write\");\n }",
|
||
" assert_eq!(std::fs::metadata(&path).unwrap().created().unwrap(), born, \"the creation time survives the automation write\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/f241bba1adfb9c7ec5dd5ed9d86f95b63c7bc2c3/crates/automation/src/workspace.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "keeps_the_original_creation_time",
|
||
"path": "crates/format/src/atomic/tests.rs",
|
||
"package": "photocraft-format",
|
||
"command": "cargo test -p photocraft-format --locked keeps_the_original_creation_time -- --nocapture",
|
||
"fixture_and_action_excerpt": " use std::os::macos::fs::FileTimesExt;\n let d = TempDir::new(\"created\");\n let p = d.0.join(\"doc.psd\");\n std::fs::write(&p, ORIGINAL).unwrap();\n // A creation time well in the past, so a reset to \"now\" can't pass for it.\n let born = std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_600_000_000);\n std::fs::OpenOptions::new().write(true).open(&p).unwrap().set_times(std::fs::FileTimes::new().set_created(born)).unwrap();\n assert_eq!(std::fs::metadata(&p).unwrap().created().unwrap(), born);\n atomic_write(&p, b\"new\").unwrap();\n assert_eq!(std::fs::read(&p).unwrap(), b\"new\");\n assert_eq!(std::fs::metadata(&p).unwrap().created().unwrap(), born, \"the creation time survives the save\");\n assert_no_temp(&d.0);",
|
||
"expected_assertions": [
|
||
" assert_eq!(std::fs::metadata(&p).unwrap().created().unwrap(), born);\n atomic_write(&p, b\"new\").unwrap();\n assert_eq!(std::fs::read(&p).unwrap(), b\"new\");\n assert_eq!(std::fs::metadata(&p).unwrap().created().unwrap(), born, \"the creation time survives the save\");",
|
||
" assert_eq!(std::fs::read(&p).unwrap(), b\"new\");\n assert_eq!(std::fs::metadata(&p).unwrap().created().unwrap(), born, \"the creation time survives the save\");\n assert_no_temp(&d.0);\n}",
|
||
" assert_eq!(std::fs::metadata(&p).unwrap().created().unwrap(), born, \"the creation time survives the save\");\n assert_no_temp(&d.0);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/f241bba1adfb9c7ec5dd5ed9d86f95b63c7bc2c3/crates/format/src/atomic/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "keeps_the_creation_time_under_a_deny_write_acl",
|
||
"path": "crates/format/src/atomic/tests.rs",
|
||
"package": "photocraft-format",
|
||
"command": "cargo test -p photocraft-format --locked keeps_the_creation_time_under_a_deny_write_acl -- --nocapture",
|
||
"fixture_and_action_excerpt": " use std::os::macos::fs::FileTimesExt;\n let d = TempDir::new(\"created-acl\");\n let p = d.0.join(\"doc.psd\");\n std::fs::write(&p, ORIGINAL).unwrap();\n let born = std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_600_000_000);\n std::fs::OpenOptions::new().write(true).open(&p).unwrap().set_times(std::fs::FileTimes::new().set_created(born)).unwrap();\n let Ok(user) = std::env::var(\"USER\") else { return };\n let deny = exacl::AclEntry::deny_user(&user, exacl::Perm::WRITE, None);\n if exacl::setfacl(&[&p], &[deny], None).is_err() {\n return; // a file system without ACLs: nothing to assert\n }\n atomic_write(&p, b\"new\").unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(std::fs::read(&p).unwrap(), b\"new\");\n assert_eq!(std::fs::metadata(&p).unwrap().created().unwrap(), born, \"the creation time survives a deny-write ACL\");\n let _ = exacl::setfacl(&[&p], &[], None);\n assert_no_temp(&d.0);",
|
||
" assert_eq!(std::fs::metadata(&p).unwrap().created().unwrap(), born, \"the creation time survives a deny-write ACL\");\n let _ = exacl::setfacl(&[&p], &[], None);\n assert_no_temp(&d.0);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/f241bba1adfb9c7ec5dd5ed9d86f95b63c7bc2c3/crates/format/src/atomic/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9416",
|
||
"pr": 9416,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Synthetic repeated tags and fixed-record stream in affinity/src/tests.rs; licensed curve document with known topology/reference",
|
||
"action": [
|
||
"cargo test -p photocraft-affinity --locked lookup_keeps_first_match_for_every_object_size -- --nocapture",
|
||
"cargo test -p photocraft-affinity --locked a_fixed_size_array_is_one_buffer_and_one_value_per_record -- --nocapture"
|
||
],
|
||
"expected": "Tag lookup preserves first occurrence for sizes 0–59 and positional-tag exclusion; five 18-byte records occupy one buffer and report five elements. Full curve import preserves finite control points, nodes and topology.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Also run full affinity suite and applicable pinned corpus tests. Record curve fixture hash and compare imported geometry/appearance; if no end-to-end contiguous-curve fixture exists, mark that subcase BLOCKED. Storage tests alone do not establish render fidelity.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-affinity --locked lookup_keeps_first_match_for_every_object_size -- --nocapture",
|
||
"cargo test -p photocraft-affinity --locked a_fixed_size_array_is_one_buffer_and_one_value_per_record -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-9590",
|
||
"pr": 9590,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-io --locked psd_contours_keep_at_most_16_points_and_their_peaks -- --nocapture",
|
||
"cargo test -p photocraft-io --locked a_point_on_a_tiny_straight_span_is_not_a_bend -- --nocapture"
|
||
],
|
||
"expected": "psd contours keep at most 16 points and their peaks; a point on a tiny straight span is not a bend",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-io --locked psd_contours_keep_at_most_16_points_and_their_peaks -- --nocapture",
|
||
"cargo test -p photocraft-io --locked a_point_on_a_tiny_straight_span_is_not_a_bend -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "psd_contours_keep_at_most_16_points_and_their_peaks",
|
||
"path": "crates/io/src/effects_map.rs",
|
||
"package": "photocraft-io",
|
||
"command": "cargo test -p photocraft-io --locked psd_contours_keep_at_most_16_points_and_their_peaks -- --nocapture",
|
||
"fixture_and_action_excerpt": " let points: Vec<CurvePoint> = (0..29)\n .map(|i| {\n let x = i as f32 / 28.0;\n // Rings at x = 0.25 and 0.75, small wiggles between.\n let y = (1.0 - ((x - 0.25).abs() * 8.0)).max(0.0).max(1.0 - (x - 0.75).abs() * 8.0) + if i % 2 == 0 { 0.0 } else { 0.01 };\n CurvePoint { input: x, output: y.clamp(0.0, 1.0) }\n })\n .collect();\n let c = Contour::Custom { name: \"Two rings\".into(), points: points.clone(), corners: vec![false; 29] };\n let out = crv(&contour_value(&c));\n assert_eq!(out.len(), 16);\n assert_eq!(out.first().copied(), Some((0.0, f64::from(points[0].output) * 255.0)));",
|
||
"expected_assertions": [
|
||
" assert_eq!(out.len(), 16);\n assert_eq!(out.first().copied(), Some((0.0, f64::from(points[0].output) * 255.0)));\n assert_eq!(out.last().map(|p| p.0), Some(255.0));\n let peak = |x: f32| out.iter().any(|p| ((p.0 / 255.0) as f32 - x).abs() < 0.03 && p.1 > 240.0);",
|
||
" assert_eq!(out.first().copied(), Some((0.0, f64::from(points[0].output) * 255.0)));\n assert_eq!(out.last().map(|p| p.0), Some(255.0));\n let peak = |x: f32| out.iter().any(|p| ((p.0 / 255.0) as f32 - x).abs() < 0.03 && p.1 > 240.0);\n assert!(peak(0.25) && peak(0.75), \"both rings kept: {out:?}\");",
|
||
" assert_eq!(out.last().map(|p| p.0), Some(255.0));\n let peak = |x: f32| out.iter().any(|p| ((p.0 / 255.0) as f32 - x).abs() < 0.03 && p.1 > 240.0);\n assert!(peak(0.25) && peak(0.75), \"both rings kept: {out:?}\");\n assert!(out.windows(2).all(|w| w[0].0 < w[1].0), \"in order: {out:?}\");",
|
||
" assert!(peak(0.25) && peak(0.75), \"both rings kept: {out:?}\");\n assert!(out.windows(2).all(|w| w[0].0 < w[1].0), \"in order: {out:?}\");\n\n let short = Contour::Custom { name: \"Short\".into(), points: points[..16].to_vec(), corners: vec![false; 16] };",
|
||
" assert!(out.windows(2).all(|w| w[0].0 < w[1].0), \"in order: {out:?}\");\n\n let short = Contour::Custom { name: \"Short\".into(), points: points[..16].to_vec(), corners: vec![false; 16] };\n assert_eq!(crv(&contour_value(&short)).len(), 16);",
|
||
" assert_eq!(crv(&contour_value(&short)).len(), 16);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/a9744ed44dc782613b19a97b8c159a091f73e669/crates/io/src/effects_map.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_point_on_a_tiny_straight_span_is_not_a_bend",
|
||
"path": "crates/io/src/effects_map.rs",
|
||
"package": "photocraft-io",
|
||
"command": "cargo test -p photocraft-io --locked a_point_on_a_tiny_straight_span_is_not_a_bend -- --nocapture",
|
||
"fixture_and_action_excerpt": " let p = |input: f32, output: f32| CurvePoint { input, output };\n // Three distinct inputs a few ulps apart near 0.5, on a straight rise from 0 to 1.\n let (a, b) = (0.5_f32, f32::from_bits(0.5_f32.to_bits() + 2));\n let mid = f32::from_bits(0.5_f32.to_bits() + 1);\n let mut points = vec![p(0.0, 0.0), p(0.2, 0.0)];\n points.extend([p(a, 0.0), p(mid, 0.5), p(b, 1.0)]);\n // Fourteen gentle bends after it, each one a real (if small) peak.\n points.extend((0..14).map(|k| p(0.55 + k as f32 * 0.03, if k % 2 == 0 { 1.0 } else { 0.9 })));\n points.push(p(1.0, 1.0));\n let kept = psd_contour_points(&points);\n assert_eq!(kept.len(), 16);\n assert!(!kept.contains(&3), \"the point on the tiny straight span was kept over a real bend: {kept:?}\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(kept.len(), 16);\n assert!(!kept.contains(&3), \"the point on the tiny straight span was kept over a real bend: {kept:?}\");\n }",
|
||
" assert!(!kept.contains(&3), \"the point on the tiny straight span was kept over a real bend: {kept:?}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/a9744ed44dc782613b19a97b8c159a091f73e669/crates/io/src/effects_map.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-4763",
|
||
"pr": 4763,
|
||
"subsystem": "Painting",
|
||
"fixture_setup": "Open Liquify on a synthetic grid; place the brush center at a known point and note the initial size.",
|
||
"action": "Use the native brush-resize gesture, vary size and restore it; inspect the HUD anchor while dragging.",
|
||
"expected": "Liquify reuses the native resize behavior and the HUD stays anchored to the gesture; no image edit is committed by resizing.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": ""
|
||
},
|
||
{
|
||
"id": "PR-4985",
|
||
"pr": 4985,
|
||
"subsystem": "Painting",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked shift_right_mode_picker_selects_journals_and_clear_erases -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked mode_picker_outside_dismissal_does_not_paint_or_erase -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked mode_control_can_pick_a_row_with_ui_click -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shift_right_mode_picker_cancels_and_other_gestures_keep_their_routes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked escape_dismissal_consumes_a_held_secondary_release -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shift_released_before_the_right_button_still_opens_the_mode_picker -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shift_right_brush_does_not_open_presets_or_paint -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked brush_mode_control_routes_modifiers_and_reports_choices_without_history -- --nocapture"
|
||
],
|
||
"expected": "shift right mode picker selects journals and clear erases; mode picker outside dismissal does not paint or erase; mode control can pick a row with ui click; shift right mode picker cancels and other gestures keep their routes; escape dismissal consumes a held secondary release; shift released before the right button still opens the mode picker; shift right brush does not open presets or paint; brush mode control routes modifiers and reports choices without history",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked shift_right_mode_picker_selects_journals_and_clear_erases -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked mode_picker_outside_dismissal_does_not_paint_or_erase -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked mode_control_can_pick_a_row_with_ui_click -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shift_right_mode_picker_cancels_and_other_gestures_keep_their_routes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked escape_dismissal_consumes_a_held_secondary_release -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shift_released_before_the_right_button_still_opens_the_mode_picker -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shift_right_brush_does_not_open_presets_or_paint -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked brush_mode_control_routes_modifiers_and_reports_choices_without_history -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "shift_right_mode_picker_selects_journals_and_clear_erases",
|
||
"path": "crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked shift_right_mode_picker_selects_journals_and_clear_erases -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n let mut h = harness(Some(\"erase\"));\n let history = h.state().session.active().unwrap().history.past_len();\n let journal = h.state().session.journal.len();\n mode_right_click(&mut h, Modifiers::SHIFT);\n assert!(h.state().ui.brush_mode_menu.is_some());\n assert!(h.state().ui.brush_picker.is_none() && h.state().drag.is_none());\n assert_eq!(h.state().session.journal.len(), journal);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n h.get_by_label(\"Multiply\").click();\n h.run_steps(2);\n assert!(h.state().ui.brush_mode_menu.is_none());",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.brush_mode_menu.is_some());\n assert!(h.state().ui.brush_picker.is_none() && h.state().drag.is_none());\n assert_eq!(h.state().session.journal.len(), journal);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);",
|
||
" assert!(h.state().ui.brush_picker.is_none() && h.state().drag.is_none());\n assert_eq!(h.state().session.journal.len(), journal);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n h.get_by_label(\"Multiply\").click();",
|
||
" assert_eq!(h.state().session.journal.len(), journal);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n h.get_by_label(\"Multiply\").click();\n h.run_steps(2);",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n h.get_by_label(\"Multiply\").click();\n h.run_steps(2);\n assert!(h.state().ui.brush_mode_menu.is_none());",
|
||
" assert!(h.state().ui.brush_mode_menu.is_none());\n assert_eq!(h.state().session.tools.brush.mode, photocraft_doc::BlendMode::Multiply);\n assert_eq!(h.state().session.journal.last().unwrap(), &(\"tools.setBrush\".into(), json!({\"brush\": {\"mode\": \"Multiply\"}})));\n let (a, b) = drag(&mut h, PointerButton::Primary);",
|
||
" assert_eq!(h.state().session.tools.brush.mode, photocraft_doc::BlendMode::Multiply);\n assert_eq!(h.state().session.journal.last().unwrap(), &(\"tools.setBrush\".into(), json!({\"brush\": {\"mode\": \"Multiply\"}})));\n let (a, b) = drag(&mut h, PointerButton::Primary);\n let mid = a + (b - a) * 0.5;",
|
||
" assert_eq!(h.state().session.journal.last().unwrap(), &(\"tools.setBrush\".into(), json!({\"brush\": {\"mode\": \"Multiply\"}})));\n let (a, b) = drag(&mut h, PointerButton::Primary);\n let mid = a + (b - a) * 0.5;\n assert!(alpha_at(&h, mid) > 0.9);",
|
||
" assert!(alpha_at(&h, mid) > 0.9);\n mode_right_click(&mut h, Modifiers::SHIFT);\n h.get_by_label(\"Clear\").click();\n h.run_steps(2);",
|
||
" assert!(h.state().ui.tool_options.brush_clear);\n assert_eq!(h.state().session.tools.brush.mode, photocraft_doc::BlendMode::Multiply, \"Clear keeps the underlying mode, as the options bar does\");\n drag(&mut h, PointerButton::Primary);\n assert_eq!(alpha_at(&h, mid), 0.0);",
|
||
" assert_eq!(h.state().session.tools.brush.mode, photocraft_doc::BlendMode::Multiply, \"Clear keeps the underlying mode, as the options bar does\");\n drag(&mut h, PointerButton::Primary);\n assert_eq!(alpha_at(&h, mid), 0.0);\n assert!(strokes(&h).last().unwrap()[\"erase\"].as_bool().unwrap());",
|
||
" assert_eq!(alpha_at(&h, mid), 0.0);\n assert!(strokes(&h).last().unwrap()[\"erase\"].as_bool().unwrap());\n}",
|
||
" assert!(strokes(&h).last().unwrap()[\"erase\"].as_bool().unwrap());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1dc98f80f60e993f3edf20af815391b6a7e7add7/crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "mode_picker_outside_dismissal_does_not_paint_or_erase",
|
||
"path": "crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked mode_picker_outside_dismissal_does_not_paint_or_erase -- --nocapture",
|
||
"fixture_and_action_excerpt": " for button in [PointerButton::Primary, PointerButton::Secondary] {\n let mut h = harness(Some(\"erase\"));\n drag(&mut h, PointerButton::Primary);\n let journal = h.state().session.journal.len();\n let history = h.state().session.active().unwrap().history.past_len();\n mode_right_click(&mut h, Modifiers::SHIFT);\n // A full outside drag must only dismiss, including its release click.\n drag(&mut h, button);\n assert!(h.state().ui.brush_mode_menu.is_none());\n assert_eq!(h.state().session.journal.len(), journal, \"dismissal must not paint/erase with {button:?}\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n }",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.brush_mode_menu.is_none());\n assert_eq!(h.state().session.journal.len(), journal, \"dismissal must not paint/erase with {button:?}\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n }",
|
||
" assert_eq!(h.state().session.journal.len(), journal, \"dismissal must not paint/erase with {button:?}\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n }\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1dc98f80f60e993f3edf20af815391b6a7e7add7/crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "mode_control_can_pick_a_row_with_ui_click",
|
||
"path": "crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked mode_control_can_pick_a_row_with_ui_click -- --nocapture",
|
||
"fixture_and_action_excerpt": " use crate::control::{ControlRequest, Outcome, handle};\n use egui_kittest::kittest::Queryable;\n let mut h = harness(Some(\"erase\"));\n let ctx = h.ctx.clone();\n let before = h.state().session.journal.len();\n let (req, _) = ControlRequest::new(\n \"ui.pointer\",\n json!({\"button\": \"right\", \"shift\": true,\n \"events\": [{\"kind\": \"down\", \"x\": 200, \"y\": 150}, {\"kind\": \"up\", \"x\": 200, \"y\": 150}]}),\n );\n assert!(matches!(handle(h.state_mut(), &ctx, &req), Outcome::Done(_)));\n h.run_steps(2);",
|
||
"expected_assertions": [
|
||
" assert!(matches!(handle(h.state_mut(), &ctx, &req), Outcome::Done(_)));\n h.run_steps(2);\n assert!(h.state().ui.brush_mode_menu.is_some());\n assert_eq!(h.state().session.journal.len(), before);",
|
||
" assert!(h.state().ui.brush_mode_menu.is_some());\n assert_eq!(h.state().session.journal.len(), before);\n let at = h.get_by_label(\"Darken\").rect().center();\n let (req, _) = ControlRequest::new(\"ui.click\", json!({\"x\": at.x, \"y\": at.y}));",
|
||
" assert_eq!(h.state().session.journal.len(), before);\n let at = h.get_by_label(\"Darken\").rect().center();\n let (req, _) = ControlRequest::new(\"ui.click\", json!({\"x\": at.x, \"y\": at.y}));\n assert!(matches!(handle(h.state_mut(), &ctx, &req), Outcome::AfterInput));",
|
||
" assert!(matches!(handle(h.state_mut(), &ctx, &req), Outcome::AfterInput));\n // The app injects these queued control events into its next frame's input.\n let events = std::mem::take(&mut h.state_mut().synthetic);\n for event in events {",
|
||
" assert!(h.state().ui.brush_mode_menu.is_none());\n assert_eq!(h.state().session.tools.brush.mode, photocraft_doc::BlendMode::Darken);\n assert_eq!(h.state().session.journal.last().unwrap(), &(\"tools.setBrush\".into(), json!({\"brush\": {\"mode\": \"Darken\"}})));\n}",
|
||
" assert_eq!(h.state().session.tools.brush.mode, photocraft_doc::BlendMode::Darken);\n assert_eq!(h.state().session.journal.last().unwrap(), &(\"tools.setBrush\".into(), json!({\"brush\": {\"mode\": \"Darken\"}})));\n}",
|
||
" assert_eq!(h.state().session.journal.last().unwrap(), &(\"tools.setBrush\".into(), json!({\"brush\": {\"mode\": \"Darken\"}})));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1dc98f80f60e993f3edf20af815391b6a7e7add7/crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "shift_right_mode_picker_cancels_and_other_gestures_keep_their_routes",
|
||
"path": "crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked shift_right_mode_picker_cancels_and_other_gestures_keep_their_routes -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness(None);\n let journal = h.state().session.journal.len();\n mode_right_click(&mut h, Modifiers::SHIFT);\n h.key_press(egui::Key::Escape);\n h.run_steps(2);\n assert!(h.state().ui.brush_mode_menu.is_none());\n mode_right_click(&mut h, Modifiers::SHIFT);\n let outside = h.state().last_canvas_rect.min + vec2(2.0, 2.0);\n h.event(egui::Event::PointerMoved(outside));\n press(&mut h, outside, PointerButton::Secondary, true);\n press(&mut h, outside, PointerButton::Secondary, false);\n assert!(h.state().ui.brush_mode_menu.is_none());",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.brush_mode_menu.is_none());\n mode_right_click(&mut h, Modifiers::SHIFT);\n let outside = h.state().last_canvas_rect.min + vec2(2.0, 2.0);\n h.event(egui::Event::PointerMoved(outside));",
|
||
" assert!(h.state().ui.brush_mode_menu.is_none());\n mode_right_click(&mut h, Modifiers::SHIFT);\n h.state_mut().ui.tool = Tool::Pencil;\n h.run_steps(2);",
|
||
" assert!(h.state().ui.brush_mode_menu.is_none());\n mode_right_click(&mut h, Modifiers::SHIFT);\n assert!(h.state().ui.brush_mode_menu.is_none() && h.state().ui.brush_picker.is_some());\n h.state_mut().ui.brush_picker = None;",
|
||
" assert!(h.state().ui.brush_mode_menu.is_none() && h.state().ui.brush_picker.is_some());\n h.state_mut().ui.brush_picker = None;\n h.state_mut().ui.tool = Tool::Brush;\n mode_right_click(&mut h, Modifiers::NONE);",
|
||
" assert!(h.state().ui.brush_picker.is_some() && h.state().ui.brush_mode_menu.is_none());\n assert_eq!(h.state().session.journal.len(), journal, \"opening/cancelling never changes brush or pixels\");\n}",
|
||
" assert_eq!(h.state().session.journal.len(), journal, \"opening/cancelling never changes brush or pixels\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1dc98f80f60e993f3edf20af815391b6a7e7add7/crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "escape_dismissal_consumes_a_held_secondary_release",
|
||
"path": "crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked escape_dismissal_consumes_a_held_secondary_release -- --nocapture",
|
||
"fixture_and_action_excerpt": " for release_shift in [false, true] {\n let mut h = harness(Some(\"erase\"));\n let journal = h.state().session.journal.len();\n let history = h.state().session.active().unwrap().history.past_len();\n let p = h.state().last_canvas_rect.center();\n h.event(egui::Event::ModifiersChanged(Modifiers::SHIFT));\n h.event(egui::Event::PointerMoved(p));\n h.event(egui::Event::PointerButton { pos: p, button: PointerButton::Secondary, pressed: true, modifiers: Modifiers::SHIFT });\n h.run_steps(1);\n // A quick second press can arrive in the frame that opens the menu for the first\n // click's release, leaving the secondary button held while the picker is visible.\n h.event(egui::Event::PointerButton { pos: p, button: PointerButton::Secondary, pressed: false, modifiers: Modifiers::SHIFT });",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.brush_mode_menu.is_some());\n assert!(h.ctx.input(|i| i.pointer.secondary_down()));\n h.key_press(egui::Key::Escape);\n h.run_steps(1);",
|
||
" assert!(h.ctx.input(|i| i.pointer.secondary_down()));\n h.key_press(egui::Key::Escape);\n h.run_steps(1);\n assert!(h.state().ui.brush_mode_menu.is_none());",
|
||
" assert!(h.state().ui.brush_mode_menu.is_none());\n let mods = if release_shift { Modifiers::NONE } else { Modifiers::SHIFT };\n h.event(egui::Event::ModifiersChanged(mods));\n h.run_steps(1);",
|
||
" assert!(h.state().ui.brush_mode_menu.is_none(), \"Escape must consume the pending release\");\n assert!(h.state().ui.brush_picker.is_none() && h.state().drag.is_none() && !h.state().secondary_erase);\n assert_eq!(h.state().session.journal.len(), journal);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);",
|
||
" assert!(h.state().ui.brush_picker.is_none() && h.state().drag.is_none() && !h.state().secondary_erase);\n assert_eq!(h.state().session.journal.len(), journal);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n mode_right_click(&mut h, Modifiers::SHIFT);",
|
||
" assert_eq!(h.state().session.journal.len(), journal);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n mode_right_click(&mut h, Modifiers::SHIFT);\n assert!(h.state().ui.brush_mode_menu.is_some(), \"the next gesture must still work\");",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n mode_right_click(&mut h, Modifiers::SHIFT);\n assert!(h.state().ui.brush_mode_menu.is_some(), \"the next gesture must still work\");\n }",
|
||
" assert!(h.state().ui.brush_mode_menu.is_some(), \"the next gesture must still work\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1dc98f80f60e993f3edf20af815391b6a7e7add7/crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "shift_released_before_the_right_button_still_opens_the_mode_picker",
|
||
"path": "crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked shift_released_before_the_right_button_still_opens_the_mode_picker -- --nocapture",
|
||
"fixture_and_action_excerpt": " // egui reports `secondary_clicked` on release. With Erase on, a click that lost Shift a\n // frame early must open the menu, not erase a dab.\n let mut h = harness(Some(\"erase\"));\n let history = h.state().session.active().unwrap().history.past_len();\n let journal = h.state().session.journal.len();\n let p = h.state().last_canvas_rect.center();\n h.event(egui::Event::ModifiersChanged(Modifiers::SHIFT));\n h.event(egui::Event::PointerMoved(p));\n h.run_steps(1);\n h.event(egui::Event::PointerButton { pos: p, button: PointerButton::Secondary, pressed: true, modifiers: Modifiers::SHIFT });\n h.run_steps(1);\n // Shift goes up in a frame of its own while the right button is still down.",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.brush_mode_menu.is_some(), \"the press decided the gesture\");\n assert!(h.state().drag.is_none() && !h.state().secondary_erase);\n assert_eq!(h.state().session.journal.len(), journal, \"no erase dab\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);",
|
||
" assert!(h.state().drag.is_none() && !h.state().secondary_erase);\n assert_eq!(h.state().session.journal.len(), journal, \"no erase dab\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n}",
|
||
" assert_eq!(h.state().session.journal.len(), journal, \"no erase dab\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1dc98f80f60e993f3edf20af815391b6a7e7add7/crates/ui-egui/src/canvas/paint_mouse/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "shift_right_brush_does_not_open_presets_or_paint",
|
||
"path": "crates/ui-egui/src/control/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked shift_right_brush_does_not_open_presets_or_paint -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 64, \"height\": 64})).unwrap();\n app.ui.tool = crate::state::Tool::Brush;\n let ctx = egui::Context::default();\n let before = app.session.journal.len();\n call(\n &mut app,\n &ctx,\n \"ui.pointer\",\n json!({\"button\": \"right\", \"shift\": true,\n \"events\": [{\"kind\": \"down\", \"x\": 20, \"y\": 20}, {\"kind\": \"up\", \"x\": 20, \"y\": 20}]}),\n );",
|
||
"expected_assertions": [
|
||
" assert!(app.ui.brush_picker.is_none(), \"Shift+right opens Mode, not Brush Presets\");\n assert!(app.drag.is_none());\n assert_eq!(app.session.journal.len(), before, \"opening a menu does not paint or journal\");\n}",
|
||
" assert!(app.drag.is_none());\n assert_eq!(app.session.journal.len(), before, \"opening a menu does not paint or journal\");\n}",
|
||
" assert_eq!(app.session.journal.len(), before, \"opening a menu does not paint or journal\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1dc98f80f60e993f3edf20af815391b6a7e7add7/crates/ui-egui/src/control/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "brush_mode_control_routes_modifiers_and_reports_choices_without_history",
|
||
"path": "crates/ui-egui/src/control/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked brush_mode_control_routes_modifiers_and_reports_choices_without_history -- --nocapture",
|
||
"fixture_and_action_excerpt": " let ctx = egui::Context::default();\n for (tool, modifiers, expected) in [\n (\"brush\", json!({\"shift\": true}), \"mode\"),\n (\"brush\", json!({}), \"erase\"),\n (\"brush\", json!({\"shift\": true, \"alt\": true}), \"resize\"),\n (\"brush\", json!({\"shift\": true, \"ctrl\": true}), if cfg!(target_os = \"macos\") { \"erase\" } else { \"layer\" }),\n (\"brush\", json!({\"shift\": true, \"command\": true}), \"layer\"),\n (\"pencil\", json!({\"shift\": true}), \"preset\"),\n ] {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 64, \"height\": 64, \"background\": \"white\"})).unwrap();\n app.run(\"prefs.set\", json!({\"path\": \"tools.rightClickWithPaintingTools\", \"value\": \"erase\"})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(app.ui.brush_mode_menu.is_some(), expected == \"mode\", \"{tool}: {modifiers}\");\n match expected {\n \"mode\" => {\n assert!(app.drag.is_none() && !app.secondary_erase);",
|
||
" assert!(app.drag.is_none() && !app.secondary_erase);\n assert_eq!(app.session.active().unwrap().history.past_len(), history);\n let inspect = inspect(&app, &ctx);\n assert_eq!(inspect[\"brushModeMenu\"][\"choices\"], json!(crate::brush_mode_menu::choices().iter().map(|(_, label)| *label).collect::<Vec<_>>()));",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), history);\n let inspect = inspect(&app, &ctx);\n assert_eq!(inspect[\"brushModeMenu\"][\"choices\"], json!(crate::brush_mode_menu::choices().iter().map(|(_, label)| *label).collect::<Vec<_>>()));\n let journal = app.session.journal.len();",
|
||
" assert_eq!(inspect[\"brushModeMenu\"][\"choices\"], json!(crate::brush_mode_menu::choices().iter().map(|(_, label)| *label).collect::<Vec<_>>()));\n let journal = app.session.journal.len();\n call(\n &mut app,",
|
||
" assert!(app.ui.brush_mode_menu.is_none() && app.drag.is_none());\n assert_eq!(app.session.journal.len(), journal, \"control dismissal cannot paint\");\n }\n \"preset\" => assert!(app.ui.brush_picker.is_some()),",
|
||
" assert_eq!(app.session.journal.len(), journal, \"control dismissal cannot paint\");\n }\n \"preset\" => assert!(app.ui.brush_picker.is_some()),\n \"layer\" => assert!(app.ui.layer_menu.is_some()),",
|
||
" \"preset\" => assert!(app.ui.brush_picker.is_some()),\n \"layer\" => assert!(app.ui.layer_menu.is_some()),\n \"resize\" => assert!(app.brush_resize.is_some()),\n \"erase\" => assert!(app.drag.as_ref().is_some_and(|d| d.erase)),",
|
||
" \"layer\" => assert!(app.ui.layer_menu.is_some()),\n \"resize\" => assert!(app.brush_resize.is_some()),\n \"erase\" => assert!(app.drag.as_ref().is_some_and(|d| d.erase)),\n _ => panic!(\"unknown fixture route: {expected}\"),",
|
||
" \"resize\" => assert!(app.brush_resize.is_some()),\n \"erase\" => assert!(app.drag.as_ref().is_some_and(|d| d.erase)),\n _ => panic!(\"unknown fixture route: {expected}\"),\n }",
|
||
" \"erase\" => assert!(app.drag.as_ref().is_some_and(|d| d.erase)),\n _ => panic!(\"unknown fixture route: {expected}\"),\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1dc98f80f60e993f3edf20af815391b6a7e7add7/crates/ui-egui/src/control/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-5082",
|
||
"pr": 5082,
|
||
"subsystem": "Painting",
|
||
"fixture_setup": "Red/green canvas with blue foreground from alt_click_tests.rs; engine 80×40 transparent canvas with blue stroke and red foreground",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked alt_click_with_the_mixer_brush_loads_the_reservoir_not_the_foreground -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked mixer_load_fills_the_reservoir_from_the_canvas_and_keeps_the_foreground -- --nocapture"
|
||
],
|
||
"expected": "Alt-click loads Current Brush Load/reservoir, preserving foreground and document revision and painting nothing. Dry stroke uses sampled blue until foreground changes; green foreground then paints green. Transparent sampling loads nothing; invalid coordinates preserve all state.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Historical PR title is stale: this case follows reviewed reservoir behavior, not foreground replacement. Repeat Alt/Option-click natively as a separate NOT RUN subcase.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked alt_click_with_the_mixer_brush_loads_the_reservoir_not_the_foreground -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked mixer_load_fills_the_reservoir_from_the_canvas_and_keeps_the_foreground -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-5165",
|
||
"pr": 5165,
|
||
"subsystem": "Painting",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked selecting_a_controls_section_keeps_its_enabled_flag_and_brush_history -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked controls_section_checkbox_toggles_without_selecting_its_settings -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked f5_edits_the_default_brush_with_every_section -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked section_boxes_show_a_pressed_state -- --nocapture"
|
||
],
|
||
"expected": "selecting a controls section keeps its enabled flag and brush history; controls section checkbox toggles without selecting its settings; f5 edits the default brush with every section; section boxes show a pressed state",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked selecting_a_controls_section_keeps_its_enabled_flag_and_brush_history -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked controls_section_checkbox_toggles_without_selecting_its_settings -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked f5_edits_the_default_brush_with_every_section -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked section_boxes_show_a_pressed_state -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "selecting_a_controls_section_keeps_its_enabled_flag_and_brush_history",
|
||
"path": "crates/ui-egui/src/brush_panel_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked selecting_a_controls_section_keeps_its_enabled_flag_and_brush_history -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n\n for (section, name) in [(1, \"Shape Dynamics\"), (2, \"Scattering\"), (3, \"Texture\")] {\n let mut h = harness(0, 0);\n let before = h.state().session.tools.brush.clone();\n let journal = h.state().session.journal.len();\n\n h.get_by_label(name).click();\n h.run_steps(3);\n\n assert_eq!(h.state().ui.brush_section, section, \"{name} settings are visible\");\n assert_eq!(h.state().session.tools.brush, before, \"{name} remains disabled\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().ui.brush_section, section, \"{name} settings are visible\");\n assert_eq!(h.state().session.tools.brush, before, \"{name} remains disabled\");\n assert_eq!(h.state().session.journal.len(), journal, \"selecting {name} is not a brush edit\");\n }",
|
||
" assert_eq!(h.state().session.tools.brush, before, \"{name} remains disabled\");\n assert_eq!(h.state().session.journal.len(), journal, \"selecting {name} is not a brush edit\");\n }\n}",
|
||
" assert_eq!(h.state().session.journal.len(), journal, \"selecting {name} is not a brush edit\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/27bc6e4b37b701480efa69559ab13eafc52bd94c/crates/ui-egui/src/brush_panel_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "controls_section_checkbox_toggles_without_selecting_its_settings",
|
||
"path": "crates/ui-egui/src/brush_panel_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked controls_section_checkbox_toggles_without_selecting_its_settings -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n\n let mut h = harness(0, 0);\n let row = h.get_by_label(\"Scattering\").rect();\n let checkbox = egui::pos2(row.left() + 12.0, row.center().y);\n let journal = h.state().session.journal.len();\n\n for enabled in [true, false] {\n h.hover_at(checkbox);\n h.run_steps(1);\n h.drag_at(checkbox);\n h.run_steps(1);",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().session.tools.brush.scattering.enabled, enabled);\n assert_eq!(h.state().ui.brush_section, 0, \"the checkbox does not select Scattering\");\n assert_eq!(last_journal(h.state()).unwrap().1[\"brush\"], json!({\"scattering\": {\"enabled\": enabled}}));\n }",
|
||
" assert_eq!(h.state().ui.brush_section, 0, \"the checkbox does not select Scattering\");\n assert_eq!(last_journal(h.state()).unwrap().1[\"brush\"], json!({\"scattering\": {\"enabled\": enabled}}));\n }\n assert_eq!(h.state().session.journal.len(), journal + 2);",
|
||
" assert_eq!(last_journal(h.state()).unwrap().1[\"brush\"], json!({\"scattering\": {\"enabled\": enabled}}));\n }\n assert_eq!(h.state().session.journal.len(), journal + 2);\n}",
|
||
" assert_eq!(h.state().session.journal.len(), journal + 2);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/27bc6e4b37b701480efa69559ab13eafc52bd94c/crates/ui-egui/src/brush_panel_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "f5_edits_the_default_brush_with_every_section",
|
||
"path": "crates/ui-egui/src/brush_panel_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked f5_edits_the_default_brush_with_every_section -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n let mut h = app_harness();\n assert!(!h.state().ui.panels.brush_settings);\n let fresh = h.state().session.tools.brush.clone();\n assert!(!fresh.shape_dynamics.enabled && !fresh.transfer.enabled, \"the default round brush has no dynamics yet\");\n h.key_press(egui::Key::F5);\n h.run_steps(3);\n assert!(h.state().ui.panels.brush_settings && h.state().ui.brush_tab == 0, \"F5 shows Brush Settings\");\n // Every section is there for the built-in round brush, not only for sampled or imported ones.\n for (name, _) in SECTIONS {\n assert!(h.query_all_by_label(name).next().is_some(), \"{name} listed\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(!h.state().ui.panels.brush_settings);\n let fresh = h.state().session.tools.brush.clone();\n assert!(!fresh.shape_dynamics.enabled && !fresh.transfer.enabled, \"the default round brush has no dynamics yet\");\n h.key_press(egui::Key::F5);",
|
||
" assert!(!fresh.shape_dynamics.enabled && !fresh.transfer.enabled, \"the default round brush has no dynamics yet\");\n h.key_press(egui::Key::F5);\n h.run_steps(3);\n assert!(h.state().ui.panels.brush_settings && h.state().ui.brush_tab == 0, \"F5 shows Brush Settings\");",
|
||
" assert!(h.state().ui.panels.brush_settings && h.state().ui.brush_tab == 0, \"F5 shows Brush Settings\");\n // Every section is there for the built-in round brush, not only for sampled or imported ones.\n for (name, _) in SECTIONS {\n assert!(h.query_all_by_label(name).next().is_some(), \"{name} listed\");",
|
||
" assert!(h.query_all_by_label(name).next().is_some(), \"{name} listed\");\n }\n // Clicking a section's name shows its settings without changing its enable flag.\n let n = h.state().session.journal.len();",
|
||
" assert_eq!(h.state().ui.brush_section, 1);\n assert_eq!(h.state().session.tools.brush.shape_dynamics.enabled, shape_enabled);\n assert_eq!(h.state().session.journal.len(), n);\n // A section's box toggles it without showing it.",
|
||
" assert_eq!(h.state().session.tools.brush.shape_dynamics.enabled, shape_enabled);\n assert_eq!(h.state().session.journal.len(), n);\n // A section's box toggles it without showing it.\n h.get_by_label(\"Enable Transfer\").click();",
|
||
" assert_eq!(h.state().session.journal.len(), n);\n // A section's box toggles it without showing it.\n h.get_by_label(\"Enable Transfer\").click();\n h.run_steps(3);",
|
||
" assert!(h.state().session.tools.brush.transfer.enabled);\n assert_eq!(h.state().ui.brush_section, 1);\n assert_eq!(h.state().session.journal.len(), n + 1);\n // The rest of the brush is untouched.",
|
||
" assert_eq!(h.state().ui.brush_section, 1);\n assert_eq!(h.state().session.journal.len(), n + 1);\n // The rest of the brush is untouched.\n let b = &h.state().session.tools.brush;",
|
||
" assert_eq!(h.state().session.journal.len(), n + 1);\n // The rest of the brush is untouched.\n let b = &h.state().session.tools.brush;\n assert_eq!((b.size, b.hardness, &b.tip), (fresh.size, fresh.hardness, &fresh.tip));",
|
||
" assert_eq!((b.size, b.hardness, &b.tip), (fresh.size, fresh.hardness, &fresh.tip));\n // F5 again hides the panel.\n h.key_press(egui::Key::F5);\n h.run_steps(2);",
|
||
" assert!(!h.state().ui.panels.brush_settings);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/27bc6e4b37b701480efa69559ab13eafc52bd94c/crates/ui-egui/src/brush_panel_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "section_boxes_show_a_pressed_state",
|
||
"path": "crates/ui-egui/src/brush_panel_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked section_boxes_show_a_pressed_state -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n let mut h = app_harness();\n h.key_press(egui::Key::F5);\n h.run_steps(3);\n let t = Tokens::get(&h.ctx);\n let boxr = h.get_by_label(\"Enable Shape Dynamics\").rect();\n let row = h.get_by_label(\"Shape Dynamics\").rect();\n assert!(!h.state().session.tools.brush.shape_dynamics.enabled);\n assert_eq!(box_fill(&h, boxr), Some(widgets::check_box_fill(false, false, &t)));\n // Selecting the controls row leaves its checkbox untouched, including while held.\n let at = egui::pos2(row.center().x, row.center().y);\n h.drag_at(at);",
|
||
"expected_assertions": [
|
||
" assert!(!h.state().session.tools.brush.shape_dynamics.enabled);\n assert_eq!(box_fill(&h, boxr), Some(widgets::check_box_fill(false, false, &t)));\n // Selecting the controls row leaves its checkbox untouched, including while held.\n let at = egui::pos2(row.center().x, row.center().y);",
|
||
" assert_eq!(box_fill(&h, boxr), Some(widgets::check_box_fill(false, false, &t)));\n // Selecting the controls row leaves its checkbox untouched, including while held.\n let at = egui::pos2(row.center().x, row.center().y);\n h.drag_at(at);",
|
||
" assert_eq!(box_fill(&h, boxr), Some(widgets::check_box_fill(false, false, &t)), \"row press leaves checkbox untouched\");\n h.drop_at(at);\n h.run_steps(3);\n assert!(!h.state().session.tools.brush.shape_dynamics.enabled);",
|
||
" assert!(!h.state().session.tools.brush.shape_dynamics.enabled);\n assert_eq!(box_fill(&h, boxr), Some(widgets::check_box_fill(false, false, &t)));\n // The checkbox itself still shows its pressed state and toggles the section.\n h.drag_at(boxr.center());",
|
||
" assert_eq!(box_fill(&h, boxr), Some(widgets::check_box_fill(false, false, &t)));\n // The checkbox itself still shows its pressed state and toggles the section.\n h.drag_at(boxr.center());\n h.run_steps(2);",
|
||
" assert_eq!(box_fill(&h, boxr), Some(widgets::check_box_fill(false, true, &t)), \"pressed, unchecked\");\n h.drop_at(boxr.center());\n h.run_steps(3);\n assert!(h.state().session.tools.brush.shape_dynamics.enabled);",
|
||
" assert!(h.state().session.tools.brush.shape_dynamics.enabled);\n assert_eq!(box_fill(&h, boxr), Some(widgets::check_box_fill(true, false, &t)));\n // Held on the checked box itself: less opaque, then the release turns it off.\n h.drag_at(boxr.center());",
|
||
" assert_eq!(box_fill(&h, boxr), Some(widgets::check_box_fill(true, false, &t)));\n // Held on the checked box itself: less opaque, then the release turns it off.\n h.drag_at(boxr.center());\n h.run_steps(2);",
|
||
" assert_eq!(box_fill(&h, boxr), Some(widgets::check_box_fill(true, true, &t)), \"pressed, checked\");\n h.drop_at(boxr.center());\n h.run_steps(3);\n assert!(!h.state().session.tools.brush.shape_dynamics.enabled);",
|
||
" assert!(!h.state().session.tools.brush.shape_dynamics.enabled);\n // A checkbox-only row (no settings of its own) is one checkbox across the row: a press\n // anywhere on it presses its box, and the release toggles it.\n let wet = h.get_by_label(\"Wet Edges\").rect();",
|
||
" assert_eq!(box_fill(&h, wet_box), Some(widgets::check_box_fill(was, true, &t)), \"pressed checkbox-only row\");\n h.drop_at(wet.center());\n h.run_steps(3);\n assert_ne!(h.state().session.tools.brush.wet_edges, was);",
|
||
" assert_ne!(h.state().session.tools.brush.wet_edges, was);\n // The four looks are distinct.\n let looks = [(false, false), (false, true), (true, false), (true, true)].map(|(on, pressed)| widgets::check_box_fill(on, pressed, &t));\n for (i, a) in looks.iter().enumerate() {",
|
||
" assert!(looks.iter().skip(i + 1).all(|b| b != a), \"{looks:?}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/27bc6e4b37b701480efa69559ab13eafc52bd94c/crates/ui-egui/src/brush_panel_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-5453",
|
||
"pr": 5453,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Synthetic distinct paints and imported/clipboard patterns in shape_paint_fidelity.rs, shape_patterns.rs and shape_pattern_clipboard.rs across their depth/model matrix",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked exact_paints_roundtrip_through_create_edit_and_undo -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked solid_alpha_and_library_patterns_render_and_embed_in_the_same_history_step -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked patterned_shapes_embed_render_and_undo_in_one_command_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked patterned_fill_and_stroke_clipboards_keep_cow_tiles_after_source_closes -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked unresolved_and_conflicting_pattern_clipboards_fail_atomically -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked pattern_shape_fill_and_stroke_render_at_every_depth_and_model -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked patterned_shape_fill_and_stroke_clip_and_effects_match_cpu -- --nocapture"
|
||
],
|
||
"expected": "Distinct solid/gradient/pattern fill and stroke survive create/edit/undo. Pattern embedding shares the history transaction; copied paints retain pixels after source closes; unresolved/conflicting clipboard patterns refuse atomically. GPU matches CPU at the existing tolerance.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Verified adapter required for GPU comparison; cache-budget checks are additional reliability coverage, not a replacement.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked exact_paints_roundtrip_through_create_edit_and_undo -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked solid_alpha_and_library_patterns_render_and_embed_in_the_same_history_step -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked patterned_shapes_embed_render_and_undo_in_one_command_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked patterned_fill_and_stroke_clipboards_keep_cow_tiles_after_source_closes -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked unresolved_and_conflicting_pattern_clipboards_fail_atomically -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked pattern_shape_fill_and_stroke_render_at_every_depth_and_model -- --nocapture",
|
||
"cargo test -p photocraft-gpu --locked patterned_shape_fill_and_stroke_clip_and_effects_match_cpu -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-5939",
|
||
"pr": 5939,
|
||
"subsystem": "Painting",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked blur_scales_with_brush_size_and_diffuses_pixels_visibly -- --nocapture"
|
||
],
|
||
"expected": "blur scales with brush size and diffuses pixels visibly",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked blur_scales_with_brush_size_and_diffuses_pixels_visibly -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "blur_scales_with_brush_size_and_diffuses_pixels_visibly",
|
||
"path": "crates/engine/src/retouch_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked blur_scales_with_brush_size_and_diffuses_pixels_visibly -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [8u64, 16] {\n let run = |size: u32| {\n let mut s = session(120, 40, depth, \"rgb\");\n paint_layer(&mut s, |x, _| if x < 60 { [0.0, 0.0, 0.0, 1.0] } else { [1.0, 1.0, 1.0, 1.0] });\n s.execute(\"paint.blur\", json!({\"points\": [[60, 20]], \"size\": size, \"hardness\": 100, \"strength\": 100})).unwrap();\n (0..120).map(|x| rgba(&s, x, 20)[0]).collect::<Vec<_>>()\n };\n let p20 = run(20);\n let p60 = run(60);\n // Size 20 (sigma = 3.0, radius 10, footprint [50, 70]) leaves x=45 and x=75 untouched.\n assert_eq!(p20[45], 0.0, \"size 20 footprint does not reach x=45\");\n assert_eq!(p20[75], 1.0, \"size 20 footprint does not reach x=75\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(p20[45], 0.0, \"size 20 footprint does not reach x=45\");\n assert_eq!(p20[75], 1.0, \"size 20 footprint does not reach x=75\");\n // Size 60 (sigma = 9.0, radius 30, footprint [30, 90]) diffuses light and dark across a wider band.\n assert!(p60[45] > 0.0, \"size 60 diffuses light past x=45: {}\", p60[45]);",
|
||
" assert_eq!(p20[75], 1.0, \"size 20 footprint does not reach x=75\");\n // Size 60 (sigma = 9.0, radius 30, footprint [30, 90]) diffuses light and dark across a wider band.\n assert!(p60[45] > 0.0, \"size 60 diffuses light past x=45: {}\", p60[45]);\n assert!(p60[75] < 1.0, \"size 60 diffuses dark past x=75: {}\", p60[75]);",
|
||
" assert!(p60[45] > 0.0, \"size 60 diffuses light past x=45: {}\", p60[45]);\n assert!(p60[75] < 1.0, \"size 60 diffuses dark past x=75: {}\", p60[75]);\n // Near the step edge (x=55), size 60 diffuses more than size 20 due to larger sigma.\n assert!(p60[55] > p20[55], \"larger sigma diffuses deeper near edge: p60={} p20={}\", p60[55], p20[55]);",
|
||
" assert!(p60[75] < 1.0, \"size 60 diffuses dark past x=75: {}\", p60[75]);\n // Near the step edge (x=55), size 60 diffuses more than size 20 due to larger sigma.\n assert!(p60[55] > p20[55], \"larger sigma diffuses deeper near edge: p60={} p20={}\", p60[55], p20[55]);\n }",
|
||
" assert!(p60[55] > p20[55], \"larger sigma diffuses deeper near edge: p60={} p20={}\", p60[55], p20[55]);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/7348e060b4be7204fb69b59079c3b9d808e9aad3/crates/engine/src/retouch_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-6139",
|
||
"pr": 6139,
|
||
"subsystem": "Painting",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-automation --locked a_refresh_outside_command_execution_surfaces_the_denial_instead_of_rendering_unfiltered -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked behind_brush_and_pencil_preserve_foreground_and_round_trip_history -- --nocapture",
|
||
"cargo test -p photocraft-paint --locked behind_preserves_native_channels_and_respects_alpha_selection_and_locks -- --nocapture",
|
||
"cargo test -p photocraft-paint --locked live_union_of_passes_matches_merging_the_finished_passes_after_every_chunk -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked german_color_picker_fits_its_actions_and_translates_the_title -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked file_info_multiline_fields_keep_enter_and_cancel_discards_edits -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked file_info_keeps_multiline_metadata_on_confirm_and_reopen -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked mask_sampling_sets_gray_swatches_without_changing_pixel_sampling -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked move_alt_copy_cursor_follows_the_latched_duplication_drag -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked assignable_pick_layer_shortcut_follows_transformed_canvas_without_editing -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_wheel_over_the_brush_mode_dropdown_steps_the_painting_mode -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked space_repositions_a_pen_anchor_and_keeps_its_handles -- --nocapture"
|
||
],
|
||
"expected": "a refresh outside command execution surfaces the denial instead of rendering unfiltered; behind brush and pencil preserve foreground and round trip history; behind preserves native channels and respects alpha selection and locks; live union of passes matches merging the finished passes after every chunk; german color picker fits its actions and translates the title; file info multiline fields keep enter and cancel discards edits; file info keeps multiline metadata on confirm and reopen; mask sampling sets gray swatches without changing pixel sampling; move alt copy cursor follows the latched duplication drag; assignable pick layer shortcut follows transformed canvas without editing; the wheel over the brush mode dropdown steps the painting mode; space repositions a pen anchor and keeps its handles",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-automation --locked a_refresh_outside_command_execution_surfaces_the_denial_instead_of_rendering_unfiltered -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked behind_brush_and_pencil_preserve_foreground_and_round_trip_history -- --nocapture",
|
||
"cargo test -p photocraft-paint --locked behind_preserves_native_channels_and_respects_alpha_selection_and_locks -- --nocapture",
|
||
"cargo test -p photocraft-paint --locked live_union_of_passes_matches_merging_the_finished_passes_after_every_chunk -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked german_color_picker_fits_its_actions_and_translates_the_title -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked file_info_multiline_fields_keep_enter_and_cancel_discards_edits -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked file_info_keeps_multiline_metadata_on_confirm_and_reopen -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked mask_sampling_sets_gray_swatches_without_changing_pixel_sampling -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked move_alt_copy_cursor_follows_the_latched_duplication_drag -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked assignable_pick_layer_shortcut_follows_transformed_canvas_without_editing -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_wheel_over_the_brush_mode_dropdown_steps_the_painting_mode -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked space_repositions_a_pen_anchor_and_keeps_its_handles -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "a_refresh_outside_command_execution_surfaces_the_denial_instead_of_rendering_unfiltered",
|
||
"path": "crates/automation/tests/smart_filter_authorization.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked a_refresh_outside_command_execution_surfaces_the_denial_instead_of_rendering_unfiltered -- --nocapture",
|
||
"fixture_and_action_excerpt": " // link-watch and transform paths re-render through Session::edit, not Session::execute or\n // jobs::run; the gate must reach them and the denial must not silently pass pixels through\n // into the process-wide stack cache.\n for lookup in [false, true] {\n let f = Fixture::new();\n let (doc, layer) = f.saved_filter(lookup);\n let mut h = f.headless();\n h.open(Path::new(\"stored.pcraft\")).unwrap();\n let before = h.session.active().unwrap().doc.clone();\n // Session::edit is the outside-execute mutation path (an edit closure the UI or a\n // linked-file change runs); the stored filter must be denied there too.\n assert_denied(h.session.edit(\"Re-render\", |d, _| match smart_cmds::refresh(d, layer) {",
|
||
"expected_assertions": [
|
||
" assert!(Arc::ptr_eq(&before, &h.session.active().unwrap().doc));\n // A trusted session (no gate) still renders the same document.\n let mut trusted = Session::new();\n trusted.add_document(doc, None);",
|
||
" assert!(smart_cmds::refresh(&mut d, layer).is_ok());\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/automation/tests/smart_filter_authorization.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "behind_brush_and_pencil_preserve_foreground_and_round_trip_history",
|
||
"path": "crates/engine/src/brush_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked behind_brush_and_pencil_preserve_foreground_and_round_trip_history -- --nocapture",
|
||
"fixture_and_action_excerpt": " for cmd in [\"paint.stroke\", \"paint.pencil\"] {\n let mut s = session(40, 20);\n s.execute(cmd, json!({\"points\": [[10, 10]], \"size\": 6, \"color\": \"#ff0000\", \"hardness\": 1.0})).unwrap();\n let before = surface(&s);\n s.execute(cmd, json!({\"points\": [[2, 10], [38, 10]], \"size\": 6, \"color\": \"#0000ff\", \"mode\": \"behind\", \"hardness\": 1.0})).unwrap();\n assert_eq!(rgba(&s, 10, 10), [1.0, 0.0, 0.0, 1.0], \"{cmd}: existing opaque paint\");\n assert_eq!(rgba(&s, 25, 10), [0.0, 0.0, 1.0, 1.0], \"{cmd}: transparent pixels\");\n let painted = surface(&s);\n s.execute(\"edit.undo\", json!({})).unwrap();\n assert!(same_pixels(&surface(&s), &before, Rect::new(0, 0, 40, 20)));\n s.execute(\"edit.redo\", json!({})).unwrap();\n assert!(same_pixels(&surface(&s), &painted, Rect::new(0, 0, 40, 20)));",
|
||
"expected_assertions": [
|
||
" assert_eq!(rgba(&s, 10, 10), [1.0, 0.0, 0.0, 1.0], \"{cmd}: existing opaque paint\");\n assert_eq!(rgba(&s, 25, 10), [0.0, 0.0, 1.0, 1.0], \"{cmd}: transparent pixels\");\n let painted = surface(&s);\n s.execute(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(rgba(&s, 25, 10), [0.0, 0.0, 1.0, 1.0], \"{cmd}: transparent pixels\");\n let painted = surface(&s);\n s.execute(\"edit.undo\", json!({})).unwrap();\n assert!(same_pixels(&surface(&s), &before, Rect::new(0, 0, 40, 20)));",
|
||
" assert!(same_pixels(&surface(&s), &before, Rect::new(0, 0, 40, 20)));\n s.execute(\"edit.redo\", json!({})).unwrap();\n assert!(same_pixels(&surface(&s), &painted, Rect::new(0, 0, 40, 20)));\n }",
|
||
" assert!(same_pixels(&surface(&s), &painted, Rect::new(0, 0, 40, 20)));\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/engine/src/brush_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "behind_preserves_native_channels_and_respects_alpha_selection_and_locks",
|
||
"path": "crates/paint/src/brush_tests.rs",
|
||
"package": "photocraft-paint",
|
||
"command": "cargo test -p photocraft-paint --locked behind_preserves_native_channels_and_respects_alpha_selection_and_locks -- --nocapture",
|
||
"fixture_and_action_excerpt": " for mode in [ColorMode::Rgb, ColorMode::Grayscale, ColorMode::Cmyk, ColorMode::Lab] {\n for sample in [SampleType::U8, SampleType::U16, SampleType::F32] {\n let fmt = PixelFormat::new(mode, sample, true);\n let b = BrushSettings { size: 12.0, behind: true, opacity: 0.5, color: [0.1, 0.3, 0.8, 1.0], ..brush() };\n let mut s = Surface::new(fmt);\n let native = photocraft_raster::from_rgba(&fmt, [0.8, 0.2, 0.1, 0.5]);\n s.fill_rect(Rect::new(0, 0, 12, 12), &native);\n let before = s.pixel(6, 6);\n let mut selection = Surface::new(PixelFormat::new(ColorMode::Grayscale, SampleType::F32, false));\n selection.fill_rect(Rect::new(0, 0, 8, 12), &[0.5]);\n render_stroke(&mut s, &b, &[StrokePoint::new(6.0, 6.0, 1.0)], Some(&selection), false, 1.0);\n let source = photocraft_raster::from_rgba(&fmt, b.color);",
|
||
"expected_assertions": [
|
||
" assert!((got[a] - alpha).abs() < 0.005, \"{fmt:?}: {got:?}\");\n for c in 0..a {\n let expected = (before[c] * before[a] + source[c] * under) / alpha;\n assert!((got[c] - expected).abs() < 0.005, \"{fmt:?} channel {c}: {got:?}, expected {expected}\");",
|
||
" assert!((got[c] - expected).abs() < 0.005, \"{fmt:?} channel {c}: {got:?}, expected {expected}\");\n }\n assert_eq!(s.pixel(9, 6), before, \"outside selection\");\n let locked = s.clone();",
|
||
" assert_eq!(s.pixel(9, 6), before, \"outside selection\");\n let locked = s.clone();\n render_stroke(&mut s, &b, &[StrokePoint::new(6.0, 6.0, 1.0)], None, true, 1.0);\n assert_eq!(s.read_region(Rect::new(0, 0, 12, 12)), locked.read_region(Rect::new(0, 0, 12, 12)), \"locked transparency\");",
|
||
" assert_eq!(s.read_region(Rect::new(0, 0, 12, 12)), locked.read_region(Rect::new(0, 0, 12, 12)), \"locked transparency\");\n s.fill_rect(Rect::new(0, 0, 12, 12), &photocraft_raster::from_rgba(&fmt, [0.8, 0.2, 0.1, 1.0]));\n let opaque = s.pixel(6, 6);\n render_stroke(&mut s, &b, &[StrokePoint::new(6.0, 6.0, 1.0)], None, false, 1.0);",
|
||
" assert_eq!(s.pixel(6, 6), opaque, \"opaque pixels\");\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/paint/src/brush_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "live_union_of_passes_matches_merging_the_finished_passes_after_every_chunk",
|
||
"path": "crates/paint/src/brush_tests.rs",
|
||
"package": "photocraft-paint",
|
||
"command": "cargo test -p photocraft-paint --locked live_union_of_passes_matches_merging_the_finished_passes_after_every_chunk -- --nocapture",
|
||
"fixture_and_action_excerpt": " // Symmetric painting previews the stroke and its mirrors with `composite_union_live`, which\n // redraws only changed tiles; after every chunk the target must be exactly what finishing\n // every pass and merging them with `composite_union_many` gives (the commit takes these pixels).\n let base = BrushSettings { size: 14.0, hardness: 0.6, opacity: 0.6, ..brush() };\n let mut brushes = vec![base.clone()];\n brushes.push(BrushSettings { smoothing: Smoothing { amount: 0.7, ..Default::default() }, ..base.clone() });\n let mut b = base.clone();\n b.dual_brush.enabled = true;\n b.dual_brush.size = 6.0;\n b.dual_brush.scatter = 1.5;\n brushes.push(b);\n let mut b = base.clone();",
|
||
"expected_assertions": [
|
||
" assert!(\n target.read_region(area) == expected.read_region(area),\n \"{sample:?}, brush {bi}, four {four}, selection {}, points ..{end}\",\n selection.is_some()",
|
||
" assert_eq!(live.bounds(), finished.iter().fold(Rect::EMPTY, |r, f| r.union(&f.bounds())));\n at = end;\n chunk = chunk % 3 + 1;\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/paint/src/brush_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "german_color_picker_fits_its_actions_and_translates_the_title",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked german_color_picker_fits_its_actions_and_translates_the_title -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::{Harness, kittest::Queryable};\n let lang = crate::i18n::Lang::from_pref(\"de\");\n let text = |key| crate::i18n::with_language(lang, || crate::i18n::t(key).to_owned());\n let app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n let mut h =\n Harness::builder().with_size(egui::vec2(760.0, 480.0)).build_ui_state(move |ui, app| crate::i18n::with_language(lang, || show(app, ui.ctx())), app);\n PhotocraftApp::setup_context(&h.ctx, Default::default());\n crate::color_picker_ui::open(h.state_mut(), \"foreground\");\n h.run_steps(4);\n let title = h.get_by_label(\"Farbwähler (Vordergrundfarbe)\").rect();\n let swatch = h.get_by_label(&text(\"Click to restore the current colour\")).rect();\n let frame = rects(&h.ctx)[0];",
|
||
"expected_assertions": [
|
||
" assert!(r.left() > swatch.right(), \"{label} must stay beside the swatches: {r:?}, {swatch:?}\");\n assert!((r.right() - title.right()).abs() < 1.0, \"{label} aligns with the title edge\");\n }\n assert!(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(760.0, 480.0)).contains_rect(frame), \"{frame:?}\");",
|
||
" assert!((r.right() - title.right()).abs() < 1.0, \"{label} aligns with the title edge\");\n }\n assert!(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(760.0, 480.0)).contains_rect(frame), \"{frame:?}\");\n }",
|
||
" assert!(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(760.0, 480.0)).contains_rect(frame), \"{frame:?}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "file_info_multiline_fields_keep_enter_and_cancel_discards_edits",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked file_info_multiline_fields_keep_enter_and_cancel_discards_edits -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n\n crate::i18n::with_language(crate::i18n::Lang::EN, || {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 64, \"height\": 64})).unwrap();\n let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(900.0, 700.0)).build_ui_state(|ui, app| show(app, ui.ctx()), app);\n PhotocraftApp::setup_context(&h.ctx, crate::theme::ThemeKind::ALL[0]);\n let ctx = h.ctx.clone();\n crate::menus::invoke(h.state_mut(), &ctx, \"file.fileInfo\", json!({})).unwrap();\n h.run_steps(4);\n let labels = [\"Document Title\", \"Author\", \"Author title\", \"Description\", \"Keywords\", \"Copyright status\", \"Copyright Notice\", \"Copyright Info URL\"];\n for pair in labels.windows(2) {",
|
||
"expected_assertions": [
|
||
" assert!(h.get_by_label(pair[0]).rect().center().y < h.get_by_label(pair[1]).rect().center().y, \"field order: {pair:?}\");\n }\n for (label, key) in [(\"Description\", \"description\"), (\"Keywords\", \"keywords\"), (\"Copyright Notice\", \"copyright\")] {\n h.get_by_label(label).click();",
|
||
" assert_eq!(dialog.fields[key], \"First\\nSecond\", \"{label}\");\n }\n h.get_by_label(\"Cancel\").click();\n h.run_steps(2);",
|
||
" assert!(h.state().ui.dialogs.is_empty());\n assert_eq!(h.state_mut().run(\"file.fileInfo\", json!({})).unwrap()[\"description\"], \"\");\n });\n }",
|
||
" assert_eq!(h.state_mut().run(\"file.fileInfo\", json!({})).unwrap()[\"description\"], \"\");\n });\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "file_info_keeps_multiline_metadata_on_confirm_and_reopen",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked file_info_keeps_multiline_metadata_on_confirm_and_reopen -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 64, \"height\": 64})).unwrap();\n let ctx = egui::Context::default();\n let id = crate::menus::invoke(&mut app, &ctx, \"file.fileInfo\", json!({})).unwrap()[\"dialog\"].as_u64().unwrap();\n for key in [\"description\", \"copyright\"] {\n app.ui.dialog_mut(id).unwrap().fields.insert(key.into(), json!(\"First line\\nSecond line\"));\n }\n confirm(&mut app, id).unwrap();\n let id = crate::menus::invoke(&mut app, &ctx, \"file.fileInfo\", json!({})).unwrap()[\"dialog\"].as_u64().unwrap();\n for key in [\"description\", \"copyright\"] {\n assert_eq!(app.ui.dialog_mut(id).unwrap().fields[key], \"First line\\nSecond line\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(app.ui.dialog_mut(id).unwrap().fields[key], \"First line\\nSecond line\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "mask_sampling_sets_gray_swatches_without_changing_pixel_sampling",
|
||
"path": "crates/ui-egui/src/eyedropper_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked mask_sampling_sets_gray_swatches_without_changing_pixel_sampling -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [8, 16, 32] {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 20, \"height\": 20, \"depth\": depth, \"background\": \"transparent\"})).unwrap();\n app.session\n .edit(\"red\", |doc, _| {\n let surface = doc.layers[0].surface_mut().unwrap();\n surface.fill_rect(photocraft_geom::Rect::new(0, 0, 20, 20), &photocraft_raster::from_rgba(&surface.format(), [1.0, 0.0, 0.0, 1.0]));\n doc.layers[0].mask = Some(photocraft_doc::LayerMask::reveal_all());\n Ok(())\n })\n .unwrap();\n app.ui.tool = Tool::Eyedropper;",
|
||
"expected_assertions": [
|
||
" assert_eq!(fg(&app), [gray, gray, gray, 1.0], \"depth {depth}\");\n click(&mut app, 5.0, 5.0, egui::Modifiers::ALT);\n assert_eq!(app.session.tools.background, [gray, gray, gray, 1.0]);\n app.ui.mask_target = false;",
|
||
" assert_eq!(app.session.tools.background, [gray, gray, gray, 1.0]);\n app.ui.mask_target = false;\n click(&mut app, 5.0, 5.0, egui::Modifiers::NONE);\n assert_eq!(fg(&app), [1.0, 0.0, 0.0, 1.0]);",
|
||
" assert_eq!(fg(&app), [1.0, 0.0, 0.0, 1.0]);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/ui-egui/src/eyedropper_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "move_alt_copy_cursor_follows_the_latched_duplication_drag",
|
||
"path": "crates/ui-egui/src/input_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked move_alt_copy_cursor_follows_the_latched_duplication_drag -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n h.state_mut().run(\"shape.create\", json!({\"kind\": \"rect\", \"rect\": [150, 100, 100, 100], \"fill\": \"#ff0000\"})).unwrap();\n h.state_mut().ui.tool = crate::state::Tool::Move;\n h.state_mut().ui.tool_options.move_show_transform = false;\n let before = h.state().session.active().unwrap().doc.layers.len();\n let p = h.state().last_canvas_rect.center();\n h.hover_at(p);\n h.run_steps(2);\n assert_eq!(h.output().platform_output.cursor_icon, egui::CursorIcon::Default);\n h.event(egui::Event::ModifiersChanged(Modifiers::ALT));\n h.run_steps(2);\n assert_eq!(h.output().platform_output.cursor_icon, egui::CursorIcon::Copy);",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.output().platform_output.cursor_icon, egui::CursorIcon::Default);\n h.event(egui::Event::ModifiersChanged(Modifiers::ALT));\n h.run_steps(2);\n assert_eq!(h.output().platform_output.cursor_icon, egui::CursorIcon::Copy);",
|
||
" assert_eq!(h.output().platform_output.cursor_icon, egui::CursorIcon::Copy);\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), before, \"hovering never duplicates\");\n h.event(egui::Event::PointerButton { pos: p, button: egui::PointerButton::Primary, pressed: true, modifiers: Modifiers::ALT });\n h.run_steps(1);",
|
||
" assert_eq!(h.state().session.active().unwrap().doc.layers.len(), before, \"hovering never duplicates\");\n h.event(egui::Event::PointerButton { pos: p, button: egui::PointerButton::Primary, pressed: true, modifiers: Modifiers::ALT });\n h.run_steps(1);\n let end = p + vec2(25.0, 15.0);",
|
||
" assert_eq!(h.output().platform_output.cursor_icon, egui::CursorIcon::Copy, \"releasing Alt does not undo an active copy\");\n h.event(egui::Event::PointerButton { pos: end, button: egui::PointerButton::Primary, pressed: false, modifiers: Modifiers::NONE });\n h.run_steps(2);\n assert_eq!(h.output().platform_output.cursor_icon, egui::CursorIcon::Default);",
|
||
" assert_eq!(h.output().platform_output.cursor_icon, egui::CursorIcon::Default);\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), before + 1);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().doc.layers.len(), before + 1);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/ui-egui/src/input_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "assignable_pick_layer_shortcut_follows_transformed_canvas_without_editing",
|
||
"path": "crates/ui-egui/src/input_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked assignable_pick_layer_shortcut_follows_transformed_canvas_without_editing -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n let base = h.state().session.active().unwrap().active_layer.unwrap();\n h.state_mut().run(\"layer.new.layer\", json!({\"name\": \"Paint\"})).unwrap();\n let paint = h.state().session.active().unwrap().active_layer.unwrap();\n h.state_mut().run(\"select.rect\", json!({\"x\": 100, \"y\": 100, \"width\": 40, \"height\": 40})).unwrap();\n h.state_mut().run(\"edit.fill\", json!({\"color\": \"#ff0000\"})).unwrap();\n h.state_mut().run(\"select.deselect\", json!({})).unwrap();\n h.state_mut().run(\"layer.new.layer\", json!({\"name\": \"Empty\"})).unwrap();\n h.state_mut().run(\"prefs.set\", json!({\"path\": \"shortcuts.layer.selectUnderCursor\", \"value\": \"Cmd+Alt+K\"})).unwrap();\n h.state_mut().ui.tool = crate::state::Tool::Brush;\n for (zoom, rotation, flip) in [(1.0, 0.0, false), (2.0, 37.0, true), (0.5, -90.0, false)] {\n h.state_mut().ui.views[0].zoom = zoom;",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().session.active().unwrap().active_layer, Some(expected));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history, \"picking never adds a document edit\");\n assert!(!h.state().session.journal.iter().any(|(id, _)| id == \"paint.stroke\"));\n }",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history, \"picking never adds a document edit\");\n assert!(!h.state().session.journal.iter().any(|(id, _)| id == \"paint.stroke\"));\n }\n }",
|
||
" assert!(!h.state().session.journal.iter().any(|(id, _)| id == \"paint.stroke\"));\n }\n }\n h.state_mut().run(\"layer.setProps\", json!({\"layer\": paint.0, \"visible\": false})).unwrap();",
|
||
" assert_eq!(h.state().session.active().unwrap().active_layer, Some(base));\n // Outside the document and modal dialogs preserve the current selection.\n h.state_mut().run(\"layer.select\", json!({\"layer\": paint.0})).unwrap();\n h.hover_at(pos2(0.0, 0.0));",
|
||
" assert_eq!(h.state().session.active().unwrap().active_layer, Some(paint));\n open_dialog(&mut h);\n h.hover_at(p);\n h.key_press_modifiers(Modifiers::COMMAND | Modifiers::ALT, Key::K);",
|
||
" assert_eq!(h.state().session.active().unwrap().active_layer, Some(paint));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/ui-egui/src/input_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_wheel_over_the_brush_mode_dropdown_steps_the_painting_mode",
|
||
"path": "crates/ui-egui/src/options_bar_mode_wheel_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_wheel_over_the_brush_mode_dropdown_steps_the_painting_mode -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness(Tool::Brush);\n let at = mode_dropdown(&h).center();\n assert_eq!(brush_mode(&h), BlendMode::Normal);\n wheel(&mut h, at, -1.0);\n assert_eq!(brush_mode(&h), BlendMode::Dissolve);\n wheel(&mut h, at, -1.0);\n assert!(h.state().session.tools.brush.behind, \"Behind follows Dissolve\");\n wheel(&mut h, at, -1.0);\n assert!(h.state().ui.tool_options.brush_clear, \"Clear follows Behind\");\n assert!(!h.state().session.tools.brush.behind);\n wheel(&mut h, at, -1.0);\n assert!(!h.state().ui.tool_options.brush_clear);",
|
||
"expected_assertions": [
|
||
" assert_eq!(brush_mode(&h), BlendMode::Normal);\n wheel(&mut h, at, -1.0);\n assert_eq!(brush_mode(&h), BlendMode::Dissolve);\n wheel(&mut h, at, -1.0);",
|
||
" assert_eq!(brush_mode(&h), BlendMode::Dissolve);\n wheel(&mut h, at, -1.0);\n assert!(h.state().session.tools.brush.behind, \"Behind follows Dissolve\");\n wheel(&mut h, at, -1.0);",
|
||
" assert!(h.state().session.tools.brush.behind, \"Behind follows Dissolve\");\n wheel(&mut h, at, -1.0);\n assert!(h.state().ui.tool_options.brush_clear, \"Clear follows Behind\");\n assert!(!h.state().session.tools.brush.behind);",
|
||
" assert!(h.state().ui.tool_options.brush_clear, \"Clear follows Behind\");\n assert!(!h.state().session.tools.brush.behind);\n wheel(&mut h, at, -1.0);\n assert!(!h.state().ui.tool_options.brush_clear);",
|
||
" assert!(!h.state().session.tools.brush.behind);\n wheel(&mut h, at, -1.0);\n assert!(!h.state().ui.tool_options.brush_clear);\n assert_eq!(brush_mode(&h), BlendMode::Darken);",
|
||
" assert!(!h.state().ui.tool_options.brush_clear);\n assert_eq!(brush_mode(&h), BlendMode::Darken);\n wheel(&mut h, at, 4.0);\n assert_eq!(brush_mode(&h), BlendMode::Normal, \"up steps back and stops at the first mode\");",
|
||
" assert_eq!(brush_mode(&h), BlendMode::Darken);\n wheel(&mut h, at, 4.0);\n assert_eq!(brush_mode(&h), BlendMode::Normal, \"up steps back and stops at the first mode\");\n}",
|
||
" assert_eq!(brush_mode(&h), BlendMode::Normal, \"up steps back and stops at the first mode\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/ui-egui/src/options_bar_mode_wheel_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "space_repositions_a_pen_anchor_and_keeps_its_handles",
|
||
"path": "crates/ui-egui/src/pen_draw_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked space_repositions_a_pen_anchor_and_keeps_its_handles -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n h.state_mut().ui.extras.snap = false;\n click(&mut h, [20.0, 20.0]);\n let center = h.state().ui.views[0].center;\n let p = screen(&h, [80.0, 50.0]);\n h.event(egui::Event::PointerMoved(p));\n button(&mut h, p, true, Modifiers::NONE);\n move_to(&mut h, [80.0, 50.0], [100.0, 60.0]);\n h.event(egui::Event::Key { key: Key::Space, physical_key: None, pressed: true, repeat: false, modifiers: Modifiers::NONE });\n h.run_steps(1);\n move_to(&mut h, [100.0, 60.0], [120.0, 90.0]);\n let k = h.state().ui.pen.as_ref().unwrap().knots[1];",
|
||
"expected_assertions": [
|
||
" assert!(near(k[0], [100.0, 80.0]) && near(k[1], [80.0, 70.0]) && near(k[2], [120.0, 90.0]), \"anchor and handles moved together: {k:?}\");\n assert_eq!(h.state().ui.views[0].center, center, \"the canvas never pans\");\n h.event(egui::Event::Key { key: Key::Space, physical_key: None, pressed: false, repeat: false, modifiers: Modifiers::NONE });\n h.run_steps(1);",
|
||
" assert_eq!(h.state().ui.views[0].center, center, \"the canvas never pans\");\n h.event(egui::Event::Key { key: Key::Space, physical_key: None, pressed: false, repeat: false, modifiers: Modifiers::NONE });\n h.run_steps(1);\n move_to(&mut h, [120.0, 90.0], [130.0, 80.0]);",
|
||
" assert!(near(k[0], [100.0, 80.0]) && near(k[1], [70.0, 80.0]) && near(k[2], [130.0, 80.0]), \"releasing Space resumes handle shaping: {k:?}\");\n h.key_press(Key::Enter);\n h.run_steps(2);\n assert!(h.state().session.active().unwrap().doc.work_path.is_some());",
|
||
" assert!(h.state().session.active().unwrap().doc.work_path.is_some());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e2347f8ead85d929193044f139788b850e31c06f/crates/ui-egui/src/pen_draw_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-7848",
|
||
"pr": 7848,
|
||
"subsystem": "Painting",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked pressure_shape_and_smoothing_match_replay -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked native_modes_selection_and_lock_match_replay -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked changed_document_refuses_live_pixels -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked smudge_pickup_matches_full_neighborhood_when_pressure_expands -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked pressure_sized_live_dabs_commit_only_the_requested_mask_or_channel -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pressure_sized_smudge_release_matches_replay_and_undo_redo -- --nocapture"
|
||
],
|
||
"expected": "pressure shape and smoothing match replay; native modes selection and lock match replay; changed document refuses live pixels; smudge pickup matches full neighborhood when pressure expands; pressure sized live dabs commit only the requested mask or channel; pressure sized smudge release matches replay and undo redo",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked pressure_shape_and_smoothing_match_replay -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked native_modes_selection_and_lock_match_replay -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked changed_document_refuses_live_pixels -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked smudge_pickup_matches_full_neighborhood_when_pressure_expands -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked pressure_sized_live_dabs_commit_only_the_requested_mask_or_channel -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pressure_sized_smudge_release_matches_replay_and_undo_redo -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "pressure_shape_and_smoothing_match_replay",
|
||
"path": "crates/engine/tests/live_dab_matches_replay.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked pressure_shape_and_smoothing_match_replay -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut failures = Vec::new();\n for cmd in [\"paint.smudge\", \"paint.blur\", \"paint.sharpen\", \"paint.dodge\", \"paint.burn\", \"paint.sponge\"] {\n for case in [\"pressure\", \"locked\", \"ellipse\", \"smoothing\", \"scattering\"] {\n for depth in [8, 16, 32] {\n let mut s = setup(depth, \"rgb\");\n match case {\n \"locked\" => {\n s.edit(\"lock alpha\", |doc, active| {\n doc.layer_mut(active.unwrap()).unwrap().locks.transparency = true;\n Ok(())\n })\n .unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(result[\"fromLive\"], true);\n let got = pixels(&s);\n let count = got.iter().zip(&want).filter(|(a, b)| a != b).count();\n let max = got.iter().zip(&want).map(|(a, b)| (a - b).abs()).fold(0.0f32, f32::max);",
|
||
" assert!(failures.is_empty(), \"{}\", failures.join(\"\\n\"));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/389a1d5bd67072d5581c27989080222a7065b585/crates/engine/tests/live_dab_matches_replay.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "native_modes_selection_and_lock_match_replay",
|
||
"path": "crates/engine/tests/live_dab_matches_replay.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked native_modes_selection_and_lock_match_replay -- --nocapture",
|
||
"fixture_and_action_excerpt": " for mode in [\"rgb\", \"gray\", \"cmyk\", \"lab\"] {\n for depth in [8, 16, 32] {\n let mut s = setup(depth, mode);\n s.edit(\"lock alpha\", |doc, active| {\n doc.layer_mut(active.unwrap()).unwrap().locks.transparency = true;\n Ok(())\n })\n .unwrap();\n s.execute(\"select.rect\", json!({\"x\":30,\"y\":20,\"width\":110,\"height\":60})).unwrap();\n let points = [[-10.0, 30.0], [80.0, 50.0], [160.0, 80.0], [60.0, 60.0]];\n for cmd in [\"paint.blur\", \"paint.sharpen\", \"paint.dodge\", \"paint.burn\", \"paint.sponge\", \"paint.smudge\"] {\n let params = json!({\"points\":points,\"size\":30,\"hardness\":40,\"strength\":70,\"opacity\":37});",
|
||
"expected_assertions": [
|
||
" assert_eq!(result[\"fromLive\"], true);\n assert_eq!(result[\"damage\"], expected_damage);\n assert_eq!(pixels(&s), want, \"{mode} {depth} {cmd}\");\n s.execute(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(result[\"damage\"], expected_damage);\n assert_eq!(pixels(&s), want, \"{mode} {depth} {cmd}\");\n s.execute(\"edit.undo\", json!({})).unwrap();\n }",
|
||
" assert_eq!(pixels(&s), want, \"{mode} {depth} {cmd}\");\n s.execute(\"edit.undo\", json!({})).unwrap();\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/389a1d5bd67072d5581c27989080222a7065b585/crates/engine/tests/live_dab_matches_replay.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "changed_document_refuses_live_pixels",
|
||
"path": "crates/engine/tests/live_dab_matches_replay.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked changed_document_refuses_live_pixels -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = setup(8, \"rgb\");\n let p = json!({\"points\":[[40,40],[80,60]],\"size\":30});\n let live = LiveDab::begin(&s, \"paint.blur\", &p).unwrap();\n s.execute(\"paint.stroke\", json!({\"points\":[[40,40],[80,60]],\"color\":\"#ffffff\",\"size\":20})).unwrap();\n let mut replay = Session::new();\n replay.add_document((*s.active().unwrap().doc).clone(), None);\n replay.tools.brush = s.tools.brush.clone();\n s.offer_live_dab(live).unwrap();\n assert!(s.execute(\"paint.blur\", p.clone()).unwrap().get(\"fromLive\").is_none());\n replay.execute(\"paint.blur\", p).unwrap();\n assert_eq!(pixels(&s), pixels(&replay));\n}",
|
||
"expected_assertions": [
|
||
" assert!(s.execute(\"paint.blur\", p.clone()).unwrap().get(\"fromLive\").is_none());\n replay.execute(\"paint.blur\", p).unwrap();\n assert_eq!(pixels(&s), pixels(&replay));\n}",
|
||
" assert_eq!(pixels(&s), pixels(&replay));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/389a1d5bd67072d5581c27989080222a7065b585/crates/engine/tests/live_dab_matches_replay.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "smudge_pickup_matches_full_neighborhood_when_pressure_expands",
|
||
"path": "crates/engine/tests/live_dab_matches_replay.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked smudge_pickup_matches_full_neighborhood_when_pressure_expands -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_paint::{\n Stroke,\n retouch::{Smudge, apply_dab_stroke},\n };\n\n let points = [[40.0, 40.0, 0.1], [65.0, 50.0, 0.4], [100.0, 60.0, 1.0], [140.0, 70.0, 0.7], [60.0, 40.0, 0.2]];\n for depth in [8, 16, 32] {\n let mut s = setup(depth, \"rgb\");\n let params = json!({\"points\":points,\"size\":40,\"hardness\":70,\"strength\":80,\"opacity\":55,\"spacing\":25});\n let (mut expected, lock) = {\n let st = s.active().unwrap();\n let id = st.active_layer.unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(pixels(&s) == want, \"command must read the whole pickup square at depth {depth}\");\n s.execute(\"edit.undo\", json!({})).unwrap();\n let live = LiveDab::begin(&s, \"paint.smudge\", ¶ms).unwrap();\n s.offer_live_dab(live).unwrap();",
|
||
" assert_eq!(s.execute(\"paint.smudge\", params).unwrap()[\"fromLive\"], true);\n assert!(pixels(&s) == want, \"a single batch uses the same pickup square at depth {depth}\");\n }\n}",
|
||
" assert!(pixels(&s) == want, \"a single batch uses the same pickup square at depth {depth}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/389a1d5bd67072d5581c27989080222a7065b585/crates/engine/tests/live_dab_matches_replay.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "pressure_sized_live_dabs_commit_only_the_requested_mask_or_channel",
|
||
"path": "crates/engine/tests/live_dab_matches_replay.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked pressure_sized_live_dabs_commit_only_the_requested_mask_or_channel -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_raster::Surface;\n\n let fill = |surface: &mut Surface| {\n let values: Vec<f32> = (0..120).flat_map(|y| (0..200).map(move |x| ((x * 7 + y * 3) % 31) as f32 / 31.0)).collect();\n surface.write_region(photocraft_geom::Rect::new(0, 0, 200, 120), &values);\n };\n for depth in [8, 16, 32] {\n let mut s = setup(depth, \"rgb\");\n s.execute(\"layer.new.layer\", json!({})).unwrap();\n s.execute(\"layer.layerMask.revealAll\", json!({})).unwrap();\n s.execute(\"channel.new\", json!({\"fill\":\"white\"})).unwrap();\n s.execute(\"select.editInQuickMaskMode\", json!({\"on\":true})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(s.execute(cmd, params).unwrap()[\"fromLive\"], true);\n assert_eq!(s.active().unwrap().doc, want, \"depth={depth} {cmd} target={target}\");\n s.execute(\"edit.undo\", json!({})).unwrap();\n assert_eq!(s.active().unwrap().doc, before);",
|
||
" assert_eq!(s.active().unwrap().doc, want, \"depth={depth} {cmd} target={target}\");\n s.execute(\"edit.undo\", json!({})).unwrap();\n assert_eq!(s.active().unwrap().doc, before);\n }",
|
||
" assert_eq!(s.active().unwrap().doc, before);\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/389a1d5bd67072d5581c27989080222a7065b585/crates/engine/tests/live_dab_matches_replay.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "pressure_sized_smudge_release_matches_replay_and_undo_redo",
|
||
"path": "crates/ui-egui/src/stroke_timing_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked pressure_sized_smudge_release_matches_replay_and_undo_redo -- --nocapture",
|
||
"fixture_and_action_excerpt": " use crate::stylus::PenSample;\n\n let setup = |run: &mut dyn FnMut(&str, Value)| {\n run(\"tools.setBrush\", json!({\"brush\": {\"size\":40,\"hardness\":0.7,\"pressureSize\":true,\"smoothing\":{\"amount\":0.4}}}));\n run(\"paint.stroke\", json!({\"points\":[[10,20],[190,80]],\"size\":30,\"color\":\"#2060c0\"}));\n };\n let mut h = harness();\n h.state_mut().ui.tool = Tool::Smudge;\n h.run_steps(1);\n setup(&mut |id, p| {\n h.state_mut().run(id, p).unwrap();\n });",
|
||
"expected_assertions": [
|
||
" assert!(h.state().live_stroke.is_some());\n button(&mut h, 60.0, 40.0, false);\n h.run_steps(2);\n assert!(h.state().retouch_from_live, \"release must actually reuse the live pixels\");",
|
||
" assert!(h.state().retouch_from_live, \"release must actually reuse the live pixels\");\n let (_, params) = h.state().session.journal.iter().rev().find(|(id, _)| id == \"paint.smudge\").cloned().unwrap();\n let points = params[\"points\"].as_array().unwrap();\n assert!(points.iter().any(|p| p[2].as_f64().unwrap() < 0.2));",
|
||
" assert!(points.iter().any(|p| p[2].as_f64().unwrap() < 0.2));\n assert!(points.iter().any(|p| p[2].as_f64().unwrap() > 0.9));\n\n let mut fresh = photocraft_engine::Session::new();",
|
||
" assert!(points.iter().any(|p| p[2].as_f64().unwrap() > 0.9));\n\n let mut fresh = photocraft_engine::Session::new();\n fresh.execute(\"file.new\", json!({\"width\":200,\"height\":100,\"background\":\"white\"})).unwrap();",
|
||
" assert_eq!(h.state().session.tools.brush, fresh.tools.brush, \"replay uses the Smudge tool's actual brush\");\n assert!(\n photocraft_compose::render(&before, before.bounds()).px == photocraft_compose::render(&fresh.active().unwrap().doc, before.bounds()).px,\n \"the replay fixture starts with identical pixels\"",
|
||
" assert!(\n photocraft_compose::render(&before, before.bounds()).px == photocraft_compose::render(&fresh.active().unwrap().doc, before.bounds()).px,\n \"the replay fixture starts with identical pixels\"\n );",
|
||
" assert!(fresh.execute(\"paint.smudge\", params).unwrap().get(\"fromLive\").is_none());\n let committed = h.state().session.active().unwrap().doc.clone();\n let expected = photocraft_compose::render(&fresh.active().unwrap().doc, committed.bounds());\n assert!(photocraft_compose::render(&committed, committed.bounds()).px == expected.px, \"live commit and replay must paint identical pixels\");",
|
||
" assert!(photocraft_compose::render(&committed, committed.bounds()).px == expected.px, \"live commit and replay must paint identical pixels\");\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(h.state().session.active().unwrap().doc, before);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();",
|
||
" assert_eq!(h.state().session.active().unwrap().doc, before);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();\n assert_eq!(h.state().session.active().unwrap().doc, committed);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().doc, committed);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/389a1d5bd67072d5581c27989080222a7065b585/crates/ui-egui/src/stroke_timing_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9623",
|
||
"pr": 9623,
|
||
"subsystem": "Painting",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-paint --locked pencil_1px_freehand_line_never_breaks_where_it_turns -- --nocapture"
|
||
],
|
||
"expected": "pencil 1px freehand line never breaks where it turns",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-paint --locked pencil_1px_freehand_line_never_breaks_where_it_turns -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "pencil_1px_freehand_line_never_breaks_where_it_turns",
|
||
"path": "crates/paint/src/brush_tests.rs",
|
||
"package": "photocraft-paint",
|
||
"command": "cargo test -p photocraft-paint --locked pencil_1px_freehand_line_never_breaks_where_it_turns -- --nocapture",
|
||
"fixture_and_action_excerpt": " // #8040: each segment of a freehand stroke samples its own line, so where the stroke turned\n // the last pixel of one segment and the first of the next could sit two pixels apart.\n let b = BrushSettings { aliased: true, hardness: 1.0, size: 1.0, ..brush() };\n let mut seed = 0x2545_f491_4f6c_dd1du64;\n let mut rnd = || {\n seed ^= seed << 13;\n seed ^= seed >> 7;\n seed ^= seed << 17;\n (seed >> 11) as f64 / (1u64 << 53) as f64\n };\n for _ in 0..300 {\n let mut pts = vec![StrokePoint::new(20.0 + rnd() * 8.0, 20.0 + rnd() * 8.0, 1.0)];",
|
||
"expected_assertions": [
|
||
" assert_eq!(reached.len(), painted.len(), \"the line breaks along {path:?}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/652075f4da7fe905ad651eebc3a6c276fe1d7a5d/crates/paint/src/brush_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-3554",
|
||
"pr": 3554,
|
||
"subsystem": "Platform and reliability",
|
||
"fixture_setup": "Run the checked-in AppRun CLI test; it builds stand-in binaries under a path with spaces.",
|
||
"action": "bash packaging/linux/apprun-cli-test.sh",
|
||
"expected": "Argument boundaries, MCP stdio round trip, exit status 37 and unchanged GUI entry behavior all pass the script assertions.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": ""
|
||
},
|
||
{
|
||
"id": "PR-4742",
|
||
"pr": 4742,
|
||
"subsystem": "Platform and reliability",
|
||
"fixture_setup": "Frozen-SHA macOS bundle containing executable Contents/MacOS/photocraft-cli; synthetic droplet and image paths with spaces",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked droplets_are_written_and_run -- --nocapture"
|
||
],
|
||
"expected": "Explicit PHOTOCRAFT_CLI wins, then supported /Applications and ~/Applications bundles, then PATH. Arguments remain separate; the intended action runs without standalone CLI installation; ordinary signature verification succeeds.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Use an authorized test installation; do not replace user's app. Installed-bundle resolution is BLOCKED if required bundle is absent. Finder dropping onto a plain shell shim is not promised; app wrapper is separate.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked droplets_are_written_and_run -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-7743",
|
||
"pr": 7743,
|
||
"subsystem": "Platform and reliability",
|
||
"fixture_setup": "Obtain an existing portable Windows ZIP built from the frozen integration; record its artifact identity.",
|
||
"action": "List root archive entries and extract into a new empty directory; launch the app from the extracted root.",
|
||
"expected": "Application files are directly at ZIP root without a redundant wrapping folder; extracted layout launches correctly.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": ""
|
||
},
|
||
{
|
||
"id": "PR-8985",
|
||
"pr": 8985,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked field_marker_stays_inside_the_field -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked color_field_cursor_stays_inside_the_field -- --nocapture"
|
||
],
|
||
"expected": "field marker stays inside the field; color field cursor stays inside the field",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked field_marker_stays_inside_the_field -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked color_field_cursor_stays_inside_the_field -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "field_marker_stays_inside_the_field",
|
||
"path": "crates/ui-egui/src/color_picker_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked field_marker_stays_inside_the_field -- --nocapture",
|
||
"fixture_and_action_excerpt": " // Black in the default \"h\" mode: the marker is at the bottom-left corner.\n let h = picker(\"#000000\");\n let mut field = None;\n let mut circles = Vec::new();\n for clipped in &h.output().shapes {\n match &clipped.shape {\n egui::Shape::Mesh(m) if m.vertices.len() == 33 * 33 => {\n // The component slider is a 33 x 33 mesh too, drawn after the field.\n field.get_or_insert(m.calc_bounds());\n }\n egui::Shape::Circle(c) => circles.push((c.center, c.radius, clipped.clip_rect)),\n _ => {}",
|
||
"expected_assertions": [
|
||
" assert!(!circles.is_empty(), \"the marker is drawn\");\n for (center, radius, clip) in circles {\n let visible = Rect::from_center_size(center, vec2(2.0 * radius, 2.0 * radius)).intersect(clip);\n assert!(field.contains_rect(visible), \"marker {visible:?} leaves the field {field:?}\");",
|
||
" assert!(field.contains_rect(visible), \"marker {visible:?} leaves the field {field:?}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8e695caf885b529f01f482b3f0c90cdb34df1915/crates/ui-egui/src/color_picker_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "color_field_cursor_stays_inside_the_field",
|
||
"path": "crates/ui-egui/src/panels.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked color_field_cursor_stays_inside_the_field -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n // Black is s = 0, v = 0: the bottom-left corner.\n app.session.tools.foreground = [0.0, 0.0, 0.0, 1.0];\n let h = field_harness(app);\n let mut field = None;\n let mut circles = Vec::new();\n for clipped in &h.output().shapes {\n match &clipped.shape {\n // The saturation/brightness field is the 17 x 17 mesh; the hue strip is a 25 x 25 grid.\n egui::Shape::Mesh(m) if m.vertices.len() == 17 * 17 => field = Some(m.calc_bounds()),\n egui::Shape::Circle(c) => circles.push((c.center, c.radius, clipped.clip_rect)),\n _ => {}",
|
||
"expected_assertions": [
|
||
" assert!(rings.iter().any(|(_, radius, _)| *radius == 5.0), \"inner ring sits at the field's bottom-left corner\");\n assert!(rings.iter().any(|(_, radius, _)| *radius == 6.5), \"outer ring sits at the field's bottom-left corner\");\n for (center, radius, clip) in rings {\n let visible = egui::Rect::from_center_size(center, vec2(2.0 * radius, 2.0 * radius)).intersect(clip);",
|
||
" assert!(rings.iter().any(|(_, radius, _)| *radius == 6.5), \"outer ring sits at the field's bottom-left corner\");\n for (center, radius, clip) in rings {\n let visible = egui::Rect::from_center_size(center, vec2(2.0 * radius, 2.0 * radius)).intersect(clip);\n assert!(field.contains_rect(visible), \"cursor ring {visible:?} leaves the field {field:?}\");",
|
||
" assert!(field.contains_rect(visible), \"cursor ring {visible:?} leaves the field {field:?}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8e695caf885b529f01f482b3f0c90cdb34df1915/crates/ui-egui/src/panels.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9019",
|
||
"pr": 9019,
|
||
"subsystem": "Platform and reliability",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p xtask --locked unknown_bench_is_rejected_before_updating_the_baseline -- --nocapture"
|
||
],
|
||
"expected": "unknown bench is rejected before updating the baseline",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p xtask --locked unknown_bench_is_rejected_before_updating_the_baseline -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "unknown_bench_is_rejected_before_updating_the_baseline",
|
||
"path": "xtask/src/perf.rs",
|
||
"package": "xtask",
|
||
"command": "cargo test -p xtask --locked unknown_bench_is_rejected_before_updating_the_baseline -- --nocapture",
|
||
"fixture_and_action_excerpt": " let root = std::env::temp_dir().join(format!(\"photocraft-perf-unknown-bench-{}\", std::process::id()));\n std::fs::create_dir(&root).unwrap();\n std::fs::create_dir(root.join(\"perf\")).unwrap();\n std::fs::write(root.join(BUDGETS), \"[[bench]]\\nname = \\\"known\\\"\\npackage = \\\"unused\\\"\\nrequires = \\\"missing.rs\\\"\\n\").unwrap();\n let baseline = \"{\\\"schema\\\":1,\\\"sentinel\\\":true}\";\n std::fs::write(root.join(BASELINE), baseline).unwrap();\n let results = [\n run(&root, &[\"--bench\", \"unknown\", \"--reuse\", \"--update-baseline\"]),\n run(&root, &[\"--bench\", \"known\", \"--bench\", \"unknown\", \"--quick\", \"--reuse\", \"--update-baseline\"]),\n ];\n let after = std::fs::read_to_string(root.join(BASELINE)).unwrap();\n std::fs::remove_dir_all(root).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(result, Err(format!(\"perf: unknown bench `unknown` (see {BUDGETS})\")));\n }\n assert_eq!(after, baseline, \"an unknown bench must not update the baseline\");\n }",
|
||
" assert_eq!(after, baseline, \"an unknown bench must not update the baseline\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/364c4be1c19728aefa601ee924bc7a0cd6a09789/xtask/src/perf.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9110",
|
||
"pr": 9110,
|
||
"subsystem": "Platform and reliability",
|
||
"fixture_setup": "Windows Intel host with functioning DX12; record OS, GPU and driver; frozen integration build",
|
||
"action": [
|
||
"cargo test -p photocraft-gpu --locked injected_fault_skips_the_gpu -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layout_document_composites_on_the_gpu_like_the_cpu -- --nocapture"
|
||
],
|
||
"expected": "Every process honors WGPU_BACKEND=dx12. Example completes real composition; fault test renders before injecting loss and returns expected lost-device error; layout test executes CPU/GPU assertions.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Run cargo run --release -p photocraft-gpu --locked --example bench_stack_reuse -- --quick with WGPU_BACKEND=dx12. Record adapter/vendor/device/backend/driver and proof each comparison executed. Silent early returns are BLOCKED. Do not load the known-crashing Intel Vulkan backend.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-gpu --locked injected_fault_skips_the_gpu -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layout_document_composites_on_the_gpu_like_the_cpu -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-9436",
|
||
"pr": 9436,
|
||
"subsystem": "Platform and reliability",
|
||
"fixture_setup": "startup_report.rs terminal/automation/display combinations and synthetic renderer/error/log text",
|
||
"action": [
|
||
"cargo test -p photocraft --locked a_desktop_launch_asks_the_user_and_a_script_does_not -- --nocapture",
|
||
"cargo test -p photocraft --locked the_text_names_the_error_renderer_version_and_log -- --nocapture",
|
||
"cargo test -p photocraft --locked a_fallback_that_was_not_the_preference_is_explained -- --nocapture",
|
||
"cargo test -p photocraft --locked path_names_the_attached_log_file -- --nocapture"
|
||
],
|
||
"expected": "Desktop launch with display and without terminal/control asks via dialog; terminal/headless/automation do not hang. Text contains error, attempted renderer, version, actual log path and applicable fallback reason; no invented log path.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Native dialog subcase uses only an existing safe failure reproduction in temporary settings. If unavailable, mark BLOCKED; never force a GPU driver crash.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft --locked a_desktop_launch_asks_the_user_and_a_script_does_not -- --nocapture",
|
||
"cargo test -p photocraft --locked the_text_names_the_error_renderer_version_and_log -- --nocapture",
|
||
"cargo test -p photocraft --locked a_fallback_that_was_not_the_preference_is_explained -- --nocapture",
|
||
"cargo test -p photocraft --locked path_names_the_attached_log_file -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-2300",
|
||
"pr": 2300,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_continues_with_button_up_and_keeps_vertices_fixed -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_places_the_next_vertex_in_the_panned_view_and_commits_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_keeps_pixel_aspect_and_shift_constrained_segments -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_pauses_for_dialogs_and_temporary_navigation -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_never_moves_an_inactive_pane_or_survives_a_document_or_tool_switch -- --nocapture"
|
||
],
|
||
"expected": "polygon edge scroll continues with button up and keeps vertices fixed; polygon edge scroll places the next vertex in the panned view and commits once; polygon edge scroll keeps pixel aspect and shift constrained segments; polygon edge scroll pauses for dialogs and temporary navigation; polygon edge scroll never moves an inactive pane or survives a document or tool switch",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_continues_with_button_up_and_keeps_vertices_fixed -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_places_the_next_vertex_in_the_panned_view_and_commits_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_keeps_pixel_aspect_and_shift_constrained_segments -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_pauses_for_dialogs_and_temporary_navigation -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_never_moves_an_inactive_pane_or_survives_a_document_or_tool_switch -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "polygon_edge_scroll_continues_with_button_up_and_keeps_vertices_fixed",
|
||
"path": "crates/ui-egui/src/polygon_lasso_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_continues_with_button_up_and_keeps_vertices_fixed -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (dx, dy, flip, rotation) in [\n (-1.0, 0.0, false, 0.0),\n (1.0, 0.0, false, 0.0),\n (0.0, -1.0, false, 0.0),\n (0.0, 1.0, false, 0.0),\n (-1.0, -1.0, false, 0.0),\n (1.0, -1.0, false, 0.0),\n (-1.0, 1.0, false, 0.0),\n (1.0, 1.0, false, 0.0),\n (1.0, 0.0, true, 0.0),\n (1.0, 0.0, false, 90.0),\n ] {",
|
||
"expected_assertions": [
|
||
" assert!(movement.dot(direction) > 0.1, \"edge ({dx},{dy}), flip={flip}, rotation={rotation}: {movement:?}\");\n assert!((movement.x * direction.y - movement.y * direction.x).abs() < 0.001, \"scroll follows the displayed axes\");\n assert!((next[0] - first[0]).hypot(next[1] - first[1]) > 0.1, \"stationary pointer keeps scrolling\");\n assert_eq!(h.state().ui.polygon, points, \"view motion never adds or moves vertices\");",
|
||
" assert!((movement.x * direction.y - movement.y * direction.x).abs() < 0.001, \"scroll follows the displayed axes\");\n assert!((next[0] - first[0]).hypot(next[1] - first[1]) > 0.1, \"stationary pointer keeps scrolling\");\n assert_eq!(h.state().ui.polygon, points, \"view motion never adds or moves vertices\");\n assert_eq!(steps(&h), before);",
|
||
" assert!((next[0] - first[0]).hypot(next[1] - first[1]) > 0.1, \"stationary pointer keeps scrolling\");\n assert_eq!(h.state().ui.polygon, points, \"view motion never adds or moves vertices\");\n assert_eq!(steps(&h), before);\n assert!(selection(&h).is_none());",
|
||
" assert_eq!(h.state().ui.polygon, points, \"view motion never adds or moves vertices\");\n assert_eq!(steps(&h), before);\n assert!(selection(&h).is_none());\n assert!(!h.ctx.input(|i| i.pointer.any_down()));",
|
||
" assert_eq!(steps(&h), before);\n assert!(selection(&h).is_none());\n assert!(!h.ctx.input(|i| i.pointer.any_down()));\n assert!(h.output().viewport_output[&egui::ViewportId::ROOT].repaint_delay.is_zero());",
|
||
" assert!(selection(&h).is_none());\n assert!(!h.ctx.input(|i| i.pointer.any_down()));\n assert!(h.output().viewport_output[&egui::ViewportId::ROOT].repaint_delay.is_zero());\n h.event(egui::Event::PointerMoved(xf.rect.center()));",
|
||
" assert!(!h.ctx.input(|i| i.pointer.any_down()));\n assert!(h.output().viewport_output[&egui::ViewportId::ROOT].repaint_delay.is_zero());\n h.event(egui::Event::PointerMoved(xf.rect.center()));\n h.run_steps(1);",
|
||
" assert!(h.output().viewport_output[&egui::ViewportId::ROOT].repaint_delay.is_zero());\n h.event(egui::Event::PointerMoved(xf.rect.center()));\n h.run_steps(1);\n let stopped = h.state().ui.views[0].center;",
|
||
" assert_eq!(h.state().ui.views[0].center, stopped, \"returning to the interior stops scrolling\");\n }\n\n let mut h = zoomed_polygon();",
|
||
" assert!((center[0] - (400.0 - xf.rect.width() / (2.0 * xf.zoom))).abs() < 0.001, \"Overscroll off stops at the image's right edge\");\n h.run_steps(10);\n assert_eq!(h.state().ui.views[0].center, center, \"a long edge hold stays clamped\");\n assert_eq!(h.state().ui.polygon, points);",
|
||
" assert_eq!(h.state().ui.views[0].center, center, \"a long edge hold stays clamped\");\n assert_eq!(h.state().ui.polygon, points);\n assert_eq!(steps(&h), before);\n}",
|
||
" assert_eq!(h.state().ui.polygon, points);\n assert_eq!(steps(&h), before);\n}",
|
||
" assert_eq!(steps(&h), before);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ebf3777aec961d1815aa141d9987eaa645c2273f/crates/ui-egui/src/polygon_lasso_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "polygon_edge_scroll_places_the_next_vertex_in_the_panned_view_and_commits_once",
|
||
"path": "crates/ui-egui/src/polygon_lasso_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_places_the_next_vertex_in_the_panned_view_and_commits_once -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = zoomed_polygon();\n let before = steps(&h);\n let original = ViewXform::active(h.state()).unwrap();\n h.event(egui::Event::PointerMoved(original.rect.right_center() - vec2(4.0, 0.0)));\n h.run_steps(10);\n let panned = ViewXform::active(h.state()).unwrap();\n assert!(panned.center[0] > original.center[0], \"the zoomed image pans toward the right edge\");\n let at = panned.rect.center() + vec2(60.0, 0.0);\n let expected = panned.to_doc(at);\n h.event(egui::Event::PointerMoved(at));\n h.run_steps(20);\n button(&mut h, at, true, Modifiers::NONE);",
|
||
"expected_assertions": [
|
||
" assert!(panned.center[0] > original.center[0], \"the zoomed image pans toward the right edge\");\n let at = panned.rect.center() + vec2(60.0, 0.0);\n let expected = panned.to_doc(at);\n h.event(egui::Event::PointerMoved(at));",
|
||
" assert_eq!(h.state().ui.polygon[1], expected, \"the next click uses the updated view transform\");\n h.run_steps(30);\n click(&mut h, expected[0] as f32, 190.0, Modifiers::NONE);\n h.key_press(egui::Key::Enter);",
|
||
" assert!(h.state().ui.polygon.is_empty());\n assert!(selection(&h).is_some_and(|r| near(r, 170, 130, expected[0].ceil() as i32, 190)), \"{:?}\", selection(&h));\n assert_eq!(steps(&h), before + 1);\n h.event(egui::Event::PointerMoved(original.rect.right_center()));",
|
||
" assert!(selection(&h).is_some_and(|r| near(r, 170, 130, expected[0].ceil() as i32, 190)), \"{:?}\", selection(&h));\n assert_eq!(steps(&h), before + 1);\n h.event(egui::Event::PointerMoved(original.rect.right_center()));\n h.run_steps(4);",
|
||
" assert_eq!(steps(&h), before + 1);\n h.event(egui::Event::PointerMoved(original.rect.right_center()));\n h.run_steps(4);\n assert_eq!(h.state().ui.views[0].center, panned.center, \"a finished polygon never scrolls\");",
|
||
" assert_eq!(h.state().ui.views[0].center, panned.center, \"a finished polygon never scrolls\");\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert!(selection(&h).is_none(), \"one undo removes the completed selection\");\n}",
|
||
" assert!(selection(&h).is_none(), \"one undo removes the completed selection\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ebf3777aec961d1815aa141d9987eaa645c2273f/crates/ui-egui/src/polygon_lasso_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "polygon_edge_scroll_keeps_pixel_aspect_and_shift_constrained_segments",
|
||
"path": "crates/ui-egui/src/polygon_lasso_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_keeps_pixel_aspect_and_shift_constrained_segments -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (flip, rotation) in [(false, 0.0), (true, 0.0), (false, 45.0), (true, 90.0)] {\n let mut h = zoomed_polygon();\n h.state_mut().ui.view.pixel_aspect = \"custom:2:Wide\".into();\n h.state_mut().ui.view.flip_horizontal = flip;\n h.state_mut().ui.views[0].rotation = rotation;\n h.run_steps(2);\n let original = ViewXform::active(h.state()).unwrap();\n let points = h.state().ui.polygon.clone();\n h.event(egui::Event::PointerMoved(original.rect.right_center() + vec2(4.0, 0.0)));\n h.run_steps(5);\n let panned = ViewXform::active(h.state()).unwrap();\n let movement = original.map_vec(vec2(panned.center[0] - original.center[0], panned.center[1] - original.center[1]));",
|
||
"expected_assertions": [
|
||
" assert!(movement.x > 1.0 && movement.y.abs() < 0.001, \"wide pixels, flip={flip}, rotation={rotation}: {movement:?}\");\n assert_eq!(h.state().ui.polygon, points, \"scrolling keeps existing document-space vertices\");\n\n let at = panned.rect.center() + vec2(60.0, 30.0);",
|
||
" assert_eq!(h.state().ui.polygon, points, \"scrolling keeps existing document-space vertices\");\n\n let at = panned.rect.center() + vec2(60.0, 30.0);\n let expected = crate::canvas::constrained_polygon_point(points[0], panned.to_doc(at));",
|
||
" assert_eq!(h.state().ui.polygon.len(), 2);\n assert_eq!(h.state().ui.polygon[1], expected, \"Shift still snaps in document space after panning\");\n assert_eq!(h.state().ui.polygon_mode, \"replace\", \"Shift after the first vertex does not change selection intent\");\n }",
|
||
" assert_eq!(h.state().ui.polygon[1], expected, \"Shift still snaps in document space after panning\");\n assert_eq!(h.state().ui.polygon_mode, \"replace\", \"Shift after the first vertex does not change selection intent\");\n }\n",
|
||
" assert_eq!(h.state().ui.polygon_mode, \"replace\", \"Shift after the first vertex does not change selection intent\");\n }\n\n let mut h = zoomed_polygon();",
|
||
" assert!((center[0] - rightmost).abs() < 0.001, \"Overscroll off clamps using the displayed pixel aspect\");\n h.run_steps(10);\n assert_eq!(h.state().ui.views[0].center, center);\n}",
|
||
" assert_eq!(h.state().ui.views[0].center, center);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ebf3777aec961d1815aa141d9987eaa645c2273f/crates/ui-egui/src/polygon_lasso_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "polygon_edge_scroll_pauses_for_dialogs_and_temporary_navigation",
|
||
"path": "crates/ui-egui/src/polygon_lasso_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_pauses_for_dialogs_and_temporary_navigation -- --nocapture",
|
||
"fixture_and_action_excerpt": " for pause in [\"dialog\", \"space\", \"middle\"] {\n let mut h = zoomed_polygon();\n let rect = ViewXform::active(h.state()).unwrap().rect;\n let edge = rect.right_center() + vec2(4.0, 0.0);\n h.event(egui::Event::PointerMoved(edge));\n h.run_steps(1);\n match pause {\n \"dialog\" => {\n h.state_mut().ui.open_dialog(crate::state::DialogKind::Error, json!({\"message\":\"Pause\"}).as_object().unwrap().clone());\n }\n \"space\" => h.event(egui::Event::Key { key: egui::Key::Space, physical_key: None, pressed: true, repeat: false, modifiers: Modifiers::NONE }),\n _ => h.event(egui::Event::PointerButton { pos: edge, button: PointerButton::Middle, pressed: true, modifiers: Modifiers::NONE }),",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().ui.views[0].center, center, \"paused for {pause}\");\n assert_eq!(h.state().ui.polygon, points, \"{pause} retains the unfinished selection\");\n }\n}",
|
||
" assert_eq!(h.state().ui.polygon, points, \"{pause} retains the unfinished selection\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ebf3777aec961d1815aa141d9987eaa645c2273f/crates/ui-egui/src/polygon_lasso_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "polygon_edge_scroll_never_moves_an_inactive_pane_or_survives_a_document_or_tool_switch",
|
||
"path": "crates/ui-egui/src/polygon_lasso_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked polygon_edge_scroll_never_moves_an_inactive_pane_or_survives_a_document_or_tool_switch -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = zoomed_polygon();\n // Creating a document now cancels the old polygon immediately. Start a fresh one after\n // returning, so the inactive-pane and Enter checks exercise an outline that can commit.\n h.state_mut().run(\"file.new\", json!({\"width\":400,\"height\":300})).unwrap();\n h.state_mut().session.set_active(0);\n h.run_steps(2);\n for (x, y) in [(170.0, 130.0), (200.0, 130.0), (200.0, 170.0)] {\n click(&mut h, x, y, Modifiers::NONE);\n h.run_steps(30);\n }\n assert_eq!(h.state().ui.polygon.len(), 3);\n h.state_mut().ui.views[1].zoom = 4.0;",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().ui.polygon.len(), 3);\n h.state_mut().ui.views[1].zoom = 4.0;\n h.state_mut().ui.views[1].center = [200.0, 150.0];\n h.state_mut().ui.views[1].fit_pending = false;",
|
||
" assert_eq!(h.state().ui.views.iter().map(|v| v.center).collect::<Vec<_>>(), centers, \"hovering the other pane never pans either view\");\n assert_eq!(h.state().ui.polygon.len(), 3, \"the active polygon is still unfinished\");\n h.state_mut().session.set_active(1);\n h.key_press(egui::Key::Enter);",
|
||
" assert_eq!(h.state().ui.polygon.len(), 3, \"the active polygon is still unfinished\");\n h.state_mut().session.set_active(1);\n h.key_press(egui::Key::Enter);\n h.run_steps(2);",
|
||
" assert!(h.state().ui.polygon.is_empty(), \"the old document's unfinished polygon is discarded before Enter\");\n assert!(selection(&h).is_none());\n\n let mut h = zoomed_polygon();",
|
||
" assert!(selection(&h).is_none());\n\n let mut h = zoomed_polygon();\n h.state_mut().ui.tool = Tool::Brush;",
|
||
" assert!(h.state().ui.polygon.is_empty(), \"changing tools drops the polygon\");\n h.state_mut().ui.tool = Tool::PolygonLasso;\n click(&mut h, 170.0, 130.0, Modifiers::NONE);\n h.key_press(egui::Key::Escape);",
|
||
" assert!(h.state().ui.polygon.is_empty());\n assert_eq!(h.state().ui.views[0].center, center, \"Escape stops edge scrolling\");\n}",
|
||
" assert_eq!(h.state().ui.views[0].center, center, \"Escape stops edge scrolling\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ebf3777aec961d1815aa141d9987eaa645c2273f/crates/ui-egui/src/polygon_lasso_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-5010",
|
||
"pr": 5010,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked dragging_the_title_bar_moves_the_dialog -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_keeps_one_size_on_every_page -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_fits_a_short_screen -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_is_laid_out_like_photoshops -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_ok_cancel_and_enter -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_bin_deletes_the_selected_effect -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked every_effect_row_shows_a_checkbox -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked move_instance_reorders_within_its_kind -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked fx_menu_adds_or_shows_an_effect -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pending_style_is_the_dialogs_and_leaves_the_document_alone -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked body_keeps_invalid_params_and_renders_without_panicking -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked blending_page_renders_for_every_mode_and_odd_fields -- --nocapture"
|
||
],
|
||
"expected": "dragging the title bar moves the dialog; layer style keeps one size on every page; layer style fits a short screen; layer style is laid out like photoshops; layer style ok cancel and enter; layer style bin deletes the selected effect; every effect row shows a checkbox; move instance reorders within its kind; fx menu adds or shows an effect; pending style is the dialogs and leaves the document alone; body keeps invalid params and renders without panicking; blending page renders for every mode and odd fields",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked dragging_the_title_bar_moves_the_dialog -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_keeps_one_size_on_every_page -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_fits_a_short_screen -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_is_laid_out_like_photoshops -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_ok_cancel_and_enter -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_bin_deletes_the_selected_effect -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked every_effect_row_shows_a_checkbox -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked move_instance_reorders_within_its_kind -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked fx_menu_adds_or_shows_an_effect -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pending_style_is_the_dialogs_and_leaves_the_document_alone -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked body_keeps_invalid_params_and_renders_without_panicking -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked blending_page_renders_for_every_mode_and_odd_fields -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "dragging_the_title_bar_moves_the_dialog",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked dragging_the_title_bar_moves_the_dialog -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::{Harness, kittest::Queryable};\n\n let app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n let mut harness = Harness::builder().with_size(egui::vec2(1400.0, 1100.0)).build_ui_state(|ui, app| show(app, ui.ctx()), app);\n PhotocraftApp::setup_context(&harness.ctx, crate::theme::ThemeKind::ALL[0]);\n harness.state_mut().ui.open_dialog(DialogKind::LayerStyle, serde_json::Map::new());\n harness.run_steps(3);\n let before = harness.get_by_label(\"Layer Style\").rect();\n\n // Grab the title text itself: it must move the dialog, not select the text.\n let from = before.center();\n harness.hover_at(from);",
|
||
"expected_assertions": [
|
||
" assert!((moved - egui::vec2(-120.0, 80.0)).length() < 1.0, \"dialog moved by {moved:?}\");\n assert_eq!(harness.state().ui.dialogs.len(), 1, \"dragging must not close the dialog\");\n }",
|
||
" assert_eq!(harness.state().ui.dialogs.len(), 1, \"dragging must not close the dialog\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_style_keeps_one_size_on_every_page",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_style_keeps_one_size_on_every_page -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = layer_style_on_bevel(egui::vec2(1400.0, 900.0));\n let size = frame(&h).size();\n let dialog = h.state().ui.dialogs[0].id;\n for page in [\"blendingOptions\", \"styles\"] {\n h.state_mut().ui.dialog_mut(dialog).expect(\"still open\").fields.insert(\"selected\".into(), json!(page));\n h.run_steps(3);\n assert_eq!(frame(&h).size(), size, \"{page}\");\n }\n let grip = egui::Id::new((\"dialog\", dialog)).with(\"resize\").with(\"__resize_corner\");\n assert!(h.ctx.read_response(grip).is_none(), \"no resize grip\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(frame(&h).size(), size, \"{page}\");\n }\n let grip = egui::Id::new((\"dialog\", dialog)).with(\"resize\").with(\"__resize_corner\");\n assert!(h.ctx.read_response(grip).is_none(), \"no resize grip\");",
|
||
" assert!(h.ctx.read_response(grip).is_none(), \"no resize grip\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_style_fits_a_short_screen",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_style_fits_a_short_screen -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n\n let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1366.0, 640.0));\n let h = layer_style_on_bevel(screen.size());\n assert!(screen.contains_rect(frame(&h)), \"{:?} fits on {screen:?}\", frame(&h));\n for button in [\"OK\", \"Cancel\"] {\n assert!(screen.contains_rect(h.get_by_label(button).rect()), \"{button} is on screen\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(screen.contains_rect(frame(&h)), \"{:?} fits on {screen:?}\", frame(&h));\n for button in [\"OK\", \"Cancel\"] {\n assert!(screen.contains_rect(h.get_by_label(button).rect()), \"{button} is on screen\");\n }",
|
||
" assert!(screen.contains_rect(h.get_by_label(button).rect()), \"{button} is on screen\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_style_is_laid_out_like_photoshops",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_style_is_laid_out_like_photoshops -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n\n let h = layer_style_on_bevel(egui::vec2(1400.0, 900.0));\n let at = |label: &str| h.get_by_label(label).rect();\n let frame = frame(&h);\n assert!(frame.width() > frame.height() * 1.3, \"wide and short: {:?}\", frame.size());\n // The list's rows are painted; its bar's fx button marks the column.\n let (list, page) = (at(\"Add a layer style\"), at(\"Depth\"));\n let [ok, cancel, new_style, preview] = [\"OK\", \"Cancel\", \"New Style…\", \"Preview\"].map(at);\n assert!(list.right() < page.left(), \"the list is left of the page\");\n for (name, r) in [(\"OK\", ok), (\"Cancel\", cancel), (\"New Style…\", new_style), (\"Preview\", preview)] {\n assert!(r.left() > page.right(), \"{name} is right of the page\");",
|
||
"expected_assertions": [
|
||
" assert!(frame.width() > frame.height() * 1.3, \"wide and short: {:?}\", frame.size());\n // The list's rows are painted; its bar's fx button marks the column.\n let (list, page) = (at(\"Add a layer style\"), at(\"Depth\"));\n let [ok, cancel, new_style, preview] = [\"OK\", \"Cancel\", \"New Style…\", \"Preview\"].map(at);",
|
||
" assert!(list.right() < page.left(), \"the list is left of the page\");\n for (name, r) in [(\"OK\", ok), (\"Cancel\", cancel), (\"New Style…\", new_style), (\"Preview\", preview)] {\n assert!(r.left() > page.right(), \"{name} is right of the page\");\n }",
|
||
" assert!(r.left() > page.right(), \"{name} is right of the page\");\n }\n assert!(ok.top() < cancel.top() && cancel.top() < new_style.top() && new_style.top() < preview.top(), \"top to bottom\");\n }",
|
||
" assert!(ok.top() < cancel.top() && cancel.top() < new_style.top() && new_style.top() < preview.top(), \"top to bottom\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_style_ok_cancel_and_enter",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_style_ok_cancel_and_enter -- --nocapture",
|
||
"fixture_and_action_excerpt": " let bevels = |h: &egui_kittest::Harness<'_, PhotocraftApp>| {\n let st = h.state().session.active().unwrap();\n let layer = st.doc.layer(st.active_layer.unwrap()).unwrap();\n layer.effects.items.iter().filter(|e| matches!(e, photocraft_doc::Effect::BevelEmboss { .. })).count()\n };\n for (how, applied) in [(\"OK\", 1), (\"Cancel\", 0), (\"Enter\", 1)] {\n use egui_kittest::kittest::Queryable;\n\n let mut h = layer_style_on_bevel(egui::vec2(1400.0, 900.0));\n if how == \"Enter\" {\n h.key_press(egui::Key::Enter);\n } else {",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.dialogs.is_empty(), \"{how} closes the dialog\");\n assert_eq!(bevels(&h), applied, \"{how}\");\n }\n }",
|
||
" assert_eq!(bevels(&h), applied, \"{how}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_style_bin_deletes_the_selected_effect",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_style_bin_deletes_the_selected_effect -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n\n let mut h = layer_style_on_bevel(egui::vec2(1400.0, 900.0));\n let effects = |h: &egui_kittest::Harness<'_, PhotocraftApp>| h.state().ui.dialogs[0].fields[\"effects\"].as_array().map_or(0, Vec::len);\n assert_eq!(effects(&h), 1);\n h.get_by_label(\"Delete effect\").click();\n h.run_steps(3);\n assert_eq!(effects(&h), 0, \"Bevel & Emboss is gone from the list\");\n assert_eq!(h.state().ui.dialogs.len(), 1, \"the dialog stays open\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(effects(&h), 1);\n h.get_by_label(\"Delete effect\").click();\n h.run_steps(3);\n assert_eq!(effects(&h), 0, \"Bevel & Emboss is gone from the list\");",
|
||
" assert_eq!(effects(&h), 0, \"Bevel & Emboss is gone from the list\");\n assert_eq!(h.state().ui.dialogs.len(), 1, \"the dialog stays open\");\n }",
|
||
" assert_eq!(h.state().ui.dialogs.len(), 1, \"the dialog stays open\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "every_effect_row_shows_a_checkbox",
|
||
"path": "crates/ui-egui/src/layer_style.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked every_effect_row_shows_a_checkbox -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 32, \"height\": 32})).unwrap();\n let l = Layer::raster(\"x\", photocraft_doc::PixelFormat::RGBA8);\n let fields = initial_fields(&l, Some(BLENDING), 120.0);\n let mut h = egui_kittest::Harness::builder().with_size(vec2(900.0, 700.0)).build_ui_state(\n move |ui, app: &mut PhotocraftApp| {\n if !ui.ctx().fonts(|f| f.families().contains(&egui::FontFamily::Name(\"medium\".into()))) {\n return;\n }\n let mut f = fields.clone();\n body(app, ui, &mut f, false);\n },",
|
||
"expected_assertions": [
|
||
" assert_eq!(rows, KINDS.len(), \"one empty checkbox per effect row\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/layer_style.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "move_instance_reorders_within_its_kind",
|
||
"path": "crates/ui-egui/src/layer_style.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked move_instance_reorders_within_its_kind -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session();\n s.execute(\"layer.layerStyle.stroke\", json!({\"size\": 3})).unwrap();\n let st = s.active().unwrap();\n let mut f = initial_fields(st.doc.layer(st.active_layer.unwrap()).unwrap(), None, 120.0);\n add_instance(&mut f, \"dropShadow\");\n add_instance(&mut f, \"stroke\");\n assert_eq!(ids(&f), [\"fx1\", \"fx3\", \"fx2\"], \"a new stroke goes after the last stroke\");\n move_instance(&mut f, \"fx3\", -1);\n assert_eq!(ids(&f), [\"fx3\", \"fx1\", \"fx2\"]);\n move_instance(&mut f, \"fx3\", -1);\n assert_eq!(ids(&f), [\"fx3\", \"fx1\", \"fx2\"], \"already the first stroke\");\n move_instance(&mut f, \"fx2\", 1);",
|
||
"expected_assertions": [
|
||
" assert_eq!(ids(&f), [\"fx1\", \"fx3\", \"fx2\"], \"a new stroke goes after the last stroke\");\n move_instance(&mut f, \"fx3\", -1);\n assert_eq!(ids(&f), [\"fx3\", \"fx1\", \"fx2\"]);\n move_instance(&mut f, \"fx3\", -1);",
|
||
" assert_eq!(ids(&f), [\"fx3\", \"fx1\", \"fx2\"]);\n move_instance(&mut f, \"fx3\", -1);\n assert_eq!(ids(&f), [\"fx3\", \"fx1\", \"fx2\"], \"already the first stroke\");\n move_instance(&mut f, \"fx2\", 1);",
|
||
" assert_eq!(ids(&f), [\"fx3\", \"fx1\", \"fx2\"], \"already the first stroke\");\n move_instance(&mut f, \"fx2\", 1);\n assert_eq!(ids(&f), [\"fx3\", \"fx1\", \"fx2\"], \"the only drop shadow stays put\");\n for (id, by) in [(\"fx1\", isize::MAX), (\"fx1\", isize::MIN), (\"nope\", 1)] {",
|
||
" assert_eq!(ids(&f), [\"fx3\", \"fx1\", \"fx2\"], \"the only drop shadow stays put\");\n for (id, by) in [(\"fx1\", isize::MAX), (\"fx1\", isize::MIN), (\"nope\", 1)] {\n move_instance(&mut f, id, by);\n }",
|
||
" assert_eq!(ids(&f), [\"fx3\", \"fx1\", \"fx2\"], \"out-of-range moves and unknown ids change nothing\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/layer_style.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "fx_menu_adds_or_shows_an_effect",
|
||
"path": "crates/ui-egui/src/layer_style.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked fx_menu_adds_or_shows_an_effect -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session();\n s.execute(\"layer.layerStyle.stroke\", json!({\"size\": 3})).unwrap();\n s.execute(\"layer.layerStyle.satin\", json!({\"enabled\": false})).unwrap();\n let st = s.active().unwrap();\n let mut f = initial_fields(st.doc.layer(st.active_layer.unwrap()).unwrap(), None, 120.0);\n let before = effects_of(&f).len();\n pick_from_fx_menu(&mut f, \"stroke\");\n assert_eq!(effects_of(&f).len(), before + 1, \"a second stroke\");\n let satin = effects_of(&f).iter().find(|e| e[\"kind\"] == \"satin\").and_then(|e| e[\"id\"].as_str()).unwrap().to_string();\n pick_from_fx_menu(&mut f, \"satin\");\n assert_eq!(effects_of(&f).len(), before + 1, \"no second satin\");\n assert_eq!(f[\"selected\"], json!(satin));",
|
||
"expected_assertions": [
|
||
" assert_eq!(effects_of(&f).len(), before + 1, \"a second stroke\");\n let satin = effects_of(&f).iter().find(|e| e[\"kind\"] == \"satin\").and_then(|e| e[\"id\"].as_str()).unwrap().to_string();\n pick_from_fx_menu(&mut f, \"satin\");\n assert_eq!(effects_of(&f).len(), before + 1, \"no second satin\");",
|
||
" assert_eq!(effects_of(&f).len(), before + 1, \"no second satin\");\n assert_eq!(f[\"selected\"], json!(satin));\n assert_eq!(entry(&f, &satin).unwrap()[\"on\"], json!(true));\n }",
|
||
" assert_eq!(f[\"selected\"], json!(satin));\n assert_eq!(entry(&f, &satin).unwrap()[\"on\"], json!(true));\n }",
|
||
" assert_eq!(entry(&f, &satin).unwrap()[\"on\"], json!(true));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/layer_style.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "pending_style_is_the_dialogs_and_leaves_the_document_alone",
|
||
"path": "crates/ui-egui/src/layer_style.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked pending_style_is_the_dialogs_and_leaves_the_document_alone -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), Default::default());\n app.run(\"file.new\", json!({\"width\": 16, \"height\": 16})).unwrap();\n app.run(\"layer.new.layer\", json!({})).unwrap();\n let id = app.session.active().unwrap().active_layer.unwrap();\n let mut f = initial_fields(app.session.active().unwrap().doc.layer(id).unwrap(), Some(\"stroke\"), 120.0);\n set_param(&mut f, \"fx1\", \"size\", json!(9));\n let style = pending_style(&app, &f).expect(\"the pending style builds\");\n let sizes: Vec<f32> = style\n .effects\n .iter()\n .filter_map(|e| match e {\n Effect::Stroke(s) => Some(s.size),",
|
||
"expected_assertions": [
|
||
" assert_eq!(sizes, [9.0]);\n assert!(app.session.active().unwrap().doc.layer(id).unwrap().effects.items.is_empty(), \"the document is untouched\");\n let rgba = photocraft_engine::presets::styles::thumbnail(&app.session, &style, 32);\n assert_eq!(rgba.len(), 32 * 32 * 4);",
|
||
" assert!(app.session.active().unwrap().doc.layer(id).unwrap().effects.items.is_empty(), \"the document is untouched\");\n let rgba = photocraft_engine::presets::styles::thumbnail(&app.session, &style, 32);\n assert_eq!(rgba.len(), 32 * 32 * 4);\n }",
|
||
" assert_eq!(rgba.len(), 32 * 32 * 4);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/layer_style.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "body_keeps_invalid_params_and_renders_without_panicking",
|
||
"path": "crates/ui-egui/src/layer_style.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked body_keeps_invalid_params_and_renders_without_panicking -- --nocapture",
|
||
"fixture_and_action_excerpt": " let ctx = egui::Context::default();\n PhotocraftApp::setup_context(&ctx, crate::theme::ThemeKind::ALL[0]);\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), Default::default());\n for bad in [json!(7), json!(null), json!(\"x\")] {\n let mut fields = Map::new();\n fields.insert(\"selected\".into(), json!(\"fx1\"));\n fields.insert(\"effects\".into(), json!([{\"id\": \"fx1\", \"kind\": \"dropShadow\", \"on\": true, \"params\": bad.clone()}]));\n\n let mut out = ctx.run_ui(Default::default(), |ui| {\n body(&mut app, ui, &mut fields, false);\n });\n out.textures_delta.clear();",
|
||
"expected_assertions": [
|
||
" assert_eq!(entry(&fields, \"fx1\").unwrap()[\"params\"], bad);\n }\n for bad in [json!(7), json!([1])] {\n let mut fields = Map::new();",
|
||
" assert_eq!(fields.get(\"p:blendingOptions\"), Some(&bad));\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/layer_style.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "blending_page_renders_for_every_mode_and_odd_fields",
|
||
"path": "crates/ui-egui/src/layer_style.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked blending_page_renders_for_every_mode_and_odd_fields -- --nocapture",
|
||
"fixture_and_action_excerpt": " let ctx = egui::Context::default();\n PhotocraftApp::setup_context(&ctx, crate::theme::ThemeKind::ALL[0]);\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), Default::default());\n let mut layer = photocraft_doc::Layer::new(\"L\", photocraft_doc::LayerContent::Adjustment(photocraft_doc::Adjustment::Invert));\n layer.advanced.knockout = photocraft_doc::Knockout::Deep;\n for mode in\n [photocraft_color::ColorMode::Rgb, photocraft_color::ColorMode::Cmyk, photocraft_color::ColorMode::Lab, photocraft_color::ColorMode::Grayscale]\n {\n let mut f = initial_fields(&layer, Some(BLENDING), 120.0);\n set_blending_fields(&mut f, &layer, mode);\n let mut out = ctx.run_ui(Default::default(), |ui| {\n body(&mut app, ui, &mut f, false);",
|
||
"expected_assertions": [
|
||
" assert_eq!(f[\"p:blendingOptions\"][\"knockout\"], \"deep\", \"{mode:?}\");\n // Hostile dialog state (only reachable through `ui.dialog.set`) still renders.\n let bo = f.get_mut(\"p:blendingOptions\").unwrap();\n bo[\"blendIfChannel\"] = json!(99);"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/cc865221894e21f846d92b721cce7421ea338363/crates/ui-egui/src/layer_style.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-5493",
|
||
"pr": 5493,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Synthetic multi-shape CSH, duplicate names, inner holes and malformed second shape; empty temporary library/preferences",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked csh_import_makes_an_original_shape_available_without_a_document -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked csh_invalid_second_shape_does_not_partially_import_a_set -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked csh_multiple_shapes_with_matching_names_remain_individually_available -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked csh_repeat_import_names_are_unique_and_survive_preferences_reload -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked csh_same_winding_inner_subpath_stays_a_hole_after_place_and_reload -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked csh_open_imports_presets_and_shows_shapes_without_opening_a_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked malformed_csh_open_preserves_the_library -- --nocapture"
|
||
],
|
||
"expected": "Valid sets populate Shapes without a document; duplicate names stay individually addressable after reload; placed holes remain holes. Invalid later shape does not partially change library/revision. Malformed UI open preserves the library.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Retain inline-data authorization test separately; capture native Shapes panel as additional visual evidence.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked csh_import_makes_an_original_shape_available_without_a_document -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked csh_invalid_second_shape_does_not_partially_import_a_set -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked csh_multiple_shapes_with_matching_names_remain_individually_available -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked csh_repeat_import_names_are_unique_and_survive_preferences_reload -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked csh_same_winding_inner_subpath_stays_a_hole_after_place_and_reload -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked csh_open_imports_presets_and_shows_shapes_without_opening_a_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked malformed_csh_open_preserves_the_library -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-5515",
|
||
"pr": 5515,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked select_subject_samples_the_selected_layer_else_the_composite -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked select_subject_repeat_reuses_the_mask_until_pixels_change -- --nocapture"
|
||
],
|
||
"expected": "select subject samples the selected layer else the composite; select subject repeat reuses the mask until pixels change",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked select_subject_samples_the_selected_layer_else_the_composite -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked select_subject_repeat_reuses_the_mask_until_pixels_change -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "select_subject_samples_the_selected_layer_else_the_composite",
|
||
"path": "crates/engine/src/smartselect_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked select_subject_samples_the_selected_layer_else_the_composite -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut s, inside) = disc(8);\n // A layer above holding only a small square in the corner: the disc is not on it.\n s.execute(\"layer.new.layer\", json!({})).unwrap();\n s.execute(\"paint.pencil\", json!({\"points\": [[10, 10], [30, 10]], \"size\": 3, \"color\": \"#000000\"})).unwrap();\n s.execute(\"select.subject\", json!({})).unwrap();\n assert!(cov(&s, 100, 80) < 0.5, \"the disc on the layer below was selected\");\n s.execute(\"select.deselect\", json!({})).unwrap();\n // No layer selected: the whole image, so the disc is found.\n s.execute(\"select.deselectLayers\", json!({})).unwrap();\n s.execute(\"select.subject\", json!({})).unwrap();\n assert!(sel_iou(&s, 200, 160, &inside) > 0.9);\n }",
|
||
"expected_assertions": [
|
||
" assert!(cov(&s, 100, 80) < 0.5, \"the disc on the layer below was selected\");\n s.execute(\"select.deselect\", json!({})).unwrap();\n // No layer selected: the whole image, so the disc is found.\n s.execute(\"select.deselectLayers\", json!({})).unwrap();",
|
||
" assert!(sel_iou(&s, 200, 160, &inside) > 0.9);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/375d4894a119b6cd5933d53e8fe7f506d2783392/crates/engine/src/smartselect_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "select_subject_repeat_reuses_the_mask_until_pixels_change",
|
||
"path": "crates/engine/src/smartselect_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked select_subject_repeat_reuses_the_mask_until_pixels_change -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut s, _) = disc(8);\n let sel = |s: &Session| {\n let mut v = Vec::new();\n s.active().unwrap().doc.selection.as_ref().unwrap().read_region_into(Rect::new(0, 0, 200, 160), &mut v);\n v\n };\n let cached = |s: &Session| s.subject_cache.region.clone().unwrap();\n s.execute(\"select.subject\", json!({})).unwrap();\n let (first, mask) = (sel(&s), cached(&s));\n s.execute(\"select.deselect\", json!({})).unwrap();\n s.execute(\"select.subject\", json!({})).unwrap();\n assert!(std::sync::Arc::ptr_eq(&mask, &cached(&s)), \"the repeat recomputed the mask\");",
|
||
"expected_assertions": [
|
||
" assert!(std::sync::Arc::ptr_eq(&mask, &cached(&s)), \"the repeat recomputed the mask\");\n assert_eq!(sel(&s), first);\n // Another sampled target (the composite rather than the layer) is a miss.\n s.execute(\"select.subject\", json!({\"sampleAllLayers\": true})).unwrap();",
|
||
" assert_eq!(sel(&s), first);\n // Another sampled target (the composite rather than the layer) is a miss.\n s.execute(\"select.subject\", json!({\"sampleAllLayers\": true})).unwrap();\n assert!(!std::sync::Arc::ptr_eq(&mask, &cached(&s)));",
|
||
" assert!(!std::sync::Arc::ptr_eq(&mask, &cached(&s)));\n // A pixel edit drops the entry; the next run recomputes it.\n s.edit(\"paint\", |doc, _| {\n let bg = doc.layers[0].surface_mut().unwrap();",
|
||
" assert!(s.subject_cache.region.is_none());\n s.execute(\"select.subject\", json!({})).unwrap();\n assert_eq!(sel(&s), first);\n }",
|
||
" assert_eq!(sel(&s), first);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/375d4894a119b6cd5933d53e8fe7f506d2783392/crates/engine/src/smartselect_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-5650",
|
||
"pr": 5650,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked move_guide_turns_a_guide -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_panel_hover_outlines_layer_on_canvas -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked guide_drags_create_move_and_delete -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked alt_turns_a_guide_dragged_out_of_a_ruler -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked alt_turns_a_guide_moved_with_the_move_tool -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_guide_dropped_on_either_ruler_is_deleted -- --nocapture"
|
||
],
|
||
"expected": "move guide turns a guide; layer panel hover outlines layer on canvas; guide drags create move and delete; alt turns a guide dragged out of a ruler; alt turns a guide moved with the move tool; a guide dropped on either ruler is deleted",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked move_guide_turns_a_guide -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_panel_hover_outlines_layer_on_canvas -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked guide_drags_create_move_and_delete -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked alt_turns_a_guide_dragged_out_of_a_ruler -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked alt_turns_a_guide_moved_with_the_move_tool -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_guide_dropped_on_either_ruler_is_deleted -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "move_guide_turns_a_guide",
|
||
"path": "crates/engine/src/edit_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked move_guide_turns_a_guide -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.execute(\"file.new\", json!({\"width\": 200, \"height\": 100})).unwrap();\n s.execute(\"view.newGuide\", json!({\"orientation\": \"horizontal\", \"position\": 30, \"color\": \"magenta\"})).unwrap();\n s.execute(\"view.newGuide\", json!({\"orientation\": \"horizontal\", \"position\": 70})).unwrap();\n s.execute(\"view.moveGuide\", json!({\"orientation\": \"horizontal\", \"index\": 0, \"position\": \"50%\", \"toOrientation\": \"vertical\"})).unwrap();\n let g = &s.active().unwrap().doc.guides;\n assert_eq!((g.horizontal.clone(), g.vertical.clone()), (vec![70.0], vec![100.0]), \"50% of the width\");\n assert_eq!(g.color(true, 100.0), Some([255, 0, 255]), \"the colour moves with the guide\");\n assert_eq!(g.color(false, 30.0), None);\n // The same orientation is a plain move.\n s.execute(\"view.moveGuide\", json!({\"orientation\": \"vertical\", \"index\": 0, \"position\": 20, \"toOrientation\": \"vertical\"})).unwrap();\n assert_eq!(s.active().unwrap().doc.guides.vertical, vec![20.0]);",
|
||
"expected_assertions": [
|
||
" assert_eq!((g.horizontal.clone(), g.vertical.clone()), (vec![70.0], vec![100.0]), \"50% of the width\");\n assert_eq!(g.color(true, 100.0), Some([255, 0, 255]), \"the colour moves with the guide\");\n assert_eq!(g.color(false, 30.0), None);\n // The same orientation is a plain move.",
|
||
" assert_eq!(g.color(true, 100.0), Some([255, 0, 255]), \"the colour moves with the guide\");\n assert_eq!(g.color(false, 30.0), None);\n // The same orientation is a plain move.\n s.execute(\"view.moveGuide\", json!({\"orientation\": \"vertical\", \"index\": 0, \"position\": 20, \"toOrientation\": \"vertical\"})).unwrap();",
|
||
" assert_eq!(g.color(false, 30.0), None);\n // The same orientation is a plain move.\n s.execute(\"view.moveGuide\", json!({\"orientation\": \"vertical\", \"index\": 0, \"position\": 20, \"toOrientation\": \"vertical\"})).unwrap();\n assert_eq!(s.active().unwrap().doc.guides.vertical, vec![20.0]);",
|
||
" assert_eq!(s.active().unwrap().doc.guides.vertical, vec![20.0]);\n s.undo();\n s.undo();\n let g = &s.active().unwrap().doc.guides;",
|
||
" assert_eq!((g.horizontal.clone(), g.vertical.clone()), (vec![30.0, 70.0], vec![]), \"one undo step per move\");\n // Bad params are refused and leave the guides alone.\n assert!(s.execute(\"view.moveGuide\", json!({\"orientation\": \"horizontal\", \"index\": 0, \"position\": 5, \"toOrientation\": \"diagonal\"})).is_err());\n assert!(s.execute(\"view.moveGuide\", json!({\"orientation\": \"horizontal\", \"index\": 0, \"position\": 5, \"toOrientation\": 1})).is_err());",
|
||
" assert!(s.execute(\"view.moveGuide\", json!({\"orientation\": \"horizontal\", \"index\": 0, \"position\": 5, \"toOrientation\": \"diagonal\"})).is_err());\n assert!(s.execute(\"view.moveGuide\", json!({\"orientation\": \"horizontal\", \"index\": 0, \"position\": 5, \"toOrientation\": 1})).is_err());\n assert!(s.execute(\"view.newGuide\", json!({\"orientation\": \"horizontal\", \"position\": 5, \"toOrientation\": \"vertical\"})).is_err());\n assert!(s.execute(\"view.moveGuide\", json!({\"orientation\": \"horizontal\", \"index\": 9, \"position\": 5, \"toOrientation\": \"vertical\"})).is_err());",
|
||
" assert!(s.execute(\"view.moveGuide\", json!({\"orientation\": \"horizontal\", \"index\": 0, \"position\": 5, \"toOrientation\": 1})).is_err());\n assert!(s.execute(\"view.newGuide\", json!({\"orientation\": \"horizontal\", \"position\": 5, \"toOrientation\": \"vertical\"})).is_err());\n assert!(s.execute(\"view.moveGuide\", json!({\"orientation\": \"horizontal\", \"index\": 9, \"position\": 5, \"toOrientation\": \"vertical\"})).is_err());\n let g = &s.active().unwrap().doc.guides;",
|
||
" assert!(s.execute(\"view.newGuide\", json!({\"orientation\": \"horizontal\", \"position\": 5, \"toOrientation\": \"vertical\"})).is_err());\n assert!(s.execute(\"view.moveGuide\", json!({\"orientation\": \"horizontal\", \"index\": 9, \"position\": 5, \"toOrientation\": \"vertical\"})).is_err());\n let g = &s.active().unwrap().doc.guides;\n assert_eq!((g.horizontal.clone(), g.vertical.clone()), (vec![30.0, 70.0], vec![]));",
|
||
" assert!(s.execute(\"view.moveGuide\", json!({\"orientation\": \"horizontal\", \"index\": 9, \"position\": 5, \"toOrientation\": \"vertical\"})).is_err());\n let g = &s.active().unwrap().doc.guides;\n assert_eq!((g.horizontal.clone(), g.vertical.clone()), (vec![30.0, 70.0], vec![]));\n }",
|
||
" assert_eq!((g.horizontal.clone(), g.vertical.clone()), (vec![30.0, 70.0], vec![]));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/4b1bd6fb6d264f885cb9caa3b8a6578ee527bd7b/crates/engine/src/edit_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_panel_hover_outlines_layer_on_canvas",
|
||
"path": "crates/ui-egui/src/move_hover.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_panel_hover_outlines_layer_on_canvas -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.session.execute(\"file.new\", json!({\"width\": 64, \"height\": 64})).unwrap();\n app.session.execute(\"layer.new.layer\", json!({})).unwrap();\n app.session\n .edit(\"paint\", |doc, a| {\n doc.layer_mut(a.unwrap()).unwrap().surface_mut().unwrap().fill_rect(Rect::new(8, 8, 24, 24), &[1.0, 0.0, 0.0, 1.0]);\n Ok(())\n })\n .unwrap();\n let target_layer = app.session.active().unwrap().active_layer.unwrap();\n let a = Rect::new(8, 8, 24, 24);\n",
|
||
"expected_assertions": [
|
||
" assert_eq!(active_outline(&mut app, None, false, false), None);\n app.hover_layer = Some(target_layer);\n assert_eq!(active_outline(&mut app, None, false, false), Some(a));\n",
|
||
" assert_eq!(active_outline(&mut app, None, false, false), Some(a));\n\n // When a drag or transform is in progress, no outline:\n app.guide_drag = Some(crate::rulers::GuideDrag { vertical: false, index: None, pos: 10.0, ..Default::default() });",
|
||
" assert_eq!(active_outline(&mut app, None, false, false), None);\n app.guide_drag = None;\n\n // When rollover preference is disabled, no outline:",
|
||
" assert_eq!(active_outline(&mut app, None, false, false), None);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/4b1bd6fb6d264f885cb9caa3b8a6578ee527bd7b/crates/ui-egui/src/move_hover.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "guide_drags_create_move_and_delete",
|
||
"path": "crates/ui-egui/src/rulers.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked guide_drags_create_move_and_delete -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.session.execute(\"file.new\", json!({\"width\": 200, \"height\": 100})).unwrap();\n app.sync_views();\n finish_drag(&mut app, GuideDrag { vertical: true, index: None, pos: 50.0, ..Default::default() });\n finish_drag(&mut app, GuideDrag { vertical: false, index: None, pos: 500.0, ..Default::default() }); // off canvas: ignored\n assert_eq!(app.session.active().unwrap().doc.guides.vertical, vec![50.0]);\n assert!(app.session.active().unwrap().doc.guides.horizontal.is_empty());\n assert_eq!(guide_at(&app, 51.0, 10.0), Some((true, 0)));\n finish_drag(&mut app, GuideDrag { vertical: true, index: Some(0), pos: 120.0, ..Default::default() });\n assert_eq!(app.session.active().unwrap().doc.guides.vertical, vec![120.0]);\n finish_drag(&mut app, GuideDrag { vertical: true, index: Some(0), pos: -30.0, ..Default::default() });\n assert!(app.session.active().unwrap().doc.guides.vertical.is_empty());",
|
||
"expected_assertions": [
|
||
" assert_eq!(app.session.active().unwrap().doc.guides.vertical, vec![50.0]);\n assert!(app.session.active().unwrap().doc.guides.horizontal.is_empty());\n assert_eq!(guide_at(&app, 51.0, 10.0), Some((true, 0)));\n finish_drag(&mut app, GuideDrag { vertical: true, index: Some(0), pos: 120.0, ..Default::default() });",
|
||
" assert!(app.session.active().unwrap().doc.guides.horizontal.is_empty());\n assert_eq!(guide_at(&app, 51.0, 10.0), Some((true, 0)));\n finish_drag(&mut app, GuideDrag { vertical: true, index: Some(0), pos: 120.0, ..Default::default() });\n assert_eq!(app.session.active().unwrap().doc.guides.vertical, vec![120.0]);",
|
||
" assert_eq!(guide_at(&app, 51.0, 10.0), Some((true, 0)));\n finish_drag(&mut app, GuideDrag { vertical: true, index: Some(0), pos: 120.0, ..Default::default() });\n assert_eq!(app.session.active().unwrap().doc.guides.vertical, vec![120.0]);\n finish_drag(&mut app, GuideDrag { vertical: true, index: Some(0), pos: -30.0, ..Default::default() });",
|
||
" assert_eq!(app.session.active().unwrap().doc.guides.vertical, vec![120.0]);\n finish_drag(&mut app, GuideDrag { vertical: true, index: Some(0), pos: -30.0, ..Default::default() });\n assert!(app.session.active().unwrap().doc.guides.vertical.is_empty());\n app.ui.extras.lock_guides = true;",
|
||
" assert!(app.session.active().unwrap().doc.guides.vertical.is_empty());\n app.ui.extras.lock_guides = true;\n assert_eq!(guide_at(&app, 0.0, 0.0), None);\n }",
|
||
" assert_eq!(guide_at(&app, 0.0, 0.0), None);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/4b1bd6fb6d264f885cb9caa3b8a6578ee527bd7b/crates/ui-egui/src/rulers.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "alt_turns_a_guide_dragged_out_of_a_ruler",
|
||
"path": "crates/ui-egui/src/rulers.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked alt_turns_a_guide_dragged_out_of_a_ruler -- --nocapture",
|
||
"fixture_and_action_excerpt": " let full = Rect::from_min_size(Pos2::ZERO, vec2(400.0, 300.0));\n let rect = Rect::from_min_max(full.min + vec2(RULER, RULER), full.max);\n let xf = ViewXform { rect, zoom: 1.0, center: [128.0, 64.0], flip: false, rotation: 0.0, aspect: 1.0 };\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 256, \"height\": 128})).unwrap();\n let mut h = egui_kittest::Harness::builder().with_size(vec2(400.0, 300.0)).build_ui_state(move |ui, app| draw_rulers(app, ui, full, &xf), app);\n // ⌥ held for the whole drag (`event_modifiers` would let go of it after each event).\n let alt = egui::Modifiers::ALT;\n h.event(egui::Event::ModifiersChanged(alt));\n let (from, to) = (pos2(RULER / 2.0, 100.0), xf.to_screen(37.0, 51.0));\n h.event(egui::Event::PointerMoved(from));\n h.event(egui::Event::PointerButton { pos: from, button: egui::PointerButton::Primary, pressed: true, modifiers: alt });",
|
||
"expected_assertions": [
|
||
" assert!(h.state().guide_drag.is_some_and(|d| !d.shows_vertical()), \"drawn horizontal while ⌥ is held\");\n h.event(egui::Event::PointerButton { pos: to, button: egui::PointerButton::Primary, pressed: false, modifiers: alt });\n h.run_steps(2);\n let g = &h.state().session.active().unwrap().doc.guides;",
|
||
" assert_eq!((g.vertical.clone(), g.horizontal.clone()), (vec![], vec![51.0]));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/4b1bd6fb6d264f885cb9caa3b8a6578ee527bd7b/crates/ui-egui/src/rulers.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "alt_turns_a_guide_moved_with_the_move_tool",
|
||
"path": "crates/ui-egui/src/rulers.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked alt_turns_a_guide_moved_with_the_move_tool -- --nocapture",
|
||
"fixture_and_action_excerpt": " use crate::canvas::{ToolEvent, tool_event};\n let new_app = || {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 80, \"height\": 60})).unwrap();\n app.sync_views();\n app.ui.tool = crate::state::Tool::Move;\n app.run(\"view.newGuide\", json!({\"orientation\": \"vertical\", \"position\": 50})).unwrap();\n app\n };\n let guides = |app: &PhotocraftApp| {\n let g = &app.session.active().unwrap().doc.guides;\n (g.vertical.clone(), g.horizontal.clone())",
|
||
"expected_assertions": [
|
||
" assert!(app.guide_drag.is_some_and(|d| !d.shows_vertical() && d.pos == 17.0));\n tool_event(&mut app, ToolEvent::Up { x: 63.0, y: 17.0 }, alt);\n assert_eq!(guides(&app), (vec![], vec![17.0]));\n assert!(app.session.undo());",
|
||
" assert_eq!(guides(&app), (vec![], vec![17.0]));\n assert!(app.session.undo());\n assert_eq!(guides(&app), (vec![50.0], vec![]), \"one undo step\");\n",
|
||
" assert!(app.session.undo());\n assert_eq!(guides(&app), (vec![50.0], vec![]), \"one undo step\");\n\n // ⌥ let go before the release: still vertical, moved along x.",
|
||
" assert_eq!(guides(&app), (vec![50.0], vec![]), \"one undo step\");\n\n // ⌥ let go before the release: still vertical, moved along x.\n let mut app = new_app();",
|
||
" assert_eq!(guides(&app), (vec![63.0], vec![]));\n\n // An ⌥-click turns the guide where it was clicked.\n let mut app = new_app();",
|
||
" assert_eq!(guides(&app), (vec![], vec![44.0]));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/4b1bd6fb6d264f885cb9caa3b8a6578ee527bd7b/crates/ui-egui/src/rulers.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_guide_dropped_on_either_ruler_is_deleted",
|
||
"path": "crates/ui-egui/src/rulers.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked a_guide_dropped_on_either_ruler_is_deleted -- --nocapture",
|
||
"fixture_and_action_excerpt": " let full = Rect::from_min_size(Pos2::ZERO, vec2(400.0, 300.0));\n let rect = Rect::from_min_max(full.min + vec2(RULER, RULER), full.max);\n let xf = ViewXform { rect, zoom: 1.0, center: [128.0, 64.0], flip: false, rotation: 0.0, aspect: 1.0 };\n for (pointer, over) in [(pos2(RULER / 2.0, 150.0), true), (pos2(200.0, RULER / 2.0), true), (pos2(200.0, 150.0), false)] {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 256, \"height\": 128})).unwrap();\n app.run(\"view.newGuide\", json!({\"orientation\": \"horizontal\", \"position\": 30})).unwrap();\n app.guide_drag = Some(GuideDrag { vertical: false, index: Some(0), pos: 64.0, ..Default::default() });\n let mut h = egui_kittest::Harness::builder().with_size(vec2(400.0, 300.0)).build_ui_state(move |ui, app| draw_rulers(app, ui, full, &xf), app);\n h.event(egui::Event::PointerMoved(pointer));\n h.run_steps(1);\n let d = h.state().guide_drag.unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(d.over_ruler, over, \"{pointer:?}\");\n let app = h.state_mut();\n app.guide_drag = None;\n finish_drag(app, d);",
|
||
" assert_eq!(left, if over { vec![] } else { vec![64.0] }, \"{pointer:?}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/4b1bd6fb6d264f885cb9caa3b8a6578ee527bd7b/crates/ui-egui/src/rulers.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-6026",
|
||
"pr": 6026,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked fixed_size_px_is_exactly_the_size -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked fixed_size_selects_exactly_the_entered_size -- --nocapture"
|
||
],
|
||
"expected": "fixed size px is exactly the size; fixed size selects exactly the entered size",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked fixed_size_px_is_exactly_the_size -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked fixed_size_selects_exactly_the_entered_size -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "fixed_size_px_is_exactly_the_size",
|
||
"path": "crates/ui-egui/src/canvas.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked fixed_size_px_is_exactly_the_size -- --nocapture",
|
||
"fixture_and_action_excerpt": " use super::fixed_size_px;\n // Down-right from (10.4, 20.6): 10 × 10 from the closest pixel edges.\n assert_eq!(fixed_size_px([10.4, 20.6], [20.4, 30.6], 10.0, 10.0), [10.0, 21.0, 20.0, 31.0]);\n // Up-left: the far corner is the low one; still exactly the size.\n assert_eq!(fixed_size_px([10.4, 20.6], [-53.6, -11.4], 64.0, 32.0), [-54.0, -11.0, 10.0, 21.0]);\n // 1 × 1 is one pixel, and a fractional size rounds to whole pixels.\n assert_eq!(fixed_size_px([3.5, 3.5], [4.5, 4.5], 1.0, 1.0), [4.0, 4.0, 5.0, 5.0]);\n assert_eq!(fixed_size_px([0.0, 0.0], [2.6, 2.4], 2.6, 2.4), [0.0, 0.0, 3.0, 2.0]);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(fixed_size_px([10.4, 20.6], [20.4, 30.6], 10.0, 10.0), [10.0, 21.0, 20.0, 31.0]);\n // Up-left: the far corner is the low one; still exactly the size.\n assert_eq!(fixed_size_px([10.4, 20.6], [-53.6, -11.4], 64.0, 32.0), [-54.0, -11.0, 10.0, 21.0]);\n // 1 × 1 is one pixel, and a fractional size rounds to whole pixels.",
|
||
" assert_eq!(fixed_size_px([10.4, 20.6], [-53.6, -11.4], 64.0, 32.0), [-54.0, -11.0, 10.0, 21.0]);\n // 1 × 1 is one pixel, and a fractional size rounds to whole pixels.\n assert_eq!(fixed_size_px([3.5, 3.5], [4.5, 4.5], 1.0, 1.0), [4.0, 4.0, 5.0, 5.0]);\n assert_eq!(fixed_size_px([0.0, 0.0], [2.6, 2.4], 2.6, 2.4), [0.0, 0.0, 3.0, 2.0]);",
|
||
" assert_eq!(fixed_size_px([3.5, 3.5], [4.5, 4.5], 1.0, 1.0), [4.0, 4.0, 5.0, 5.0]);\n assert_eq!(fixed_size_px([0.0, 0.0], [2.6, 2.4], 2.6, 2.4), [0.0, 0.0, 3.0, 2.0]);\n }",
|
||
" assert_eq!(fixed_size_px([0.0, 0.0], [2.6, 2.4], 2.6, 2.4), [0.0, 0.0, 3.0, 2.0]);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/248ba660576f4896f69cbb6639353e2f1d295271/crates/ui-egui/src/canvas.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "fixed_size_selects_exactly_the_entered_size",
|
||
"path": "crates/ui-egui/src/marquee_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked fixed_size_selects_exactly_the_entered_size -- --nocapture",
|
||
"fixture_and_action_excerpt": " for tool in [Tool::RectMarquee, Tool::EllipseMarquee] {\n for (w, ht) in [(10, 10), (1, 1), (64, 32)] {\n let mut h = harness(tool);\n let o = &mut h.state_mut().ui.tool_options;\n o.marquee_style = \"fixedSize\".into();\n (o.marquee_width, o.marquee_height) = (w as f32, ht as f32);\n press_at(&mut h, 50.4, 60.6, Modifiers::NONE);\n assert!(readout(&h, w, ht), \"{tool:?} {w} × {ht}: the readout shows the entered size\");\n release_at(&mut h, 90.0, 90.0, Modifiers::NONE);\n assert_eq!(selection(&h), Rect::new(50, 61, 50 + w, 61 + ht), \"{tool:?} {w} × {ht}: dragged\");\n\n // A click: the button goes down and up at one point.",
|
||
"expected_assertions": [
|
||
" assert!(readout(&h, w, ht), \"{tool:?} {w} × {ht}: the readout shows the entered size\");\n release_at(&mut h, 90.0, 90.0, Modifiers::NONE);\n assert_eq!(selection(&h), Rect::new(50, 61, 50 + w, 61 + ht), \"{tool:?} {w} × {ht}: dragged\");\n",
|
||
" assert_eq!(selection(&h), Rect::new(50, 61, 50 + w, 61 + ht), \"{tool:?} {w} × {ht}: dragged\");\n\n // A click: the button goes down and up at one point.\n h.state_mut().run(\"select.deselect\", json!({})).unwrap();",
|
||
" assert_eq!(selection(&h), Rect::new(121, 100, 121 + w, 100 + ht), \"{tool:?} {w} × {ht}: clicked\");\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/248ba660576f4896f69cbb6639353e2f1d295271/crates/ui-egui/src/marquee_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-6236",
|
||
"pr": 6236,
|
||
"subsystem": "Painting",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked shift_alt_right_press_opens_the_hud_not_the_picker -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked quick_selections_shift_alt_right_opens_only_the_selection_menu -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_hud_clamped_under_the_still_pointer_picks_nothing_until_it_moves -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked dragging_over_the_hud_picks_the_foreground_live_and_release_keeps_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked escape_restores_the_starting_colour -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked plain_right_click_still_opens_the_picker_and_alt_drag_still_resizes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shift_alt_right_drag_does_not_resize_the_brush -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_control_channel_opens_and_closes_the_hud -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked hue_strip_mesh_indices_stay_within_its_rows -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pick_at_maps_the_rects_and_ignores_the_gaps -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shift_alt_right_through_the_control_channel_respects_the_erase_preference -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_control_channel_up_closes_the_hud_without_repeating_its_modifiers -- --nocapture"
|
||
],
|
||
"expected": "shift alt right press opens the hud not the picker; quick selections shift alt right opens only the selection menu; a hud clamped under the still pointer picks nothing until it moves; dragging over the hud picks the foreground live and release keeps it; escape restores the starting colour; plain right click still opens the picker and alt drag still resizes; shift alt right drag does not resize the brush; the control channel opens and closes the hud; hue strip mesh indices stay within its rows; pick at maps the rects and ignores the gaps; shift alt right through the control channel respects the erase preference; a control channel up closes the hud without repeating its modifiers",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked shift_alt_right_press_opens_the_hud_not_the_picker -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked quick_selections_shift_alt_right_opens_only_the_selection_menu -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_hud_clamped_under_the_still_pointer_picks_nothing_until_it_moves -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked dragging_over_the_hud_picks_the_foreground_live_and_release_keeps_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked escape_restores_the_starting_colour -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked plain_right_click_still_opens_the_picker_and_alt_drag_still_resizes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shift_alt_right_drag_does_not_resize_the_brush -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_control_channel_opens_and_closes_the_hud -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked hue_strip_mesh_indices_stay_within_its_rows -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked pick_at_maps_the_rects_and_ignores_the_gaps -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shift_alt_right_through_the_control_channel_respects_the_erase_preference -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_control_channel_up_closes_the_hud_without_repeating_its_modifiers -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "shift_alt_right_press_opens_the_hud_not_the_picker",
|
||
"path": "crates/ui-egui/src/color_hud.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked shift_alt_right_press_opens_the_hud_not_the_picker -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n let c = h.state().last_canvas_rect.center();\n h.event(egui::Event::PointerMoved(c));\n h.run_steps(1);\n button(&mut h, c, true, SHIFT_ALT);\n let hud = h.state().ui.color_hud.expect(\"the HUD opened\");\n assert!(hud.hold);\n assert_eq!(hud.start, [0.0, 0.0, 1.0, 1.0], \"seeded from the foreground\");\n assert_eq!(h.state().ui.brush_picker, None, \"the Brush Preset picker stays closed\");\n // The HUD shows under the pointer, on screen.\n let (strip, square) = rects(&h);\n assert!(strip.height() > 100.0 && square.width() > 100.0);",
|
||
"expected_assertions": [
|
||
" assert!(hud.hold);\n assert_eq!(hud.start, [0.0, 0.0, 1.0, 1.0], \"seeded from the foreground\");\n assert_eq!(h.state().ui.brush_picker, None, \"the Brush Preset picker stays closed\");\n // The HUD shows under the pointer, on screen.",
|
||
" assert_eq!(hud.start, [0.0, 0.0, 1.0, 1.0], \"seeded from the foreground\");\n assert_eq!(h.state().ui.brush_picker, None, \"the Brush Preset picker stays closed\");\n // The HUD shows under the pointer, on screen.\n let (strip, square) = rects(&h);",
|
||
" assert_eq!(h.state().ui.brush_picker, None, \"the Brush Preset picker stays closed\");\n // The HUD shows under the pointer, on screen.\n let (strip, square) = rects(&h);\n assert!(strip.height() > 100.0 && square.width() > 100.0);",
|
||
" assert!(strip.height() > 100.0 && square.width() > 100.0);\n assert!(square.right() < h.ctx.content_rect().right());\n // Nothing painted.\n assert!(!h.state().session.journal.iter().any(|(id, _)| id == \"paint.stroke\"));",
|
||
" assert!(square.right() < h.ctx.content_rect().right());\n // Nothing painted.\n assert!(!h.state().session.journal.iter().any(|(id, _)| id == \"paint.stroke\"));\n }",
|
||
" assert!(!h.state().session.journal.iter().any(|(id, _)| id == \"paint.stroke\"));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/color_hud.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "quick_selections_shift_alt_right_opens_only_the_selection_menu",
|
||
"path": "crates/ui-egui/src/color_hud.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked quick_selections_shift_alt_right_opens_only_the_selection_menu -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n h.state_mut().ui.tool = Tool::QuickSelection;\n h.run_steps(1);\n let c = h.state().last_canvas_rect.center();\n h.event(egui::Event::PointerMoved(c));\n h.run_steps(1);\n button(&mut h, c, true, SHIFT_ALT);\n assert_eq!(h.state().ui.color_hud, None, \"no HUD for Quick Selection\");\n assert_eq!(h.state().ui.brush_picker, None, \"and no Brush Preset picker\");\n button(&mut h, c, false, SHIFT_ALT);\n assert_eq!(h.state().ui.color_hud, None, \"the release does not open it either\");\n assert!(h.state().ui.canvas_tool_menu.is_some(), \"the selection menu opens, once\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().ui.color_hud, None, \"no HUD for Quick Selection\");\n assert_eq!(h.state().ui.brush_picker, None, \"and no Brush Preset picker\");\n button(&mut h, c, false, SHIFT_ALT);\n assert_eq!(h.state().ui.color_hud, None, \"the release does not open it either\");",
|
||
" assert_eq!(h.state().ui.brush_picker, None, \"and no Brush Preset picker\");\n button(&mut h, c, false, SHIFT_ALT);\n assert_eq!(h.state().ui.color_hud, None, \"the release does not open it either\");\n assert!(h.state().ui.canvas_tool_menu.is_some(), \"the selection menu opens, once\");",
|
||
" assert_eq!(h.state().ui.color_hud, None, \"the release does not open it either\");\n assert!(h.state().ui.canvas_tool_menu.is_some(), \"the selection menu opens, once\");\n }",
|
||
" assert!(h.state().ui.canvas_tool_menu.is_some(), \"the selection menu opens, once\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/color_hud.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_hud_clamped_under_the_still_pointer_picks_nothing_until_it_moves",
|
||
"path": "crates/ui-egui/src/color_hud.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked a_hud_clamped_under_the_still_pointer_picks_nothing_until_it_moves -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness_size(1200, 800);\n let near = egui::pos2(h.state().last_canvas_rect.max.x - 10.0, h.state().last_canvas_rect.max.y - 10.0);\n h.event(egui::Event::PointerMoved(near));\n h.run_steps(1);\n button(&mut h, near, true, SHIFT_ALT);\n assert!(h.state().ui.color_hud.is_some_and(|hud| hud.just_opened), \"the HUD opened under the pointer\");\n let (_strip, square) = rects(&h);\n assert!(square.contains(near), \"the clamped HUD sits under the pointer: {near:?} in {square:?}\");\n h.run_steps(4);\n assert_eq!(foreground(&h), [0.0, 0.0, 1.0, 1.0], \"the stationary opening pointer picks nothing\");\n // Moving inside the HUD now picks, as during any other gesture.\n let to = square.min + vec2(1.0, square.height() - 1.0);",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.color_hud.is_some_and(|hud| hud.just_opened), \"the HUD opened under the pointer\");\n let (_strip, square) = rects(&h);\n assert!(square.contains(near), \"the clamped HUD sits under the pointer: {near:?} in {square:?}\");\n h.run_steps(4);",
|
||
" assert!(square.contains(near), \"the clamped HUD sits under the pointer: {near:?} in {square:?}\");\n h.run_steps(4);\n assert_eq!(foreground(&h), [0.0, 0.0, 1.0, 1.0], \"the stationary opening pointer picks nothing\");\n // Moving inside the HUD now picks, as during any other gesture.",
|
||
" assert_eq!(foreground(&h), [0.0, 0.0, 1.0, 1.0], \"the stationary opening pointer picks nothing\");\n // Moving inside the HUD now picks, as during any other gesture.\n let to = square.min + vec2(1.0, square.height() - 1.0);\n h.event(egui::Event::PointerMoved(to));",
|
||
" assert_ne!(foreground(&h), [0.0, 0.0, 1.0, 1.0], \"the move picks\");\n button(&mut h, to, false, SHIFT_ALT);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/color_hud.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "dragging_over_the_hud_picks_the_foreground_live_and_release_keeps_it",
|
||
"path": "crates/ui-egui/src/color_hud.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked dragging_over_the_hud_picks_the_foreground_live_and_release_keeps_it -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n let c = h.state().last_canvas_rect.center();\n h.event(egui::Event::PointerMoved(c));\n h.run_steps(1);\n button(&mut h, c, true, SHIFT_ALT);\n let j0 = h.state().session.journal.len();\n let (_strip, square) = rects(&h);\n // Top-right of the square: full saturation, full value at the current hue (blue).\n let pick = egui::pos2(square.max.x - 1.0, square.min.y + 1.0);\n h.event(egui::Event::PointerMoved(pick));\n h.run_steps(2);\n let fg = foreground(&h);",
|
||
"expected_assertions": [
|
||
" assert!(fg[2] > 0.9 && fg[0] < 0.1 && fg[1] < 0.1, \"still blue at the top of the square: {fg:?}\");\n // Bottom-left: value 0 → black.\n h.event(egui::Event::PointerMoved(square.min + vec2(1.0, square.height() - 1.0)));\n h.run_steps(2);",
|
||
" assert!(fg[..3].iter().all(|v| *v < 0.02), \"black at the bottom: {fg:?}\");\n // The hue strip: its middle is cyan-ish (180°), at the square's current s/v.\n let (strip, _) = rects(&h);\n h.event(egui::Event::PointerMoved(egui::pos2(square.max.x - 1.0, square.min.y + 1.0)));",
|
||
" assert!(fg[2] > 0.5 && fg[0] < 0.5, \"hue moved off red: {fg:?}\");\n // The gesture's edits share one coalesce key (one history step, like the brush HUD).\n let sets: Vec<&serde_json::Value> = h.state().session.journal[j0..].iter().filter(|(id, _)| id == \"tools.setColors\").map(|(_, p)| p).collect();\n assert!(!sets.is_empty(), \"the picks are journaled\");",
|
||
" assert!(!sets.is_empty(), \"the picks are journaled\");\n let keys: Vec<&str> = sets.iter().map(|p| p[\"coalesce\"].as_str().unwrap()).collect();\n assert!(keys.windows(2).all(|w| w[0] == w[1]), \"one gesture, one key: {keys:?}\");\n // Releasing the right button closes the HUD and keeps the colour.",
|
||
" assert!(keys.windows(2).all(|w| w[0] == w[1]), \"one gesture, one key: {keys:?}\");\n // Releasing the right button closes the HUD and keeps the colour.\n let kept = foreground(&h);\n button(&mut h, strip.center(), false, SHIFT_ALT);",
|
||
" assert_eq!(h.state().ui.color_hud, None);\n assert_eq!(foreground(&h), kept);\n }",
|
||
" assert_eq!(foreground(&h), kept);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/color_hud.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "escape_restores_the_starting_colour",
|
||
"path": "crates/ui-egui/src/color_hud.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked escape_restores_the_starting_colour -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n let c = h.state().last_canvas_rect.center();\n h.event(egui::Event::PointerMoved(c));\n h.run_steps(1);\n button(&mut h, c, true, SHIFT_ALT);\n let (_strip, square) = rects(&h);\n h.event(egui::Event::PointerMoved(square.center()));\n h.run_steps(2);\n assert_ne!(foreground(&h), [0.0, 0.0, 1.0, 1.0], \"the pick is live\");\n h.key_press(egui::Key::Escape);\n h.run_steps(2);\n assert_eq!(h.state().ui.color_hud, None);",
|
||
"expected_assertions": [
|
||
" assert_ne!(foreground(&h), [0.0, 0.0, 1.0, 1.0], \"the pick is live\");\n h.key_press(egui::Key::Escape);\n h.run_steps(2);\n assert_eq!(h.state().ui.color_hud, None);",
|
||
" assert_eq!(h.state().ui.color_hud, None);\n assert_eq!(foreground(&h), [0.0, 0.0, 1.0, 1.0], \"Escape restores the colour\");\n }",
|
||
" assert_eq!(foreground(&h), [0.0, 0.0, 1.0, 1.0], \"Escape restores the colour\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/color_hud.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "plain_right_click_still_opens_the_picker_and_alt_drag_still_resizes",
|
||
"path": "crates/ui-egui/src/color_hud.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked plain_right_click_still_opens_the_picker_and_alt_drag_still_resizes -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n let c = h.state().last_canvas_rect.center();\n h.event(egui::Event::PointerMoved(c));\n h.run_steps(1);\n button(&mut h, c, true, Modifiers::NONE);\n button(&mut h, c, false, Modifiers::NONE);\n assert!(h.state().ui.brush_picker.is_some() && h.state().ui.color_hud.is_none());\n // Alt+right-drag (no Shift) resizes the brush, as before.\n h.state_mut().ui.brush_picker = None;\n h.run_steps(1);\n h.event(egui::Event::ModifiersChanged(Modifiers::ALT));\n h.event(egui::Event::PointerMoved(c));",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.brush_picker.is_some() && h.state().ui.color_hud.is_none());\n // Alt+right-drag (no Shift) resizes the brush, as before.\n h.state_mut().ui.brush_picker = None;\n h.run_steps(1);",
|
||
" assert!(h.state().brush_resize.is_some_and(|r| r.secondary), \"Alt+right still resizes\");\n assert!(h.state().ui.color_hud.is_none());\n button(&mut h, c + vec2(40.0, 0.0), false, Modifiers::ALT);\n }",
|
||
" assert!(h.state().ui.color_hud.is_none());\n button(&mut h, c + vec2(40.0, 0.0), false, Modifiers::ALT);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/color_hud.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "shift_alt_right_drag_does_not_resize_the_brush",
|
||
"path": "crates/ui-egui/src/color_hud.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked shift_alt_right_drag_does_not_resize_the_brush -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness();\n let size0 = h.state().session.tools.brush.size;\n let c = h.state().last_canvas_rect.center();\n h.event(egui::Event::PointerMoved(c));\n h.run_steps(1);\n button(&mut h, c, true, SHIFT_ALT);\n for k in 1..=6 {\n h.event(egui::Event::PointerMoved(c + vec2(20.0 * k as f32, 0.0)));\n h.run_steps(1);\n }\n assert!(h.state().brush_resize.is_none(), \"the HUD gesture is not a resize\");\n assert_eq!(h.state().session.tools.brush.size, size0);",
|
||
"expected_assertions": [
|
||
" assert!(h.state().brush_resize.is_none(), \"the HUD gesture is not a resize\");\n assert_eq!(h.state().session.tools.brush.size, size0);\n button(&mut h, c + vec2(120.0, 0.0), false, SHIFT_ALT);\n }",
|
||
" assert_eq!(h.state().session.tools.brush.size, size0);\n button(&mut h, c + vec2(120.0, 0.0), false, SHIFT_ALT);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/color_hud.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_control_channel_opens_and_closes_the_hud",
|
||
"path": "crates/ui-egui/src/color_hud.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_control_channel_opens_and_closes_the_hud -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), Default::default());\n app.run(\"file.new\", json!({\"width\": 100, \"height\": 100})).unwrap();\n app.run(\"tools.setColors\", json!({\"foreground\": \"#ff0000\"})).unwrap();\n app.ui.tool = Tool::Brush;\n let ctx = egui::Context::default();\n let (req, _rx) = crate::control::ControlRequest::new(\n \"ui.pointer\",\n json!({\"button\": \"right\", \"shift\": true, \"alt\": true, \"events\": [{\"kind\": \"down\", \"x\": 50, \"y\": 50}, {\"kind\": \"up\", \"x\": 50, \"y\": 50}]}),\n );\n let _ = crate::control::handle(&mut app, &ctx, &req);\n assert!(app.ui.color_hud.is_none(), \"the Up event closed it\");\n assert!(app.ui.brush_picker.is_none(), \"the picker stayed closed\");",
|
||
"expected_assertions": [
|
||
" assert!(app.ui.color_hud.is_none(), \"the Up event closed it\");\n assert!(app.ui.brush_picker.is_none(), \"the picker stayed closed\");\n // A down without its up leaves the HUD open for the next frame's edits.\n let (req, _rx) = crate::control::ControlRequest::new(",
|
||
" assert!(app.ui.brush_picker.is_none(), \"the picker stayed closed\");\n // A down without its up leaves the HUD open for the next frame's edits.\n let (req, _rx) = crate::control::ControlRequest::new(\n \"ui.pointer\",",
|
||
" assert!(app.ui.color_hud.is_some_and(|h| !h.hold));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/color_hud.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "hue_strip_mesh_indices_stay_within_its_rows",
|
||
"path": "crates/ui-egui/src/color_hud.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked hue_strip_mesh_indices_stay_within_its_rows -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mesh = hue_strip_mesh(Rect::from_min_size(Pos2::ZERO, vec2(HUE_W, SQUARE)));\n let rows = 13; // n + 1 rows, two vertices each\n assert_eq!(mesh.vertices.len(), 2 * rows);\n assert_eq!(mesh.indices.len(), 3 * 2 * (rows - 1), \"two triangles per band\");\n for (j, tri) in mesh.indices.chunks(3).enumerate() {\n // Band k = j/2 joins rows k and k+1: vertices 2k..=2k+3, nothing further ahead.\n let k = j / 2;\n for &i in tri {\n assert!((2 * k) as u32 <= i && i <= (2 * k + 3) as u32, \"band {k} uses index {i}: {tri:?}\");\n assert!((i as usize) < mesh.vertices.len(), \"index {i} out of range\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(mesh.vertices.len(), 2 * rows);\n assert_eq!(mesh.indices.len(), 3 * 2 * (rows - 1), \"two triangles per band\");\n for (j, tri) in mesh.indices.chunks(3).enumerate() {\n // Band k = j/2 joins rows k and k+1: vertices 2k..=2k+3, nothing further ahead.",
|
||
" assert_eq!(mesh.indices.len(), 3 * 2 * (rows - 1), \"two triangles per band\");\n for (j, tri) in mesh.indices.chunks(3).enumerate() {\n // Band k = j/2 joins rows k and k+1: vertices 2k..=2k+3, nothing further ahead.\n let k = j / 2;",
|
||
" assert!((2 * k) as u32 <= i && i <= (2 * k + 3) as u32, \"band {k} uses index {i}: {tri:?}\");\n assert!((i as usize) < mesh.vertices.len(), \"index {i} out of range\");\n }\n }",
|
||
" assert!((i as usize) < mesh.vertices.len(), \"index {i} out of range\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/color_hud.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "pick_at_maps_the_rects_and_ignores_the_gaps",
|
||
"path": "crates/ui-egui/src/color_hud.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked pick_at_maps_the_rects_and_ignores_the_gaps -- --nocapture",
|
||
"fixture_and_action_excerpt": " let strip = Rect::from_min_size(Pos2::new(0.0, 0.0), vec2(HUE_W, SQUARE));\n let square = Rect::from_min_max(vec2(HUE_W + GAP, 0.0).to_pos2(), Pos2::new(HUE_W + GAP + SQUARE, SQUARE));\n assert_eq!(pick_at([120.0, 0.5, 0.5], strip, square, square.center()), Some([120.0, 0.5, 0.5]));\n let p = pick_at([120.0, 0.5, 0.5], strip, square, square.left_top() + vec2(1.0, 1.0)).expect(\"in the square\");\n assert!(p[0] == 120.0 && p[1] < 0.02 && p[2] > 0.98, \"top-left is saturated and bright: {p:?}\");\n assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, strip.center()), Some([180.0, 0.5, 0.5]));\n assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, Pos2::new(HUE_W + GAP / 2.0, 10.0)), None, \"the gap picks nothing\");\n assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, Pos2::new(1e9, -1e9)), None);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(pick_at([120.0, 0.5, 0.5], strip, square, square.center()), Some([120.0, 0.5, 0.5]));\n let p = pick_at([120.0, 0.5, 0.5], strip, square, square.left_top() + vec2(1.0, 1.0)).expect(\"in the square\");\n assert!(p[0] == 120.0 && p[1] < 0.02 && p[2] > 0.98, \"top-left is saturated and bright: {p:?}\");\n assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, strip.center()), Some([180.0, 0.5, 0.5]));",
|
||
" assert!(p[0] == 120.0 && p[1] < 0.02 && p[2] > 0.98, \"top-left is saturated and bright: {p:?}\");\n assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, strip.center()), Some([180.0, 0.5, 0.5]));\n assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, Pos2::new(HUE_W + GAP / 2.0, 10.0)), None, \"the gap picks nothing\");\n assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, Pos2::new(1e9, -1e9)), None);",
|
||
" assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, strip.center()), Some([180.0, 0.5, 0.5]));\n assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, Pos2::new(HUE_W + GAP / 2.0, 10.0)), None, \"the gap picks nothing\");\n assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, Pos2::new(1e9, -1e9)), None);\n }",
|
||
" assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, Pos2::new(HUE_W + GAP / 2.0, 10.0)), None, \"the gap picks nothing\");\n assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, Pos2::new(1e9, -1e9)), None);\n }",
|
||
" assert_eq!(pick_at([0.0, 0.5, 0.5], strip, square, Pos2::new(1e9, -1e9)), None);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/color_hud.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "shift_alt_right_through_the_control_channel_respects_the_erase_preference",
|
||
"path": "crates/ui-egui/src/paint_mouse.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked shift_alt_right_through_the_control_channel_respects_the_erase_preference -- --nocapture",
|
||
"fixture_and_action_excerpt": " // As on the canvas, with the right-erase preference the erase stroke wins over the HUD\n // for Brush/Eraser; without it, Shift+Alt+right opens the HUD (#6098).\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 120, \"height\": 80})).unwrap();\n app.ui.tool = Tool::Brush;\n let shift_alt = egui::Modifiers { shift: true, alt: true, ..Default::default() };\n app.run(\"prefs.set\", json!({\"path\": \"tools.rightClickWithPaintingTools\", \"value\": \"erase\"})).unwrap();\n assert!(pointer_secondary(&mut app, &egui::Context::default(), true, shift_alt, [10.0, 10.0]), \"the events reach the tool\");\n assert!(app.ui.color_hud.is_none(), \"no HUD with the erase preference\");\n assert!(app.secondary_erase, \"the down arms the erasing stroke\");\n pointer_secondary(&mut app, &egui::Context::default(), false, shift_alt, [10.0, 10.0]);\n // With the default preference the same gesture opens the HUD instead.",
|
||
"expected_assertions": [
|
||
" assert!(pointer_secondary(&mut app, &egui::Context::default(), true, shift_alt, [10.0, 10.0]), \"the events reach the tool\");\n assert!(app.ui.color_hud.is_none(), \"no HUD with the erase preference\");\n assert!(app.secondary_erase, \"the down arms the erasing stroke\");\n pointer_secondary(&mut app, &egui::Context::default(), false, shift_alt, [10.0, 10.0]);",
|
||
" assert!(app.ui.color_hud.is_none(), \"no HUD with the erase preference\");\n assert!(app.secondary_erase, \"the down arms the erasing stroke\");\n pointer_secondary(&mut app, &egui::Context::default(), false, shift_alt, [10.0, 10.0]);\n // With the default preference the same gesture opens the HUD instead.",
|
||
" assert!(app.secondary_erase, \"the down arms the erasing stroke\");\n pointer_secondary(&mut app, &egui::Context::default(), false, shift_alt, [10.0, 10.0]);\n // With the default preference the same gesture opens the HUD instead.\n app.run(\"prefs.set\", json!({\"path\": \"tools.rightClickWithPaintingTools\", \"value\": \"brushPicker\"})).unwrap();",
|
||
" assert!(!pointer_secondary(&mut app, &egui::Context::default(), true, shift_alt, [10.0, 10.0]));\n assert!(app.ui.color_hud.is_some_and(|h| !h.hold), \"the control-channel HUD opened\");\n }",
|
||
" assert!(app.ui.color_hud.is_some_and(|h| !h.hold), \"the control-channel HUD opened\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/paint_mouse.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_control_channel_up_closes_the_hud_without_repeating_its_modifiers",
|
||
"path": "crates/ui-egui/src/paint_mouse.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked a_control_channel_up_closes_the_hud_without_repeating_its_modifiers -- --nocapture",
|
||
"fixture_and_action_excerpt": " // Each control-channel request carries its own modifiers, so an Up sent after the keys\n // are released arrives without Shift+Alt: it must still close the HUD it opened, or the\n // HUD stays up and keeps picking from the hover (#6098 review).\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 120, \"height\": 80})).unwrap();\n app.ui.tool = Tool::Brush;\n let shift_alt = egui::Modifiers { shift: true, alt: true, ..Default::default() };\n assert!(!pointer_secondary(&mut app, &egui::Context::default(), true, shift_alt, [10.0, 10.0]));\n assert!(app.ui.color_hud.is_some_and(|h| !h.hold), \"the control-channel HUD opened\");\n assert!(!pointer_secondary(&mut app, &egui::Context::default(), false, egui::Modifiers::NONE, [10.0, 10.0]));\n assert!(app.ui.color_hud.is_none(), \"the Up closes it whatever the modifiers say\");\n // A real-mouse HUD belongs to the canvas gesture and waits for its own button release.",
|
||
"expected_assertions": [
|
||
" assert!(!pointer_secondary(&mut app, &egui::Context::default(), true, shift_alt, [10.0, 10.0]));\n assert!(app.ui.color_hud.is_some_and(|h| !h.hold), \"the control-channel HUD opened\");\n assert!(!pointer_secondary(&mut app, &egui::Context::default(), false, egui::Modifiers::NONE, [10.0, 10.0]));\n assert!(app.ui.color_hud.is_none(), \"the Up closes it whatever the modifiers say\");",
|
||
" assert!(app.ui.color_hud.is_some_and(|h| !h.hold), \"the control-channel HUD opened\");\n assert!(!pointer_secondary(&mut app, &egui::Context::default(), false, egui::Modifiers::NONE, [10.0, 10.0]));\n assert!(app.ui.color_hud.is_none(), \"the Up closes it whatever the modifiers say\");\n // A real-mouse HUD belongs to the canvas gesture and waits for its own button release.",
|
||
" assert!(!pointer_secondary(&mut app, &egui::Context::default(), false, egui::Modifiers::NONE, [10.0, 10.0]));\n assert!(app.ui.color_hud.is_none(), \"the Up closes it whatever the modifiers say\");\n // A real-mouse HUD belongs to the canvas gesture and waits for its own button release.\n crate::color_hud::open(&mut app, [10.0, 10.0], true);",
|
||
" assert!(app.ui.color_hud.is_none(), \"the Up closes it whatever the modifiers say\");\n // A real-mouse HUD belongs to the canvas gesture and waits for its own button release.\n crate::color_hud::open(&mut app, [10.0, 10.0], true);\n pointer_secondary(&mut app, &egui::Context::default(), false, egui::Modifiers::NONE, [10.0, 10.0]);",
|
||
" assert!(app.ui.color_hud.is_some_and(|h| h.hold), \"a held HUD is left to the canvas\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ce546dd4b5451a17b843ef1e129bdb40fbfe3160/crates/ui-egui/src/paint_mouse.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-6510",
|
||
"pr": 6510,
|
||
"subsystem": "Actions and automation",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-automation --locked canonical_windows_prefixes_match_without_ambient_resolution -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked windows_root_case_variants_keep_io_inside_the_grant -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked unix_root_prefixes_remain_case_sensitive -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked configured_parent_components_accept_resolved_absolute_paths -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked relative_configured_root_accepts_resolved_absolute_paths -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked trusted_root_names_are_not_validated_as_relative_request_names -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked linked_root_accepts_both_spellings_and_new_nested_exports -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked root_alias_tests_work_with_an_aliased_windows_temp -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked ungranted_absolute_aliases_and_link_escapes_are_refused -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked retargeting_root_alias_does_not_regrant_the_held_authority -- --nocapture"
|
||
],
|
||
"expected": "canonical windows prefixes match without ambient resolution; windows root case variants keep io inside the grant; unix root prefixes remain case sensitive; configured parent components accept resolved absolute paths; relative configured root accepts resolved absolute paths; trusted root names are not validated as relative request names; linked root accepts both spellings and new nested exports; root alias tests work with an aliased windows temp; ungranted absolute aliases and link escapes are refused; retargeting root alias does not regrant the held authority",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-automation --locked canonical_windows_prefixes_match_without_ambient_resolution -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked windows_root_case_variants_keep_io_inside_the_grant -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked unix_root_prefixes_remain_case_sensitive -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked configured_parent_components_accept_resolved_absolute_paths -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked relative_configured_root_accepts_resolved_absolute_paths -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked trusted_root_names_are_not_validated_as_relative_request_names -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked linked_root_accepts_both_spellings_and_new_nested_exports -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked root_alias_tests_work_with_an_aliased_windows_temp -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked ungranted_absolute_aliases_and_link_escapes_are_refused -- --nocapture",
|
||
"cargo test -p photocraft-automation --locked retargeting_root_alias_does_not_regrant_the_held_authority -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "canonical_windows_prefixes_match_without_ambient_resolution",
|
||
"path": "crates/automation/src/workspace/tests.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked canonical_windows_prefixes_match_without_ambient_resolution -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (request, root) in [\n (r\"c:\\root\\new.bin\", r\"\\\\?\\C:\\root\"),\n (r\"\\\\?\\C:\\root\\new.bin\", r\"C:\\root\"),\n (r\"\\\\server\\share\\root\\new.bin\", r\"\\\\?\\UNC\\SERVER\\SHARE\\root\"),\n (r\"c:\\ROOT\\new.bin\", r\"\\\\?\\C:\\root\"),\n (r\"\\\\?\\C:\\ROOT\\new.bin\", r\"c:\\root\"),\n (r\"\\\\server\\share\\ROOT\\new.bin\", r\"\\\\?\\UNC\\SERVER\\SHARE\\root\"),\n ] {\n let remaining = path_beneath_root(Path::new(request), Path::new(root)).unwrap();\n assert_eq!(remaining.as_path(), Path::new(\"new.bin\"));\n }\n for request in [r\"C:\\root-sibling\\new.bin\", r\"D:\\root\\new.bin\", r\"\\\\.\\C:\\root\\new.bin\", r\"\\\\other\\share\\root\\new.bin\"] {",
|
||
"expected_assertions": [
|
||
" assert_eq!(remaining.as_path(), Path::new(\"new.bin\"));\n }\n for request in [r\"C:\\root-sibling\\new.bin\", r\"D:\\root\\new.bin\", r\"\\\\.\\C:\\root\\new.bin\", r\"\\\\other\\share\\root\\new.bin\"] {\n assert!(path_beneath_root(Path::new(request), Path::new(r\"\\\\?\\C:\\root\")).is_none());",
|
||
" assert!(path_beneath_root(Path::new(request), Path::new(r\"\\\\?\\C:\\root\")).is_none());\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bb0a5e67474d36ae08d565251edb1ae780dd044/crates/automation/src/workspace/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "windows_root_case_variants_keep_io_inside_the_grant",
|
||
"path": "crates/automation/src/workspace/tests.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked windows_root_case_variants_keep_io_inside_the_grant -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (inside, outside, workspace) = roots(\"root-case\");\n let configured = PathBuf::from(inside.to_string_lossy().to_ascii_uppercase());\n let canonical = PathBuf::from(std::fs::canonicalize(&inside).unwrap().to_string_lossy().to_ascii_uppercase());\n for spelling in [&configured, &canonical] {\n let path = spelling.join(\"new.bin\");\n workspace.write(&path.to_string_lossy(), b\"inside\").unwrap();\n assert_eq!(workspace.read(&path.to_string_lossy()).unwrap(), b\"inside\");\n assert!(workspace.write(&spelling.join(\"..\").join(\"outside\").join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());\n }\n assert_eq!(std::fs::read(inside.join(\"new.bin\")).unwrap(), b\"inside\");\n assert!(workspace.write(&configured.with_file_name(\"INSIDE-SIBLING\").join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!outside.join(\"blocked.bin\").exists());",
|
||
"expected_assertions": [
|
||
" assert_eq!(workspace.read(&path.to_string_lossy()).unwrap(), b\"inside\");\n assert!(workspace.write(&spelling.join(\"..\").join(\"outside\").join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());\n }\n assert_eq!(std::fs::read(inside.join(\"new.bin\")).unwrap(), b\"inside\");",
|
||
" assert!(workspace.write(&spelling.join(\"..\").join(\"outside\").join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());\n }\n assert_eq!(std::fs::read(inside.join(\"new.bin\")).unwrap(), b\"inside\");\n assert!(workspace.write(&configured.with_file_name(\"INSIDE-SIBLING\").join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());",
|
||
" assert_eq!(std::fs::read(inside.join(\"new.bin\")).unwrap(), b\"inside\");\n assert!(workspace.write(&configured.with_file_name(\"INSIDE-SIBLING\").join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!outside.join(\"blocked.bin\").exists());\n}",
|
||
" assert!(workspace.write(&configured.with_file_name(\"INSIDE-SIBLING\").join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!outside.join(\"blocked.bin\").exists());\n}",
|
||
" assert!(!outside.join(\"blocked.bin\").exists());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bb0a5e67474d36ae08d565251edb1ae780dd044/crates/automation/src/workspace/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "unix_root_prefixes_remain_case_sensitive",
|
||
"path": "crates/automation/src/workspace/tests.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked unix_root_prefixes_remain_case_sensitive -- --nocapture",
|
||
"fixture_and_action_excerpt": " assert!(path_beneath_root(Path::new(\"/Root/new.bin\"), Path::new(\"/root\")).is_none());\n}",
|
||
"expected_assertions": [
|
||
" assert!(path_beneath_root(Path::new(\"/Root/new.bin\"), Path::new(\"/root\")).is_none());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bb0a5e67474d36ae08d565251edb1ae780dd044/crates/automation/src/workspace/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "configured_parent_components_accept_resolved_absolute_paths",
|
||
"path": "crates/automation/src/workspace/tests.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked configured_parent_components_accept_resolved_absolute_paths -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (inside, outside, _) = roots(\"resolved-parent-root\");\n let configured = inside.join(\"..\").join(\"inside\");\n let workspace = AuthorizedWorkspace::new(Some(&configured), Some(&configured)).unwrap();\n let resolved = std::fs::canonicalize(&inside).unwrap();\n workspace.write(&resolved.join(\"new.bin\").to_string_lossy(), b\"new\").unwrap();\n assert_eq!(workspace.read(&resolved.join(\"new.bin\").to_string_lossy()).unwrap(), b\"new\");\n workspace.write(&configured.join(\"launch-spelling.bin\").to_string_lossy(), b\"trusted prefix\").unwrap();\n assert_eq!(workspace.read(&configured.join(\"launch-spelling.bin\").to_string_lossy()).unwrap(), b\"trusted prefix\");\n assert_eq!(workspace.read(&resolved.join(\"launch-spelling.bin\").to_string_lossy()).unwrap(), b\"trusted prefix\");\n assert!(workspace.write(&configured.join(\"..\").join(\"outside/escaped.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!outside.join(\"escaped.bin\").exists());\n assert!(workspace.write(&outside.join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());",
|
||
"expected_assertions": [
|
||
" assert_eq!(workspace.read(&resolved.join(\"new.bin\").to_string_lossy()).unwrap(), b\"new\");\n workspace.write(&configured.join(\"launch-spelling.bin\").to_string_lossy(), b\"trusted prefix\").unwrap();\n assert_eq!(workspace.read(&configured.join(\"launch-spelling.bin\").to_string_lossy()).unwrap(), b\"trusted prefix\");\n assert_eq!(workspace.read(&resolved.join(\"launch-spelling.bin\").to_string_lossy()).unwrap(), b\"trusted prefix\");",
|
||
" assert_eq!(workspace.read(&configured.join(\"launch-spelling.bin\").to_string_lossy()).unwrap(), b\"trusted prefix\");\n assert_eq!(workspace.read(&resolved.join(\"launch-spelling.bin\").to_string_lossy()).unwrap(), b\"trusted prefix\");\n assert!(workspace.write(&configured.join(\"..\").join(\"outside/escaped.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!outside.join(\"escaped.bin\").exists());",
|
||
" assert_eq!(workspace.read(&resolved.join(\"launch-spelling.bin\").to_string_lossy()).unwrap(), b\"trusted prefix\");\n assert!(workspace.write(&configured.join(\"..\").join(\"outside/escaped.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!outside.join(\"escaped.bin\").exists());\n assert!(workspace.write(&outside.join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());",
|
||
" assert!(workspace.write(&configured.join(\"..\").join(\"outside/escaped.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!outside.join(\"escaped.bin\").exists());\n assert!(workspace.write(&outside.join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!outside.join(\"blocked.bin\").exists());",
|
||
" assert!(!outside.join(\"escaped.bin\").exists());\n assert!(workspace.write(&outside.join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!outside.join(\"blocked.bin\").exists());\n}",
|
||
" assert!(workspace.write(&outside.join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!outside.join(\"blocked.bin\").exists());\n}",
|
||
" assert!(!outside.join(\"blocked.bin\").exists());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bb0a5e67474d36ae08d565251edb1ae780dd044/crates/automation/src/workspace/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "relative_configured_root_accepts_resolved_absolute_paths",
|
||
"path": "crates/automation/src/workspace/tests.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked relative_configured_root_accepts_resolved_absolute_paths -- --nocapture",
|
||
"fixture_and_action_excerpt": " let relative = PathBuf::from(\"target\").join(format!(\"automation-relative-root-{}\", std::process::id()));\n std::fs::create_dir_all(&relative).unwrap();\n let workspace = AuthorizedWorkspace::new(Some(&relative), Some(&relative)).unwrap();\n let resolved = std::fs::canonicalize(&relative).unwrap();\n workspace.write(&resolved.join(\"new.bin\").to_string_lossy(), b\"relative\").unwrap();\n assert_eq!(workspace.read(&resolved.join(\"new.bin\").to_string_lossy()).unwrap(), b\"relative\");\n std::fs::remove_file(resolved.join(\"new.bin\")).unwrap();\n drop(workspace);\n std::fs::remove_dir(resolved).unwrap();\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(workspace.read(&resolved.join(\"new.bin\").to_string_lossy()).unwrap(), b\"relative\");\n std::fs::remove_file(resolved.join(\"new.bin\")).unwrap();\n drop(workspace);\n std::fs::remove_dir(resolved).unwrap();"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bb0a5e67474d36ae08d565251edb1ae780dd044/crates/automation/src/workspace/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "trusted_root_names_are_not_validated_as_relative_request_names",
|
||
"path": "crates/automation/src/workspace/tests.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked trusted_root_names_are_not_validated_as_relative_request_names -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (inside, outside, _) = roots(\"trusted-root-names\");\n let root = inside.join(\"aux\");\n std::fs::create_dir(&root).unwrap();\n let alias = outside.join(\"CON\");\n link_directory(&root, &alias);\n let workspace = AuthorizedWorkspace::new(Some(&alias), Some(&alias)).unwrap();\n for spelling in [&root, &alias] {\n workspace.write(&spelling.join(\"new.bin\").to_string_lossy(), b\"trusted\").unwrap();\n assert_eq!(workspace.read(&spelling.join(\"new.bin\").to_string_lossy()).unwrap(), b\"trusted\");\n assert!(workspace.write(&spelling.join(\"NUL\").to_string_lossy(), b\"no\").is_err());\n }\n assert!(!root.join(\"NUL\").exists());",
|
||
"expected_assertions": [
|
||
" assert_eq!(workspace.read(&spelling.join(\"new.bin\").to_string_lossy()).unwrap(), b\"trusted\");\n assert!(workspace.write(&spelling.join(\"NUL\").to_string_lossy(), b\"no\").is_err());\n }\n assert!(!root.join(\"NUL\").exists());",
|
||
" assert!(workspace.write(&spelling.join(\"NUL\").to_string_lossy(), b\"no\").is_err());\n }\n assert!(!root.join(\"NUL\").exists());\n remove_directory_link(&alias);",
|
||
" assert!(!root.join(\"NUL\").exists());\n remove_directory_link(&alias);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bb0a5e67474d36ae08d565251edb1ae780dd044/crates/automation/src/workspace/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "linked_root_accepts_both_spellings_and_new_nested_exports",
|
||
"path": "crates/automation/src/workspace/tests.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked linked_root_accepts_both_spellings_and_new_nested_exports -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (inside, outside, _) = roots(\"linked-root\");\n let link = outside.join(\"root-link\");\n link_directory(&inside, &link);\n let workspace = AuthorizedWorkspace::new(Some(&link), Some(&link)).unwrap();\n let resolved = std::fs::canonicalize(&inside).unwrap();\n for (i, spelling) in [resolved, link.clone()].iter().enumerate() {\n let name = format!(\"new-{i}.bin\");\n workspace.write(&spelling.join(&name).to_string_lossy(), b\"new\").unwrap();\n assert_eq!(workspace.read(&spelling.join(&name).to_string_lossy()).unwrap(), b\"new\");\n assert_eq!(workspace.read(&name).unwrap(), b\"new\");\n let mut export = workspace.export_sequence(&spelling.join(format!(\"frames-{i}\")).join(\"nested\").to_string_lossy()).unwrap();\n export.write(\"frame.png\", b\"frame\").unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(workspace.read(&spelling.join(&name).to_string_lossy()).unwrap(), b\"new\");\n assert_eq!(workspace.read(&name).unwrap(), b\"new\");\n let mut export = workspace.export_sequence(&spelling.join(format!(\"frames-{i}\")).join(\"nested\").to_string_lossy()).unwrap();\n export.write(\"frame.png\", b\"frame\").unwrap();",
|
||
" assert_eq!(workspace.read(&name).unwrap(), b\"new\");\n let mut export = workspace.export_sequence(&spelling.join(format!(\"frames-{i}\")).join(\"nested\").to_string_lossy()).unwrap();\n export.write(\"frame.png\", b\"frame\").unwrap();\n export.commit();",
|
||
" assert_eq!(std::fs::read(inside.join(format!(\"frames-{i}/nested/frame.png\"))).unwrap(), b\"frame\");\n }\n remove_directory_link(&link);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bb0a5e67474d36ae08d565251edb1ae780dd044/crates/automation/src/workspace/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "root_alias_tests_work_with_an_aliased_windows_temp",
|
||
"path": "crates/automation/src/workspace/tests.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked root_alias_tests_work_with_an_aliased_windows_temp -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (inside, outside, _) = roots(\"aliased-temp\");\n let temp_alias = outside.join(\"temp-alias\");\n link_directory(&inside, &temp_alias);\n let exe = std::env::current_exe().unwrap();\n for test in [\n \"workspace::tests::ungranted_absolute_aliases_and_link_escapes_are_refused\",\n \"workspace::tests::retargeting_root_alias_does_not_regrant_the_held_authority\",\n ] {\n // Set TEMP only in the child; changing the process environment races other tests.\n let output = std::process::Command::new(&exe).args([\"--exact\", test, \"--nocapture\"]).env(\"TEMP\", &temp_alias).env(\"TMP\", &temp_alias).output().unwrap();\n let stdout = String::from_utf8_lossy(&output.stdout);\n let stderr = String::from_utf8_lossy(&output.stderr);",
|
||
"expected_assertions": [
|
||
" assert!(output.status.success(), \"{test}: {stdout}\\n{stderr}\");\n assert!(stdout.contains(\"1 passed;\"), \"child must run the requested test: {stdout}\");\n }\n remove_directory_link(&temp_alias);",
|
||
" assert!(stdout.contains(\"1 passed;\"), \"child must run the requested test: {stdout}\");\n }\n remove_directory_link(&temp_alias);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bb0a5e67474d36ae08d565251edb1ae780dd044/crates/automation/src/workspace/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "ungranted_absolute_aliases_and_link_escapes_are_refused",
|
||
"path": "crates/automation/src/workspace/tests.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked ungranted_absolute_aliases_and_link_escapes_are_refused -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (inside, outside, workspace) = roots(\"request-alias\");\n // TEMP may use an 8.3 name or a junction. A grant through `alias` below recognises\n // that configured alias and the canonical target, not every other name for `inside`.\n let resolved_inside = std::fs::canonicalize(&inside).unwrap();\n let alias = outside.join(\"inside-alias\");\n link_directory(&inside, &alias);\n workspace.write(\"new.bin\", b\"inside\").unwrap();\n assert!(workspace.read(&alias.join(\"new.bin\").to_string_lossy()).is_err());\n assert!(workspace.write(&alias.join(\"ungranted.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!inside.join(\"ungranted.bin\").exists());\n std::fs::write(outside.join(\"secret.bin\"), b\"outside\").unwrap();\n let escape = inside.join(\"escape\");",
|
||
"expected_assertions": [
|
||
" assert!(workspace.read(&alias.join(\"new.bin\").to_string_lossy()).is_err());\n assert!(workspace.write(&alias.join(\"ungranted.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!inside.join(\"ungranted.bin\").exists());\n std::fs::write(outside.join(\"secret.bin\"), b\"outside\").unwrap();",
|
||
" assert!(workspace.write(&alias.join(\"ungranted.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!inside.join(\"ungranted.bin\").exists());\n std::fs::write(outside.join(\"secret.bin\"), b\"outside\").unwrap();\n let escape = inside.join(\"escape\");",
|
||
" assert!(!inside.join(\"ungranted.bin\").exists());\n std::fs::write(outside.join(\"secret.bin\"), b\"outside\").unwrap();\n let escape = inside.join(\"escape\");\n link_directory(&outside, &escape);",
|
||
" assert!(workspace.read(&escape.join(\"secret.bin\").to_string_lossy()).is_err());\n assert!(workspace.write(&escape.join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(workspace.export_sequence(&escape.join(\"frames\").join(\"nested\").to_string_lossy()).is_err());\n assert!(!outside.join(\"blocked.bin\").exists());",
|
||
" assert!(workspace.write(&escape.join(\"blocked.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(workspace.export_sequence(&escape.join(\"frames\").join(\"nested\").to_string_lossy()).is_err());\n assert!(!outside.join(\"blocked.bin\").exists());\n assert!(!outside.join(\"frames\").exists());",
|
||
" assert!(workspace.export_sequence(&escape.join(\"frames\").join(\"nested\").to_string_lossy()).is_err());\n assert!(!outside.join(\"blocked.bin\").exists());\n assert!(!outside.join(\"frames\").exists());\n assert_eq!(std::fs::read(outside.join(\"secret.bin\")).unwrap(), b\"outside\");",
|
||
" assert!(!outside.join(\"blocked.bin\").exists());\n assert!(!outside.join(\"frames\").exists());\n assert_eq!(std::fs::read(outside.join(\"secret.bin\")).unwrap(), b\"outside\");\n let read_only = AuthorizedWorkspace::new(Some(&alias), Some(&outside)).unwrap();",
|
||
" assert!(!outside.join(\"frames\").exists());\n assert_eq!(std::fs::read(outside.join(\"secret.bin\")).unwrap(), b\"outside\");\n let read_only = AuthorizedWorkspace::new(Some(&alias), Some(&outside)).unwrap();\n assert_eq!(read_only.read(&resolved_inside.join(\"new.bin\").to_string_lossy()).unwrap(), b\"inside\");",
|
||
" assert_eq!(std::fs::read(outside.join(\"secret.bin\")).unwrap(), b\"outside\");\n let read_only = AuthorizedWorkspace::new(Some(&alias), Some(&outside)).unwrap();\n assert_eq!(read_only.read(&resolved_inside.join(\"new.bin\").to_string_lossy()).unwrap(), b\"inside\");\n assert!(read_only.write(&alias.join(\"denied.bin\").to_string_lossy(), b\"no\").is_err());",
|
||
" assert_eq!(read_only.read(&resolved_inside.join(\"new.bin\").to_string_lossy()).unwrap(), b\"inside\");\n assert!(read_only.write(&alias.join(\"denied.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!inside.join(\"denied.bin\").exists());\n remove_directory_link(&escape);",
|
||
" assert!(read_only.write(&alias.join(\"denied.bin\").to_string_lossy(), b\"no\").is_err());\n assert!(!inside.join(\"denied.bin\").exists());\n remove_directory_link(&escape);\n remove_directory_link(&alias);",
|
||
" assert!(!inside.join(\"denied.bin\").exists());\n remove_directory_link(&escape);\n remove_directory_link(&alias);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bb0a5e67474d36ae08d565251edb1ae780dd044/crates/automation/src/workspace/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "retargeting_root_alias_does_not_regrant_the_held_authority",
|
||
"path": "crates/automation/src/workspace/tests.rs",
|
||
"package": "photocraft-automation",
|
||
"command": "cargo test -p photocraft-automation --locked retargeting_root_alias_does_not_regrant_the_held_authority -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (inside, outside, _) = roots(\"retargeted-root\");\n let resolved_inside = std::fs::canonicalize(&inside).unwrap();\n let alias = outside.join(\"root-alias\");\n link_directory(&inside, &alias);\n let workspace = AuthorizedWorkspace::new(Some(&alias), Some(&alias)).unwrap();\n remove_directory_link(&alias);\n link_directory(&outside, &alias);\n std::fs::write(outside.join(\"secret.bin\"), b\"secret\").unwrap();\n workspace.write(\"held.bin\", b\"held\").unwrap();\n assert_eq!(workspace.read(&resolved_inside.join(\"held.bin\").to_string_lossy()).unwrap(), b\"held\");\n assert!(workspace.read(&alias.join(\"secret.bin\").to_string_lossy()).is_err());\n workspace.write(&alias.join(\"held-alias.bin\").to_string_lossy(), b\"original grant\").unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(workspace.read(&resolved_inside.join(\"held.bin\").to_string_lossy()).unwrap(), b\"held\");\n assert!(workspace.read(&alias.join(\"secret.bin\").to_string_lossy()).is_err());\n workspace.write(&alias.join(\"held-alias.bin\").to_string_lossy(), b\"original grant\").unwrap();\n assert_eq!(std::fs::read(inside.join(\"held-alias.bin\")).unwrap(), b\"original grant\");",
|
||
" assert!(workspace.read(&alias.join(\"secret.bin\").to_string_lossy()).is_err());\n workspace.write(&alias.join(\"held-alias.bin\").to_string_lossy(), b\"original grant\").unwrap();\n assert_eq!(std::fs::read(inside.join(\"held-alias.bin\")).unwrap(), b\"original grant\");\n assert!(!outside.join(\"held-alias.bin\").exists());",
|
||
" assert_eq!(std::fs::read(inside.join(\"held-alias.bin\")).unwrap(), b\"original grant\");\n assert!(!outside.join(\"held-alias.bin\").exists());\n assert_eq!(std::fs::read(outside.join(\"secret.bin\")).unwrap(), b\"secret\");\n remove_directory_link(&alias);",
|
||
" assert!(!outside.join(\"held-alias.bin\").exists());\n assert_eq!(std::fs::read(outside.join(\"secret.bin\")).unwrap(), b\"secret\");\n remove_directory_link(&alias);\n}",
|
||
" assert_eq!(std::fs::read(outside.join(\"secret.bin\")).unwrap(), b\"secret\");\n remove_directory_link(&alias);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bb0a5e67474d36ae08d565251edb1ae780dd044/crates/automation/src/workspace/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-6621",
|
||
"pr": 6621,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked crop_menu_ratio_rows_fit_the_frame_like_the_options_bar -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked crop_menu_gear_rows_toggle_the_shield_options -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked crop_menu_reset_cancel_and_commit_act_on_the_frame -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked crop_menu_lists_saved_presets_and_applies_one -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked crop_menu_closes_when_the_crop_is_no_longer_pending -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked right_click_on_a_pending_crop_opens_the_crop_menu -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked right_click_without_a_pending_crop_opens_no_menu -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked reset_then_commit_crops_nothing -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked reset_edit_undo_then_commit_crops_nothing -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked reset_then_a_still_click_keeps_the_no_op -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked reset_then_frame_edit_back_to_bounds_commits_a_real_crop -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked type_layers_offer_free_transform_but_not_distort_or_perspective -- --nocapture"
|
||
],
|
||
"expected": "crop menu ratio rows fit the frame like the options bar; crop menu gear rows toggle the shield options; crop menu reset cancel and commit act on the frame; crop menu lists saved presets and applies one; crop menu closes when the crop is no longer pending; right click on a pending crop opens the crop menu; right click without a pending crop opens no menu; reset then commit crops nothing; reset edit undo then commit crops nothing; reset then a still click keeps the no op; reset then frame edit back to bounds commits a real crop; type layers offer free transform but not distort or perspective",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked crop_menu_ratio_rows_fit_the_frame_like_the_options_bar -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked crop_menu_gear_rows_toggle_the_shield_options -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked crop_menu_reset_cancel_and_commit_act_on_the_frame -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked crop_menu_lists_saved_presets_and_applies_one -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked crop_menu_closes_when_the_crop_is_no_longer_pending -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked right_click_on_a_pending_crop_opens_the_crop_menu -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked right_click_without_a_pending_crop_opens_no_menu -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked reset_then_commit_crops_nothing -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked reset_edit_undo_then_commit_crops_nothing -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked reset_then_a_still_click_keeps_the_no_op -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked reset_then_frame_edit_back_to_bounds_commits_a_real_crop -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked type_layers_offer_free_transform_but_not_distort_or_perspective -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "crop_menu_ratio_rows_fit_the_frame_like_the_options_bar",
|
||
"path": "crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked crop_menu_ratio_rows_fit_the_frame_like_the_options_bar -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = crop_app();\n crop_open(&mut app);\n let menu = app.ui.canvas_tool_menu.clone().unwrap();\n assert!(menu.crop && available(&app, &menu, \"crop.ratio.16:9\"));\n choose(&mut app, &Context::default(), \"crop.ratio.16:9\");\n assert_eq!(app.ui.tool_options.crop_ratio, \"16:9\");\n assert!((frame_ratio(&app) - 16.0 / 9.0).abs() < 1e-9, \"the frame is fitted to the ratio\");\n // The current ratio shows checked; the others do not.\n crop_open(&mut app);\n let menu = app.ui.canvas_tool_menu.clone().unwrap();\n assert!(mode_checked(&app, &menu, \"crop.ratio.16:9\") && !mode_checked(&app, &menu, \"crop.ratio.1:1\"));\n choose(&mut app, &Context::default(), \"crop.ratio.1:1\");",
|
||
"expected_assertions": [
|
||
" assert!(menu.crop && available(&app, &menu, \"crop.ratio.16:9\"));\n choose(&mut app, &Context::default(), \"crop.ratio.16:9\");\n assert_eq!(app.ui.tool_options.crop_ratio, \"16:9\");\n assert!((frame_ratio(&app) - 16.0 / 9.0).abs() < 1e-9, \"the frame is fitted to the ratio\");",
|
||
" assert_eq!(app.ui.tool_options.crop_ratio, \"16:9\");\n assert!((frame_ratio(&app) - 16.0 / 9.0).abs() < 1e-9, \"the frame is fitted to the ratio\");\n // The current ratio shows checked; the others do not.\n crop_open(&mut app);",
|
||
" assert!((frame_ratio(&app) - 16.0 / 9.0).abs() < 1e-9, \"the frame is fitted to the ratio\");\n // The current ratio shows checked; the others do not.\n crop_open(&mut app);\n let menu = app.ui.canvas_tool_menu.clone().unwrap();",
|
||
" assert!(mode_checked(&app, &menu, \"crop.ratio.16:9\") && !mode_checked(&app, &menu, \"crop.ratio.1:1\"));\n choose(&mut app, &Context::default(), \"crop.ratio.1:1\");\n assert!((frame_ratio(&app) - 1.0).abs() < 1e-9);\n }",
|
||
" assert!((frame_ratio(&app) - 1.0).abs() < 1e-9);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "crop_menu_gear_rows_toggle_the_shield_options",
|
||
"path": "crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked crop_menu_gear_rows_toggle_the_shield_options -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = crop_app();\n crop_open(&mut app);\n choose(&mut app, &Context::default(), CROP_SHOW_CROPPED);\n assert!(!app.ui.tool_options.crop_shield.show_cropped_area);\n crop_open(&mut app);\n assert!(!mode_checked(&app, app.ui.canvas_tool_menu.as_ref().unwrap(), CROP_SHOW_CROPPED), \"the row shows the option's state\");\n choose(&mut app, &Context::default(), CROP_CLASSIC);\n assert!(app.ui.tool_options.crop_shield.classic_mode);\n // As in the gear menu, Classic Mode greys out the other two options.\n crop_open(&mut app);\n let menu = app.ui.canvas_tool_menu.clone().unwrap();\n assert!(!entry_enabled(&app, &menu, CROP_SHOW_CROPPED) && !entry_enabled(&app, &menu, CROP_AUTO_CENTER));",
|
||
"expected_assertions": [
|
||
" assert!(!app.ui.tool_options.crop_shield.show_cropped_area);\n crop_open(&mut app);\n assert!(!mode_checked(&app, app.ui.canvas_tool_menu.as_ref().unwrap(), CROP_SHOW_CROPPED), \"the row shows the option's state\");\n choose(&mut app, &Context::default(), CROP_CLASSIC);",
|
||
" assert!(!mode_checked(&app, app.ui.canvas_tool_menu.as_ref().unwrap(), CROP_SHOW_CROPPED), \"the row shows the option's state\");\n choose(&mut app, &Context::default(), CROP_CLASSIC);\n assert!(app.ui.tool_options.crop_shield.classic_mode);\n // As in the gear menu, Classic Mode greys out the other two options.",
|
||
" assert!(app.ui.tool_options.crop_shield.classic_mode);\n // As in the gear menu, Classic Mode greys out the other two options.\n crop_open(&mut app);\n let menu = app.ui.canvas_tool_menu.clone().unwrap();",
|
||
" assert!(!entry_enabled(&app, &menu, CROP_SHOW_CROPPED) && !entry_enabled(&app, &menu, CROP_AUTO_CENTER));\n assert!(entry_enabled(&app, &menu, CROP_CLASSIC));\n choose(&mut app, &Context::default(), CROP_CLASSIC);\n assert!(!app.ui.tool_options.crop_shield.classic_mode);",
|
||
" assert!(entry_enabled(&app, &menu, CROP_CLASSIC));\n choose(&mut app, &Context::default(), CROP_CLASSIC);\n assert!(!app.ui.tool_options.crop_shield.classic_mode);\n }",
|
||
" assert!(!app.ui.tool_options.crop_shield.classic_mode);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "crop_menu_reset_cancel_and_commit_act_on_the_frame",
|
||
"path": "crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked crop_menu_reset_cancel_and_commit_act_on_the_frame -- --nocapture",
|
||
"fixture_and_action_excerpt": " // Reset: the whole canvas, still a pending frame.\n let mut app = crop_app();\n crop_open(&mut app);\n choose(&mut app, &Context::default(), CROP_RESET);\n assert_eq!(app.ui.crop_rect, Some([0.0, 0.0, 32.0, 32.0]));\n assert!(crate::crop_ui::pending(&app), \"Reset keeps the crop active, as in Photoshop\");\n // Cancel: the frame is dropped (the tool's next frame is the default one).\n crop_open(&mut app);\n choose(&mut app, &Context::default(), CROP_CANCEL);\n assert!(app.ui.crop_rect.is_none() && !crate::crop_ui::pending(&app));\n // Commit: the document is cropped to the frame.\n let mut app = crop_app();",
|
||
"expected_assertions": [
|
||
" assert_eq!(app.ui.crop_rect, Some([0.0, 0.0, 32.0, 32.0]));\n assert!(crate::crop_ui::pending(&app), \"Reset keeps the crop active, as in Photoshop\");\n // Cancel: the frame is dropped (the tool's next frame is the default one).\n crop_open(&mut app);",
|
||
" assert!(crate::crop_ui::pending(&app), \"Reset keeps the crop active, as in Photoshop\");\n // Cancel: the frame is dropped (the tool's next frame is the default one).\n crop_open(&mut app);\n choose(&mut app, &Context::default(), CROP_CANCEL);",
|
||
" assert!(app.ui.crop_rect.is_none() && !crate::crop_ui::pending(&app));\n // Commit: the document is cropped to the frame.\n let mut app = crop_app();\n crop_open(&mut app);",
|
||
" assert_eq!(app.session.active().unwrap().doc.size, photocraft_doc::Size::new(20, 20));\n assert!(app.ui.crop_rect.is_none());\n }",
|
||
" assert!(app.ui.crop_rect.is_none());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "crop_menu_lists_saved_presets_and_applies_one",
|
||
"path": "crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked crop_menu_lists_saved_presets_and_applies_one -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = crop_app();\n app.run(\"tool.presets.new\", json!({\"name\": \"Wide\", \"tool\": \"crop\", \"options\": {\"toolOptions\": {\"crop_ratio\": \"16:9\"}}})).unwrap();\n crop_open(&mut app);\n let menu = app.ui.canvas_tool_menu.clone().unwrap();\n assert_eq!(menu.crop_presets, [\"Wide\"]);\n assert!(available(&app, &menu, \"crop.preset.0\"));\n assert!(crop_rows(&menu).iter().flatten().any(|(label, _)| label == \"Wide\"), \"the preset is a row: {:?}\", crop_rows(&menu));\n choose(&mut app, &Context::default(), \"crop.preset.0\");\n // As in the options bar's dropdown: the preset fills the fields (the frame follows on the\n // next resize or ratio apply).\n assert_eq!(app.ui.tool_options.crop_ratio, \"16:9\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(menu.crop_presets, [\"Wide\"]);\n assert!(available(&app, &menu, \"crop.preset.0\"));\n assert!(crop_rows(&menu).iter().flatten().any(|(label, _)| label == \"Wide\"), \"the preset is a row: {:?}\", crop_rows(&menu));\n choose(&mut app, &Context::default(), \"crop.preset.0\");",
|
||
" assert!(available(&app, &menu, \"crop.preset.0\"));\n assert!(crop_rows(&menu).iter().flatten().any(|(label, _)| label == \"Wide\"), \"the preset is a row: {:?}\", crop_rows(&menu));\n choose(&mut app, &Context::default(), \"crop.preset.0\");\n // As in the options bar's dropdown: the preset fills the fields (the frame follows on the",
|
||
" assert!(crop_rows(&menu).iter().flatten().any(|(label, _)| label == \"Wide\"), \"the preset is a row: {:?}\", crop_rows(&menu));\n choose(&mut app, &Context::default(), \"crop.preset.0\");\n // As in the options bar's dropdown: the preset fills the fields (the frame follows on the\n // next resize or ratio apply).",
|
||
" assert_eq!(app.ui.tool_options.crop_ratio, \"16:9\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "crop_menu_closes_when_the_crop_is_no_longer_pending",
|
||
"path": "crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked crop_menu_closes_when_the_crop_is_no_longer_pending -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = crop_app();\n crop_open(&mut app);\n assert!(app.ui.canvas_tool_menu.is_some());\n crate::crop_ui::cancel(&mut app);\n show(&mut app, &Context::default());\n assert!(app.ui.canvas_tool_menu.is_none(), \"the menu does not outlive the pending frame\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(app.ui.canvas_tool_menu.is_some());\n crate::crop_ui::cancel(&mut app);\n show(&mut app, &Context::default());\n assert!(app.ui.canvas_tool_menu.is_none(), \"the menu does not outlive the pending frame\");",
|
||
" assert!(app.ui.canvas_tool_menu.is_none(), \"the menu does not outlive the pending frame\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "right_click_on_a_pending_crop_opens_the_crop_menu",
|
||
"path": "crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked right_click_on_a_pending_crop_opens_the_crop_menu -- --nocapture",
|
||
"fixture_and_action_excerpt": " let app = crop_app();\n let mut h = harness(app);\n let center = h.state().last_canvas_rect.center();\n right_click(&mut h, center, Modifiers::NONE);\n let menu = h.state().ui.canvas_tool_menu.clone().expect(\"right-click on a pending crop opens a menu\");\n assert!(menu.crop && !menu.pasteboard && !menu.transform);\n let ctx = h.ctx.clone();\n choose(h.state_mut(), &ctx, \"crop.ratio.16:9\");\n let r = h.state().ui.crop_rect.unwrap();\n assert!(((r[2] - r[0]) / (r[3] - r[1]) - 16.0 / 9.0).abs() < 1e-9, \"choosing 16:9 refits the frame\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(menu.crop && !menu.pasteboard && !menu.transform);\n let ctx = h.ctx.clone();\n choose(h.state_mut(), &ctx, \"crop.ratio.16:9\");\n let r = h.state().ui.crop_rect.unwrap();",
|
||
" assert!(((r[2] - r[0]) / (r[3] - r[1]) - 16.0 / 9.0).abs() < 1e-9, \"choosing 16:9 refits the frame\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "right_click_without_a_pending_crop_opens_no_menu",
|
||
"path": "crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked right_click_without_a_pending_crop_opens_no_menu -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n app.ui.tool = Tool::Crop;\n crate::crop_ui::ensure_frame(&mut app);\n assert!(app.ui.crop_rect.is_some() && !crate::crop_ui::pending(&app), \"the untouched default frame is not pending\");\n let mut h = harness(app);\n let center = h.state().last_canvas_rect.center();\n right_click(&mut h, center, Modifiers::NONE);\n assert!(h.state().ui.canvas_tool_menu.is_none(), \"no menu on the untouched default frame\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(app.ui.crop_rect.is_some() && !crate::crop_ui::pending(&app), \"the untouched default frame is not pending\");\n let mut h = harness(app);\n let center = h.state().last_canvas_rect.center();\n right_click(&mut h, center, Modifiers::NONE);",
|
||
" assert!(h.state().ui.canvas_tool_menu.is_none(), \"no menu on the untouched default frame\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/canvas_tool_menu.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "reset_then_commit_crops_nothing",
|
||
"path": "crates/ui-egui/src/crop_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked reset_then_commit_crops_nothing -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(SampleType::U8);\n app.ui.tool_options.crop_delete = true;\n // A layer whose pixels reach past the right edge: a full-canvas crop with delete would\n // trim them.\n app.run(\"layer.new.layer\", json!({\"name\": \"over\"})).unwrap();\n app.run(\"edit.fill\", json!({\"color\": \"#ff0000\"})).unwrap();\n app.run(\"layer.translate\", json!({\"dx\": 40, \"dy\": 0})).unwrap();\n let over = app.session.active().unwrap().doc.layers.iter().rev().find(|l| l.name == \"over\").unwrap();\n let past = over.surface().unwrap().content_bounds().x1;\n assert!(past > 200, \"the layer reaches past the canvas: {past}\");\n // A drawn frame, then Reset: the whole canvas again, still pending.\n drag(&mut app, &[[10.0, 10.0], [50.0, 40.0]], NONE);",
|
||
"expected_assertions": [
|
||
" assert!(past > 200, \"the layer reaches past the canvas: {past}\");\n // A drawn frame, then Reset: the whole canvas again, still pending.\n drag(&mut app, &[[10.0, 10.0], [50.0, 40.0]], NONE);\n reset(&mut app);",
|
||
" assert_eq!(app.ui.crop_rect, Some([0.0, 0.0, 200.0, 100.0]));\n assert!(pending(&app), \"Reset keeps the crop pending\");\n let steps = app.session.active().unwrap().history.past_len();\n crate::canvas::commit_crop(&mut app);",
|
||
" assert!(pending(&app), \"Reset keeps the crop pending\");\n let steps = app.session.active().unwrap().history.past_len();\n crate::canvas::commit_crop(&mut app);\n let st = app.session.active().unwrap();",
|
||
" assert_eq!((st.doc.size, st.history.past_len()), (Size::new(200, 100), steps), \"a reset frame commits as a no-op\");\n assert!(app.ui.crop_rect.is_none(), \"the frame is gone\");\n let over = st.doc.layers.iter().rev().find(|l| l.name == \"over\").unwrap();\n assert_eq!(over.surface().unwrap().content_bounds().x1, past, \"pixels outside the canvas are kept\");",
|
||
" assert!(app.ui.crop_rect.is_none(), \"the frame is gone\");\n let over = st.doc.layers.iter().rev().find(|l| l.name == \"over\").unwrap();\n assert_eq!(over.surface().unwrap().content_bounds().x1, past, \"pixels outside the canvas are kept\");\n }",
|
||
" assert_eq!(over.surface().unwrap().content_bounds().x1, past, \"pixels outside the canvas are kept\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/crop_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "reset_edit_undo_then_commit_crops_nothing",
|
||
"path": "crates/ui-egui/src/crop_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked reset_edit_undo_then_commit_crops_nothing -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(SampleType::U8);\n app.ui.tool_options.crop_delete = true;\n app.run(\"layer.new.layer\", json!({\"name\": \"over\"})).unwrap();\n app.run(\"edit.fill\", json!({\"color\": \"#ff0000\"})).unwrap();\n app.run(\"layer.translate\", json!({\"dx\": 40, \"dy\": 0})).unwrap();\n let over = app.session.active().unwrap().doc.layers.iter().rev().find(|l| l.name == \"over\").unwrap();\n let past = over.surface().unwrap().content_bounds().x1;\n assert!(past > 200, \"the layer reaches past the canvas: {past}\");\n // Reset, then a gesture that shrinks the frame, then Undo back to the reset frame.\n reset(&mut app);\n drag(&mut app, &[[0.0, 0.0], [50.0, 40.0]], NONE);\n assert_eq!(app.ui.crop_rect, Some([50.0, 40.0, 200.0, 100.0]), \"the corner drag resizes the frame\");",
|
||
"expected_assertions": [
|
||
" assert!(past > 200, \"the layer reaches past the canvas: {past}\");\n // Reset, then a gesture that shrinks the frame, then Undo back to the reset frame.\n reset(&mut app);\n drag(&mut app, &[[0.0, 0.0], [50.0, 40.0]], NONE);",
|
||
" assert_eq!(app.ui.crop_rect, Some([50.0, 40.0, 200.0, 100.0]), \"the corner drag resizes the frame\");\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(app.ui.crop_rect, Some([0.0, 0.0, 200.0, 100.0]), \"Undo restores the reset frame\");\n assert!(pending(&app));",
|
||
" assert_eq!(app.ui.crop_rect, Some([0.0, 0.0, 200.0, 100.0]), \"Undo restores the reset frame\");\n assert!(pending(&app));\n let steps = app.session.active().unwrap().history.past_len();\n crate::canvas::commit_crop(&mut app);",
|
||
" assert!(pending(&app));\n let steps = app.session.active().unwrap().history.past_len();\n crate::canvas::commit_crop(&mut app);\n let st = app.session.active().unwrap();",
|
||
" assert_eq!((st.doc.size, st.history.past_len()), (Size::new(200, 100), steps), \"the undone reset frame commits as a no-op\");\n assert!(app.ui.crop_rect.is_none(), \"the frame is gone\");\n let over = st.doc.layers.iter().rev().find(|l| l.name == \"over\").unwrap();\n assert_eq!(over.surface().unwrap().content_bounds().x1, past, \"pixels outside the canvas are kept\");",
|
||
" assert!(app.ui.crop_rect.is_none(), \"the frame is gone\");\n let over = st.doc.layers.iter().rev().find(|l| l.name == \"over\").unwrap();\n assert_eq!(over.surface().unwrap().content_bounds().x1, past, \"pixels outside the canvas are kept\");\n }",
|
||
" assert_eq!(over.surface().unwrap().content_bounds().x1, past, \"pixels outside the canvas are kept\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/crop_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "reset_then_a_still_click_keeps_the_no_op",
|
||
"path": "crates/ui-egui/src/crop_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked reset_then_a_still_click_keeps_the_no_op -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(SampleType::U8);\n app.ui.tool_options.crop_delete = true;\n app.run(\"layer.new.layer\", json!({\"name\": \"over\"})).unwrap();\n app.run(\"edit.fill\", json!({\"color\": \"#ff0000\"})).unwrap();\n app.run(\"layer.translate\", json!({\"dx\": 40, \"dy\": 0})).unwrap();\n reset(&mut app);\n drag(&mut app, &[[100.0, 50.0], [100.0, 50.0]], NONE);\n assert!(app.crop.reset_frame, \"a click without a frame change keeps the reset marker\");\n let steps = app.session.active().unwrap().history.past_len();\n crate::canvas::commit_crop(&mut app);\n let st = app.session.active().unwrap();\n assert_eq!((st.doc.size, st.history.past_len()), (Size::new(200, 100), steps), \"the click leaves the no-op\");",
|
||
"expected_assertions": [
|
||
" assert!(app.crop.reset_frame, \"a click without a frame change keeps the reset marker\");\n let steps = app.session.active().unwrap().history.past_len();\n crate::canvas::commit_crop(&mut app);\n let st = app.session.active().unwrap();",
|
||
" assert_eq!((st.doc.size, st.history.past_len()), (Size::new(200, 100), steps), \"the click leaves the no-op\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/crop_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "reset_then_frame_edit_back_to_bounds_commits_a_real_crop",
|
||
"path": "crates/ui-egui/src/crop_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked reset_then_frame_edit_back_to_bounds_commits_a_real_crop -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(SampleType::U8);\n app.ui.tool_options.crop_delete = true;\n app.run(\"layer.new.layer\", json!({\"name\": \"over\"})).unwrap();\n app.run(\"edit.fill\", json!({\"color\": \"#ff0000\"})).unwrap();\n app.run(\"layer.translate\", json!({\"dx\": 40, \"dy\": 0})).unwrap();\n let over = app.session.active().unwrap().doc.layers.iter().rev().find(|l| l.name == \"over\").unwrap();\n let past = over.surface().unwrap().content_bounds().x1;\n assert!(past > 200, \"the layer reaches past the canvas: {past}\");\n reset(&mut app);\n drag(&mut app, &[[0.0, 0.0], [50.0, 40.0]], NONE); // shrink: a real edit\n assert!(!app.crop.reset_frame, \"moving the frame ends the reset no-op\");\n drag(&mut app, &[[50.0, 40.0], [0.0, 0.0]], NONE); // back to the full bounds",
|
||
"expected_assertions": [
|
||
" assert!(past > 200, \"the layer reaches past the canvas: {past}\");\n reset(&mut app);\n drag(&mut app, &[[0.0, 0.0], [50.0, 40.0]], NONE); // shrink: a real edit\n assert!(!app.crop.reset_frame, \"moving the frame ends the reset no-op\");",
|
||
" assert!(!app.crop.reset_frame, \"moving the frame ends the reset no-op\");\n drag(&mut app, &[[50.0, 40.0], [0.0, 0.0]], NONE); // back to the full bounds\n assert_eq!(app.ui.crop_rect, Some([0.0, 0.0, 200.0, 100.0]));\n let steps = app.session.active().unwrap().history.past_len();",
|
||
" assert_eq!(app.ui.crop_rect, Some([0.0, 0.0, 200.0, 100.0]));\n let steps = app.session.active().unwrap().history.past_len();\n crate::canvas::commit_crop(&mut app);\n let st = app.session.active().unwrap();",
|
||
" assert_eq!(st.history.past_len(), steps + 1, \"the restored frame commits as a real crop\");\n let over = st.doc.layers.iter().rev().find(|l| l.name == \"over\").unwrap();\n assert_eq!(over.surface().unwrap().content_bounds().x1, 200, \"pixels outside the canvas are deleted\");\n }",
|
||
" assert_eq!(over.surface().unwrap().content_bounds().x1, 200, \"pixels outside the canvas are deleted\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/crop_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "type_layers_offer_free_transform_but_not_distort_or_perspective",
|
||
"path": "crates/ui-egui/src/transform_type_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked type_layers_offer_free_transform_but_not_distort_or_perspective -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n for selection in [false, true] {\n if selection {\n select_left_half(&mut app);\n }\n for id in [\"edit.freeTransform\", \"edit.transform.scale\", \"edit.transform.rotate\", \"edit.transform.skew\"] {\n assert!(crate::menus::is_enabled(&app, id), \"{id} (selection: {selection})\");\n }\n for id in [\"edit.transform.distort\", \"edit.transform.perspective\"] {\n assert!(!crate::menus::is_enabled(&app, id), \"{id} is greyed for editable type (selection: {selection})\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(crate::menus::is_enabled(&app, id), \"{id} (selection: {selection})\");\n }\n for id in [\"edit.transform.distort\", \"edit.transform.perspective\"] {\n assert!(!crate::menus::is_enabled(&app, id), \"{id} is greyed for editable type (selection: {selection})\");",
|
||
" assert!(!crate::menus::is_enabled(&app, id), \"{id} is greyed for editable type (selection: {selection})\");\n }\n }\n // The same rows in the marquee's canvas context menu.",
|
||
" assert!(crate::canvas_tool_menu::available(&app, &menu, \"edit.freeTransform\"));\n assert!(!crate::canvas_tool_menu::available(&app, &menu, \"edit.transform.distort\"));\n assert!(!crate::canvas_tool_menu::available(&app, &menu, \"edit.transform.perspective\"));\n // Rasterized, the type is pixels and can be distorted.",
|
||
" assert!(!crate::canvas_tool_menu::available(&app, &menu, \"edit.transform.distort\"));\n assert!(!crate::canvas_tool_menu::available(&app, &menu, \"edit.transform.perspective\"));\n // Rasterized, the type is pixels and can be distorted.\n app.run(\"layer.rasterize.type\", json!({})).unwrap();",
|
||
" assert!(!crate::canvas_tool_menu::available(&app, &menu, \"edit.transform.perspective\"));\n // Rasterized, the type is pixels and can be distorted.\n app.run(\"layer.rasterize.type\", json!({})).unwrap();\n assert!(crate::menus::is_enabled(&app, \"edit.transform.distort\") && crate::menus::is_enabled(&app, \"edit.transform.perspective\"));",
|
||
" assert!(crate::menus::is_enabled(&app, \"edit.transform.distort\") && crate::menus::is_enabled(&app, \"edit.transform.perspective\"));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ead45134d320cb1002724d5ef44f5c56588bbe1d/crates/ui-egui/src/transform_type_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-7648",
|
||
"pr": 7648,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked merge_shape_components_bakes_a_paths_operations -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked merge_shape_components_on_a_shape_layer_rerenders_it -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked merging_a_vector_mask_to_nothing_keeps_what_it_shows -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked set_operation_changes_existing_components -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked set_operation_on_a_joined_subpath_changes_its_component -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked set_operation_leaves_the_first_component_combining -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked bad_set_operation_params_change_nothing -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked bad_merge_params_change_nothing -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked merge_refuses_open_subpaths -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ui_set_drives_the_pen_path_operation -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_selected_component_takes_the_picked_operation -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked plus_and_minus_pick_combine_and_subtract -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked path_selection_selects_and_moves_components -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_stale_selection_changes_nothing -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_first_component_keeps_combining -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_pen_does_not_edit_a_hidden_component_selection -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked dragging_a_live_shape_keeps_it_live -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_pen_carries_on_an_open_shape_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked an_open_component_of_a_filled_shape_keeps_its_paint -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_pen_carries_on_a_vector_masks_open_subpath -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked subtract_front_shape_cuts_a_hole_in_the_selected_shape_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_locked_shape_layer_keeps_the_drawn_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked switching_tools_ends_a_refused_draft_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked esc_ends_a_refused_draft_and_return_keeps_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked an_operation_without_a_selected_shape_starts_a_new_shape_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked path_mode_adds_subpaths_with_the_operation -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_options_bar_menu_sets_the_operation_and_merges -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked merge_is_disabled_with_fewer_than_two_components -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked an_unknown_operation_falls_back_to_new_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_refuses_a_locked_shape_before_starting_a_stroke -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked failed_stale_pen_commit_preserves_the_draft_until_retry -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked stale_pen_commits_to_its_owner_across_document_changes -- --nocapture"
|
||
],
|
||
"expected": "merge shape components bakes a paths operations; merge shape components on a shape layer rerenders it; merging a vector mask to nothing keeps what it shows; set operation changes existing components; set operation on a joined subpath changes its component; set operation leaves the first component combining; bad set operation params change nothing; bad merge params change nothing; merge refuses open subpaths; ui set drives the pen path operation; a selected component takes the picked operation; plus and minus pick combine and subtract; path selection selects and moves components; a stale selection changes nothing; the first component keeps combining; the pen does not edit a hidden component selection; dragging a live shape keeps it live; the pen carries on an open shape path; an open component of a filled shape keeps its paint; the pen carries on a vector masks open subpath; subtract front shape cuts a hole in the selected shape layer; a locked shape layer keeps the drawn path; switching tools ends a refused draft once; esc ends a refused draft and return keeps it; an operation without a selected shape starts a new shape layer; path mode adds subpaths with the operation; the options bar menu sets the operation and merges; merge is disabled with fewer than two components; an unknown operation falls back to new layer; freeform refuses a locked shape before starting a stroke; failed stale pen commit preserves the draft until retry; stale pen commits to its owner across document changes",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked merge_shape_components_bakes_a_paths_operations -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked merge_shape_components_on_a_shape_layer_rerenders_it -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked merging_a_vector_mask_to_nothing_keeps_what_it_shows -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked set_operation_changes_existing_components -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked set_operation_on_a_joined_subpath_changes_its_component -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked set_operation_leaves_the_first_component_combining -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked bad_set_operation_params_change_nothing -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked bad_merge_params_change_nothing -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked merge_refuses_open_subpaths -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ui_set_drives_the_pen_path_operation -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_selected_component_takes_the_picked_operation -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked plus_and_minus_pick_combine_and_subtract -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked path_selection_selects_and_moves_components -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_stale_selection_changes_nothing -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_first_component_keeps_combining -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_pen_does_not_edit_a_hidden_component_selection -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked dragging_a_live_shape_keeps_it_live -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_pen_carries_on_an_open_shape_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked an_open_component_of_a_filled_shape_keeps_its_paint -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_pen_carries_on_a_vector_masks_open_subpath -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked subtract_front_shape_cuts_a_hole_in_the_selected_shape_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_locked_shape_layer_keeps_the_drawn_path -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked switching_tools_ends_a_refused_draft_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked esc_ends_a_refused_draft_and_return_keeps_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked an_operation_without_a_selected_shape_starts_a_new_shape_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked path_mode_adds_subpaths_with_the_operation -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_options_bar_menu_sets_the_operation_and_merges -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked merge_is_disabled_with_fewer_than_two_components -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked an_unknown_operation_falls_back_to_new_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked freeform_refuses_a_locked_shape_before_starting_a_stroke -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked failed_stale_pen_commit_preserves_the_draft_until_retry -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked stale_pen_commits_to_its_owner_across_document_changes -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "merge_shape_components_bakes_a_paths_operations",
|
||
"path": "crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked merge_shape_components_bakes_a_paths_operations -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session();\n s.execute(\"path.set\", json!({\"path\": square()})).unwrap();\n let hole = json!({\"subpaths\": [{\"closed\": true, \"knots\": [[25, 25], [45, 25], [45, 45], [25, 45]]}]});\n s.execute(\"path.set\", json!({\"path\": hole, \"op\": \"subtract\"})).unwrap();\n let before = work(&s);\n let r = s.execute(\"path.mergeShapeComponents\", json!({})).unwrap();\n assert_eq!(r[\"name\"], json!(\"work\"));\n assert_eq!(s.active().unwrap().history.undo_label(), Some(\"Merge Shape Components\"));\n let merged = work(&s);\n assert_eq!(merged.subpaths.len(), 2, \"the outline and its hole\");\n for (x, y) in [(15, 15), (35, 35), (55, 50), (5, 5)] {\n assert!((covered(&merged, x, y) - covered(&before, x, y)).abs() < 0.01, \"({x}, {y})\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(r[\"name\"], json!(\"work\"));\n assert_eq!(s.active().unwrap().history.undo_label(), Some(\"Merge Shape Components\"));\n let merged = work(&s);\n assert_eq!(merged.subpaths.len(), 2, \"the outline and its hole\");",
|
||
" assert_eq!(s.active().unwrap().history.undo_label(), Some(\"Merge Shape Components\"));\n let merged = work(&s);\n assert_eq!(merged.subpaths.len(), 2, \"the outline and its hole\");\n for (x, y) in [(15, 15), (35, 35), (55, 50), (5, 5)] {",
|
||
" assert_eq!(merged.subpaths.len(), 2, \"the outline and its hole\");\n for (x, y) in [(15, 15), (35, 35), (55, 50), (5, 5)] {\n assert!((covered(&merged, x, y) - covered(&before, x, y)).abs() < 0.01, \"({x}, {y})\");\n }",
|
||
" assert!((covered(&merged, x, y) - covered(&before, x, y)).abs() < 0.01, \"({x}, {y})\");\n }\n assert_eq!((covered(&merged, 35, 35), covered(&merged, 15, 15)), (0.0, 1.0), \"the hole stays a hole\");\n assert!(s.undo());",
|
||
" assert_eq!((covered(&merged, 35, 35), covered(&merged, 15, 15)), (0.0, 1.0), \"the hole stays a hole\");\n assert!(s.undo());\n assert_eq!(work(&s), before);\n // A saved path and a vector mask merge the same way; an inverted mask stays inverted.",
|
||
" assert!(s.undo());\n assert_eq!(work(&s), before);\n // A saved path and a vector mask merge the same way; an inverted mask stays inverted.\n s.execute(\"path.set\", json!({\"name\": \"Mug\", \"path\": square()})).unwrap();",
|
||
" assert_eq!(work(&s), before);\n // A saved path and a vector mask merge the same way; an inverted mask stays inverted.\n s.execute(\"path.set\", json!({\"name\": \"Mug\", \"path\": square()})).unwrap();\n s.execute(\"path.mergeShapeComponents\", json!({\"name\": \"Mug\"})).unwrap();",
|
||
" assert!(vm.path.inverted && !vm.path.subpaths.is_empty());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "merge_shape_components_on_a_shape_layer_rerenders_it",
|
||
"path": "crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked merge_shape_components_on_a_shape_layer_rerenders_it -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session();\n let id = s.execute(\"shape.create\", json!({\"kind\": \"rect\", \"rect\": [10, 10, 50, 50], \"fill\": \"#ff0000\"})).unwrap()[\"layer\"].as_u64().unwrap();\n s.execute(\"shape.create\", json!({\"kind\": \"rect\", \"rect\": [25, 25, 20, 20], \"addTo\": id, \"op\": \"subtract\"})).unwrap();\n s.execute(\"path.mergeShapeComponents\", json!({\"name\": \"layer\", \"layer\": id})).unwrap();\n let st = s.active().unwrap();\n let photocraft_doc::LayerContent::Shape(ShapeLayer { path, cache, .. }) = &st.doc.layer(LayerId(id)).unwrap().content else { panic!(\"shape\") };\n assert_eq!(covered(path, 35, 35), 0.0);\n assert!(cache.is_some());\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(covered(path, 35, 35), 0.0);\n assert!(cache.is_some());\n }",
|
||
" assert!(cache.is_some());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "merging_a_vector_mask_to_nothing_keeps_what_it_shows",
|
||
"path": "crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked merging_a_vector_mask_to_nothing_keeps_what_it_shows -- --nocapture",
|
||
"fixture_and_action_excerpt": " for inverted in [false, true] {\n let mut s = session();\n let id = s.active().unwrap().active_layer.unwrap().0;\n let mut cancelled = square();\n cancelled[\"subpaths\"].as_array_mut().unwrap().push(json!({\"closed\": true, \"op\": \"subtract\", \"knots\": [[10, 10], [60, 10], [60, 60], [10, 60]]}));\n cancelled[\"inverted\"] = json!(inverted);\n s.execute(\"layer.vectorMask.add\", json!({\"layer\": id, \"path\": cancelled})).unwrap();\n let mask = |s: &Session| s.active().unwrap().doc.layer(LayerId(id)).unwrap().vector_mask.clone().unwrap();\n let shown = |s: &Session| photocraft_vector::vector_mask_values(&mask(s), photocraft_geom::Rect::from_xywh(0, 0, 120, 100));\n let before = shown(&s);\n assert!(before.iter().all(|v| *v == if inverted { 1.0 } else { 0.0 }), \"inverted {inverted}\");\n s.execute(\"path.mergeShapeComponents\", json!({\"name\": \"layer\", \"layer\": id})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(before.iter().all(|v| *v == if inverted { 1.0 } else { 0.0 }), \"inverted {inverted}\");\n s.execute(\"path.mergeShapeComponents\", json!({\"name\": \"layer\", \"layer\": id})).unwrap();\n assert!(mask(&s).path.is_empty());\n assert_eq!(shown(&s), before, \"inverted {inverted}\");",
|
||
" assert!(mask(&s).path.is_empty());\n assert_eq!(shown(&s), before, \"inverted {inverted}\");\n }\n }",
|
||
" assert_eq!(shown(&s), before, \"inverted {inverted}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "set_operation_changes_existing_components",
|
||
"path": "crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked set_operation_changes_existing_components -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session();\n let hole = json!({\"subpaths\": [{\"closed\": true, \"knots\": [[25, 25], [45, 25], [45, 45], [25, 45]]}]});\n s.execute(\"path.set\", json!({\"path\": square()})).unwrap();\n s.execute(\"path.set\", json!({\"path\": hole, \"op\": \"combine\"})).unwrap();\n assert_eq!(covered(&work(&s), 35, 35), 1.0);\n s.execute(\"path.setOperation\", json!({\"subpaths\": [1], \"op\": \"subtract\"})).unwrap();\n assert_eq!(s.active().unwrap().history.undo_label(), Some(\"Path Operation\"));\n assert_eq!(covered(&work(&s), 35, 35), 0.0);\n assert_eq!(work(&s).subpaths[1].op, PathOp::Subtract);\n assert!(s.undo());\n assert_eq!(work(&s).subpaths[1].op, PathOp::Combine);\n",
|
||
"expected_assertions": [
|
||
" assert_eq!(covered(&work(&s), 35, 35), 1.0);\n s.execute(\"path.setOperation\", json!({\"subpaths\": [1], \"op\": \"subtract\"})).unwrap();\n assert_eq!(s.active().unwrap().history.undo_label(), Some(\"Path Operation\"));\n assert_eq!(covered(&work(&s), 35, 35), 0.0);",
|
||
" assert_eq!(s.active().unwrap().history.undo_label(), Some(\"Path Operation\"));\n assert_eq!(covered(&work(&s), 35, 35), 0.0);\n assert_eq!(work(&s).subpaths[1].op, PathOp::Subtract);\n assert!(s.undo());",
|
||
" assert_eq!(covered(&work(&s), 35, 35), 0.0);\n assert_eq!(work(&s).subpaths[1].op, PathOp::Subtract);\n assert!(s.undo());\n assert_eq!(work(&s).subpaths[1].op, PathOp::Combine);",
|
||
" assert_eq!(work(&s).subpaths[1].op, PathOp::Subtract);\n assert!(s.undo());\n assert_eq!(work(&s).subpaths[1].op, PathOp::Combine);\n",
|
||
" assert!(s.undo());\n assert_eq!(work(&s).subpaths[1].op, PathOp::Combine);\n\n let id = s.execute(\"shape.create\", json!({\"kind\": \"rect\", \"rect\": [10, 10, 50, 50], \"fill\": \"#ff0000\"})).unwrap()[\"layer\"].as_u64().unwrap();",
|
||
" assert_eq!(work(&s).subpaths[1].op, PathOp::Combine);\n\n let id = s.execute(\"shape.create\", json!({\"kind\": \"rect\", \"rect\": [10, 10, 50, 50], \"fill\": \"#ff0000\"})).unwrap()[\"layer\"].as_u64().unwrap();\n s.execute(\"shape.create\", json!({\"kind\": \"rect\", \"rect\": [25, 25, 20, 20], \"addTo\": id, \"op\": \"combine\"})).unwrap();",
|
||
" assert_eq!(covered(path, 35, 35), 0.0);\n assert!(cache.is_some());\n }",
|
||
" assert!(cache.is_some());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "set_operation_on_a_joined_subpath_changes_its_component",
|
||
"path": "crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked set_operation_on_a_joined_subpath_changes_its_component -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session();\n let mut p = square();\n let subs = p[\"subpaths\"].as_array_mut().unwrap();\n subs.push(json!({\"closed\": true, \"op\": \"combine\", \"knots\": [[70, 10], [110, 10], [110, 50], [70, 50]]}));\n subs.push(json!({\"closed\": true, \"op\": \"join\", \"knots\": [[80, 20], [80, 40], [100, 40], [100, 20]]}));\n s.execute(\"path.set\", json!({\"path\": p})).unwrap();\n s.execute(\"path.setOperation\", json!({\"subpaths\": [2], \"op\": \"exclude\"})).unwrap();\n let ops: Vec<_> = work(&s).subpaths.iter().map(|sp| sp.op).collect();\n assert_eq!(ops, [PathOp::Combine, PathOp::Exclude, PathOp::Join]);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(ops, [PathOp::Combine, PathOp::Exclude, PathOp::Join]);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "set_operation_leaves_the_first_component_combining",
|
||
"path": "crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked set_operation_leaves_the_first_component_combining -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session();\n let hole = json!({\"subpaths\": [{\"closed\": true, \"knots\": [[25, 25], [45, 25], [45, 45], [25, 45]]}]});\n s.execute(\"path.set\", json!({\"path\": square()})).unwrap();\n s.execute(\"path.set\", json!({\"path\": hole, \"op\": \"combine\"})).unwrap();\n let steps = s.active().unwrap().history.entries().len();\n let e = s.execute(\"path.setOperation\", json!({\"subpaths\": [0], \"op\": \"subtract\"})).unwrap_err().to_string();\n assert!(e.contains(\"first component\"), \"{e}\");\n assert_eq!(s.active().unwrap().history.entries().len(), steps);\n s.execute(\"path.setOperation\", json!({\"subpaths\": [0, 1], \"op\": \"subtract\"})).unwrap();\n let ops: Vec<_> = work(&s).subpaths.iter().map(|sp| sp.op).collect();\n assert_eq!(ops, [PathOp::Combine, PathOp::Subtract]);\n assert_eq!((covered(&work(&s), 35, 35), covered(&work(&s), 15, 15)), (0.0, 1.0));",
|
||
"expected_assertions": [
|
||
" assert!(e.contains(\"first component\"), \"{e}\");\n assert_eq!(s.active().unwrap().history.entries().len(), steps);\n s.execute(\"path.setOperation\", json!({\"subpaths\": [0, 1], \"op\": \"subtract\"})).unwrap();\n let ops: Vec<_> = work(&s).subpaths.iter().map(|sp| sp.op).collect();",
|
||
" assert_eq!(s.active().unwrap().history.entries().len(), steps);\n s.execute(\"path.setOperation\", json!({\"subpaths\": [0, 1], \"op\": \"subtract\"})).unwrap();\n let ops: Vec<_> = work(&s).subpaths.iter().map(|sp| sp.op).collect();\n assert_eq!(ops, [PathOp::Combine, PathOp::Subtract]);",
|
||
" assert_eq!(ops, [PathOp::Combine, PathOp::Subtract]);\n assert_eq!((covered(&work(&s), 35, 35), covered(&work(&s), 15, 15)), (0.0, 1.0));\n }",
|
||
" assert_eq!((covered(&work(&s), 35, 35), covered(&work(&s), 15, 15)), (0.0, 1.0));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "bad_set_operation_params_change_nothing",
|
||
"path": "crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked bad_set_operation_params_change_nothing -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session();\n s.execute(\"path.set\", json!({\"path\": square()})).unwrap();\n let steps = s.active().unwrap().history.entries().len();\n for (p, msg) in [\n (json!({\"subpaths\": [0]}), \"`op`\"),\n (json!({\"subpaths\": [0], \"op\": \"join\"}), \"`op`\"),\n (json!({\"subpaths\": [0], \"op\": 3}), \"`op`\"),\n (json!({\"op\": \"subtract\"}), \"`subpaths`\"),\n (json!({\"subpaths\": [], \"op\": \"subtract\"}), \"`subpaths`\"),\n (json!({\"subpaths\": [-1], \"op\": \"subtract\"}), \"index\"),\n (json!({\"subpaths\": [7], \"op\": \"subtract\"}), \"no subpath 7\"),\n (json!({\"subpaths\": [0], \"op\": \"subtract\", \"name\": \"Nope\"}), \"\"),",
|
||
"expected_assertions": [
|
||
" assert!(e.contains(msg), \"{p}: {e}\");\n }\n assert_eq!(s.active().unwrap().history.entries().len(), steps);\n assert_eq!(work(&s).subpaths[0].op, PathOp::Combine);",
|
||
" assert_eq!(s.active().unwrap().history.entries().len(), steps);\n assert_eq!(work(&s).subpaths[0].op, PathOp::Combine);\n }",
|
||
" assert_eq!(work(&s).subpaths[0].op, PathOp::Combine);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "bad_merge_params_change_nothing",
|
||
"path": "crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked bad_merge_params_change_nothing -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session();\n s.execute(\"path.set\", json!({\"path\": square()})).unwrap();\n let hole = json!({\"subpaths\": [{\"closed\": true, \"knots\": [[25, 25], [45, 25], [45, 45], [25, 45]]}]});\n s.execute(\"path.set\", json!({\"path\": hole, \"op\": \"subtract\"})).unwrap();\n let id = s.active().unwrap().active_layer.unwrap().0;\n s.execute(\"layer.vectorMask.add\", json!({\"layer\": id, \"path\": square()})).unwrap();\n let state = |s: &Session| {\n let d = s.active().unwrap();\n (d.doc.work_path.clone(), d.doc.paths.clone(), d.doc.layer(LayerId(id)).unwrap().vector_mask.clone(), d.history.entries().len())\n };\n let before = state(&s);\n for (p, msg) in [",
|
||
"expected_assertions": [
|
||
" assert!(e.contains(msg), \"{p}: {e}\");\n assert!(state(&s) == before, \"{p}: nothing changed\");\n }\n }",
|
||
" assert!(state(&s) == before, \"{p}: nothing changed\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "merge_refuses_open_subpaths",
|
||
"path": "crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked merge_refuses_open_subpaths -- --nocapture",
|
||
"fixture_and_action_excerpt": " for open in [json!({\"closed\": false, \"knots\": [[10, 10], [60, 60]]}), json!({\"closed\": false, \"knots\": [[70, 70]]})] {\n let mut s = session();\n let mut mixed = square();\n mixed[\"subpaths\"].as_array_mut().unwrap().push(open);\n s.execute(\"path.set\", json!({\"path\": mixed})).unwrap();\n let id = s.execute(\"shape.create\", json!({\"kind\": \"rect\", \"rect\": [10, 10, 50, 50]})).unwrap()[\"layer\"].as_u64().unwrap();\n s.execute(\"shape.edit\", json!({\"layer\": id, \"path\": mixed})).unwrap();\n let state = |s: &Session| {\n let d = s.active().unwrap();\n let photocraft_doc::LayerContent::Shape(sh) = &d.doc.layer(LayerId(id)).unwrap().content else { panic!(\"shape\") };\n (d.doc.work_path.clone(), sh.path.clone(), d.history.entries().len())\n };",
|
||
"expected_assertions": [
|
||
" assert!(e.contains(\"open subpaths\"), \"{cmd} {p}: {e}\");\n assert!(state(&s) == before, \"{cmd} {p}: nothing changed\");\n }\n }",
|
||
" assert!(state(&s) == before, \"{cmd} {p}: nothing changed\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/engine/src/cmd/path_edit_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "ui_set_drives_the_pen_path_operation",
|
||
"path": "crates/ui-egui/src/control/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked ui_set_drives_the_pen_path_operation -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n let ctx = egui::Context::default();\n assert_eq!(call(&mut app, &ctx, \"ui.set\", json!({\"tool\": \"pen\", \"penMode\": \"shape\", \"penPathOp\": \"subtract\"}))[\"ok\"], true);\n let o = &call(&mut app, &ctx, \"ui.inspect\", json!({}))[\"result\"][\"toolOptions\"];\n assert_eq!((o[\"vector_mode\"].clone(), o[\"pen_path_op\"].clone()), (json!(\"shape\"), json!(\"subtract\")));\n for bad in [json!({\"penPathOp\": \"melt\"}), json!({\"penPathOp\": 1}), json!({\"penMode\": \"pixels\"}), json!({\"penMode\": \"path\", \"penPathOp\": \"xor\"})] {\n assert_eq!(call(&mut app, &ctx, \"ui.set\", bad.clone())[\"ok\"], false, \"{bad}\");\n assert_eq!((app.ui.tool_options.vector_mode.as_str(), app.ui.tool_options.pen_path_op.as_str()), (\"shape\", \"subtract\"), \"{bad}: unchanged\");\n }\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(call(&mut app, &ctx, \"ui.set\", json!({\"tool\": \"pen\", \"penMode\": \"shape\", \"penPathOp\": \"subtract\"}))[\"ok\"], true);\n let o = &call(&mut app, &ctx, \"ui.inspect\", json!({}))[\"result\"][\"toolOptions\"];\n assert_eq!((o[\"vector_mode\"].clone(), o[\"pen_path_op\"].clone()), (json!(\"shape\"), json!(\"subtract\")));\n for bad in [json!({\"penPathOp\": \"melt\"}), json!({\"penPathOp\": 1}), json!({\"penMode\": \"pixels\"}), json!({\"penMode\": \"path\", \"penPathOp\": \"xor\"})] {",
|
||
" assert_eq!((o[\"vector_mode\"].clone(), o[\"pen_path_op\"].clone()), (json!(\"shape\"), json!(\"subtract\")));\n for bad in [json!({\"penPathOp\": \"melt\"}), json!({\"penPathOp\": 1}), json!({\"penMode\": \"pixels\"}), json!({\"penMode\": \"path\", \"penPathOp\": \"xor\"})] {\n assert_eq!(call(&mut app, &ctx, \"ui.set\", bad.clone())[\"ok\"], false, \"{bad}\");\n assert_eq!((app.ui.tool_options.vector_mode.as_str(), app.ui.tool_options.pen_path_op.as_str()), (\"shape\", \"subtract\"), \"{bad}: unchanged\");",
|
||
" assert_eq!(call(&mut app, &ctx, \"ui.set\", bad.clone())[\"ok\"], false, \"{bad}\");\n assert_eq!((app.ui.tool_options.vector_mode.as_str(), app.ui.tool_options.pen_path_op.as_str()), (\"shape\", \"subtract\"), \"{bad}: unchanged\");\n }\n}",
|
||
" assert_eq!((app.ui.tool_options.vector_mode.as_str(), app.ui.tool_options.pen_path_op.as_str()), (\"shape\", \"subtract\"), \"{bad}: unchanged\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/control/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_selected_component_takes_the_picked_operation",
|
||
"path": "crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked a_selected_component_takes_the_picked_operation -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n square(&mut app, 20.0, 20.0, 120.0);\n app.ui.tool_options.pen_path_op = \"combine\".into();\n square(&mut app, 60.0, 60.0, 40.0);\n let (id, sh) = shape(&app);\n assert_eq!(covered(&sh.path, 80, 80), 1.0);\n app.ui.tool = Tool::PathSelection;\n super::press(&mut app, [80.0, 80.0], false);\n let (r, _, heads) = super::selected(&app).expect(\"the inner square is selected\");\n assert_eq!((r, heads), (PathRef::Layer(id.0), vec![1]));\n let steps = history(&app);\n super::set_op(&mut app, \"subtract\").unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(covered(&sh.path, 80, 80), 1.0);\n app.ui.tool = Tool::PathSelection;\n super::press(&mut app, [80.0, 80.0], false);\n let (r, _, heads) = super::selected(&app).expect(\"the inner square is selected\");",
|
||
" assert_eq!((r, heads), (PathRef::Layer(id.0), vec![1]));\n let steps = history(&app);\n super::set_op(&mut app, \"subtract\").unwrap();\n let (_, sh) = shape(&app);",
|
||
" assert_eq!(ops(&sh.path), [PathOp::Combine, PathOp::Subtract]);\n assert_eq!((covered(&sh.path, 80, 80), covered(&sh.path, 30, 30)), (0.0, 1.0), \"a hole\");\n assert_eq!(history(&app), steps + 1);\n assert_eq!(super::selected_op(&app), Some(\"subtract\"), \"the menu shows the component's\");",
|
||
" assert_eq!((covered(&sh.path, 80, 80), covered(&sh.path, 30, 30)), (0.0, 1.0), \"a hole\");\n assert_eq!(history(&app), steps + 1);\n assert_eq!(super::selected_op(&app), Some(\"subtract\"), \"the menu shows the component's\");\n // Picking what it already has adds no step; New Layer only sets the tool.",
|
||
" assert_eq!(history(&app), steps + 1);\n assert_eq!(super::selected_op(&app), Some(\"subtract\"), \"the menu shows the component's\");\n // Picking what it already has adds no step; New Layer only sets the tool.\n super::set_op(&mut app, \"subtract\").unwrap();",
|
||
" assert_eq!(super::selected_op(&app), Some(\"subtract\"), \"the menu shows the component's\");\n // Picking what it already has adds no step; New Layer only sets the tool.\n super::set_op(&mut app, \"subtract\").unwrap();\n super::set_op(&mut app, \"newLayer\").unwrap();",
|
||
" assert_eq!(history(&app), steps + 1);\n assert!(app.session.undo());\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);\n}",
|
||
" assert!(app.session.undo());\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);\n}",
|
||
" assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "plus_and_minus_pick_combine_and_subtract",
|
||
"path": "crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked plus_and_minus_pick_combine_and_subtract -- --nocapture",
|
||
"fixture_and_action_excerpt": " let ctx = egui::Context::default();\n let mut app = app();\n square(&mut app, 20.0, 20.0, 120.0);\n app.ui.tool_options.pen_path_op = \"combine\".into();\n square(&mut app, 60.0, 60.0, 40.0);\n app.ui.tool = Tool::PathSelection;\n super::press(&mut app, [80.0, 80.0], false);\n key(&mut app, &ctx, Key::Minus, egui::Modifiers::NONE);\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Subtract]);\n assert_eq!(app.ui.tool_options.pen_path_op, \"subtract\");\n key(&mut app, &ctx, Key::Equals, egui::Modifiers::SHIFT);\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);",
|
||
"expected_assertions": [
|
||
" assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Subtract]);\n assert_eq!(app.ui.tool_options.pen_path_op, \"subtract\");\n key(&mut app, &ctx, Key::Equals, egui::Modifiers::SHIFT);\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);",
|
||
" assert_eq!(app.ui.tool_options.pen_path_op, \"subtract\");\n key(&mut app, &ctx, Key::Equals, egui::Modifiers::SHIFT);\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);\n key(&mut app, &ctx, Key::Minus, egui::Modifiers::NONE);",
|
||
" assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);\n key(&mut app, &ctx, Key::Minus, egui::Modifiers::NONE);\n key(&mut app, &ctx, Key::Plus, egui::Modifiers::NONE);\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine], \"the keypad's +\");",
|
||
" assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine], \"the keypad's +\");\n // With nothing selected the Pen's next path takes it.\n app.ui.direct_selection = Default::default();\n app.ui.tool = Tool::Pen;",
|
||
" assert_eq!(app.ui.tool_options.pen_path_op, \"subtract\");\n // The blend mode is the Move tool's to step.\n let blend = |app: &PhotocraftApp| app.session.active().unwrap().doc.layer(shape(app).0).unwrap().blend;\n let before = blend(&app);",
|
||
" assert_eq!(blend(&app), before, \"the Pen picks Combine, not a blend mode\");\n assert_eq!(app.ui.tool_options.pen_path_op, \"combine\");\n app.ui.tool = Tool::Move;\n key(&mut app, &ctx, Key::Equals, egui::Modifiers::SHIFT);",
|
||
" assert_eq!(app.ui.tool_options.pen_path_op, \"combine\");\n app.ui.tool = Tool::Move;\n key(&mut app, &ctx, Key::Equals, egui::Modifiers::SHIFT);\n assert_ne!(blend(&app), before);",
|
||
" assert_ne!(blend(&app), before);\n assert_eq!(app.ui.tool_options.pen_path_op, \"combine\");\n}",
|
||
" assert_eq!(app.ui.tool_options.pen_path_op, \"combine\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "path_selection_selects_and_moves_components",
|
||
"path": "crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked path_selection_selects_and_moves_components -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n square(&mut app, 10.0, 10.0, 40.0);\n app.ui.tool_options.pen_path_op = \"combine\".into();\n square(&mut app, 100.0, 10.0, 40.0);\n square(&mut app, 100.0, 100.0, 40.0);\n app.ui.tool = Tool::PathSelection;\n let heads = |app: &PhotocraftApp| super::selected(app).map(|(.., h)| h).unwrap_or_default();\n super::press(&mut app, [30.0, 30.0], false);\n super::press(&mut app, [120.0, 120.0], true);\n assert_eq!(heads(&app), [0, 2]);\n // Pressing a selected one keeps both, for the drag.\n super::press(&mut app, [120.0, 120.0], false);",
|
||
"expected_assertions": [
|
||
" assert_eq!(heads(&app), [0, 2]);\n // Pressing a selected one keeps both, for the drag.\n super::press(&mut app, [120.0, 120.0], false);\n assert_eq!(heads(&app), [0, 2]);",
|
||
" assert_eq!(heads(&app), [0, 2]);\n crate::vector_ui::path_selection_finish(&mut app, [120.0, 120.0], [125.0, 130.0]);\n let (_, sh) = shape(&app);\n let first = |s: usize| sh.path.subpaths[s].knots[0].anchor;",
|
||
" assert_eq!((first(0).x, first(0).y), (15.0, 20.0));\n assert_eq!((first(1).x, first(1).y), (100.0, 10.0), \"not selected: stays\");\n assert_eq!((first(2).x, first(2).y), (105.0, 110.0));\n super::press(&mut app, [125.0, 130.0], true);",
|
||
" assert_eq!((first(1).x, first(1).y), (100.0, 10.0), \"not selected: stays\");\n assert_eq!((first(2).x, first(2).y), (105.0, 110.0));\n super::press(&mut app, [125.0, 130.0], true);\n assert_eq!(heads(&app), [0]);",
|
||
" assert_eq!((first(2).x, first(2).y), (105.0, 110.0));\n super::press(&mut app, [125.0, 130.0], true);\n assert_eq!(heads(&app), [0]);\n super::press(&mut app, [190.0, 190.0], false);",
|
||
" assert_eq!(heads(&app), [0]);\n super::press(&mut app, [190.0, 190.0], false);\n assert!(super::selected(&app).is_none(), \"a click off every component deselects\");\n}",
|
||
" assert!(super::selected(&app).is_none(), \"a click off every component deselects\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_stale_selection_changes_nothing",
|
||
"path": "crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked a_stale_selection_changes_nothing -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n square(&mut app, 10.0, 10.0, 40.0);\n let (id, _) = shape(&app);\n app.ui.tool = Tool::PathSelection;\n app.ui.direct_selection = crate::direct_select::DirectSelection { target: Some(PathRef::Layer(id.0)), anchors: vec![[5, 0]], ..Default::default() };\n assert!(super::selected(&app).is_none());\n let steps = history(&app);\n super::set_op(&mut app, \"subtract\").unwrap();\n assert_eq!(history(&app), steps);\n assert_eq!(super::move_selected(&mut app, [3.0, 3.0]), None);\n}",
|
||
"expected_assertions": [
|
||
" assert!(super::selected(&app).is_none());\n let steps = history(&app);\n super::set_op(&mut app, \"subtract\").unwrap();\n assert_eq!(history(&app), steps);",
|
||
" assert_eq!(history(&app), steps);\n assert_eq!(super::move_selected(&mut app, [3.0, 3.0]), None);\n}",
|
||
" assert_eq!(super::move_selected(&mut app, [3.0, 3.0]), None);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_first_component_keeps_combining",
|
||
"path": "crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_first_component_keeps_combining -- --nocapture",
|
||
"fixture_and_action_excerpt": " let ctx = egui::Context::default();\n let mut app = app();\n square(&mut app, 20.0, 20.0, 120.0);\n app.ui.tool_options.pen_path_op = \"combine\".into();\n square(&mut app, 60.0, 60.0, 40.0);\n app.ui.tool = Tool::PathSelection;\n super::press(&mut app, [30.0, 30.0], false);\n assert_eq!(super::selected(&app).map(|(.., h)| h), Some(vec![0]));\n let steps = history(&app);\n key(&mut app, &ctx, Key::Minus, egui::Modifiers::NONE);\n super::set_op(&mut app, \"intersect\").unwrap();\n assert_eq!(history(&app), steps, \"no step\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(super::selected(&app).map(|(.., h)| h), Some(vec![0]));\n let steps = history(&app);\n key(&mut app, &ctx, Key::Minus, egui::Modifiers::NONE);\n super::set_op(&mut app, \"intersect\").unwrap();",
|
||
" assert_eq!(history(&app), steps, \"no step\");\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);\n assert_eq!(super::selected_op(&app), Some(\"combine\"), \"the menu shows what it draws as\");\n super::press(&mut app, [80.0, 80.0], true);",
|
||
" assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);\n assert_eq!(super::selected_op(&app), Some(\"combine\"), \"the menu shows what it draws as\");\n super::press(&mut app, [80.0, 80.0], true);\n super::set_op(&mut app, \"subtract\").unwrap();",
|
||
" assert_eq!(super::selected_op(&app), Some(\"combine\"), \"the menu shows what it draws as\");\n super::press(&mut app, [80.0, 80.0], true);\n super::set_op(&mut app, \"subtract\").unwrap();\n assert_eq!(history(&app), steps + 1);",
|
||
" assert_eq!(history(&app), steps + 1);\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Subtract]);\n assert_eq!(super::selected_op(&app), None, \"they differ\");\n}",
|
||
" assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Subtract]);\n assert_eq!(super::selected_op(&app), None, \"they differ\");\n}",
|
||
" assert_eq!(super::selected_op(&app), None, \"they differ\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_pen_does_not_edit_a_hidden_component_selection",
|
||
"path": "crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_pen_does_not_edit_a_hidden_component_selection -- --nocapture",
|
||
"fixture_and_action_excerpt": " let ctx = egui::Context::default();\n let mut app = app();\n square(&mut app, 20.0, 20.0, 120.0);\n app.ui.tool_options.pen_path_op = \"combine\".into();\n square(&mut app, 60.0, 60.0, 40.0);\n app.ui.tool = Tool::PathSelection;\n super::press(&mut app, [80.0, 80.0], false);\n assert!(super::selected(&app).is_some());\n app.ui.tool = Tool::Pen;\n let steps = history(&app);\n key(&mut app, &ctx, Key::Minus, egui::Modifiers::NONE);\n assert_eq!(app.ui.tool_options.pen_path_op, \"subtract\", \"the next path's\");",
|
||
"expected_assertions": [
|
||
" assert!(super::selected(&app).is_some());\n app.ui.tool = Tool::Pen;\n let steps = history(&app);\n key(&mut app, &ctx, Key::Minus, egui::Modifiers::NONE);",
|
||
" assert_eq!(app.ui.tool_options.pen_path_op, \"subtract\", \"the next path's\");\n assert_eq!(super::selected_op(&app), None);\n assert_eq!(history(&app), steps);\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);",
|
||
" assert_eq!(super::selected_op(&app), None);\n assert_eq!(history(&app), steps);\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);\n}",
|
||
" assert_eq!(history(&app), steps);\n assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);\n}",
|
||
" assert_eq!(ops(&shape(&app).1.path), [PathOp::Combine, PathOp::Combine]);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "dragging_a_live_shape_keeps_it_live",
|
||
"path": "crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked dragging_a_live_shape_keeps_it_live -- --nocapture",
|
||
"fixture_and_action_excerpt": " for kind in [\"rect\", \"ellipse\"] {\n let mut app = app();\n app.run(\"shape.create\", json!({\"kind\": kind, \"rect\": [20, 20, 60, 40], \"fill\": \"#ff0000\"})).unwrap();\n assert!(shape(&app).1.live.is_some(), \"{kind}\");\n app.ui.tool = Tool::PathSelection;\n super::press(&mut app, [50.0, 40.0], false);\n assert_eq!(super::selected(&app).map(|(.., h)| h), Some(vec![0]), \"{kind}\");\n let steps = history(&app);\n crate::vector_ui::path_selection_finish(&mut app, [50.0, 40.0], [60.0, 45.0]);\n let (_, sh) = shape(&app);\n assert_eq!(history(&app), steps + 1, \"{kind}\");\n let (x0, y0, ..) = sh.path.control_bounds().unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(shape(&app).1.live.is_some(), \"{kind}\");\n app.ui.tool = Tool::PathSelection;\n super::press(&mut app, [50.0, 40.0], false);\n assert_eq!(super::selected(&app).map(|(.., h)| h), Some(vec![0]), \"{kind}\");",
|
||
" assert_eq!(super::selected(&app).map(|(.., h)| h), Some(vec![0]), \"{kind}\");\n let steps = history(&app);\n crate::vector_ui::path_selection_finish(&mut app, [50.0, 40.0], [60.0, 45.0]);\n let (_, sh) = shape(&app);",
|
||
" assert_eq!(history(&app), steps + 1, \"{kind}\");\n let (x0, y0, ..) = sh.path.control_bounds().unwrap();\n assert_eq!((x0.round(), y0.round()), (30.0, 25.0), \"{kind}: moved\");\n match sh.live {",
|
||
" assert_eq!((x0.round(), y0.round()), (30.0, 25.0), \"{kind}: moved\");\n match sh.live {\n Some(photocraft_doc::vector::LiveShape::Rect { rect, .. } | photocraft_doc::vector::LiveShape::Ellipse { rect }) => {\n assert_eq!(rect, [30.0, 25.0, 60.0, 40.0], \"{kind}\")",
|
||
" assert_eq!(rect, [30.0, 25.0, 60.0, 40.0], \"{kind}\")\n }\n other => panic!(\"{kind}: still live, got {other:?}\"),\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_pen_carries_on_an_open_shape_path",
|
||
"path": "crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_pen_carries_on_an_open_shape_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n app.ui.tool_options.shape_fill = true;\n app.ui.tool_options.stroke_width = 0.0;\n for (x, y) in [(20.0, 20.0), (120.0, 20.0), (120.0, 120.0)] {\n click(&mut app, x, y);\n }\n assert!(pen_commit(&mut app, false));\n let (id, sh) = shape(&app);\n assert!(sh.fill.is_none() && sh.stroke.is_some(), \"an open path is stroked\");\n let count = app.session.active().unwrap().doc.layers.len();\n let steps = history(&app);\n click(&mut app, 120.0, 120.0); // its last anchor: carry on",
|
||
"expected_assertions": [
|
||
" assert!(pen_commit(&mut app, false));\n let (id, sh) = shape(&app);\n assert!(sh.fill.is_none() && sh.stroke.is_some(), \"an open path is stroked\");\n let count = app.session.active().unwrap().doc.layers.len();",
|
||
" assert!(sh.fill.is_none() && sh.stroke.is_some(), \"an open path is stroked\");\n let count = app.session.active().unwrap().doc.layers.len();\n let steps = history(&app);\n click(&mut app, 120.0, 120.0); // its last anchor: carry on",
|
||
" assert!(app.ui.pen.is_none(), \"closing commits\");\n let (same, sh) = shape(&app);\n assert_eq!((same, app.session.active().unwrap().doc.layers.len()), (id, count), \"no new layer\");\n assert_eq!(sh.path.subpaths.len(), 1);",
|
||
" assert_eq!((same, app.session.active().unwrap().doc.layers.len()), (id, count), \"no new layer\");\n assert_eq!(sh.path.subpaths.len(), 1);\n assert!(sh.path.subpaths[0].closed);\n assert_eq!(sh.path.subpaths[0].knots.len(), 4);",
|
||
" assert_eq!(sh.path.subpaths.len(), 1);\n assert!(sh.path.subpaths[0].closed);\n assert_eq!(sh.path.subpaths[0].knots.len(), 4);\n assert!(sh.fill.is_some() && sh.stroke.is_none(), \"filled like a path drawn closed\");",
|
||
" assert!(sh.path.subpaths[0].closed);\n assert_eq!(sh.path.subpaths[0].knots.len(), 4);\n assert!(sh.fill.is_some() && sh.stroke.is_none(), \"filled like a path drawn closed\");\n assert_eq!(history(&app), steps + 1);",
|
||
" assert_eq!(sh.path.subpaths[0].knots.len(), 4);\n assert!(sh.fill.is_some() && sh.stroke.is_none(), \"filled like a path drawn closed\");\n assert_eq!(history(&app), steps + 1);\n assert!(app.session.undo());",
|
||
" assert!(sh.fill.is_some() && sh.stroke.is_none(), \"filled like a path drawn closed\");\n assert_eq!(history(&app), steps + 1);\n assert!(app.session.undo());\n assert!(!shape(&app).1.path.subpaths[0].closed);",
|
||
" assert_eq!(history(&app), steps + 1);\n assert!(app.session.undo());\n assert!(!shape(&app).1.path.subpaths[0].closed);\n}",
|
||
" assert!(app.session.undo());\n assert!(!shape(&app).1.path.subpaths[0].closed);\n}",
|
||
" assert!(!shape(&app).1.path.subpaths[0].closed);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "an_open_component_of_a_filled_shape_keeps_its_paint",
|
||
"path": "crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked an_open_component_of_a_filled_shape_keeps_its_paint -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n square(&mut app, 10.0, 10.0, 60.0);\n let (id, before) = shape(&app);\n // An open component added to the layer.\n app.ui.tool_options.pen_path_op = \"combine\".into();\n for (x, y) in [(100.0, 100.0), (150.0, 100.0)] {\n click(&mut app, x, y);\n }\n assert!(pen_commit(&mut app, false));\n app.ui.tool_options.shape_fill = false;\n click(&mut app, 100.0, 100.0); // its first anchor\n click(&mut app, 100.0, 150.0);",
|
||
"expected_assertions": [
|
||
" assert!(pen_commit(&mut app, false));\n app.ui.tool_options.shape_fill = false;\n click(&mut app, 100.0, 100.0); // its first anchor\n click(&mut app, 100.0, 150.0);",
|
||
" assert!(pen_commit(&mut app, false));\n let (same, sh) = shape(&app);\n assert_eq!(same, id);\n assert_eq!(sh.path.subpaths.len(), 2);",
|
||
" assert_eq!(same, id);\n assert_eq!(sh.path.subpaths.len(), 2);\n assert_eq!(sh.path.subpaths[1].knots.len(), 3);\n assert_eq!((sh.fill, sh.stroke), (before.fill, before.stroke));",
|
||
" assert_eq!(sh.path.subpaths.len(), 2);\n assert_eq!(sh.path.subpaths[1].knots.len(), 3);\n assert_eq!((sh.fill, sh.stroke), (before.fill, before.stroke));\n}",
|
||
" assert_eq!(sh.path.subpaths[1].knots.len(), 3);\n assert_eq!((sh.fill, sh.stroke), (before.fill, before.stroke));\n}",
|
||
" assert_eq!((sh.fill, sh.stroke), (before.fill, before.stroke));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_pen_carries_on_a_vector_masks_open_subpath",
|
||
"path": "crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_pen_carries_on_a_vector_masks_open_subpath -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n app.ui.tool_options.vector_mode = \"path\".into();\n app.run(\"layer.new.layer\", json!({})).unwrap();\n let id = app.session.active().unwrap().active_layer.unwrap().0;\n let open = json!({\"subpaths\": [{\"closed\": false, \"knots\": [[20, 20], [120, 20]]}]});\n app.run(\"layer.vectorMask.add\", json!({\"layer\": id, \"path\": open})).unwrap();\n app.ui.vector_mask_target = true;\n click(&mut app, 120.0, 20.0);\n click(&mut app, 120.0, 120.0);\n assert!(pen_commit(&mut app, false));\n let st = app.session.active().unwrap();\n let mask = st.doc.layer(LayerId(id)).unwrap().vector_mask.clone().unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(pen_commit(&mut app, false));\n let st = app.session.active().unwrap();\n let mask = st.doc.layer(LayerId(id)).unwrap().vector_mask.clone().unwrap();\n assert_eq!(mask.path.subpaths.len(), 1);",
|
||
" assert_eq!(mask.path.subpaths.len(), 1);\n assert_eq!(mask.path.subpaths[0].knots.len(), 3);\n assert!(st.doc.work_path.is_none());\n}",
|
||
" assert_eq!(mask.path.subpaths[0].knots.len(), 3);\n assert!(st.doc.work_path.is_none());\n}",
|
||
" assert!(st.doc.work_path.is_none());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/path_components/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "subtract_front_shape_cuts_a_hole_in_the_selected_shape_layer",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked subtract_front_shape_cuts_a_hole_in_the_selected_shape_layer -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n app.ui.tool_options.vector_mode = \"shape\".into();\n assert_eq!(app.ui.tool_options.pen_path_op, \"newLayer\", \"Photoshop's default in Shape mode\");\n square(&mut app, 20.0, 20.0, 100.0);\n let (id, _) = shape_path(&app);\n let count = layers(&app);\n app.ui.tool_options.pen_path_op = \"subtract\".into();\n square(&mut app, 50.0, 50.0, 40.0);\n let (same, path) = shape_path(&app);\n assert_eq!((same, layers(&app)), (id, count), \"no new layer\");\n assert_eq!(path.subpaths.iter().map(|s| s.op).collect::<Vec<_>>(), [PathOp::Combine, PathOp::Subtract]);\n assert_eq!((covered(&path, 70, 70), covered(&path, 30, 30)), (0.0, 1.0), \"a hole in the body\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(app.ui.tool_options.pen_path_op, \"newLayer\", \"Photoshop's default in Shape mode\");\n square(&mut app, 20.0, 20.0, 100.0);\n let (id, _) = shape_path(&app);\n let count = layers(&app);",
|
||
" assert_eq!((same, layers(&app)), (id, count), \"no new layer\");\n assert_eq!(path.subpaths.iter().map(|s| s.op).collect::<Vec<_>>(), [PathOp::Combine, PathOp::Subtract]);\n assert_eq!((covered(&path, 70, 70), covered(&path, 30, 30)), (0.0, 1.0), \"a hole in the body\");\n app.session.undo();",
|
||
" assert_eq!(path.subpaths.iter().map(|s| s.op).collect::<Vec<_>>(), [PathOp::Combine, PathOp::Subtract]);\n assert_eq!((covered(&path, 70, 70), covered(&path, 30, 30)), (0.0, 1.0), \"a hole in the body\");\n app.session.undo();\n assert_eq!(shape_path(&app).1.subpaths.len(), 1, \"undo takes back only the hole\");",
|
||
" assert_eq!((covered(&path, 70, 70), covered(&path, 30, 30)), (0.0, 1.0), \"a hole in the body\");\n app.session.undo();\n assert_eq!(shape_path(&app).1.subpaths.len(), 1, \"undo takes back only the hole\");\n app.session.redo();",
|
||
" assert_eq!(shape_path(&app).1.subpaths.len(), 1, \"undo takes back only the hole\");\n app.session.redo();\n // Intersect and Exclude are stored the same way.\n for (op, want) in [(\"intersect\", PathOp::Intersect), (\"exclude\", PathOp::Exclude), (\"combine\", PathOp::Combine)] {",
|
||
" assert_eq!(shape_path(&app).1.subpaths.last().map(|s| s.op), Some(want), \"{op}\");\n }\n assert_eq!(layers(&app), count);\n // New Layer makes another shape layer again.",
|
||
" assert_eq!(layers(&app), count);\n // New Layer makes another shape layer again.\n app.ui.tool_options.pen_path_op = \"newLayer\".into();\n square(&mut app, 10.0, 10.0, 30.0);",
|
||
" assert_eq!(layers(&app), count + 1);\n assert_ne!(shape_path(&app).0, id);\n}",
|
||
" assert_ne!(shape_path(&app).0, id);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_locked_shape_layer_keeps_the_drawn_path",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked a_locked_shape_layer_keeps_the_drawn_path -- --nocapture",
|
||
"fixture_and_action_excerpt": " for lock in [\"all\", \"pixels\"] {\n let mut app = app();\n app.ui.tool_options.vector_mode = \"shape\".into();\n square(&mut app, 20.0, 20.0, 100.0);\n let (id, body) = shape_path(&app);\n app.run(\"layer.lockLayers\", json!({lock: true})).unwrap();\n let steps = app.session.active().unwrap().history.past_len();\n app.ui.tool_options.pen_path_op = \"subtract\".into();\n square(&mut app, 50.0, 50.0, 40.0);\n let draft = app.ui.pen.clone().unwrap_or_else(|| panic!(\"{lock}: the draft is kept\"));\n // The four corners and the close's stand-in on the first: still a closed path.\n assert!(draft.knots.len() == 5 && super::closing(&draft), \"{lock}: {:?}\", draft.knots);",
|
||
"expected_assertions": [
|
||
" assert!(draft.knots.len() == 5 && super::closing(&draft), \"{lock}: {:?}\", draft.knots);\n assert!(app.ui.status_error, \"{lock}: {}\", app.ui.status);\n assert_eq!(shape_path(&app), (id, body.clone()), \"{lock}: the shape is unchanged\");\n assert_eq!(app.session.active().unwrap().history.past_len(), steps, \"{lock}: no History step\");",
|
||
" assert!(app.ui.status_error, \"{lock}: {}\", app.ui.status);\n assert_eq!(shape_path(&app), (id, body.clone()), \"{lock}: the shape is unchanged\");\n assert_eq!(app.session.active().unwrap().history.past_len(), steps, \"{lock}: no History step\");\n // Undo takes back the lock, not the drawn path.",
|
||
" assert_eq!(shape_path(&app), (id, body.clone()), \"{lock}: the shape is unchanged\");\n assert_eq!(app.session.active().unwrap().history.past_len(), steps, \"{lock}: no History step\");\n // Undo takes back the lock, not the drawn path.\n app.session.undo();",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), steps, \"{lock}: no History step\");\n // Undo takes back the lock, not the drawn path.\n app.session.undo();\n assert!(app.ui.pen.is_some(), \"{lock}\");",
|
||
" assert!(app.ui.pen.is_some(), \"{lock}\");\n assert!(super::pen_commit(&mut app, false), \"{lock}: {}\", app.ui.status); // ↩\n assert!(app.ui.pen.is_none(), \"{lock}\");\n let (same, path) = shape_path(&app);",
|
||
" assert!(super::pen_commit(&mut app, false), \"{lock}: {}\", app.ui.status); // ↩\n assert!(app.ui.pen.is_none(), \"{lock}\");\n let (same, path) = shape_path(&app);\n assert_eq!(same, id, \"{lock}\");",
|
||
" assert!(app.ui.pen.is_none(), \"{lock}\");\n let (same, path) = shape_path(&app);\n assert_eq!(same, id, \"{lock}\");\n assert_eq!(path.subpaths.iter().map(|s| (s.op, s.closed)).collect::<Vec<_>>(), [(PathOp::Combine, true), (PathOp::Subtract, true)], \"{lock}\");",
|
||
" assert_eq!(same, id, \"{lock}\");\n assert_eq!(path.subpaths.iter().map(|s| (s.op, s.closed)).collect::<Vec<_>>(), [(PathOp::Combine, true), (PathOp::Subtract, true)], \"{lock}\");\n assert_eq!(covered(&path, 70, 70), 0.0, \"{lock}: the hole\");\n }",
|
||
" assert_eq!(path.subpaths.iter().map(|s| (s.op, s.closed)).collect::<Vec<_>>(), [(PathOp::Combine, true), (PathOp::Subtract, true)], \"{lock}\");\n assert_eq!(covered(&path, 70, 70), 0.0, \"{lock}: the hole\");\n }\n}",
|
||
" assert_eq!(covered(&path, 70, 70), 0.0, \"{lock}: the hole\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "switching_tools_ends_a_refused_draft_once",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked switching_tools_ends_a_refused_draft_once -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = egui_kittest::Harness::builder().with_size(vec2(1400.0, 900.0)).with_max_steps(64).build_eframe(|cc| {\n PhotocraftApp::setup_context(&cc.egui_ctx, Default::default());\n app()\n });\n h.run_steps(2);\n let (id, body, steps) = refused_hole(h.state_mut());\n h.state_mut().ui.tool = Tool::Brush;\n h.run_steps(2);\n assert_kept_as_work_path(h.state(), id, &body, steps);\n let status = h.state().ui.status.clone();\n h.run_steps(4);\n assert_eq!(h.state().ui.status, status, \"no retry\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().ui.status, status, \"no retry\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), steps + 1);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), steps + 1);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "esc_ends_a_refused_draft_and_return_keeps_it",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked esc_ends_a_refused_draft_and_return_keeps_it -- --nocapture",
|
||
"fixture_and_action_excerpt": " let ctx = egui::Context::default();\n let key = |app: &mut PhotocraftApp, key: egui::Key| {\n let raw = egui::RawInput {\n events: vec![egui::Event::Key { key, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::NONE }],\n ..Default::default()\n };\n ctx.begin_pass(raw);\n crate::shortcuts::handle(app, &ctx);\n ctx.end_pass().textures_delta.clear();\n };\n for lang in crate::i18n::Lang::all() {\n crate::i18n::with_language(lang, || {",
|
||
"expected_assertions": [
|
||
" assert!(crate::i18n::has(lang, message), \"{}: {message}\", lang.code());\n }\n }\n let mut app = app();",
|
||
" assert_eq!(app.ui.pen, draft, \"↩ keeps the draft\");\n assert_eq!(app.session.active().unwrap().history.past_len(), steps);\n let refused = app.ui.status.clone();\n key(&mut app, egui::Key::Escape);",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), steps);\n let refused = app.ui.status.clone();\n key(&mut app, egui::Key::Escape);\n assert_kept_as_work_path(&app, id, &body, steps);",
|
||
" assert_eq!(app.ui.status, format!(\"{refused} ({})\", tl!(\"The path was kept as the Work Path\")));\n });\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "an_operation_without_a_selected_shape_starts_a_new_shape_layer",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked an_operation_without_a_selected_shape_starts_a_new_shape_layer -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n app.ui.tool_options.vector_mode = \"shape\".into();\n app.ui.tool_options.pen_path_op = \"subtract\".into();\n let count = layers(&app);\n square(&mut app, 20.0, 20.0, 100.0);\n let (id, path) = shape_path(&app);\n assert_eq!((layers(&app), path.subpaths.len()), (count + 1, 1));\n assert_eq!(covered(&path, 60, 60), 1.0, \"a lone first component draws\");\n square(&mut app, 50.0, 50.0, 40.0);\n assert_eq!((shape_path(&app).0, layers(&app)), (id, count + 1));\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!((layers(&app), path.subpaths.len()), (count + 1, 1));\n assert_eq!(covered(&path, 60, 60), 1.0, \"a lone first component draws\");\n square(&mut app, 50.0, 50.0, 40.0);\n assert_eq!((shape_path(&app).0, layers(&app)), (id, count + 1));",
|
||
" assert_eq!(covered(&path, 60, 60), 1.0, \"a lone first component draws\");\n square(&mut app, 50.0, 50.0, 40.0);\n assert_eq!((shape_path(&app).0, layers(&app)), (id, count + 1));\n}",
|
||
" assert_eq!((shape_path(&app).0, layers(&app)), (id, count + 1));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "path_mode_adds_subpaths_with_the_operation",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked path_mode_adds_subpaths_with_the_operation -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n assert_eq!(pen_path_op(&app.ui.tool_options), Some(\"combine\"));\n square(&mut app, 20.0, 20.0, 100.0);\n square(&mut app, 30.0, 30.0, 10.0);\n app.ui.tool_options.pen_path_op = \"intersect\".into();\n square(&mut app, 50.0, 50.0, 100.0);\n assert_eq!(work(&app).subpaths.iter().map(|s| s.op).collect::<Vec<_>>(), [PathOp::Combine, PathOp::Combine, PathOp::Intersect]);\n // A selected saved path.\n app.run(\"path.set\", json!({\"name\": \"Saved\", \"path\": {\"subpaths\": [{\"closed\": true, \"knots\": [[2, 2], [60, 2], [60, 60]]}]}})).unwrap();\n app.ui.selected_path = Some(\"Saved\".into());\n app.ui.tool_options.pen_path_op = \"exclude\".into();\n square(&mut app, 10.0, 10.0, 20.0);",
|
||
"expected_assertions": [
|
||
" assert_eq!(pen_path_op(&app.ui.tool_options), Some(\"combine\"));\n square(&mut app, 20.0, 20.0, 100.0);\n square(&mut app, 30.0, 30.0, 10.0);\n app.ui.tool_options.pen_path_op = \"intersect\".into();",
|
||
" assert_eq!(work(&app).subpaths.iter().map(|s| s.op).collect::<Vec<_>>(), [PathOp::Combine, PathOp::Combine, PathOp::Intersect]);\n // A selected saved path.\n app.run(\"path.set\", json!({\"name\": \"Saved\", \"path\": {\"subpaths\": [{\"closed\": true, \"knots\": [[2, 2], [60, 2], [60, 60]]}]}})).unwrap();\n app.ui.selected_path = Some(\"Saved\".into());",
|
||
" assert_eq!(saved.subpaths.last().map(|s| s.op), Some(PathOp::Exclude));\n // A targeted vector mask.\n let id = app.session.active().unwrap().active_layer.unwrap().0;\n app.run(\"layer.vectorMask.add\", json!({\"layer\": id, \"path\": {\"subpaths\": [{\"closed\": true, \"knots\": [[0, 0], [100, 0], [100, 100], [0, 100]]}]}})).unwrap();",
|
||
" assert_eq!(vm.path.subpaths.iter().map(|s| s.op).collect::<Vec<_>>(), [PathOp::Combine, PathOp::Subtract]);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_options_bar_menu_sets_the_operation_and_merges",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_options_bar_menu_sets_the_operation_and_merges -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n square(&mut app, 20.0, 20.0, 100.0);\n app.ui.tool_options.pen_path_op = \"subtract\".into();\n square(&mut app, 50.0, 50.0, 40.0);\n app.ui.tool_options.pen_path_op = \"combine\".into();\n let mut h = egui_kittest::Harness::builder().with_size(vec2(1100.0, 400.0)).build_ui_state(\n |ui, app: &mut PhotocraftApp| {\n if ui.ctx().fonts(|f| f.families().contains(&egui::FontFamily::Name(\"medium\".into()))) {\n ui.horizontal(|ui| super::options_bar(app, ui, Tool::Pen));\n }\n },\n app,",
|
||
"expected_assertions": [
|
||
" assert!(h.get_by_label(\"New Layer\").accesskit_node().is_disabled(), \"Path mode has no New Layer\");\n h.get_by_label(\"Exclude Overlapping Shapes\").click();\n h.run_steps(3);\n assert_eq!(h.state().ui.tool_options.pen_path_op, \"exclude\");",
|
||
" assert_eq!(h.state().ui.tool_options.pen_path_op, \"exclude\");\n assert!(h.query_by_label(\"Exclude Overlapping Shapes\").is_none(), \"choosing closes the menu\");\n // Merge Shape Components: the Work Path's hole stays a hole, now as plain outlines.\n let before = work(h.state());",
|
||
" assert!(h.query_by_label(\"Exclude Overlapping Shapes\").is_none(), \"choosing closes the menu\");\n // Merge Shape Components: the Work Path's hole stays a hole, now as plain outlines.\n let before = work(h.state());\n open(&mut h);",
|
||
" assert_ne!(merged, before);\n assert_eq!((covered(&merged, 70, 70), covered(&merged, 30, 30)), (0.0, 1.0));\n // Shape mode offers New Layer.\n h.state_mut().ui.tool_options.vector_mode = \"shape\".into();",
|
||
" assert_eq!((covered(&merged, 70, 70), covered(&merged, 30, 30)), (0.0, 1.0));\n // Shape mode offers New Layer.\n h.state_mut().ui.tool_options.vector_mode = \"shape\".into();\n h.run_steps(2);",
|
||
" assert!(!h.get_by_label(\"New Layer\").accesskit_node().is_disabled());\n h.get_by_label(\"New Layer\").click();\n h.run_steps(3);\n assert_eq!(pen_path_op(&h.state().ui.tool_options), None);",
|
||
" assert_eq!(pen_path_op(&h.state().ui.tool_options), None);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "merge_is_disabled_with_fewer_than_two_components",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked merge_is_disabled_with_fewer_than_two_components -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n square(&mut app, 20.0, 20.0, 100.0);\n let mut h = egui_kittest::Harness::builder().with_size(vec2(1100.0, 400.0)).build_ui_state(\n |ui, app: &mut PhotocraftApp| {\n if ui.ctx().fonts(|f| f.families().contains(&egui::FontFamily::Name(\"medium\".into()))) {\n ui.horizontal(|ui| super::options_bar(app, ui, Tool::Pen));\n }\n },\n app,\n );\n PhotocraftApp::setup_context(&h.ctx, crate::theme::ThemeKind::Studio);\n h.run_steps(4);",
|
||
"expected_assertions": [
|
||
" assert!(h.get_by_label(\"Merge Shape Components\").accesskit_node().is_disabled());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "an_unknown_operation_falls_back_to_new_layer",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked an_unknown_operation_falls_back_to_new_layer -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n app.ui.tool_options.pen_path_op = \"melt\".into();\n assert_eq!(pen_path_op(&app.ui.tool_options), Some(\"combine\"));\n app.ui.tool_options.vector_mode = \"shape\".into();\n assert_eq!(pen_path_op(&app.ui.tool_options), None);\n let count = layers(&app);\n square(&mut app, 20.0, 20.0, 50.0);\n square(&mut app, 30.0, 30.0, 50.0);\n assert_eq!(layers(&app), count + 2);\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(pen_path_op(&app.ui.tool_options), Some(\"combine\"));\n app.ui.tool_options.vector_mode = \"shape\".into();\n assert_eq!(pen_path_op(&app.ui.tool_options), None);\n let count = layers(&app);",
|
||
" assert_eq!(pen_path_op(&app.ui.tool_options), None);\n let count = layers(&app);\n square(&mut app, 20.0, 20.0, 50.0);\n square(&mut app, 30.0, 30.0, 50.0);",
|
||
" assert_eq!(layers(&app), count + 2);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "freeform_refuses_a_locked_shape_before_starting_a_stroke",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked freeform_refuses_a_locked_shape_before_starting_a_stroke -- --nocapture",
|
||
"fixture_and_action_excerpt": " use crate::canvas::{ToolEvent, tool_event};\n for lock in [\"all\", \"pixels\"] {\n let mut app = app();\n app.ui.tool_options.vector_mode = \"shape\".into();\n square(&mut app, 20.0, 20.0, 100.0);\n let (id, body) = shape_path(&app);\n app.run(\"layer.lockLayers\", json!({lock: true})).unwrap();\n let steps = app.session.active().unwrap().history.past_len();\n app.ui.tool = Tool::FreeformPen;\n app.ui.tool_options.pen_path_op = \"subtract\".into();\n tool_event(&mut app, ToolEvent::Down { x: 50.0, y: 50.0, pressure: 1.0 }, egui::Modifiers::NONE);\n assert!(app.drag.is_none(), \"{lock}: stroke was not started\");",
|
||
"expected_assertions": [
|
||
" assert!(app.drag.is_none(), \"{lock}: stroke was not started\");\n assert!(app.ui.status_error, \"{lock}\");\n assert_eq!(shape_path(&app), (id, body), \"{lock}\");\n assert_eq!(app.session.active().unwrap().history.past_len(), steps, \"{lock}\");",
|
||
" assert!(app.ui.status_error, \"{lock}\");\n assert_eq!(shape_path(&app), (id, body), \"{lock}\");\n assert_eq!(app.session.active().unwrap().history.past_len(), steps, \"{lock}\");\n app.session.undo();",
|
||
" assert_eq!(shape_path(&app), (id, body), \"{lock}\");\n assert_eq!(app.session.active().unwrap().history.past_len(), steps, \"{lock}\");\n app.session.undo();\n tool_event(&mut app, ToolEvent::Down { x: 50.0, y: 50.0, pressure: 1.0 }, egui::Modifiers::NONE);",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), steps, \"{lock}\");\n app.session.undo();\n tool_event(&mut app, ToolEvent::Down { x: 50.0, y: 50.0, pressure: 1.0 }, egui::Modifiers::NONE);\n assert!(app.drag.is_some(), \"{lock}: unlocked stroke can start\");",
|
||
" assert!(app.drag.is_some(), \"{lock}: unlocked stroke can start\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/pen_path_ops_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "failed_stale_pen_commit_preserves_the_draft_until_retry",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked failed_stale_pen_commit_preserves_the_draft_until_retry -- --nocapture",
|
||
"fixture_and_action_excerpt": " for action in [\"pen\", \"curvature\", \"undo\", \"commit\", \"command\"] {\n let mut app = app();\n app.run(\"path.set\", json!({\"name\": \"work\", \"path\": {\"subpaths\": [{\"closed\": false, \"knots\": [[5, 5], [10, 10]]}]}})).unwrap();\n let original = app.session.active().unwrap().doc.work_path.clone().unwrap();\n app.ui.tool = Tool::Pen;\n for (x, y) in [(20.0, 20.0), (80.0, 60.0)] {\n pen_down(&mut app, x, y, false);\n pen_up(&mut app);\n }\n let draft = app.ui.pen.clone();\n let owner = app.ui.pen_doc;\n app.session.execute(\"file.new\", json!({\"width\": 200, \"height\": 200})).unwrap();",
|
||
"expected_assertions": [
|
||
" \"undo\" => assert!(!pen_undo_last_point(&mut app)),\n \"commit\" => {\n pen_commit(&mut app, true);\n }",
|
||
" assert!(app.run(\"file.close\", json!({})).is_err());\n }\n }\n assert_eq!(app.ui.pen, draft, \"{action}: failed save retains all anchors\");",
|
||
" assert_eq!(app.ui.pen, draft, \"{action}: failed save retains all anchors\");\n assert_eq!(app.ui.pen_doc, owner);\n assert_eq!(app.session.active_index(), Some(1));\n assert_eq!(app.session.documents()[0].doc.work_path.as_ref(), Some(&original));",
|
||
" assert_eq!(app.ui.pen_doc, owner);\n assert_eq!(app.session.active_index(), Some(1));\n assert_eq!(app.session.documents()[0].doc.work_path.as_ref(), Some(&original));\n assert!(app.session.documents()[1].doc.work_path.is_none());",
|
||
" assert_eq!(app.session.active_index(), Some(1));\n assert_eq!(app.session.documents()[0].doc.work_path.as_ref(), Some(&original));\n assert!(app.session.documents()[1].doc.work_path.is_none());\n assert!(app.ui.status_error);",
|
||
" assert_eq!(app.session.documents()[0].doc.work_path.as_ref(), Some(&original));\n assert!(app.session.documents()[1].doc.work_path.is_none());\n assert!(app.ui.status_error);\n assert!(!crate::direct_select::candidates(&app).iter().any(|(target, _)| *target == crate::direct_select::PathRef::Pen));",
|
||
" assert!(app.session.documents()[1].doc.work_path.is_none());\n assert!(app.ui.status_error);\n assert!(!crate::direct_select::candidates(&app).iter().any(|(target, _)| *target == crate::direct_select::PathRef::Pen));\n app.session.authorize = None;",
|
||
" assert!(app.ui.status_error);\n assert!(!crate::direct_select::candidates(&app).iter().any(|(target, _)| *target == crate::direct_select::PathRef::Pen));\n app.session.authorize = None;\n app.sync_views();",
|
||
" assert!(!crate::direct_select::candidates(&app).iter().any(|(target, _)| *target == crate::direct_select::PathRef::Pen));\n app.session.authorize = None;\n app.sync_views();\n assert!(app.ui.pen.is_none());",
|
||
" assert!(app.ui.pen.is_none());\n assert_eq!(app.session.active_index(), Some(1));\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"foreign named path\"));\n let saved = app.session.documents()[0].doc.work_path.clone().unwrap();",
|
||
" assert_eq!(app.session.active_index(), Some(1));\n assert_eq!(app.ui.selected_path.as_deref(), Some(\"foreign named path\"));\n let saved = app.session.documents()[0].doc.work_path.clone().unwrap();\n assert_eq!(saved.subpaths.len(), original.subpaths.len() + 1);",
|
||
" assert_eq!(app.ui.selected_path.as_deref(), Some(\"foreign named path\"));\n let saved = app.session.documents()[0].doc.work_path.clone().unwrap();\n assert_eq!(saved.subpaths.len(), original.subpaths.len() + 1);\n assert_eq!(saved.subpaths[0], original.subpaths[0]);",
|
||
" assert_eq!(saved.subpaths.len(), original.subpaths.len() + 1);\n assert_eq!(saved.subpaths[0], original.subpaths[0]);\n app.sync_views();\n assert_eq!(app.session.documents()[0].doc.work_path.as_ref(), Some(&saved), \"retry never duplicates the path\");",
|
||
" assert_eq!(saved.subpaths[0], original.subpaths[0]);\n app.sync_views();\n assert_eq!(app.session.documents()[0].doc.work_path.as_ref(), Some(&saved), \"retry never duplicates the path\");\n assert!(app.session.set_active(0));",
|
||
" assert_eq!(app.session.documents()[0].doc.work_path.as_ref(), Some(&saved), \"retry never duplicates the path\");\n assert!(app.session.set_active(0));\n assert!(app.session.undo());\n assert_eq!(app.session.active().unwrap().doc.work_path.as_ref(), Some(&original));",
|
||
" assert!(app.session.set_active(0));\n assert!(app.session.undo());\n assert_eq!(app.session.active().unwrap().doc.work_path.as_ref(), Some(&original));\n }",
|
||
" assert!(app.session.undo());\n assert_eq!(app.session.active().unwrap().doc.work_path.as_ref(), Some(&original));\n }\n}",
|
||
" assert_eq!(app.session.active().unwrap().doc.work_path.as_ref(), Some(&original));\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "stale_pen_commits_to_its_owner_across_document_changes",
|
||
"path": "crates/ui-egui/src/tools/vector_ui/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked stale_pen_commits_to_its_owner_across_document_changes -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_doc::{ColorMode, SampleType, Size};\n for tool in [Tool::Pen, Tool::CurvaturePen] {\n for action in [\"switch\", \"open\", \"closeOther\", \"pen\", \"curvature\", \"undo\", \"commit\"] {\n let mut app = app();\n app.run(\"file.new\", json!({\"width\": 200, \"height\": 200})).unwrap();\n app.ui.tool = tool;\n for (x, y) in [(20.0, 20.0), (80.0, 60.0), (120.0, 30.0)] {\n if tool == Tool::Pen {\n pen_down(&mut app, x, y, false);\n pen_up(&mut app);\n } else {\n curvature_down(&mut app, x, y);",
|
||
"expected_assertions": [
|
||
" assert!(app.session.set_active(0));\n match action {\n \"open\" => {\n app.services.import = Some(Box::new(|name, _, _| Ok((Document::new(name, Size::new(4, 4), ColorMode::Rgb, SampleType::U8), Vec::new()))));",
|
||
" \"undo\" => assert!(!pen_undo_last_point(&mut app)),\n \"commit\" => {\n pen_commit(&mut app, true);\n }",
|
||
" assert_eq!(path, &expected, \"{tool:?} {action}\");\n assert!(app.session.documents().iter().filter(|d| d.doc.id != owner).all(|d| d.doc.work_path.is_none()));\n if action != \"closeOther\" {\n assert_ne!(app.session.active().unwrap().doc.id, owner, \"the active document is restored\");",
|
||
" assert!(app.session.documents().iter().filter(|d| d.doc.id != owner).all(|d| d.doc.work_path.is_none()));\n if action != \"closeOther\" {\n assert_ne!(app.session.active().unwrap().doc.id, owner, \"the active document is restored\");\n }",
|
||
" assert_ne!(app.session.active().unwrap().doc.id, owner, \"the active document is restored\");\n }\n assert_eq!(app.ui.direct_selection, Default::default());\n let index = app.session.documents().iter().position(|d| d.doc.id == owner).unwrap();",
|
||
" assert_eq!(app.ui.direct_selection, Default::default());\n let index = app.session.documents().iter().position(|d| d.doc.id == owner).unwrap();\n assert!(app.session.set_active(index));\n assert!(app.session.undo());",
|
||
" assert!(app.session.set_active(index));\n assert!(app.session.undo());\n assert!(app.session.active().unwrap().doc.work_path.is_none());\n assert!(app.session.redo());",
|
||
" assert!(app.session.undo());\n assert!(app.session.active().unwrap().doc.work_path.is_none());\n assert!(app.session.redo());\n assert!(app.session.active().unwrap().doc.work_path.is_some());",
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_none());\n assert!(app.session.redo());\n assert!(app.session.active().unwrap().doc.work_path.is_some());\n }",
|
||
" assert!(app.session.redo());\n assert!(app.session.active().unwrap().doc.work_path.is_some());\n }\n }",
|
||
" assert!(app.session.active().unwrap().doc.work_path.is_some());\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d24669d412f64ab079a668b0b8520ddbc607410c/crates/ui-egui/src/tools/vector_ui/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-8074",
|
||
"pr": 8074,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked tool_options_survive_a_restart -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked interpolation_selection_is_reused_for_the_next_transform -- --nocapture"
|
||
],
|
||
"expected": "tool options survive a restart; interpolation selection is reused for the next transform",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked tool_options_survive_a_restart -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked interpolation_selection_is_reused_for_the_next_transform -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "tool_options_survive_a_restart",
|
||
"path": "crates/ui-egui/src/prefs_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked tool_options_survive_a_restart -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut app, store) = app_with_store();\n let ctx = egui::Context::default();\n tick(&mut app, &ctx);\n app.ui.tool_options.move_auto_select = false;\n app.ui.tool_options.feather = 12.0;\n app.ui.tool_options.transform_interpolation = Some(photocraft_engine::prefs::Interpolation::Nearest);\n crate::tool_memory::persist(&mut app, &ctx);\n tick(&mut app, &ctx);\n // Only what differs from the defaults is stored.\n assert_eq!(stored(&store)[\"toolOptions\"], json!({\"move_auto_select\": false, \"feather\": 12.0, \"transform_interpolation\": \"nearestNeighbor\"}));\n let saved = store.lock().unwrap().clone().unwrap();\n let (mut app2, _) = app_with_saved(Some(saved));",
|
||
"expected_assertions": [
|
||
" assert_eq!(stored(&store)[\"toolOptions\"], json!({\"move_auto_select\": false, \"feather\": 12.0, \"transform_interpolation\": \"nearestNeighbor\"}));\n let saved = store.lock().unwrap().clone().unwrap();\n let (mut app2, _) = app_with_saved(Some(saved));\n tick(&mut app2, &ctx);",
|
||
" assert!(!app2.ui.tool_options.move_auto_select);\n assert_eq!(app2.ui.tool_options.feather, 12.0);\n assert_eq!(app2.ui.tool_options.transform_interpolation, Some(photocraft_engine::prefs::Interpolation::Nearest));\n assert_eq!(app2.ui.tool_options.tolerance, crate::state::ToolOptions::default().tolerance);",
|
||
" assert_eq!(app2.ui.tool_options.feather, 12.0);\n assert_eq!(app2.ui.tool_options.transform_interpolation, Some(photocraft_engine::prefs::Interpolation::Nearest));\n assert_eq!(app2.ui.tool_options.tolerance, crate::state::ToolOptions::default().tolerance);\n // A hand-edited file: unreadable fields keep their defaults, the good ones still load.",
|
||
" assert_eq!(app2.ui.tool_options.transform_interpolation, Some(photocraft_engine::prefs::Interpolation::Nearest));\n assert_eq!(app2.ui.tool_options.tolerance, crate::state::ToolOptions::default().tolerance);\n // A hand-edited file: unreadable fields keep their defaults, the good ones still load.\n for bad in [json!(\"junk\"), json!({\"move_auto_select\": \"no\", \"feather\": 1e300, \"tolerance\": 5.0, \"unknown\": 1})] {",
|
||
" assert_eq!(app2.ui.tool_options.tolerance, crate::state::ToolOptions::default().tolerance);\n // A hand-edited file: unreadable fields keep their defaults, the good ones still load.\n for bad in [json!(\"junk\"), json!({\"move_auto_select\": \"no\", \"feather\": 1e300, \"tolerance\": 5.0, \"unknown\": 1})] {\n let (mut app3, _) = app_with_saved(Some(json!({\"toolOptions\": bad}).to_string()));",
|
||
" assert!(o.move_auto_select && o.feather == 0.0, \"{bad}\");\n assert_eq!(o.tolerance, if bad.is_object() { 5.0 } else { 32.0 });\n }\n }",
|
||
" assert_eq!(o.tolerance, if bad.is_object() { 5.0 } else { 32.0 });\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/290f924d0fecc3bf6bea159c0d9e86255d326a96/crates/ui-egui/src/prefs_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "interpolation_selection_is_reused_for_the_next_transform",
|
||
"path": "crates/ui-egui/src/transform_tool.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked interpolation_selection_is_reused_for_the_next_transform -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui::accesskit::Role;\n use egui_kittest::{Harness, kittest::Queryable};\n\n let app = app_with_square(64, photocraft_geom::Rect::new(8, 8, 24, 24));\n let mut h = Harness::builder().with_size(vec2(2400.0, 360.0)).build_ui_state(\n |ui, app: &mut PhotocraftApp| {\n if ui.ctx().fonts(|f| f.families().contains(&egui::FontFamily::Name(\"medium\".into()))) {\n ui.horizontal_centered(|ui| options_bar(app, ui));\n }\n },\n app,\n );",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.transform.is_some(), \"transform stays open while the bar renders\");\n\n h.get_by_role(Role::ComboBox).click();\n h.run();",
|
||
" assert!(h.state().ui.transform.is_some(), \"opening interpolation dropdown keeps the transform open\");\n h.key_press(egui::Key::ArrowDown);\n h.run();\n assert!(h.state().ui.transform.is_some(), \"first interpolation step keeps the transform open\");",
|
||
" assert!(h.state().ui.transform.is_some(), \"first interpolation step keeps the transform open\");\n h.key_press(egui::Key::ArrowDown);\n h.run();\n assert!(h.state().ui.transform.is_some(), \"second interpolation step keeps the transform open\");",
|
||
" assert!(h.state().ui.transform.is_some(), \"second interpolation step keeps the transform open\");\n assert_eq!(h.state().ui.transform.as_ref().unwrap().interpolation, \"nearest\");\n assert_eq!(h.state().ui.tool_options.transform_interpolation, Some(photocraft_engine::prefs::Interpolation::Nearest));\n assert_eq!(h.state().session.prefs().general.image_interpolation, photocraft_engine::prefs::Interpolation::BicubicAutomatic);",
|
||
" assert_eq!(h.state().ui.transform.as_ref().unwrap().interpolation, \"nearest\");\n assert_eq!(h.state().ui.tool_options.transform_interpolation, Some(photocraft_engine::prefs::Interpolation::Nearest));\n assert_eq!(h.state().session.prefs().general.image_interpolation, photocraft_engine::prefs::Interpolation::BicubicAutomatic);\n",
|
||
" assert_eq!(h.state().ui.tool_options.transform_interpolation, Some(photocraft_engine::prefs::Interpolation::Nearest));\n assert_eq!(h.state().session.prefs().general.image_interpolation, photocraft_engine::prefs::Interpolation::BicubicAutomatic);\n\n let transform = h.state_mut().ui.transform.as_mut().unwrap();",
|
||
" assert_eq!(h.state().session.prefs().general.image_interpolation, photocraft_engine::prefs::Interpolation::BicubicAutomatic);\n\n let transform = h.state_mut().ui.transform.as_mut().unwrap();\n transform.quad = transform.quad.map(|[x, y]| [x + 1.0, y]);",
|
||
" assert!(h.state().ui.transform.is_none());\n begin(h.state_mut(), &ctx).unwrap();\n assert_eq!(h.state().ui.transform.as_ref().unwrap().interpolation, \"nearest\");\n }",
|
||
" assert_eq!(h.state().ui.transform.as_ref().unwrap().interpolation, \"nearest\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/290f924d0fecc3bf6bea159c0d9e86255d326a96/crates/ui-egui/src/transform_tool.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-8896",
|
||
"pr": 8896,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Selected document/layer-mask fixtures in dialogs/select_mask_ui/tests.rs plus two-document controls; record viewport/theme/scale",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked opens_like_photoshop -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked opening_needs_a_selection_or_a_layer_mask -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked tools_make_edits_and_undo_and_redo_them -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ok_is_one_step_and_matches_the_command -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked cancel_changes_nothing -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked decontaminate_outputs_to_a_new_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked hostile_control_params_are_errors -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ok_after_a_document_switch_changes_neither_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ok_after_a_layer_switch_leaves_the_new_layer_alone -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked renders_photoshops_layout -- --nocapture"
|
||
],
|
||
"expected": "Workspace needs valid selection/mask; tools/preview affect intended target. OK matches engine output in one history step; Cancel changes nothing; decontamination outputs a new layer. Hostile controls refuse; stale document/layer targets edit neither new target.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Native refinement → undo/redo → Cancel and commit are separate NOT RUN subcases. Capture the full workspace with reachable controls, not only an overlay helper.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked opens_like_photoshop -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked opening_needs_a_selection_or_a_layer_mask -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked tools_make_edits_and_undo_and_redo_them -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ok_is_one_step_and_matches_the_command -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked cancel_changes_nothing -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked decontaminate_outputs_to_a_new_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked hostile_control_params_are_errors -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ok_after_a_document_switch_changes_neither_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ok_after_a_layer_switch_leaves_the_new_layer_alone -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked renders_photoshops_layout -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-9493",
|
||
"pr": 9493,
|
||
"subsystem": "Selection, paths and transforms",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-compose --locked feather_at_the_canvas_edge_continues_the_mask_past_it -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked soft_shape_matches_an_equal_vector_mask -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked parallel_gaussian_matches_the_sequential_reference -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked padding_each_line_matches_padding_the_plane -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked benchmark_50mp_mask_blur -- --nocapture --ignored",
|
||
"cargo test -p photocraft-vector --locked a_maximum_feather_does_not_pad_the_whole_plane -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked a_failed_line_buffer_never_leaves_a_half_blurred_mask -- --nocapture"
|
||
],
|
||
"expected": "feather at the canvas edge continues the mask past it; soft shape matches an equal vector mask; parallel gaussian matches the sequential reference; padding each line matches padding the plane; benchmark 50mp mask blur; a maximum feather does not pad the whole plane; a failed line buffer never leaves a half blurred mask",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-compose --locked feather_at_the_canvas_edge_continues_the_mask_past_it -- --nocapture",
|
||
"cargo test -p photocraft-compose --locked soft_shape_matches_an_equal_vector_mask -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked parallel_gaussian_matches_the_sequential_reference -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked padding_each_line_matches_padding_the_plane -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked benchmark_50mp_mask_blur -- --nocapture --ignored",
|
||
"cargo test -p photocraft-vector --locked a_maximum_feather_does_not_pad_the_whole_plane -- --nocapture",
|
||
"cargo test -p photocraft-vector --locked a_failed_line_buffer_never_leaves_a_half_blurred_mask -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "feather_at_the_canvas_edge_continues_the_mask_past_it",
|
||
"path": "crates/compose/src/masks.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked feather_at_the_canvas_edge_continues_the_mask_past_it -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut layer = Layer::raster(\"edge\", PixelFormat::RGBA8);\n let mut mask = photocraft_doc::LayerMask::hide_all();\n mask.surface.fill_rect(Rect::new(40, 20, 120, 60), &[1.0]);\n mask.feather = 32.0;\n layer.mask = Some(mask);\n let canvas = Rect::new(0, 0, 160, 80);\n let tight = combined_mask(&layer, canvas).unwrap().read_region(canvas);\n let tall = combined_mask(&layer, Rect::new(0, -200, 160, 280)).unwrap().read_region(canvas);\n let worst = tight.iter().zip(&tall).map(|(a, b)| (a - b).abs()).fold(0.0_f32, f32::max);\n assert!(worst < 1e-4, \"the canvas edge changed the feather by {worst}\");\n\n let mut half = photocraft_doc::LayerMask::hide_all();",
|
||
"expected_assertions": [
|
||
" assert!(worst < 1e-4, \"the canvas edge changed the feather by {worst}\");\n\n let mut half = photocraft_doc::LayerMask::hide_all();\n half.surface.fill_rect(Rect::new(0, 0, 80, 80), &[1.0]);",
|
||
" assert!(row.iter().zip(middle).all(|(a, b)| (a - b).abs() < 1e-5), \"row {y} differs from row 40\");\n }\n assert!(middle[0] > 0.99, \"the left edge stays white: {}\", middle[0]);\n }",
|
||
" assert!(middle[0] > 0.99, \"the left edge stays white: {}\", middle[0]);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61a413d8df9e90ee545eb08e57c5615aa2b29cea/crates/compose/src/masks.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "soft_shape_matches_an_equal_vector_mask",
|
||
"path": "crates/compose/src/soft_shape_tests.rs",
|
||
"package": "photocraft-compose",
|
||
"command": "cargo test -p photocraft-compose --locked soft_shape_matches_an_equal_vector_mask -- --nocapture",
|
||
"fixture_and_action_excerpt": " // 40 px reaches past the canvas edge: both feather it the same way there (#9475).\n for (density, feather) in [(1.0, 10.0), (0.45, 0.0), (0.3, 6.5), (0.0, 0.0), (1.0, 0.0), (0.5, 3.0), (1.0, 40.0)] {\n for depth in [SampleType::U8, SampleType::U16] {\n let (s, f) = (shape_doc(depth, density, feather, None), fill_doc(depth, density, feather));\n for y in [0, 45, 50, 100, 151, 199] {\n // An 8-bit shape keeps its rendering in 8-bit pixels (the fill layer's mask is\n // 16-bit), which can round its alpha one level apart, as at any anti-aliased edge.\n let d8 = max_diff(&row(&s, y), &row(&f, y));\n assert!(d8 <= i32::from(depth == SampleType::U8), \"{depth:?} density {density} feather {feather}, row {y}: {d8} levels\");\n // The compositor keeps masks at 16 bits (an 8-bit shape's pixels are 8-bit).\n if depth == SampleType::U16 {\n let d16 = max_diff(&row16(&s, y), &row16(&f, y));",
|
||
"expected_assertions": [
|
||
" assert!(d8 <= i32::from(depth == SampleType::U8), \"{depth:?} density {density} feather {feather}, row {y}: {d8} levels\");\n // The compositor keeps masks at 16 bits (an 8-bit shape's pixels are 8-bit).\n if depth == SampleType::U16 {\n let d16 = max_diff(&row16(&s, y), &row16(&f, y));",
|
||
" assert!(d16 <= 2, \"{depth:?} density {density} feather {feather}, row {y}: {d16} 16-bit levels\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61a413d8df9e90ee545eb08e57c5615aa2b29cea/crates/compose/src/soft_shape_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "parallel_gaussian_matches_the_sequential_reference",
|
||
"path": "crates/vector/src/feather.rs",
|
||
"package": "photocraft-vector",
|
||
"command": "cargo test -p photocraft-vector --locked parallel_gaussian_matches_the_sequential_reference -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h, sigma): (usize, usize, f32) = (320, 256, 13.0);\n let mut parallel: Vec<_> = (0..w * h).map(|i| ((i * 37 % 1009) as f32) / 1008.0).collect();\n let mut sequential = parallel.clone();\n let pass = BoxPass::for_sigma(sigma).unwrap();\n let source = parallel.clone();\n for halo in [0, 3 * (pass.r + 1)] {\n parallel.copy_from_slice(&source);\n sequential.copy_from_slice(&source);\n gaussian_sequential(&mut sequential, w, h, pass, halo);\n blur_plane(&mut parallel, w, h, pass, halo);\n assert_eq!(parallel, sequential, \"parallel blur must retain the exact per-line arithmetic (halo {halo})\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(parallel, sequential, \"parallel blur must retain the exact per-line arithmetic (halo {halo})\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61a413d8df9e90ee545eb08e57c5615aa2b29cea/crates/vector/src/feather.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "padding_each_line_matches_padding_the_plane",
|
||
"path": "crates/vector/src/feather.rs",
|
||
"package": "photocraft-vector",
|
||
"command": "cargo test -p photocraft-vector --locked padding_each_line_matches_padding_the_plane -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h, sigma): (usize, usize, f32) = (90, 70, 9.0);\n let source: Vec<f32> = (0..w * h).map(|i| ((i * 37 % 1009) as f32) / 1008.0).collect();\n let pass = BoxPass::for_sigma(sigma).unwrap();\n let m = 3 * (pass.r + 1);\n let (pw, ph) = (w + 2 * m, h + 2 * m);\n let mut plane: Vec<f32> = (0..pw * ph).map(|i| source[((i / pw).clamp(m, m + h - 1) - m) * w + (i % pw).clamp(m, m + w - 1) - m]).collect();\n blur_plane(&mut plane, pw, ph, pass, 0);\n let want: Vec<f32> = (0..w * h).map(|i| plane[(i / w + m) * pw + i % w + m]).collect();\n let mut got = source;\n gaussian(&mut got, w, h, sigma);\n assert_eq!(got, want);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(got, want);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61a413d8df9e90ee545eb08e57c5615aa2b29cea/crates/vector/src/feather.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "benchmark_50mp_mask_blur",
|
||
"path": "crates/vector/src/feather.rs",
|
||
"package": "photocraft-vector",
|
||
"command": "cargo test -p photocraft-vector --locked benchmark_50mp_mask_blur -- --nocapture --ignored",
|
||
"fixture_and_action_excerpt": " use std::time::Instant;\n\n let (w, h, sigma): (usize, usize, f32) = (6336, 7920, 1000.0);\n let pass = BoxPass::for_sigma(sigma).unwrap();\n let source: Vec<_> = (0..w * h).map(|i| ((i * 37 % 1009) as f32) / 1008.0).collect();\n let mut sequential = source.clone();\n let start = Instant::now();\n gaussian_sequential(&mut sequential, w, h, pass, 3 * (pass.r + 1));\n let sequential_time = start.elapsed();\n let mut parallel = source;\n let start = Instant::now();\n gaussian(&mut parallel, w, h, sigma);",
|
||
"expected_assertions": [
|
||
" assert_eq!(parallel, sequential);\n eprintln!(\"50 MP mask blur: sequential={sequential_time:?}, parallel={parallel_time:?}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61a413d8df9e90ee545eb08e57c5615aa2b29cea/crates/vector/src/feather.rs",
|
||
"ignored_requires_explicit_execution": true
|
||
},
|
||
{
|
||
"name": "a_maximum_feather_does_not_pad_the_whole_plane",
|
||
"path": "crates/vector/src/feather.rs",
|
||
"package": "photocraft-vector",
|
||
"command": "cargo test -p photocraft-vector --locked a_maximum_feather_does_not_pad_the_whole_plane -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h) = (400usize, 400usize);\n let mut v: Vec<f32> = (0..w * h).map(|i| if (i % w) < w / 2 { 1.0 } else { 0.0 }).collect();\n gaussian(&mut v, w, h, feather_sigma(1000.0));\n let largest = LARGEST_BUFFER.load(std::sync::atomic::Ordering::Relaxed);\n assert!(largest <= w * h, \"the blur allocated a buffer of {largest} floats for a {w} × {h} plane\");\n assert!(v.iter().all(|x| x.is_finite()));\n }",
|
||
"expected_assertions": [
|
||
" assert!(largest <= w * h, \"the blur allocated a buffer of {largest} floats for a {w} × {h} plane\");\n assert!(v.iter().all(|x| x.is_finite()));\n }",
|
||
" assert!(v.iter().all(|x| x.is_finite()));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61a413d8df9e90ee545eb08e57c5615aa2b29cea/crates/vector/src/feather.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "a_failed_line_buffer_never_leaves_a_half_blurred_mask",
|
||
"path": "crates/vector/src/feather.rs",
|
||
"package": "photocraft-vector",
|
||
"command": "cargo test -p photocraft-vector --locked a_failed_line_buffer_never_leaves_a_half_blurred_mask -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (w, h, sigma): (usize, usize, f32) = (433, 211, 7.0);\n let source: Vec<f32> = (0..w * h).map(|i| ((i * 37 % 1009) as f32) / 1008.0).collect();\n let mut want = source.clone();\n gaussian(&mut want, w, h, sigma);\n for fail in [w, h] {\n FAIL_LINE_BUFFERS.store(fail, std::sync::atomic::Ordering::Relaxed);\n let mut got = source.clone();\n gaussian(&mut got, w, h, sigma);\n FAIL_LINE_BUFFERS.store(0, std::sync::atomic::Ordering::Relaxed);\n assert!(got == want || got == source, \"lines of {fail} failing left a partly blurred plane\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(got == want || got == source, \"lines of {fail} failing left a partly blurred plane\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/61a413d8df9e90ee545eb08e57c5615aa2b29cea/crates/vector/src/feather.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-3139",
|
||
"pr": 3139,
|
||
"subsystem": "Type and typography",
|
||
"fixture_setup": "Arabic, Hebrew, mixed Latin/digits and Persian joiner samples in bidi_label_tests.rs; record rendered font files",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked right_to_left_words_swap_places_but_keep_their_letters -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked numbers_and_latin_keep_reading_left_to_right -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked persian_joiners_stay_inside_their_word -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked arabic_draws_first_word_rightmost_with_letters_joined -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked hebrew_draws_first_word_rightmost -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_long_right_to_left_layer_name_keeps_its_beginning -- --nocapture"
|
||
],
|
||
"expected": "First RTL word is rightmost; Arabic joining and Persian joiners remain intact; Latin/digits retain direction; truncation keeps the beginning. Retain LTR-unchanged negative coverage.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Inspect Layers at 1×/2×. Missing fonts block rendered coverage; an early return is not a pass.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked right_to_left_words_swap_places_but_keep_their_letters -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked numbers_and_latin_keep_reading_left_to_right -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked persian_joiners_stay_inside_their_word -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked arabic_draws_first_word_rightmost_with_letters_joined -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked hebrew_draws_first_word_rightmost -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked a_long_right_to_left_layer_name_keeps_its_beginning -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-4783",
|
||
"pr": 4783,
|
||
"subsystem": "Type and typography",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-io --locked tysh_fallback_cannot_reintroduce_unusable_finite_or_nonfinite_transform -- --nocapture",
|
||
"cargo test -p photocraft-io --locked hostile_type_sizes_without_pixels_import_without_a_huge_render -- --nocapture",
|
||
"cargo test -p photocraft-text --locked overflowing_legacy_origin_does_not_escape_as_a_nonfinite_transform -- --nocapture",
|
||
"cargo test -p photocraft-text --locked reject_unusable_matrices_before_type_layout -- --nocapture"
|
||
],
|
||
"expected": "tysh fallback cannot reintroduce unusable finite or nonfinite transform; hostile type sizes without pixels import without a huge render; overflowing legacy origin does not escape as a nonfinite transform; reject unusable matrices before type layout",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-io --locked tysh_fallback_cannot_reintroduce_unusable_finite_or_nonfinite_transform -- --nocapture",
|
||
"cargo test -p photocraft-io --locked hostile_type_sizes_without_pixels_import_without_a_huge_render -- --nocapture",
|
||
"cargo test -p photocraft-text --locked overflowing_legacy_origin_does_not_escape_as_a_nonfinite_transform -- --nocapture",
|
||
"cargo test -p photocraft-text --locked reject_unusable_matrices_before_type_layout -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "tysh_fallback_cannot_reintroduce_unusable_finite_or_nonfinite_transform",
|
||
"path": "crates/io/src/blocks.rs",
|
||
"package": "photocraft-io",
|
||
"command": "cargo test -p photocraft-io --locked tysh_fallback_cannot_reintroduce_unusable_finite_or_nonfinite_transform -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut tysh = vec![0u8; 52];\n tysh[..2].copy_from_slice(&1u16.to_be_bytes());\n for (i, value) in [1.0f64, 0.0, 0.0, 1.0, 30.0, 40.0].iter().enumerate() {\n tysh[2 + 8 * i..10 + 8 * i].copy_from_slice(&value.to_be_bytes());\n }\n assert!(parse_tysh(&tysh).is_some(), \"normal matrices still import\");\n for value in [1e62f64, -1e62, f64::INFINITY, f64::NAN] {\n tysh[2..10].copy_from_slice(&value.to_be_bytes());\n assert!(parse_tysh(&tysh).is_none(), \"invalid matrix {value} cannot reach UI\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(parse_tysh(&tysh).is_some(), \"normal matrices still import\");\n for value in [1e62f64, -1e62, f64::INFINITY, f64::NAN] {\n tysh[2..10].copy_from_slice(&value.to_be_bytes());\n assert!(parse_tysh(&tysh).is_none(), \"invalid matrix {value} cannot reach UI\");",
|
||
" assert!(parse_tysh(&tysh).is_none(), \"invalid matrix {value} cannot reach UI\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/a9d62726bed607bc540db9d09c8dc1be4f9895aa/crates/io/src/blocks.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "hostile_type_sizes_without_pixels_import_without_a_huge_render",
|
||
"path": "crates/io/tests/psd_type_bounds.rs",
|
||
"package": "photocraft-io",
|
||
"command": "cargo test -p photocraft-io --locked hostile_type_sizes_without_pixels_import_without_a_huge_render -- --nocapture",
|
||
"fixture_and_action_excerpt": " // The import renders type layers that come without pixels; the model is untrusted, so an\n // absurd size or scale must not make opening the file allocate gigabytes (or fail).\n let scaled = |s: f64| Affine { m: [s, 0.0, 0.0, s, 10.0, 10.0] };\n for (size, transform, big) in\n [(12.0, scaled(1100.0), true), (1.0e30, scaled(1.0), false), (12.0, scaled(1.0e12), false), (f64::MAX, scaled(f64::MAX), false)]\n {\n let runs = vec![Run { len: 1, size, leading: None }];\n let data = tysh(\"M\", &runs, None, transform, [10.0, 10.0, 20.0, 20.0]);\n // Extremely large TySh transforms are now rejected before any layout or rendering.\n // Keep testing the import-time render cap for matrices within the safety gate.\n if !photocraft_text::psd::usable_tysh_transform(&transform.m) {\n assert!(photocraft_text::psd::text_layer_from_tysh(&data, 72.0).is_none(), \"unsafe transform must be rejected before layout\");",
|
||
"expected_assertions": [
|
||
" assert!(photocraft_text::psd::text_layer_from_tysh(&data, 72.0).is_none(), \"unsafe transform must be rejected before layout\");\n continue;\n }\n let mut t = photocraft_text::psd::text_layer_from_tysh(&data, 72.0).expect(\"valid TySh transform\");",
|
||
" assert!(px > 64 * 1024 * 1024 && px <= 256 * 1024 * 1024, \"{ink:?}\");\n }\n t.cache = None;\n t.psd_raw = Some(std::sync::Arc::new(data));",
|
||
" assert!(cache.content_bounds().is_empty(), \"size {size}: drew {:?}\", cache.content_bounds());\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/a9d62726bed607bc540db9d09c8dc1be4f9895aa/crates/io/tests/psd_type_bounds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "overflowing_legacy_origin_does_not_escape_as_a_nonfinite_transform",
|
||
"path": "crates/text/src/psd.rs",
|
||
"package": "photocraft-text",
|
||
"command": "cargo test -p photocraft-text --locked overflowing_legacy_origin_does_not_escape_as_a_nonfinite_transform -- --nocapture",
|
||
"fixture_and_action_excerpt": " let bounds = Descriptor::new(\"boundingBox\")\n .with(\"Left\", D::Double(1.0e308))\n .with(\"Top \", D::Double(1.0e308))\n .with(\"Rght\", D::Double(1.5e308))\n .with(\"Btom\", D::Double(1.5e308));\n let text = Descriptor::new(\"TxLr\").with(\"Txt \", D::Text(UnicodeString::new_nul(\"x\"))).with(\"boundingBox\", D::Descriptor(bounds)).with(\n \"EngineData\",\n D::RawData(\n b\"<< /EngineDict << /Rendered << /Shapes << /Children [ << /Cookie << /Photoshop << /PointBase [0.0 0.0] >> >> >> ] >> >> >> >>\".to_vec(),\n ),\n );\n let tysh = TySh { transform: Affine { m: [1.0e9, 0.0, -1.0e9, 0.0, 5000.0, 0.0] }, text, warp: None, bounds: [0.0; 4] };",
|
||
"expected_assertions": [
|
||
" assert!(engine_data(&tysh.text).is_some());\n assert!(legacy_point_origin(&tysh).is_none());\n let layer = text_layer_from_tysh(&write_tysh(&tysh), 72.0).unwrap();\n assert!(usable_tysh_transform(&layer.transform.m));",
|
||
" assert!(legacy_point_origin(&tysh).is_none());\n let layer = text_layer_from_tysh(&write_tysh(&tysh), 72.0).unwrap();\n assert!(usable_tysh_transform(&layer.transform.m));\n }",
|
||
" assert!(usable_tysh_transform(&layer.transform.m));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/a9d62726bed607bc540db9d09c8dc1be4f9895aa/crates/text/src/psd.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "reject_unusable_matrices_before_type_layout",
|
||
"path": "crates/text/src/psd.rs",
|
||
"package": "photocraft-text",
|
||
"command": "cargo test -p photocraft-text --locked reject_unusable_matrices_before_type_layout -- --nocapture",
|
||
"fixture_and_action_excerpt": " let original = TySh { transform: Affine { m: [1.0, 0.0, 0.0, 1.0, 30.0, 40.0] }, text: Descriptor::new(\"TxLr\"), warp: None, bounds: [0.0; 4] };\n let clean = write_tysh(&original);\n assert_eq!(parse_tysh(&clean).unwrap().transform, original.transform);\n for bad in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY, 1.315776645269349e62] {\n let mut bytes = clean.clone();\n bytes[2..10].copy_from_slice(&bad.to_be_bytes());\n assert!(parse_tysh(&bytes).is_none(), \"invalid matrix must not be rendered: {bad}\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(parse_tysh(&clean).unwrap().transform, original.transform);\n for bad in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY, 1.315776645269349e62] {\n let mut bytes = clean.clone();\n bytes[2..10].copy_from_slice(&bad.to_be_bytes());",
|
||
" assert!(parse_tysh(&bytes).is_none(), \"invalid matrix must not be rendered: {bad}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/a9d62726bed607bc540db9d09c8dc1be4f9895aa/crates/text/src/psd.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-8347",
|
||
"pr": 8347,
|
||
"subsystem": "Type and typography",
|
||
"fixture_setup": "Trailing punctuation, centered/justified lines and forced breaks in text layout fixtures",
|
||
"action": [
|
||
"cargo test -p photocraft-text --locked hanging_marks_do_not_steer_the_alignment -- --nocapture",
|
||
"cargo test -p photocraft-text --locked hanging_centers_a_kerned_line_exactly -- --nocapture",
|
||
"cargo test -p photocraft-text --locked hanging_only_the_mark_list_trims -- --nocapture",
|
||
"cargo test -p photocraft-text --locked hanging_keeps_marks_after_a_forced_break_on_their_row -- --nocapture",
|
||
"cargo test -p photocraft-text --locked hanging_marks_stay_off_a_justified_paragraphs_last_line -- --nocapture",
|
||
"cargo test -p photocraft-text --locked hanging_leaves_plain_paragraphs_untouched -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked character_panel_hanging_checkbox_toggles_the_paragraph_style -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked set_style_paragraph_hanging_round_trips -- --nocapture"
|
||
],
|
||
"expected": "Listed marks hang without steering alignment; kerning-aware centering stays exact; unlisted marks/plain paragraphs are unchanged; forced breaks and justified last lines retain their asserted rules. Checkbox edits actual paragraph style.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "A stored boolean alone is not layout evidence.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-text --locked hanging_marks_do_not_steer_the_alignment -- --nocapture",
|
||
"cargo test -p photocraft-text --locked hanging_centers_a_kerned_line_exactly -- --nocapture",
|
||
"cargo test -p photocraft-text --locked hanging_only_the_mark_list_trims -- --nocapture",
|
||
"cargo test -p photocraft-text --locked hanging_keeps_marks_after_a_forced_break_on_their_row -- --nocapture",
|
||
"cargo test -p photocraft-text --locked hanging_marks_stay_off_a_justified_paragraphs_last_line -- --nocapture",
|
||
"cargo test -p photocraft-text --locked hanging_leaves_plain_paragraphs_untouched -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked character_panel_hanging_checkbox_toggles_the_paragraph_style -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked set_style_paragraph_hanging_round_trips -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-9457",
|
||
"pr": 9457,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-raw --locked gauss_gives_the_bits_of_the_tap_loop -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked box_mean_gives_the_bits_of_the_column_loop -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked the_tap_tables_give_the_bits_of_the_per_pixel_lookup -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked reduce_pair_gives_the_bits_of_two_reductions -- --nocapture"
|
||
],
|
||
"expected": "gauss gives the bits of the tap loop; box mean gives the bits of the column loop; the tap tables give the bits of the per pixel lookup; reduce pair gives the bits of two reductions",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-raw --locked gauss_gives_the_bits_of_the_tap_loop -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked box_mean_gives_the_bits_of_the_column_loop -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked the_tap_tables_give_the_bits_of_the_per_pixel_lookup -- --nocapture",
|
||
"cargo test -p photocraft-raw --locked reduce_pair_gives_the_bits_of_two_reductions -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "gauss_gives_the_bits_of_the_tap_loop",
|
||
"path": "crates/raw/src/tone.rs",
|
||
"package": "photocraft-raw",
|
||
"command": "cargo test -p photocraft-raw --locked gauss_gives_the_bits_of_the_tap_loop -- --nocapture",
|
||
"fixture_and_action_excerpt": " // Sizes below, around and above the kernel (edges only, a few interior samples, mostly interior).\n for (w, h) in [(1, 1), (5, 3), (13, 40), (64, 7), (65, 70), (131, 97), (300, 41)] {\n let v = noise(w * h, (w * 31 + h) as u64);\n for sigma in [0.04, 0.42, 1.0, 2.1, 4.2, 8.4, 13.44] {\n assert!(same(&gauss(&v, w, h, sigma), &gauss_ref(&v, w, h, sigma)), \"{w}x{h} sigma {sigma}\");\n }\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(same(&gauss(&v, w, h, sigma), &gauss_ref(&v, w, h, sigma)), \"{w}x{h} sigma {sigma}\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/2863c3281c2a22dade0ce92d42bf8900074f76c6/crates/raw/src/tone.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "box_mean_gives_the_bits_of_the_column_loop",
|
||
"path": "crates/raw/src/tone.rs",
|
||
"package": "photocraft-raw",
|
||
"command": "cargo test -p photocraft-raw --locked box_mean_gives_the_bits_of_the_column_loop -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (w, h) in [(1, 1), (5, 3), (13, 40), (64, 7), (65, 70), (131, 97), (300, 41)] {\n let v = noise(w * h, (w * 17 + h) as u64);\n for r in [1, 2, 8, 32, 128] {\n assert!(same(&box_mean(&v, w, h, r), &box_mean_ref(&v, w, h, r)), \"{w}x{h} r {r}\");\n }\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(same(&box_mean(&v, w, h, r), &box_mean_ref(&v, w, h, r)), \"{w}x{h} r {r}\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/2863c3281c2a22dade0ce92d42bf8900074f76c6/crates/raw/src/tone.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_tap_tables_give_the_bits_of_the_per_pixel_lookup",
|
||
"path": "crates/raw/src/tone.rs",
|
||
"package": "photocraft-raw",
|
||
"command": "cargo test -p photocraft-raw --locked the_tap_tables_give_the_bits_of_the_per_pixel_lookup -- --nocapture",
|
||
"fixture_and_action_excerpt": " for ((sw, sh), (w, h)) in [((1, 1), (7, 5)), ((3, 2), (3, 2)), ((12, 9), (97, 61)), ((308, 205), (1232, 820)), ((1232, 616), (8256, 4128))] {\n let a = noise(sw * sh, 5);\n let b = noise(sw * sh, 6);\n let grid = Grid::new(sw, sh, w, h);\n let ab: Vec<[f32; 2]> = a.iter().zip(&b).map(|(a, b)| [*a, *b]).collect();\n for y in (0..h).step_by(if h > 1000 { 7 } else { 1 }) {\n for x in (0..w).step_by(if w > 1000 { 5 } else { 1 }) {\n let (ra, rb) = (bilinear_ref(&a, sw, sh, w, h, x, y), bilinear_ref(&b, sw, sh, w, h, x, y));\n assert_eq!(grid.at(&a, x, y).to_bits(), ra.to_bits(), \"{sw}x{sh} to {w}x{h} at {x},{y}\");\n let [pa, pb] = grid.at2(&ab, x, y);\n assert!(pa.to_bits() == ra.to_bits() && pb.to_bits() == rb.to_bits(), \"{sw}x{sh} to {w}x{h} at {x},{y}\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(grid.at(&a, x, y).to_bits(), ra.to_bits(), \"{sw}x{sh} to {w}x{h} at {x},{y}\");\n let [pa, pb] = grid.at2(&ab, x, y);\n assert!(pa.to_bits() == ra.to_bits() && pb.to_bits() == rb.to_bits(), \"{sw}x{sh} to {w}x{h} at {x},{y}\");\n }",
|
||
" assert!(pa.to_bits() == ra.to_bits() && pb.to_bits() == rb.to_bits(), \"{sw}x{sh} to {w}x{h} at {x},{y}\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/2863c3281c2a22dade0ce92d42bf8900074f76c6/crates/raw/src/tone.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "reduce_pair_gives_the_bits_of_two_reductions",
|
||
"path": "crates/raw/src/tone.rs",
|
||
"package": "photocraft-raw",
|
||
"command": "cargo test -p photocraft-raw --locked reduce_pair_gives_the_bits_of_two_reductions -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (w, h) in [(1, 1), (7, 5), (100, 61), (1233, 77), (2500, 1700), (333, 2999)] {\n let v = noise(w * h, (w + 3 * h) as u64);\n for sides in [[1232, 2464], [100, 50], [7, 8], [1232, 1232], [3, 600]] {\n let pair = reduce_pair(w, h, sides, |i| v[i]);\n for (g, side) in sides.iter().enumerate() {\n let (sw, sh, one) = reduce(w, h, *side, |i| [v[i]]);\n let one: Vec<f32> = one.into_iter().map(|[v]| v).collect();\n assert!((sw, sh) == (pair[g].0, pair[g].1) && same(&one, &pair[g].2), \"{w}x{h} side {side}\");\n }\n }\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!((sw, sh) == (pair[g].0, pair[g].1) && same(&one, &pair[g].2), \"{w}x{h} side {side}\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/2863c3281c2a22dade0ce92d42bf8900074f76c6/crates/raw/src/tone.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9478",
|
||
"pr": 9478,
|
||
"subsystem": "Type and typography",
|
||
"fixture_setup": "Roman, ligature and half-width CJK fixtures in text/vertical_tests.rs; record fonts",
|
||
"action": [
|
||
"cargo test -p photocraft-text --locked latin_stands_upright_one_per_em_by_default -- --nocapture",
|
||
"cargo test -p photocraft-text --locked upright_roman_letters_stay_apart_without_ligatures -- --nocapture",
|
||
"cargo test -p photocraft-text --locked half_width_cjk_stays_rotated_beside_upright_roman -- --nocapture",
|
||
"cargo test -p photocraft-text --locked baseline_direction_round_trips -- --nocapture"
|
||
],
|
||
"expected": "Roman defaults upright at one-em advances without ligature collapse; half-width CJK retains specified rotation. Run BaselineDirection overrides sheet defaults and survives PSD persistence.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"qualification_gap": "Capture upright/rotated text at 1×/2× and save/reopen PSD separately. Font-unavailable geometry is BLOCKED; the flag round-trip alone is insufficient.",
|
||
"tested_sha": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-text --locked latin_stands_upright_one_per_em_by_default -- --nocapture",
|
||
"cargo test -p photocraft-text --locked upright_roman_letters_stay_apart_without_ligatures -- --nocapture",
|
||
"cargo test -p photocraft-text --locked half_width_cjk_stays_rotated_beside_upright_roman -- --nocapture",
|
||
"cargo test -p photocraft-text --locked baseline_direction_round_trips -- --nocapture"
|
||
]
|
||
},
|
||
{
|
||
"id": "PR-9523",
|
||
"pr": 9523,
|
||
"subsystem": "Type and typography",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-text --locked closed_rectangle_left_edge_continues_past_the_top_left_seam -- --nocapture",
|
||
"cargo test -p photocraft-text --locked closed_ellipse_upper_left_and_apex_cross_the_seam_in_both_directions -- --nocapture",
|
||
"cargo test -p photocraft-text --locked closed_path_shows_one_lap_without_repeating_glyph_centres -- --nocapture",
|
||
"cargo test -p photocraft-text --locked open_path_clipping_offsets_and_end_tangents_stay_unchanged -- --nocapture",
|
||
"cargo test -p photocraft-text --locked closed_path_alignment_uses_one_lap_from_the_text_left_edge -- --nocapture",
|
||
"cargo test -p photocraft-text --locked closed_path_start_offsets_wrap_and_invalid_coordinates_are_hidden -- --nocapture",
|
||
"cargo test -p photocraft-text --locked caret_projection_roundtrips_closed_seams_and_open_offsets -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked closed_path_forward_hit_after_last_caret -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked open_path_hits_keep_endpoint_clamping -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked closed_path_backward_hit_before_first_caret -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked closed_path_upstream_caret_rectangle_left_edge_roundtrip -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked closed_path_aligned_selection_highlights_every_visible_cluster -- --nocapture"
|
||
],
|
||
"expected": "closed rectangle left edge continues past the top left seam; closed ellipse upper left and apex cross the seam in both directions; closed path shows one lap without repeating glyph centres; open path clipping offsets and end tangents stay unchanged; closed path alignment uses one lap from the text left edge; closed path start offsets wrap and invalid coordinates are hidden; caret projection roundtrips closed seams and open offsets; closed path forward hit after last caret; open path hits keep endpoint clamping; closed path backward hit before first caret; closed path upstream caret rectangle left edge roundtrip; closed path aligned selection highlights every visible cluster",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-text --locked closed_rectangle_left_edge_continues_past_the_top_left_seam -- --nocapture",
|
||
"cargo test -p photocraft-text --locked closed_ellipse_upper_left_and_apex_cross_the_seam_in_both_directions -- --nocapture",
|
||
"cargo test -p photocraft-text --locked closed_path_shows_one_lap_without_repeating_glyph_centres -- --nocapture",
|
||
"cargo test -p photocraft-text --locked open_path_clipping_offsets_and_end_tangents_stay_unchanged -- --nocapture",
|
||
"cargo test -p photocraft-text --locked closed_path_alignment_uses_one_lap_from_the_text_left_edge -- --nocapture",
|
||
"cargo test -p photocraft-text --locked closed_path_start_offsets_wrap_and_invalid_coordinates_are_hidden -- --nocapture",
|
||
"cargo test -p photocraft-text --locked caret_projection_roundtrips_closed_seams_and_open_offsets -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked closed_path_forward_hit_after_last_caret -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked open_path_hits_keep_endpoint_clamping -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked closed_path_backward_hit_before_first_caret -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked closed_path_upstream_caret_rectangle_left_edge_roundtrip -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked closed_path_aligned_selection_highlights_every_visible_cluster -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "closed_rectangle_left_edge_continues_past_the_top_left_seam",
|
||
"path": "crates/text/src/closed_path_tests.rs",
|
||
"package": "photocraft-text",
|
||
"command": "cargo test -p photocraft-text --locked closed_rectangle_left_edge_continues_past_the_top_left_seam -- --nocapture",
|
||
"fixture_and_action_excerpt": " let p = Subpath::polygon(&[(0.0, 0.0), (100.0, 0.0), (100.0, 100.0), (0.0, 100.0)]);\n let start = arc_length_at(&p, false, 0.0, 50.0).unwrap();\n assert!((start - 350.0).abs() < 1e-6);\n let f = PathFrame::new(&p, start as f32, false).unwrap();\n let m = f.frame(75.0).expect(\"glyph after the seam remains on the closed path\");\n let q = centre(m, 75.0);\n assert!((q.0 - 25.0).abs() < 1e-6 && q.1.abs() < 1e-6, \"{q:?}\");\n assert_eq!(&m[..4], &[1.0, 0.0, -0.0, 1.0], \"text now travels right on the top side\");\n assert_eq!(f.apply(75.0, 0.0), q, \"caret and glyph use the same wrapped parameter\");\n}",
|
||
"expected_assertions": [
|
||
" assert!((start - 350.0).abs() < 1e-6);\n let f = PathFrame::new(&p, start as f32, false).unwrap();\n let m = f.frame(75.0).expect(\"glyph after the seam remains on the closed path\");\n let q = centre(m, 75.0);",
|
||
" assert!((q.0 - 25.0).abs() < 1e-6 && q.1.abs() < 1e-6, \"{q:?}\");\n assert_eq!(&m[..4], &[1.0, 0.0, -0.0, 1.0], \"text now travels right on the top side\");\n assert_eq!(f.apply(75.0, 0.0), q, \"caret and glyph use the same wrapped parameter\");\n}",
|
||
" assert_eq!(&m[..4], &[1.0, 0.0, -0.0, 1.0], \"text now travels right on the top side\");\n assert_eq!(f.apply(75.0, 0.0), q, \"caret and glyph use the same wrapped parameter\");\n}",
|
||
" assert_eq!(f.apply(75.0, 0.0), q, \"caret and glyph use the same wrapped parameter\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/text/src/closed_path_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "closed_ellipse_upper_left_and_apex_cross_the_seam_in_both_directions",
|
||
"path": "crates/text/src/closed_path_tests.rs",
|
||
"package": "photocraft-text",
|
||
"command": "cargo test -p photocraft-text --locked closed_ellipse_upper_left_and_apex_cross_the_seam_in_both_directions -- --nocapture",
|
||
"fixture_and_action_excerpt": " for reverse in [false, true] {\n let mut p = ellipse();\n if reverse {\n p.knots.reverse();\n for k in &mut p.knots {\n std::mem::swap(&mut k.in_ctrl, &mut k.out_ctrl);\n }\n }\n for flip in [false, true] {\n let whole = PathFrame::new(&p, 0.0, flip).unwrap();\n let length = whole.length();\n for remaining in [0.001, 0.2, 30.0] {",
|
||
"expected_assertions": [
|
||
" assert!((actual.0 - point.0).hypot(actual.1 - point.1) < 1e-6);\n assert!((m[0] - tangent.0).abs() < 1e-6 && (m[1] - tangent.1).abs() < 1e-6);\n assert!((m[0] * m[3] - m[1] * m[2] - 1.0).abs() < 1e-6, \"no reflection or scale jump\");\n let before = f.apply(remaining - 0.001, 0.0);",
|
||
" assert!((m[0] - tangent.0).abs() < 1e-6 && (m[1] - tangent.1).abs() < 1e-6);\n assert!((m[0] * m[3] - m[1] * m[2] - 1.0).abs() < 1e-6, \"no reflection or scale jump\");\n let before = f.apply(remaining - 0.001, 0.0);\n let after = f.apply(remaining + 0.001, 0.0);",
|
||
" assert!((m[0] * m[3] - m[1] * m[2] - 1.0).abs() < 1e-6, \"no reflection or scale jump\");\n let before = f.apply(remaining - 0.001, 0.0);\n let after = f.apply(remaining + 0.001, 0.0);\n assert!((before.0 - after.0).hypot(before.1 - after.1) < 0.01, \"seam is continuous\");",
|
||
" assert!((before.0 - after.0).hypot(before.1 - after.1) < 0.01, \"seam is continuous\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/text/src/closed_path_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "closed_path_shows_one_lap_without_repeating_glyph_centres",
|
||
"path": "crates/text/src/closed_path_tests.rs",
|
||
"package": "photocraft-text",
|
||
"command": "cargo test -p photocraft-text --locked closed_path_shows_one_lap_without_repeating_glyph_centres -- --nocapture",
|
||
"fixture_and_action_excerpt": " let p = ellipse();\n let length = PathFrame::new(&p, 0.0, false).unwrap().length();\n let f = PathFrame::new(&p, (length - 5.0) as f32, false).unwrap();\n let mut points = Vec::new();\n for i in 0..100 {\n let x = length * i as f64 / 100.0;\n let m = f.frame(x).expect(\"one complete lap is available from the text origin\");\n points.push(centre(m, x));\n }\n for (i, a) in points.iter().enumerate() {\n assert!(points.iter().skip(i + 1).all(|b| (a.0 - b.0).hypot(a.1 - b.1) > 0.01));\n }",
|
||
"expected_assertions": [
|
||
" assert!(points.iter().skip(i + 1).all(|b| (a.0 - b.0).hypot(a.1 - b.1) > 0.01));\n }\n assert!(f.frame(length).is_none(), \"the first repeated location is overflow, not another lap\");\n assert!(f.frame(length + 20.0).is_none());",
|
||
" assert!(f.frame(length).is_none(), \"the first repeated location is overflow, not another lap\");\n assert!(f.frame(length + 20.0).is_none());\n}",
|
||
" assert!(f.frame(length + 20.0).is_none());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/text/src/closed_path_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "open_path_clipping_offsets_and_end_tangents_stay_unchanged",
|
||
"path": "crates/text/src/closed_path_tests.rs",
|
||
"package": "photocraft-text",
|
||
"command": "cargo test -p photocraft-text --locked open_path_clipping_offsets_and_end_tangents_stay_unchanged -- --nocapture",
|
||
"fixture_and_action_excerpt": " let p = Subpath::polyline(&[(0.0, 0.0), (100.0, 0.0)]);\n for flip in [false, true] {\n let f = PathFrame::new(&p, 25.0, flip).unwrap();\n assert!(f.frame(-26.0).is_none());\n assert!(f.frame(-25.0).is_some());\n assert!(f.frame(75.0).is_some());\n assert!(f.frame(76.0).is_none());\n let q = f.apply(100.0, 0.0);\n assert!((q.0 - if flip { -25.0 } else { 125.0 }).abs() < 1e-9 && q.1.abs() < 1e-9);\n }\n}",
|
||
"expected_assertions": [
|
||
" assert!(f.frame(-26.0).is_none());\n assert!(f.frame(-25.0).is_some());\n assert!(f.frame(75.0).is_some());\n assert!(f.frame(76.0).is_none());",
|
||
" assert!(f.frame(-25.0).is_some());\n assert!(f.frame(75.0).is_some());\n assert!(f.frame(76.0).is_none());\n let q = f.apply(100.0, 0.0);",
|
||
" assert!(f.frame(75.0).is_some());\n assert!(f.frame(76.0).is_none());\n let q = f.apply(100.0, 0.0);\n assert!((q.0 - if flip { -25.0 } else { 125.0 }).abs() < 1e-9 && q.1.abs() < 1e-9);",
|
||
" assert!(f.frame(76.0).is_none());\n let q = f.apply(100.0, 0.0);\n assert!((q.0 - if flip { -25.0 } else { 125.0 }).abs() < 1e-9 && q.1.abs() < 1e-9);\n }",
|
||
" assert!((q.0 - if flip { -25.0 } else { 125.0 }).abs() < 1e-9 && q.1.abs() < 1e-9);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/text/src/closed_path_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "closed_path_alignment_uses_one_lap_from_the_text_left_edge",
|
||
"path": "crates/text/src/closed_path_tests.rs",
|
||
"package": "photocraft-text",
|
||
"command": "cargo test -p photocraft-text --locked closed_path_alignment_uses_one_lap_from_the_text_left_edge -- --nocapture",
|
||
"fixture_and_action_excerpt": " let p = ellipse();\n let length = PathFrame::new(&p, 0.0, false).unwrap().length();\n for left in [-length / 2.0, -length, 0.0] {\n let shape = TextShape::Path { path: p.clone(), start: (length - 5.0) as f32, flip: false };\n let warp = Warp::on_path_with_text_start(&shape, left).unwrap();\n assert!(matches!(warp.place_glyph(left + 0.5), Placement::Frame(_)));\n assert!(matches!(warp.place_glyph(left + length - 0.5), Placement::Frame(_)));\n assert_eq!(warp.place_glyph(left - 0.5), Placement::Hidden);\n assert_eq!(warp.place_glyph(left + length + 0.5), Placement::Hidden);\n // The origin and tangent at each text coordinate are independent of clipping alignment.\n let reference = Warp::on_path(&shape).unwrap();\n assert_eq!(warp.apply(left, 0.0), reference.apply(left, 0.0));",
|
||
"expected_assertions": [
|
||
" assert!(matches!(warp.place_glyph(left + 0.5), Placement::Frame(_)));\n assert!(matches!(warp.place_glyph(left + length - 0.5), Placement::Frame(_)));\n assert_eq!(warp.place_glyph(left - 0.5), Placement::Hidden);\n assert_eq!(warp.place_glyph(left + length + 0.5), Placement::Hidden);",
|
||
" assert!(matches!(warp.place_glyph(left + length - 0.5), Placement::Frame(_)));\n assert_eq!(warp.place_glyph(left - 0.5), Placement::Hidden);\n assert_eq!(warp.place_glyph(left + length + 0.5), Placement::Hidden);\n // The origin and tangent at each text coordinate are independent of clipping alignment.",
|
||
" assert_eq!(warp.place_glyph(left - 0.5), Placement::Hidden);\n assert_eq!(warp.place_glyph(left + length + 0.5), Placement::Hidden);\n // The origin and tangent at each text coordinate are independent of clipping alignment.\n let reference = Warp::on_path(&shape).unwrap();",
|
||
" assert_eq!(warp.place_glyph(left + length + 0.5), Placement::Hidden);\n // The origin and tangent at each text coordinate are independent of clipping alignment.\n let reference = Warp::on_path(&shape).unwrap();\n assert_eq!(warp.apply(left, 0.0), reference.apply(left, 0.0));",
|
||
" assert_eq!(warp.apply(left, 0.0), reference.apply(left, 0.0));\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/text/src/closed_path_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "closed_path_start_offsets_wrap_and_invalid_coordinates_are_hidden",
|
||
"path": "crates/text/src/closed_path_tests.rs",
|
||
"package": "photocraft-text",
|
||
"command": "cargo test -p photocraft-text --locked closed_path_start_offsets_wrap_and_invalid_coordinates_are_hidden -- --nocapture",
|
||
"fixture_and_action_excerpt": " let p = Subpath::polygon(&[(0.0, 0.0), (100.0, 0.0), (100.0, 100.0), (0.0, 100.0)]);\n for start in [-10.0, 0.0, 400.0, 790.0] {\n let f = PathFrame::new(&p, start, false).unwrap();\n let reference = PathFrame::new(&p, start.rem_euclid(400.0), false).unwrap();\n assert_eq!(f.frame(20.0), reference.frame(20.0));\n assert!(f.frame(f64::NAN).is_none());\n assert!(f.frame(f64::INFINITY).is_none());\n }\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(f.frame(20.0), reference.frame(20.0));\n assert!(f.frame(f64::NAN).is_none());\n assert!(f.frame(f64::INFINITY).is_none());\n }",
|
||
" assert!(f.frame(f64::NAN).is_none());\n assert!(f.frame(f64::INFINITY).is_none());\n }\n}",
|
||
" assert!(f.frame(f64::INFINITY).is_none());\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/text/src/closed_path_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "caret_projection_roundtrips_closed_seams_and_open_offsets",
|
||
"path": "crates/text/src/closed_path_tests.rs",
|
||
"package": "photocraft-text",
|
||
"command": "cargo test -p photocraft-text --locked caret_projection_roundtrips_closed_seams_and_open_offsets -- --nocapture",
|
||
"fixture_and_action_excerpt": " let p = ellipse();\n let length = PathFrame::new(&p, 0.0, false).unwrap().length();\n for flip in [false, true] {\n for left in [0.0, -length / 2.0, -length] {\n let shape = TextShape::Path { path: p.clone(), start: (length - 20.0) as f32, flip };\n let w = Warp::on_path_with_text_start(&shape, left).unwrap();\n for x in [left + 0.5, left + 50.0, left + length / 2.0, left + length - 0.5] {\n let point = w.apply(x, 0.0);\n let actual = w.path_text_x(point.0, point.1).unwrap();\n assert!((actual - x).abs() < 1e-6, \"caret must not jump to start after seam: {actual} vs {x}\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!((actual - x).abs() < 1e-6, \"caret must not jump to start after seam: {actual} vs {x}\");\n }\n }\n let shape = TextShape::Path { path: Subpath::polyline(&[(0.0, 0.0), (100.0, 0.0)]), start: 25.0, flip };",
|
||
" assert!((x - if flip { 35.0 } else { 15.0 }).abs() < 1e-9);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/text/src/closed_path_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "closed_path_forward_hit_after_last_caret",
|
||
"path": "crates/ui-egui/src/type_tool.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked closed_path_forward_hit_after_last_caret -- --nocapture",
|
||
"fixture_and_action_excerpt": " for align in [\"left\", \"center\", \"right\"] {\n let mut app = app();\n app.ui.tool_options.type_align = align.into();\n let path = photocraft_vector::shapes::rect(20.0, 20.0, 200.0, 100.0);\n app.run(\"path.set\", json!({\"path\": photocraft_engine::vector_cmds::path_json(&path)})).unwrap();\n pointer_up(&mut app, [20.0, 45.0], [20.0, 45.0]);\n insert(&mut app, \"ssssssssssss\");\n let id = LayerId(app.ui.text_edit.as_ref().unwrap().layer);\n let (l, _, _) = layout(&mut app, id).unwrap();\n let (last, _, _) = l.caret(12);\n let s = (575.0 + f64::from(last) + 2.0).rem_euclid(600.0);\n let (x, y) = closed_path_endpoint_test_point(s);",
|
||
"expected_assertions": [
|
||
" assert_eq!(offset_at(&mut app, id, x, y), 12, \"{align}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/ui-egui/src/type_tool.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "open_path_hits_keep_endpoint_clamping",
|
||
"path": "crates/ui-egui/src/type_tool.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked open_path_hits_keep_endpoint_clamping -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n let path = photocraft_doc::vector::Path::new(vec![photocraft_doc::vector::Subpath::polyline(&[(20.0, 100.0), (380.0, 100.0)])]);\n app.run(\"path.set\", json!({\"path\": photocraft_engine::vector_cmds::path_json(&path)})).unwrap();\n pointer_up(&mut app, [200.0, 100.0], [200.0, 100.0]);\n insert(&mut app, \"ssss\");\n let id = LayerId(app.ui.text_edit.as_ref().unwrap().layer);\n assert_eq!(offset_at(&mut app, id, 198.0, 100.0), 0);\n assert_eq!(offset_at(&mut app, id, 20.0, 100.0), 0);\n assert_eq!(offset_at(&mut app, id, 380.0, 100.0), 4);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(offset_at(&mut app, id, 198.0, 100.0), 0);\n assert_eq!(offset_at(&mut app, id, 20.0, 100.0), 0);\n assert_eq!(offset_at(&mut app, id, 380.0, 100.0), 4);\n }",
|
||
" assert_eq!(offset_at(&mut app, id, 20.0, 100.0), 0);\n assert_eq!(offset_at(&mut app, id, 380.0, 100.0), 4);\n }",
|
||
" assert_eq!(offset_at(&mut app, id, 380.0, 100.0), 4);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/ui-egui/src/type_tool.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "closed_path_backward_hit_before_first_caret",
|
||
"path": "crates/ui-egui/src/type_tool.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked closed_path_backward_hit_before_first_caret -- --nocapture",
|
||
"fixture_and_action_excerpt": " for align in [\"left\", \"center\", \"right\"] {\n let mut app = app();\n app.ui.tool_options.type_align = align.into();\n let path = photocraft_vector::shapes::rect(20.0, 20.0, 200.0, 100.0);\n app.run(\"path.set\", json!({\"path\": photocraft_engine::vector_cmds::path_json(&path)})).unwrap();\n pointer_up(&mut app, [20.0, 45.0], [20.0, 45.0]);\n insert(&mut app, \"ssssssssssss\");\n let id = LayerId(app.ui.text_edit.as_ref().unwrap().layer);\n let (l, _, _) = layout(&mut app, id).unwrap();\n // The rectangle runs clockwise; the text origin is perimeter distance 575.\n // Project 2 px backward from the first caret, using an independent oracle.\n let (first, _, _) = l.caret(0);",
|
||
"expected_assertions": [
|
||
" assert_eq!(offset_at(&mut app, id, x, y), 0, \"{align}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/ui-egui/src/type_tool.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "closed_path_upstream_caret_rectangle_left_edge_roundtrip",
|
||
"path": "crates/ui-egui/src/type_tool.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked closed_path_upstream_caret_rectangle_left_edge_roundtrip -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app();\n let path = photocraft_vector::shapes::rect(20.0, 20.0, 200.0, 100.0);\n app.run(\"path.set\", json!({\"path\": photocraft_engine::vector_cmds::path_json(&path)})).unwrap();\n pointer_up(&mut app, [20.0, 45.0], [20.0, 45.0]);\n insert(&mut app, \"ssssssssssss\");\n let id = LayerId(app.ui.text_edit.as_ref().unwrap().layer);\n let (layout, _, _) = layout(&mut app, id).unwrap();\n let shape = text_layer(&app.session.active().unwrap().doc, id).unwrap().shape.clone();\n let photocraft_doc::text::TextShape::Path { start, .. } = shape else {\n assert!(matches!(shape, photocraft_doc::text::TextShape::Path { .. }), \"outline click must attach path text\");\n return;\n };",
|
||
"expected_assertions": [
|
||
" assert!(matches!(shape, photocraft_doc::text::TextShape::Path { .. }), \"outline click must attach path text\");\n return;\n };\n // Independent rectangle perimeter oracle: never use the warp under test to",
|
||
" assert!((f64::from(start) - 575.0).abs() < 0.5);\n let mut tested_after_seam = false;\n for index in [1, 4, 7, 10] {\n let (x, _, _) = layout.caret(index);",
|
||
" assert_eq!(offset_at(&mut app, id, doc.x, doc.y), index, \"caret round trip at {index}\");\n }\n assert!(tested_after_seam, \"fixture must cross the seam\");\n }",
|
||
" assert!(tested_after_seam, \"fixture must cross the seam\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/ui-egui/src/type_tool.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "closed_path_aligned_selection_highlights_every_visible_cluster",
|
||
"path": "crates/ui-egui/src/type_tool.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked closed_path_aligned_selection_highlights_every_visible_cluster -- --nocapture",
|
||
"fixture_and_action_excerpt": " for align in [\"center\", \"right\"] {\n let mut app = app();\n app.ui.tool_options.type_align = align.into();\n let path = photocraft_vector::shapes::rect(20.0, 20.0, 200.0, 100.0);\n app.run(\"path.set\", json!({\"path\":photocraft_engine::vector_cmds::path_json(&path)})).unwrap();\n pointer_up(&mut app, [20.0, 45.0], [20.0, 45.0]);\n insert(&mut app, \"ssssssssssss\");\n let id = LayerId(app.ui.text_edit.as_ref().unwrap().layer);\n let (l, _, _) = layout(&mut app, id).unwrap();\n assert!(l.bounds().unwrap()[0] < 0.0, \"{align} must exercise negative text coordinates\");\n let text_layer = text_layer(&app.session.active().unwrap().doc, id).unwrap();\n let rendered = photocraft_text::render::layout_deform(&l, text_layer).unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(l.bounds().unwrap()[0] < 0.0, \"{align} must exercise negative text coordinates\");\n let text_layer = text_layer(&app.session.active().unwrap().doc, id).unwrap();\n let rendered = photocraft_text::render::layout_deform(&l, text_layer).unwrap();\n let visible =",
|
||
" assert_eq!(visible, l.clusters.len());\n let ed = app.ui.text_edit.as_mut().unwrap();\n ed.anchor = 0;\n ed.caret = 12;",
|
||
" assert_eq!(highlights, visible, \"{align}: every visible selected cluster needs its highlight\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/728782c595e768bdb6febc7f30e4d1456d13fd36/crates/ui-egui/src/type_tool.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9594",
|
||
"pr": 9594,
|
||
"subsystem": "Type and typography",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked copied_type_keeps_its_pixel_size_across_resolutions_after_an_edit -- --nocapture"
|
||
],
|
||
"expected": "copied type keeps its pixel size across resolutions after an edit",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked copied_type_keeps_its_pixel_size_across_resolutions_after_an_edit -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "copied_type_keeps_its_pixel_size_across_resolutions_after_an_edit",
|
||
"path": "crates/engine/src/layer_copy_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked copied_type_keeps_its_pixel_size_across_resolutions_after_an_edit -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (from, to) in [(72, 300), (300, 72)] {\n let mut s = Session::new();\n s.execute(\"file.new\", json!({\"width\": 400, \"height\": 200, \"resolution\": from})).unwrap();\n let t = LayerId(s.execute(\"type.create\", json!({\"text\": \"H\", \"size\": 24, \"x\": 128, \"y\": 100})).unwrap()[\"layer\"].as_u64().unwrap());\n let original = bounds(&s, 0, t);\n s.execute(\"file.new\", json!({\"width\": 400, \"height\": 200, \"resolution\": to})).unwrap();\n s.set_active(0);\n s.execute(\"layer.select\", json!({\"layer\": t.0})).unwrap();\n let id = copied(&s.execute(\"layer.copyToDocument\", json!({\"document\": 1})).unwrap());\n assert_eq!(bounds(&s, 1, id).size(), original.size(), \"{from}→{to}: the copy\");\n s.execute(\"type.edit\", json!({\"layer\": id.0, \"text\": \"M\"})).unwrap();\n s.execute(\"type.edit\", json!({\"layer\": id.0, \"text\": \"H\"})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(bounds(&s, 1, id).size(), original.size(), \"{from}→{to}: the copy\");\n s.execute(\"type.edit\", json!({\"layer\": id.0, \"text\": \"M\"})).unwrap();\n s.execute(\"type.edit\", json!({\"layer\": id.0, \"text\": \"H\"})).unwrap();\n let after = bounds(&s, 1, id);",
|
||
" assert_eq!(after.size(), original.size(), \"{from}→{to}: after an edit, {after:?} vs {original:?}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/46512521fec2b4b462c29d9fefd16398cb81212c/crates/engine/src/layer_copy_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9596",
|
||
"pr": 9596,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-io --locked a_kept_txt2_goes_with_the_last_type_layer -- --nocapture"
|
||
],
|
||
"expected": "a kept txt2 goes with the last type layer",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-io --locked a_kept_txt2_goes_with_the_last_type_layer -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "a_kept_txt2_goes_with_the_last_type_layer",
|
||
"path": "crates/io/src/psd_export.rs",
|
||
"package": "photocraft-io",
|
||
"command": "cargo test -p photocraft-io --locked a_kept_txt2_goes_with_the_last_type_layer -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut doc = Document::new(\"t\", photocraft_geom::Size::new(8, 6), ColorMode::Rgb, SampleType::U8);\n doc.layers.push(Layer::new(\"Layer 1\", LayerContent::Raster(Surface::new(doc.pixel_format()))));\n doc.metadata.psd_global_blocks = vec![(*b\"8BIM\", *b\"Txt2\", std::sync::Arc::new(b\"<< /0 << /1 (stale) >> >>\".to_vec()))];\n let file = document_to_psd(&doc);\n assert!(!file.global_blocks.iter().any(|b| b.key == *b\"Txt2\"), \"no type layers: no Txt2\");\n\n doc.layers.push(Layer::new(\"T\", LayerContent::Text(photocraft_doc::TextLayer::default())));\n let file = document_to_psd(&doc);\n assert!(file.global_blocks.iter().any(|b| b.key == *b\"Txt2\"), \"a type layer keeps its Txt2\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(!file.global_blocks.iter().any(|b| b.key == *b\"Txt2\"), \"no type layers: no Txt2\");\n\n doc.layers.push(Layer::new(\"T\", LayerContent::Text(photocraft_doc::TextLayer::default())));\n let file = document_to_psd(&doc);",
|
||
" assert!(file.global_blocks.iter().any(|b| b.key == *b\"Txt2\"), \"a type layer keeps its Txt2\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/e62013cfd652fa60470a0f7a185fbc8f3d2a2c92/crates/io/src/psd_export.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-3345",
|
||
"pr": 3345,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked native_gradient_icons_persist_reset_and_preserve_legacy_defaults -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked opaque_ramp_has_no_checkerboard_fringe_at_fractional_pixel_edges -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked genuinely_transparent_ramp_still_shows_checkerboard_at_both_scales -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked options_bar_swatch_opens_the_editor_and_reaches_the_gradients_panel -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_options_bar_ribbon_opens_the_editor_only_in_classic_mode -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_ramp_covers_its_checkerboard_at_half_pixel_offsets -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked selected_editor_opacity_commits_once_and_delete_preserves_minimum -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preset_editor_opacity_fields_do_not_edit_document_history -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked editor_browser_expands_groups_and_selects_without_opening_the_sidebar -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_browser_replaces_color_and_opacity_preserves_geometry_and_undoes_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked classic_browser_and_editor_edit_the_tool_even_with_a_gradient_layer_selected -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked picking_a_preset_discards_an_uncommitted_location_draft -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked toolbar_popup_selects_in_both_modes_without_creating_a_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked editor_browser_can_choose_presets_without_a_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked browser_new_saves_the_edited_layer_instead_of_the_tool_gradient -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked double_clicking_an_editor_preset_does_not_create_another_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked presets_can_collapse_to_reach_controls_in_a_small_window_across_themes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked properties_dropdown_edits_the_layer_in_both_tool_modes_and_saves_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked style_icons_edit_the_selected_layer_with_one_undo_step -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked native_gradient_icons_apply_cancel_and_restart -- --nocapture"
|
||
],
|
||
"expected": "native gradient icons persist reset and preserve legacy defaults; opaque ramp has no checkerboard fringe at fractional pixel edges; genuinely transparent ramp still shows checkerboard at both scales; options bar swatch opens the editor and reaches the gradients panel; the options bar ribbon opens the editor only in classic mode; the ramp covers its checkerboard at half pixel offsets; selected editor opacity commits once and delete preserves minimum; preset editor opacity fields do not edit document history; editor browser expands groups and selects without opening the sidebar; layer browser replaces color and opacity preserves geometry and undoes once; classic browser and editor edit the tool even with a gradient layer selected; picking a preset discards an uncommitted location draft; toolbar popup selects in both modes without creating a layer; editor browser can choose presets without a document; browser new saves the edited layer instead of the tool gradient; double clicking an editor preset does not create another layer; presets can collapse to reach controls in a small window across themes; properties dropdown edits the layer in both tool modes and saves it; style icons edit the selected layer with one undo step; native gradient icons apply cancel and restart",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked native_gradient_icons_persist_reset_and_preserve_legacy_defaults -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked opaque_ramp_has_no_checkerboard_fringe_at_fractional_pixel_edges -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked genuinely_transparent_ramp_still_shows_checkerboard_at_both_scales -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked options_bar_swatch_opens_the_editor_and_reaches_the_gradients_panel -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_options_bar_ribbon_opens_the_editor_only_in_classic_mode -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_ramp_covers_its_checkerboard_at_half_pixel_offsets -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked selected_editor_opacity_commits_once_and_delete_preserves_minimum -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preset_editor_opacity_fields_do_not_edit_document_history -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked editor_browser_expands_groups_and_selects_without_opening_the_sidebar -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_browser_replaces_color_and_opacity_preserves_geometry_and_undoes_once -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked classic_browser_and_editor_edit_the_tool_even_with_a_gradient_layer_selected -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked picking_a_preset_discards_an_uncommitted_location_draft -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked toolbar_popup_selects_in_both_modes_without_creating_a_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked editor_browser_can_choose_presets_without_a_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked browser_new_saves_the_edited_layer_instead_of_the_tool_gradient -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked double_clicking_an_editor_preset_does_not_create_another_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked presets_can_collapse_to_reach_controls_in_a_small_window_across_themes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked properties_dropdown_edits_the_layer_in_both_tool_modes_and_saves_it -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked style_icons_edit_the_selected_layer_with_one_undo_step -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked native_gradient_icons_apply_cancel_and_restart -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "native_gradient_icons_persist_reset_and_preserve_legacy_defaults",
|
||
"path": "crates/engine/src/prefs/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked native_gradient_icons_persist_reset_and_preserve_legacy_defaults -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session();\n let history = s.active().unwrap().history.past_len();\n assert!(!s.prefs().interface.native_gradient_icons);\n s.execute(\"prefs.set\", json!({\"path\": \"interface.nativeGradientIcons\", \"value\": true})).unwrap();\n let mut restarted = Session::new();\n restarted.load_prefs_json(&s.prefs_to_json()).unwrap();\n assert!(restarted.prefs().interface.native_gradient_icons);\n assert_eq!(s.active().unwrap().history.past_len(), history);\n s.execute(\"prefs.reset\", json!({\"path\": \"interface.nativeGradientIcons\"})).unwrap();\n assert!(!s.prefs().interface.native_gradient_icons);\n let before = s.prefs().to_json();\n for invalid in [json!(\"true\"), json!(1), Value::Null] {",
|
||
"expected_assertions": [
|
||
" assert!(!s.prefs().interface.native_gradient_icons);\n s.execute(\"prefs.set\", json!({\"path\": \"interface.nativeGradientIcons\", \"value\": true})).unwrap();\n let mut restarted = Session::new();\n restarted.load_prefs_json(&s.prefs_to_json()).unwrap();",
|
||
" assert!(restarted.prefs().interface.native_gradient_icons);\n assert_eq!(s.active().unwrap().history.past_len(), history);\n s.execute(\"prefs.reset\", json!({\"path\": \"interface.nativeGradientIcons\"})).unwrap();\n assert!(!s.prefs().interface.native_gradient_icons);",
|
||
" assert_eq!(s.active().unwrap().history.past_len(), history);\n s.execute(\"prefs.reset\", json!({\"path\": \"interface.nativeGradientIcons\"})).unwrap();\n assert!(!s.prefs().interface.native_gradient_icons);\n let before = s.prefs().to_json();",
|
||
" assert!(!s.prefs().interface.native_gradient_icons);\n let before = s.prefs().to_json();\n for invalid in [json!(\"true\"), json!(1), Value::Null] {\n assert!(s.execute(\"prefs.set\", json!({\"values\": {\"interface.showTooltips\": false, \"interface.nativeGradientIcons\": invalid}})).is_err());",
|
||
" assert!(s.execute(\"prefs.set\", json!({\"values\": {\"interface.showTooltips\": false, \"interface.nativeGradientIcons\": invalid}})).is_err());\n assert_eq!(s.prefs().to_json(), before, \"invalid updates are atomic\");\n }\n restarted.load_prefs_json(r#\"{\"interface\":{\"showTooltips\":false}}\"#).unwrap();",
|
||
" assert_eq!(s.prefs().to_json(), before, \"invalid updates are atomic\");\n }\n restarted.load_prefs_json(r#\"{\"interface\":{\"showTooltips\":false}}\"#).unwrap();\n assert!(!restarted.prefs().interface.native_gradient_icons);",
|
||
" assert!(!restarted.prefs().interface.native_gradient_icons);\n assert!(!restarted.prefs().interface.show_tooltips);\n}",
|
||
" assert!(!restarted.prefs().interface.show_tooltips);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/engine/src/prefs/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "opaque_ramp_has_no_checkerboard_fringe_at_fractional_pixel_edges",
|
||
"path": "crates/ui-egui/src/gradient_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked opaque_ramp_has_no_checkerboard_fringe_at_fractional_pixel_edges -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::Harness;\n for scale in [1.0, 2.0] {\n let edge = 20.0 + 0.3 / scale;\n let rect = Rect::from_min_size(pos2(edge, edge), vec2(96.0, 20.0));\n let Ok(mut h) = std::panic::catch_unwind(|| {\n Harness::builder().with_size(vec2(160.0, 80.0)).with_pixels_per_point(scale).wgpu().build_ui(move |ui| {\n paint_ramp(ui.painter(), rect, |_| [0.1, 0.25, 0.2, 1.0]);\n })\n }) else {\n eprintln!(\"skipping: no GPU adapter\");\n return;\n };",
|
||
"expected_assertions": [
|
||
" assert!(pixel[channel].abs_diff(background[channel]) <= 2, \"scale={scale} at ({right}, {y}): {pixel:?} vs {background:?}\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "genuinely_transparent_ramp_still_shows_checkerboard_at_both_scales",
|
||
"path": "crates/ui-egui/src/gradient_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked genuinely_transparent_ramp_still_shows_checkerboard_at_both_scales -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::Harness;\n for scale in [1.0, 2.0] {\n let Ok(mut h) = std::panic::catch_unwind(|| {\n Harness::builder().with_size(vec2(160.0, 80.0)).with_pixels_per_point(scale).wgpu().build_ui(|ui| {\n paint_ramp(ui.painter(), Rect::from_min_size(pos2(20.0, 20.0), vec2(96.0, 20.0)), |_| [0.1, 0.25, 0.2, 0.0]);\n })\n }) else {\n eprintln!(\"skipping: no GPU adapter\");\n return;\n };\n h.run_steps(3);\n let image = h.render().unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(a[0].abs_diff(b[0]) >= 30, \"scale={scale}: {a:?} vs {b:?}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "options_bar_swatch_opens_the_editor_and_reaches_the_gradients_panel",
|
||
"path": "crates/ui-egui/src/gradient_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked options_bar_swatch_opens_the_editor_and_reaches_the_gradients_panel -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::{Harness, kittest::Queryable};\n let mut app = app_with_gradient(\"linear\");\n app.ui.tool_options.gradient_classic = true;\n let mut h = Harness::builder().with_size(vec2(440.0, 560.0)).build_ui_state(\n |ui, app: &mut PhotocraftApp| {\n if preset_swatch(app, ui) {\n app.ui.panels.gradient_editor = true;\n }\n let ctx = ui.ctx().clone();\n editor_window(app, &ctx);\n },\n app,",
|
||
"expected_assertions": [
|
||
" assert!(h.state().ui.panels.gradient_editor, \"the swatch opened the editor window\");\n // Collapse the embedded browser to reach the sidebar shortcut on a small screen.\n h.get_all_by_label(\"Presets\").last().unwrap().click();\n h.run_steps(8);",
|
||
" assert!(h.state().ui.panels.color, \"the Gradients panel opened\");\n assert_eq!(h.state().ui.dock_tabs.color, 2, \"on the Gradients tab\");\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1, \"no document layers edited\");\n }",
|
||
" assert_eq!(h.state().ui.dock_tabs.color, 2, \"on the Gradients tab\");\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1, \"no document layers edited\");\n }",
|
||
" assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1, \"no document layers edited\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_options_bar_ribbon_opens_the_editor_only_in_classic_mode",
|
||
"path": "crates/ui-egui/src/gradient_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_options_bar_ribbon_opens_the_editor_only_in_classic_mode -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n\n for classic in [false, true] {\n let mut app = app_with_gradient(\"linear\");\n app.ui.tool_options.gradient_classic = classic;\n let mut h = egui_kittest::Harness::builder().with_size(vec2(1400.0, 900.0)).build_ui_state(\n |ui, app: &mut PhotocraftApp| {\n crate::panels::options_bar(app, ui);\n let ctx = ui.ctx().clone();\n editor_window(app, &ctx);\n },\n app,",
|
||
"expected_assertions": [
|
||
" assert!(!h.state().ui.panels.gradient_editor, \"classic={classic}: starts closed\");\n if classic {\n h.get_by_label(\"Gradient picker\").click();\n } else {",
|
||
" assert_eq!(h.state().ui.panels.gradient_editor, classic, \"classic={classic}: ribbon behavior follows the mode\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_ramp_covers_its_checkerboard_at_half_pixel_offsets",
|
||
"path": "crates/ui-egui/src/gradient_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_ramp_covers_its_checkerboard_at_half_pixel_offsets -- --nocapture",
|
||
"fixture_and_action_excerpt": " let ctx = egui::Context::default();\n for ppp in [1.0, 2.0] {\n ctx.set_pixels_per_point(ppp);\n let r = Rect::from_min_size(pos2(10.0 + 0.5 / ppp, 7.0 + 0.5 / ppp), vec2(96.0, 20.0));\n // The new scale applies from the next frame.\n ctx.run_ui(egui::RawInput::default(), |_| {}).textures_delta.clear();\n let mut painted_at = 0.0;\n let mut out = ctx.run_ui(egui::RawInput::default(), |ui| {\n painted_at = ui.ctx().pixels_per_point();\n // Translucent, so the checkerboard is drawn under it.\n paint_ramp(ui.painter(), r, |u| [u, u, u, 0.5]);\n });",
|
||
"expected_assertions": [
|
||
" assert_eq!(painted_at, ppp);\n let checker = out\n .shapes\n .iter()",
|
||
" assert_eq!(ramp, checker.round_to_pixels(ppp), \"{ppp}x: the ramp covers every pixel of the checker\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "selected_editor_opacity_commits_once_and_delete_preserves_minimum",
|
||
"path": "crates/ui-egui/src/gradient_ui/editor_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked selected_editor_opacity_commits_once_and_delete_preserves_minimum -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut h, sink) = editor(true);\n select(&mut h, 0.5, true);\n let before = sink.fill(h.state()).unwrap();\n let history = h.state().session.active().unwrap().history.past_len();\n type_number(&mut h, 0, \"35\", false);\n assert_eq!(sink.fill(h.state()).unwrap(), before, \"typing previews until committed\");\n h.key_press(egui::Key::Enter);\n h.run_steps(3);\n let after = sink.fill(h.state()).unwrap();\n assert!(matches!(&after, Fill::Gradient { opacity_stops, .. } if (opacity_stops[1].1 - 0.35).abs() < 1e-5));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 1);\n let ramp = h.get_by_label(\"Gradient stops\").rect();",
|
||
"expected_assertions": [
|
||
" assert_eq!(sink.fill(h.state()).unwrap(), before, \"typing previews until committed\");\n h.key_press(egui::Key::Enter);\n h.run_steps(3);\n let after = sink.fill(h.state()).unwrap();",
|
||
" assert!(matches!(&after, Fill::Gradient { opacity_stops, .. } if (opacity_stops[1].1 - 0.35).abs() < 1e-5));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 1);\n let ramp = h.get_by_label(\"Gradient stops\").rect();\n h.get_all_by_label(\"Delete\").find(|n| n.rect().top() > ramp.bottom()).unwrap().click();",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history + 1);\n let ramp = h.get_by_label(\"Gradient stops\").rect();\n h.get_all_by_label(\"Delete\").find(|n| n.rect().top() > ramp.bottom()).unwrap().click();\n h.run_steps(3);",
|
||
" assert_eq!(stops.len(), 3);\n assert_eq!(opacity_stops.len(), 2);\n select(&mut h, 0.0, true);\n let ramp = h.get_by_label(\"Gradient stops\").rect();",
|
||
" assert_eq!(opacity_stops.len(), 2);\n select(&mut h, 0.0, true);\n let ramp = h.get_by_label(\"Gradient stops\").rect();\n assert!(h.get_all_by_label(\"Delete\").find(|n| n.rect().top() > ramp.bottom()).unwrap().accesskit_node().is_disabled());",
|
||
" assert!(h.get_all_by_label(\"Delete\").find(|n| n.rect().top() > ramp.bottom()).unwrap().accesskit_node().is_disabled());\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(sink.fill(h.state()).unwrap(), after);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(sink.fill(h.state()).unwrap(), after);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(sink.fill(h.state()).unwrap(), before);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();",
|
||
" assert_eq!(sink.fill(h.state()).unwrap(), before);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();\n assert_eq!(sink.fill(h.state()).unwrap(), after);\n}",
|
||
" assert_eq!(sink.fill(h.state()).unwrap(), after);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/editor_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "preset_editor_opacity_fields_do_not_edit_document_history",
|
||
"path": "crates/ui-egui/src/gradient_ui/editor_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked preset_editor_opacity_fields_do_not_edit_document_history -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut h, sink) = editor(false);\n let before = h.state().session.active().unwrap().doc.clone();\n let history = h.state().session.active().unwrap().history.past_len();\n select(&mut h, 0.5, true);\n type_number(&mut h, 0, \"35\", true);\n assert!(matches!(sink.fill(h.state()).unwrap(), Fill::Gradient { opacity_stops, .. } if (opacity_stops[1].1 - 0.35).abs() < 1e-5));\n let ramp = h.get_by_label(\"Gradient stops\").rect();\n h.get_all_by_label(\"Delete\").find(|n| n.rect().top() > ramp.bottom()).unwrap().click();\n h.run_steps(3);\n assert!(matches!(sink.fill(h.state()).unwrap(), Fill::Gradient { stops, opacity_stops, .. } if stops.len() == 3 && opacity_stops.len() == 2));\n assert_eq!(h.state().session.active().unwrap().doc, before);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);",
|
||
"expected_assertions": [
|
||
" assert!(matches!(sink.fill(h.state()).unwrap(), Fill::Gradient { opacity_stops, .. } if (opacity_stops[1].1 - 0.35).abs() < 1e-5));\n let ramp = h.get_by_label(\"Gradient stops\").rect();\n h.get_all_by_label(\"Delete\").find(|n| n.rect().top() > ramp.bottom()).unwrap().click();\n h.run_steps(3);",
|
||
" assert!(matches!(sink.fill(h.state()).unwrap(), Fill::Gradient { stops, opacity_stops, .. } if stops.len() == 3 && opacity_stops.len() == 2));\n assert_eq!(h.state().session.active().unwrap().doc, before);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().doc, before);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), history);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/editor_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "editor_browser_expands_groups_and_selects_without_opening_the_sidebar",
|
||
"path": "crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked editor_browser_expands_groups_and_selects_without_opening_the_sidebar -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut h, sink) = editor(false);\n let tab = h.state().ui.dock_tabs.color;\n h.get_by_label(\"Purples\").click();\n h.run_steps(3);\n h.get_by_label(\"Purple 03\").click();\n h.run_steps(3);\n assert_eq!(h.state().session.presets.gradient.name, \"Purple 03\");\n assert!(matches!(sink.fill(h.state()), Some(Fill::Gradient { stops, .. }) if stops.len() == 3));\n assert_eq!(h.state().ui.dock_tabs.color, tab);\n assert!(h.state().ui.panels.gradient_editor);\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1);\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().session.presets.gradient.name, \"Purple 03\");\n assert!(matches!(sink.fill(h.state()), Some(Fill::Gradient { stops, .. }) if stops.len() == 3));\n assert_eq!(h.state().ui.dock_tabs.color, tab);\n assert!(h.state().ui.panels.gradient_editor);",
|
||
" assert!(matches!(sink.fill(h.state()), Some(Fill::Gradient { stops, .. }) if stops.len() == 3));\n assert_eq!(h.state().ui.dock_tabs.color, tab);\n assert!(h.state().ui.panels.gradient_editor);\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1);",
|
||
" assert_eq!(h.state().ui.dock_tabs.color, tab);\n assert!(h.state().ui.panels.gradient_editor);\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1);\n}",
|
||
" assert!(h.state().ui.panels.gradient_editor);\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_browser_replaces_color_and_opacity_preserves_geometry_and_undoes_once",
|
||
"path": "crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_browser_replaces_color_and_opacity_preserves_geometry_and_undoes_once -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut h, sink) = editor(true);\n let before = sink.fill(h.state()).unwrap();\n let count = h.state().session.active().unwrap().history.past_len();\n h.get_by_label(\"Foreground to Transparent\").click();\n h.run_steps(3);\n let after = sink.fill(h.state()).unwrap();\n let Fill::Gradient { angle, scale, style, reverse, offset, dither, align, .. } = before.clone() else { panic!() };\n let Fill::Gradient { angle: a, scale: s, style: st, reverse: r, offset: o, dither: d, align: al, stops, opacity_stops, midpoints } = &after else {\n panic!()\n };\n assert_eq!((*a, *s, *st, *r, *o, *d, *al), (angle, scale, style, reverse, offset, dither, align));\n assert_eq!(stops.len(), 2);",
|
||
"expected_assertions": [
|
||
" assert_eq!((*a, *s, *st, *r, *o, *d, *al), (angle, scale, style, reverse, offset, dither, align));\n assert_eq!(stops.len(), 2);\n assert_eq!(opacity_stops, &vec![(0.0, 1.0), (1.0, 0.0)]);\n assert!(midpoints.is_empty());",
|
||
" assert_eq!(stops.len(), 2);\n assert_eq!(opacity_stops, &vec![(0.0, 1.0), (1.0, 0.0)]);\n assert!(midpoints.is_empty());\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 2);",
|
||
" assert_eq!(opacity_stops, &vec![(0.0, 1.0), (1.0, 0.0)]);\n assert!(midpoints.is_empty());\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 2);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);",
|
||
" assert!(midpoints.is_empty());\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 2);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 2);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(sink.fill(h.state()).unwrap(), before);",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(sink.fill(h.state()).unwrap(), before);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();",
|
||
" assert_eq!(sink.fill(h.state()).unwrap(), before);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();\n assert_eq!(sink.fill(h.state()).unwrap(), after);\n}",
|
||
" assert_eq!(sink.fill(h.state()).unwrap(), after);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "classic_browser_and_editor_edit_the_tool_even_with_a_gradient_layer_selected",
|
||
"path": "crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked classic_browser_and_editor_edit_the_tool_even_with_a_gradient_layer_selected -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut h, layer) = editor(true);\n h.state_mut().ui.tool_options.gradient_classic = true;\n h.run_steps(3);\n let before = layer.fill(h.state());\n let count = h.state().session.active().unwrap().history.past_len();\n h.get_by_label(\"Foreground to Transparent\").click();\n h.run_steps(3);\n assert_eq!(layer.fill(h.state()), before);\n assert_eq!(h.state().session.presets.gradient.name, \"Foreground to Transparent\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count);\n assert!(h.query_by_label(\"Gradient Options\").is_none());\n h.query_all_by_label(\"Color\").find(|n| n.accesskit_node().role() == egui::accesskit::Role::Button).unwrap().click();",
|
||
"expected_assertions": [
|
||
" assert_eq!(layer.fill(h.state()), before);\n assert_eq!(h.state().session.presets.gradient.name, \"Foreground to Transparent\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count);\n assert!(h.query_by_label(\"Gradient Options\").is_none());",
|
||
" assert_eq!(h.state().session.presets.gradient.name, \"Foreground to Transparent\");\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count);\n assert!(h.query_by_label(\"Gradient Options\").is_none());\n h.query_all_by_label(\"Color\").find(|n| n.accesskit_node().role() == egui::accesskit::Role::Button).unwrap().click();",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), count);\n assert!(h.query_by_label(\"Gradient Options\").is_none());\n h.query_all_by_label(\"Color\").find(|n| n.accesskit_node().role() == egui::accesskit::Role::Button).unwrap().click();\n h.run_steps(2);",
|
||
" assert!(h.query_by_label(\"Gradient Options\").is_none());\n h.query_all_by_label(\"Color\").find(|n| n.accesskit_node().role() == egui::accesskit::Role::Button).unwrap().click();\n h.run_steps(2);\n assert!(!h.state().ui.dialogs.is_empty());",
|
||
" assert!(!h.state().ui.dialogs.is_empty());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "picking_a_preset_discards_an_uncommitted_location_draft",
|
||
"path": "crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked picking_a_preset_discards_an_uncommitted_location_draft -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut h, sink) = editor(true);\n let count = h.state().session.active().unwrap().history.past_len();\n type_number(&mut h, 0, \"70\", false);\n h.get_by_label(\"Foreground to Transparent\").click();\n h.run_steps(4);\n assert!(matches!(sink.fill(h.state()), Some(Fill::Gradient { stops, .. }) if stops[0].0 == 0.0));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);\n}",
|
||
"expected_assertions": [
|
||
" assert!(matches!(sink.fill(h.state()), Some(Fill::Gradient { stops, .. }) if stops[0].0 == 0.0));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "toolbar_popup_selects_in_both_modes_without_creating_a_layer",
|
||
"path": "crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked toolbar_popup_selects_in_both_modes_without_creating_a_layer -- --nocapture",
|
||
"fixture_and_action_excerpt": " for classic in [false, true] {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 200, \"height\": 120})).unwrap();\n app.ui.tool = Tool::Gradient;\n app.ui.tool_options.gradient_classic = classic;\n let mut h = Harness::builder().with_size(vec2(1000.0, 800.0)).build_ui_state(\n |ui, app: &mut PhotocraftApp| {\n if preset_swatch(app, ui) {\n app.ui.panels.gradient_editor = true;\n }\n },\n app,",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().session.presets.gradient.name, \"Foreground to Transparent\");\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1);\n assert!(!h.state().ui.panels.gradient_editor);\n assert!(h.query_by_label(\"Basics\").is_none(), \"popup closes after choosing a preset\");",
|
||
" assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 1);\n assert!(!h.state().ui.panels.gradient_editor);\n assert!(h.query_by_label(\"Basics\").is_none(), \"popup closes after choosing a preset\");\n }",
|
||
" assert!(!h.state().ui.panels.gradient_editor);\n assert!(h.query_by_label(\"Basics\").is_none(), \"popup closes after choosing a preset\");\n }\n}",
|
||
" assert!(h.query_by_label(\"Basics\").is_none(), \"popup closes after choosing a preset\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "editor_browser_can_choose_presets_without_a_document",
|
||
"path": "crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked editor_browser_can_choose_presets_without_a_document -- --nocapture",
|
||
"fixture_and_action_excerpt": " let app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n let mut h = Harness::builder().with_size(vec2(1000.0, 900.0)).build_ui_state(|ui, app: &mut PhotocraftApp| editor_window(app, ui.ctx()), app);\n PhotocraftApp::setup_context(&h.ctx, crate::theme::ThemeKind::ProMedium);\n h.state_mut().ui.panels.gradient_editor = true;\n h.run_steps(3);\n h.get_by_label(\"Foreground to Transparent\").click();\n h.run_steps(3);\n assert!(h.state().session.active().is_none());\n assert_eq!(h.state().session.presets.gradient.name, \"Foreground to Transparent\");\n}",
|
||
"expected_assertions": [
|
||
" assert!(h.state().session.active().is_none());\n assert_eq!(h.state().session.presets.gradient.name, \"Foreground to Transparent\");\n}",
|
||
" assert_eq!(h.state().session.presets.gradient.name, \"Foreground to Transparent\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "browser_new_saves_the_edited_layer_instead_of_the_tool_gradient",
|
||
"path": "crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked browser_new_saves_the_edited_layer_instead_of_the_tool_gradient -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut h, sink) = editor(true);\n let before = sink.fill(h.state());\n let count = h.state().session.active().unwrap().history.past_len();\n h.get_by_label(\"Create new gradient\").click();\n h.run_steps(3);\n let saved = h.state().session.presets.gradients.iter().flat_map(|g| &g.items).find(|p| p.name == \"Custom\").unwrap();\n assert_eq!(saved.stops.len(), 3);\n assert_eq!(saved.opacity, vec![(0.0, 0.25), (0.5, 0.6), (1.0, 1.0)]);\n assert_eq!(sink.fill(h.state()), before);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count);\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(saved.stops.len(), 3);\n assert_eq!(saved.opacity, vec![(0.0, 0.25), (0.5, 0.6), (1.0, 1.0)]);\n assert_eq!(sink.fill(h.state()), before);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count);",
|
||
" assert_eq!(saved.opacity, vec![(0.0, 0.25), (0.5, 0.6), (1.0, 1.0)]);\n assert_eq!(sink.fill(h.state()), before);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count);\n}",
|
||
" assert_eq!(sink.fill(h.state()), before);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count);\n}",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), count);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "double_clicking_an_editor_preset_does_not_create_another_layer",
|
||
"path": "crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked double_clicking_an_editor_preset_does_not_create_another_layer -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut h, _) = editor(true);\n h.get_by_label(\"Foreground to Transparent\").click();\n h.run_steps(2);\n h.get_by_label(\"Foreground to Transparent\").click();\n h.run_steps(3);\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 2);\n assert_eq!(h.state().session.presets.gradient.name, \"Foreground to Transparent\");\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 2);\n assert_eq!(h.state().session.presets.gradient.name, \"Foreground to Transparent\");\n}",
|
||
" assert_eq!(h.state().session.presets.gradient.name, \"Foreground to Transparent\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "presets_can_collapse_to_reach_controls_in_a_small_window_across_themes",
|
||
"path": "crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked presets_can_collapse_to_reach_controls_in_a_small_window_across_themes -- --nocapture",
|
||
"fixture_and_action_excerpt": " for theme in crate::theme::ThemeKind::ALL {\n let (mut h, _) = editor(true);\n PhotocraftApp::setup_context(&h.ctx, theme);\n h.set_size(vec2(440.0, 560.0));\n h.run_steps(4);\n h.get_by_label(\"Presets\").click();\n h.run_steps(8);\n let reset = h.get_by_label(\"Reset Alignment\").rect();\n assert!(reset.left() >= 0.0 && reset.right() <= 440.0 && reset.bottom() <= 560.0, \"{theme:?}: {reset:?}\");\n h.get_by_label(\"Reset Alignment\").click();\n h.run_steps(3);\n assert!(h.state().ui.panels.gradient_editor);",
|
||
"expected_assertions": [
|
||
" assert!(reset.left() >= 0.0 && reset.right() <= 440.0 && reset.bottom() <= 560.0, \"{theme:?}: {reset:?}\");\n h.get_by_label(\"Reset Alignment\").click();\n h.run_steps(3);\n assert!(h.state().ui.panels.gradient_editor);",
|
||
" assert!(h.state().ui.panels.gradient_editor);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/preset_browser_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "properties_dropdown_edits_the_layer_in_both_tool_modes_and_saves_it",
|
||
"path": "crates/ui-egui/src/gradient_ui/properties_panel.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked properties_dropdown_edits_the_layer_in_both_tool_modes_and_saves_it -- --nocapture",
|
||
"fixture_and_action_excerpt": " for classic in [false, true] {\n let mut app = app();\n app.ui.tool_options.gradient_classic = classic;\n let mut h = Harness::builder().with_size(vec2(1000.0, 800.0)).build_ui_state(\n |ui, app: &mut PhotocraftApp| {\n ui.set_width(280.0);\n panel(ui, app);\n },\n app,\n );\n PhotocraftApp::setup_context(&h.ctx, theme::ThemeKind::ProMedium);\n h.run_steps(3);",
|
||
"expected_assertions": [
|
||
" assert!(arrow.left() >= strip.right() && arrow.right() - strip.left() <= 280.0, \"{arrow:?} beside {strip:?}\");\n assert!((arrow.center().y - (strip.top() + 28.0)).abs() < 1.0);\n h.get_by_label(\"Presets\").click();\n h.run_steps(3);",
|
||
" assert!((arrow.center().y - (strip.top() + 28.0)).abs() < 1.0);\n h.get_by_label(\"Presets\").click();\n h.run_steps(3);\n h.get_by_label(\"Create new gradient\").click();",
|
||
" assert_eq!(saved.opacity, vec![(0.0, 0.2), (1.0, 1.0)]);\n assert_eq!(saved.resolve([0.0; 4], [0.0; 4])[0].1, [1.0, 0.0, 0.0, 0.2]);\n assert_eq!(fill(h.state()), original);\n h.key_press(egui::Key::Escape);",
|
||
" assert_eq!(saved.resolve([0.0; 4], [0.0; 4])[0].1, [1.0, 0.0, 0.0, 0.2]);\n assert_eq!(fill(h.state()), original);\n h.key_press(egui::Key::Escape);\n h.run_steps(3);",
|
||
" assert_eq!(fill(h.state()), original);\n h.key_press(egui::Key::Escape);\n h.run_steps(3);\n h.get_by_label(\"Presets\").click();",
|
||
" assert!(matches!(fill(h.state()), Fill::Gradient { opacity_stops, .. } if opacity_stops == vec![(0.0, 1.0), (1.0, 0.0)]));\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 2);\n assert!(h.query_by_label(\"Basics\").is_none());",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 2);\n assert!(h.query_by_label(\"Basics\").is_none());\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 2);\n assert!(h.query_by_label(\"Basics\").is_none());\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(fill(h.state()), original);",
|
||
" assert!(h.query_by_label(\"Basics\").is_none());\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(fill(h.state()), original);\n }",
|
||
" assert_eq!(fill(h.state()), original);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/properties_panel.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "style_icons_edit_the_selected_layer_with_one_undo_step",
|
||
"path": "crates/ui-egui/src/gradient_ui/properties_panel.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked style_icons_edit_the_selected_layer_with_one_undo_step -- --nocapture",
|
||
"fixture_and_action_excerpt": " for native_icons in [false, true] {\n let mut app = app();\n app.run(\"prefs.set\", json!({\"path\": \"interface.nativeGradientIcons\", \"value\": native_icons})).unwrap();\n let mut h = Harness::builder().with_size(vec2(280.0, 800.0)).build_ui_state(panel, app);\n PhotocraftApp::setup_context(&h.ctx, theme::ThemeKind::ProMedium);\n h.run_steps(3);\n for (style, name) in STYLES.into_iter().skip(1) {\n let before = fill(h.state());\n let count = h.state().session.active().unwrap().history.past_len();\n h.get_by_label(name).click();\n h.run_steps(3);\n let after = fill(h.state());",
|
||
"expected_assertions": [
|
||
" assert!(matches!(&after, Fill::Gradient { style: actual, .. } if *actual == style));\n assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 2);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();",
|
||
" assert_eq!(h.state().session.active().unwrap().doc.layers.len(), 2);\n assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(fill(h.state()), before);",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), count + 1);\n h.state_mut().run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(fill(h.state()), before);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();",
|
||
" assert_eq!(fill(h.state()), before);\n h.state_mut().run(\"edit.redo\", json!({})).unwrap();\n assert_eq!(fill(h.state()), after);\n h.run_steps(2);",
|
||
" assert_eq!(fill(h.state()), after);\n h.run_steps(2);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/gradient_ui/properties_panel.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "native_gradient_icons_apply_cancel_and_restart",
|
||
"path": "crates/ui-egui/src/prefs_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked native_gradient_icons_apply_cancel_and_restart -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::{Harness, kittest::Queryable};\n let (mut app, store) = app_with_store();\n app.run(\"prefs.set\", json!({\"path\": \"interface.language\", \"value\": \"en\"})).unwrap();\n let id = open_preferences(&mut app, \"interface\");\n let mut h = Harness::builder().with_size(vec2(1280.0, 800.0)).build_eframe(move |cc| {\n PhotocraftApp::setup_context(&cc.egui_ctx, Default::default());\n app\n });\n h.run_steps(4);\n h.get_by_label(\"Use PhotoCraft-native gradient icons\").scroll_to_me();\n h.run_steps(4);\n for desired in [true, false] {",
|
||
"expected_assertions": [
|
||
" assert_eq!(h.state().session.prefs().interface.native_gradient_icons, !desired, \"draft waits for Apply\");\n h.get_by_label(\"Apply\").click();\n h.run_steps(4);\n assert_eq!(h.state().session.prefs().interface.native_gradient_icons, desired);",
|
||
" assert_eq!(h.state().session.prefs().interface.native_gradient_icons, desired);\n assert_eq!(stored(&store)[\"interface\"][\"nativeGradientIcons\"], desired);\n let (restarted, _) = app_with_saved(store.lock().unwrap().clone());\n assert_eq!(restarted.session.prefs().interface.native_gradient_icons, desired);",
|
||
" assert_eq!(stored(&store)[\"interface\"][\"nativeGradientIcons\"], desired);\n let (restarted, _) = app_with_saved(store.lock().unwrap().clone());\n assert_eq!(restarted.session.prefs().interface.native_gradient_icons, desired);\n }",
|
||
" assert_eq!(restarted.session.prefs().interface.native_gradient_icons, desired);\n }\n h.get_by_label(\"Use PhotoCraft-native gradient icons\").click();\n h.run_steps(4);",
|
||
" assert!(h.state().ui.dialogs.iter().all(|d| d.id != id));\n assert!(!h.state().session.prefs().interface.native_gradient_icons);\n assert_eq!(stored(&store)[\"interface\"][\"nativeGradientIcons\"], false);\n }",
|
||
" assert!(!h.state().session.prefs().interface.native_gradient_icons);\n assert_eq!(stored(&store)[\"interface\"][\"nativeGradientIcons\"], false);\n }",
|
||
" assert_eq!(stored(&store)[\"interface\"][\"nativeGradientIcons\"], false);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/bfb691f84896fe68543980426632153dc4b4ea69/crates/ui-egui/src/prefs_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-3461",
|
||
"pr": 3461,
|
||
"subsystem": "Actions and automation",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked recorded_eye_visibility_replays_on_another_document_and_duplicate_names -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shell_playback_resolves_recorded_eye_target_on_new_document -- --nocapture"
|
||
],
|
||
"expected": "recorded eye visibility replays on another document and duplicate names; shell playback resolves recorded eye target on new document",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked recorded_eye_visibility_replays_on_another_document_and_duplicate_names -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked shell_playback_resolves_recorded_eye_target_on_new_document -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "recorded_eye_visibility_replays_on_another_document_and_duplicate_names",
|
||
"path": "crates/engine/src/actions_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked recorded_eye_visibility_replays_on_another_document_and_duplicate_names -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.execute(\"file.new\", json!({\"width\": 8, \"height\": 8})).unwrap();\n s.execute(\"layer.new.layer\", json!({\"name\": \"Same\"})).unwrap();\n let hidden = s.execute(\"layer.new.layer\", json!({\"name\": \"Same\"})).unwrap()[\"layer\"].as_u64().unwrap();\n s.execute(\"actions.record\", json!({\"name\": \"Hide\"})).unwrap();\n s.execute(\"layer.setProps\", json!({\"layer\": hidden, \"visible\": false, \"coalesce\": \"eye-sweep\"})).unwrap();\n s.execute(\"actions.stop\", json!({})).unwrap();\n s.execute(\"file.new\", json!({\"width\": 8, \"height\": 8})).unwrap();\n let keep = s.execute(\"layer.new.layer\", json!({\"name\": \"Same\"})).unwrap()[\"layer\"].as_u64().unwrap();\n let target = s.execute(\"layer.new.layer\", json!({\"name\": \"Same\"})).unwrap()[\"layer\"].as_u64().unwrap();\n s.execute(\"select.deselectLayers\", json!({})).unwrap();\n let result = s.execute(\"actions.play\", json!({\"action\": \"Hide\"})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(result.get(\"failed\").is_none(), \"{result}\");\n assert!(s.active().unwrap().doc.layer(photocraft_doc::LayerId(keep)).unwrap().visible);\n assert!(!s.active().unwrap().doc.layer(photocraft_doc::LayerId(target)).unwrap().visible);\n s.execute(\"edit.undo\", json!({})).unwrap();",
|
||
" assert!(s.active().unwrap().doc.layer(photocraft_doc::LayerId(keep)).unwrap().visible);\n assert!(!s.active().unwrap().doc.layer(photocraft_doc::LayerId(target)).unwrap().visible);\n s.execute(\"edit.undo\", json!({})).unwrap();\n assert!(s.active().unwrap().doc.layer(photocraft_doc::LayerId(target)).unwrap().visible);",
|
||
" assert!(!s.active().unwrap().doc.layer(photocraft_doc::LayerId(target)).unwrap().visible);\n s.execute(\"edit.undo\", json!({})).unwrap();\n assert!(s.active().unwrap().doc.layer(photocraft_doc::LayerId(target)).unwrap().visible);\n }",
|
||
" assert!(s.active().unwrap().doc.layer(photocraft_doc::LayerId(target)).unwrap().visible);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5d8cb2a39ad70e31260f1f3fc2010ca132daff65/crates/engine/src/actions_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "shell_playback_resolves_recorded_eye_target_on_new_document",
|
||
"path": "crates/ui-egui/src/actions.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked shell_playback_resolves_recorded_eye_target_on_new_document -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 8, \"height\": 8})).unwrap();\n app.run(\"layer.new.layer\", json!({\"name\": \"Target\"})).unwrap();\n app.run(\"actions.record\", json!({\"name\": \"Hide\"})).unwrap();\n let id = app.session.active().unwrap().active_layer.unwrap();\n app.run(\"layer.setProps\", json!({\"layer\": id.0, \"visible\": false})).unwrap();\n app.run(\"actions.stop\", json!({})).unwrap();\n app.run(\"file.new\", json!({\"width\": 8, \"height\": 8})).unwrap();\n app.run(\"layer.new.layer\", json!({\"name\": \"Target\"})).unwrap();\n let id = app.session.active().unwrap().active_layer.unwrap();\n let result = play(&mut app, &json!({\"action\": \"Hide\"})).unwrap();\n assert!(result.get(\"failed\").is_none(), \"{result}\");",
|
||
"expected_assertions": [
|
||
" assert!(result.get(\"failed\").is_none(), \"{result}\");\n assert!(!app.session.active().unwrap().doc.layer(id).unwrap().visible);\n }",
|
||
" assert!(!app.session.active().unwrap().doc.layer(id).unwrap().visible);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/5d8cb2a39ad70e31260f1f3fc2010ca132daff65/crates/ui-egui/src/actions.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-3520",
|
||
"pr": 3520,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked studio_dark_keeps_square_colour_chips -- --nocapture"
|
||
],
|
||
"expected": "studio dark keeps square colour chips",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked studio_dark_keeps_square_colour_chips -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "studio_dark_keeps_square_colour_chips",
|
||
"path": "crates/ui-egui/src/theme.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked studio_dark_keeps_square_colour_chips -- --nocapture",
|
||
"fixture_and_action_excerpt": " assert!(!Tokens::for_kind(ThemeKind::Studio).round_chips);\n // Only the dark variant changes; the light palette retains its layout.\n assert!(Tokens::for_kind(ThemeKind::StudioLight).round_chips);\n assert!(!Tokens::for_kind(ThemeKind::Pro).round_chips);\n }",
|
||
"expected_assertions": [
|
||
" assert!(!Tokens::for_kind(ThemeKind::Studio).round_chips);\n // Only the dark variant changes; the light palette retains its layout.\n assert!(Tokens::for_kind(ThemeKind::StudioLight).round_chips);\n assert!(!Tokens::for_kind(ThemeKind::Pro).round_chips);",
|
||
" assert!(Tokens::for_kind(ThemeKind::StudioLight).round_chips);\n assert!(!Tokens::for_kind(ThemeKind::Pro).round_chips);\n }",
|
||
" assert!(!Tokens::for_kind(ThemeKind::Pro).round_chips);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d36ec9a21e9c1ed70de2e0d185efd7e084644157/crates/ui-egui/src/theme.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-4035",
|
||
"pr": 4035,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked flatten_keeps_the_inks_of_a_single_layer_exactly -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked stamp_visible_keeps_the_inks_of_a_single_layer_exactly -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked background_from_layer_keeps_the_inks_exactly -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked flatten_of_a_partly_transparent_layer_still_composites_over_white -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked merge_down_separates_through_the_document_profile -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked merge_visible_separates_through_the_document_profile -- --nocapture",
|
||
"cargo test -p photocraft-io --locked cmyk_merged_composite_reads_through_the_embedded_profile -- --nocapture"
|
||
],
|
||
"expected": "flatten keeps the inks of a single layer exactly; stamp visible keeps the inks of a single layer exactly; background from layer keeps the inks exactly; flatten of a partly transparent layer still composites over white; merge down separates through the document profile; merge visible separates through the document profile; cmyk merged composite reads through the embedded profile",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked flatten_keeps_the_inks_of_a_single_layer_exactly -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked stamp_visible_keeps_the_inks_of_a_single_layer_exactly -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked background_from_layer_keeps_the_inks_exactly -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked flatten_of_a_partly_transparent_layer_still_composites_over_white -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked merge_down_separates_through_the_document_profile -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked merge_visible_separates_through_the_document_profile -- --nocapture",
|
||
"cargo test -p photocraft-io --locked cmyk_merged_composite_reads_through_the_embedded_profile -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "flatten_keeps_the_inks_of_a_single_layer_exactly",
|
||
"path": "crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked flatten_keeps_the_inks_of_a_single_layer_exactly -- --nocapture",
|
||
"fixture_and_action_excerpt": " exact(\"Flatten Image\", |s| {\n s.execute(\"layer.flattenImage\", json!({})).unwrap();\n });\n}",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/15ebf8fc940031abdf772e5fdd687c8b55938639/crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "stamp_visible_keeps_the_inks_of_a_single_layer_exactly",
|
||
"path": "crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked stamp_visible_keeps_the_inks_of_a_single_layer_exactly -- --nocapture",
|
||
"fixture_and_action_excerpt": " exact(\"Stamp Visible\", |s| {\n s.execute(\"layer.stampVisible\", json!({})).unwrap();\n });\n}",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/15ebf8fc940031abdf772e5fdd687c8b55938639/crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "background_from_layer_keeps_the_inks_exactly",
|
||
"path": "crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked background_from_layer_keeps_the_inks_exactly -- --nocapture",
|
||
"fixture_and_action_excerpt": " exact(\"Background from Layer\", |s| {\n s.execute(\"layer.new.layerFromBackground\", json!({})).unwrap();\n s.execute(\"layer.new.backgroundFromLayer\", json!({})).unwrap();\n });\n}",
|
||
"expected_assertions": [],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/15ebf8fc940031abdf772e5fdd687c8b55938639/crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "flatten_of_a_partly_transparent_layer_still_composites_over_white",
|
||
"path": "crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked flatten_of_a_partly_transparent_layer_still_composites_over_white -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [8, 16] {\n let mut s = document(depth, true);\n s.edit(\"hole\", |doc, _| {\n doc.layers[0].surface_mut().unwrap().write_pixel(0, 0, &[0.0, 0.0, 0.0, 1.0, 0.0]);\n Ok(())\n })\n .unwrap();\n s.execute(\"layer.flattenImage\", json!({})).unwrap();\n let px = inks(&s)[0];\n // Transparent over white paper: no ink, not the hidden K.\n assert!(px.iter().all(|v| *v < 0.02), \"{depth}-bit: {px:?}\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(px.iter().all(|v| *v < 0.02), \"{depth}-bit: {px:?}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/15ebf8fc940031abdf772e5fdd687c8b55938639/crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "merge_down_separates_through_the_document_profile",
|
||
"path": "crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked merge_down_separates_through_the_document_profile -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [8, 16] {\n let d = drift(depth, true, 0, |s| {\n s.execute(\"layer.new.layer\", json!({})).unwrap();\n s.execute(\"layer.mergeDown\", json!({})).unwrap();\n });\n assert!(d <= ROUND_TRIP, \"{depth}-bit Merge Down: inks moved by {d}\");\n }\n}",
|
||
"expected_assertions": [
|
||
" assert!(d <= ROUND_TRIP, \"{depth}-bit Merge Down: inks moved by {d}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/15ebf8fc940031abdf772e5fdd687c8b55938639/crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "merge_visible_separates_through_the_document_profile",
|
||
"path": "crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked merge_visible_separates_through_the_document_profile -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [8, 16] {\n let d = drift(depth, true, 0, |s| {\n s.execute(\"layer.new.layer\", json!({})).unwrap();\n s.execute(\"layer.mergeVisible\", json!({})).unwrap();\n });\n assert!(d <= ROUND_TRIP, \"{depth}-bit Merge Visible: inks moved by {d}\");\n }\n}",
|
||
"expected_assertions": [
|
||
" assert!(d <= ROUND_TRIP, \"{depth}-bit Merge Visible: inks moved by {d}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/15ebf8fc940031abdf772e5fdd687c8b55938639/crates/engine/tests/cmyk_flatten_profile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "cmyk_merged_composite_reads_through_the_embedded_profile",
|
||
"path": "crates/io/tests/color.rs",
|
||
"package": "photocraft-io",
|
||
"command": "cargo test -p photocraft-io --locked cmyk_merged_composite_reads_through_the_embedded_profile -- --nocapture",
|
||
"fixture_and_action_excerpt": " // The merged image of a CMYK file tagged with a non-default profile is turned into RGB through\n // that profile, as the layers are, or every comparison against it is off (#3778).\n use photocraft_cms::{Intent, Transform};\n use photocraft_psd::{Compression, ImageResource, Version, testgen};\n let profile = photocraft_cms::synth::cmyk_profile(&photocraft_cms::synth::CmykParams {\n tvi: [0.26, 0.26, 0.26, 0.3],\n grid_a2b: 5,\n grid_b2a: 9,\n ..Default::default()\n });\n let reference = |p: &Profile, ink: &[f32; 4]| {\n let t = Transform::new(p, Builtin::Srgb.profile(), Intent::RelativeColorimetric, true).unwrap();",
|
||
"expected_assertions": [
|
||
" assert!((px[k] - want[k]).abs() <= 2.0 / 255.0, \"{depth}-bit {ink:?}: {px:?} vs {want:?} (built-in {coated:?})\");\n }\n }\n assert!(seen_far, \"the fixture profile differs from the built-in one\");",
|
||
" assert!(seen_far, \"the fixture profile differs from the built-in one\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/15ebf8fc940031abdf772e5fdd687c8b55938639/crates/io/tests/color.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-4042",
|
||
"pr": 4042,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked middle_drag_rotates_about_the_pointer_without_panning -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked middle_drag_ignores_invalid_or_stationary_input -- --nocapture"
|
||
],
|
||
"expected": "middle drag rotates about the pointer without panning; middle drag ignores invalid or stationary input",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked middle_drag_rotates_about_the_pointer_without_panning -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked middle_drag_ignores_invalid_or_stationary_input -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "middle_drag_rotates_about_the_pointer_without_panning",
|
||
"path": "crates/ui-egui/src/rotate_view.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked middle_drag_rotates_about_the_pointer_without_panning -- --nocapture",
|
||
"fixture_and_action_excerpt": " let rect = Rect::from_min_size(pos2(0.0, 0.0), vec2(800.0, 600.0));\n let pointer = pos2(600.0, 180.0);\n for flip in [false, true] {\n let mut view = View { zoom: 2.0, center: [130.0, 80.0], ..Default::default() };\n let xf = ViewXform { rect, zoom: 2.0, center: view.center, flip, rotation: 0.0, aspect: 1.25 };\n let original = xf.to_doc(pointer);\n assert!(middle_drag(&mut view, &xf, pointer, 90.0));\n assert!((view.rotation - 31.5).abs() < 0.001);\n let next = ViewXform { center: view.center, rotation: view.rotation, ..xf }.to_doc(pointer);\n assert!((next[0] - original[0]).abs() < 0.001 && (next[1] - original[1]).abs() < 0.001, \"{original:?} {next:?}\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(middle_drag(&mut view, &xf, pointer, 90.0));\n assert!((view.rotation - 31.5).abs() < 0.001);\n let next = ViewXform { center: view.center, rotation: view.rotation, ..xf }.to_doc(pointer);\n assert!((next[0] - original[0]).abs() < 0.001 && (next[1] - original[1]).abs() < 0.001, \"{original:?} {next:?}\");",
|
||
" assert!((view.rotation - 31.5).abs() < 0.001);\n let next = ViewXform { center: view.center, rotation: view.rotation, ..xf }.to_doc(pointer);\n assert!((next[0] - original[0]).abs() < 0.001 && (next[1] - original[1]).abs() < 0.001, \"{original:?} {next:?}\");\n }",
|
||
" assert!((next[0] - original[0]).abs() < 0.001 && (next[1] - original[1]).abs() < 0.001, \"{original:?} {next:?}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/f05098562220a663d052ee3918fd36c8c3e17a51/crates/ui-egui/src/rotate_view.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "middle_drag_ignores_invalid_or_stationary_input",
|
||
"path": "crates/ui-egui/src/rotate_view.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked middle_drag_ignores_invalid_or_stationary_input -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut view = View::default();\n let xf = ViewXform {\n rect: Rect::from_min_size(pos2(0.0, 0.0), vec2(600.0, 400.0)),\n zoom: 1.0,\n center: view.center,\n flip: false,\n rotation: 0.0,\n aspect: 1.0,\n };\n assert!(!middle_drag(&mut view, &xf, pos2(200.0, 120.0), 0.0));\n assert!(!middle_drag(&mut view, &xf, pos2(200.0, 120.0), f32::NAN));\n assert!(!middle_drag(&mut view, &xf, pos2(f32::INFINITY, 120.0), 20.0));",
|
||
"expected_assertions": [
|
||
" assert!(!middle_drag(&mut view, &xf, pos2(200.0, 120.0), 0.0));\n assert!(!middle_drag(&mut view, &xf, pos2(200.0, 120.0), f32::NAN));\n assert!(!middle_drag(&mut view, &xf, pos2(f32::INFINITY, 120.0), 20.0));\n assert_eq!(view.rotation, 0.0);",
|
||
" assert!(!middle_drag(&mut view, &xf, pos2(200.0, 120.0), f32::NAN));\n assert!(!middle_drag(&mut view, &xf, pos2(f32::INFINITY, 120.0), 20.0));\n assert_eq!(view.rotation, 0.0);\n }",
|
||
" assert!(!middle_drag(&mut view, &xf, pos2(f32::INFINITY, 120.0), 20.0));\n assert_eq!(view.rotation, 0.0);\n }",
|
||
" assert_eq!(view.rotation, 0.0);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/f05098562220a663d052ee3918fd36c8c3e17a51/crates/ui-egui/src/rotate_view.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-4547",
|
||
"pr": 4547,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft --locked windows_and_linux_icons_keep_the_round_corners -- --nocapture"
|
||
],
|
||
"expected": "windows and linux icons keep the round corners",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft --locked windows_and_linux_icons_keep_the_round_corners -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "windows_and_linux_icons_keep_the_round_corners",
|
||
"path": "apps/photocraft/src/app_icon.rs",
|
||
"package": "photocraft",
|
||
"command": "cargo test -p photocraft --locked windows_and_linux_icons_keep_the_round_corners -- --nocapture",
|
||
"fixture_and_action_excerpt": " // rx=112 of 512 leaves (10, 10) of a 256 px render transparent; the old crop filled it (#4478).\n let png = include_bytes!(\"../../../assets/app-icon/hicolor/256x256/apps/ai.storyteller.photocraft.png\");\n let icon = eframe::icon_data::from_png_bytes(png).unwrap();\n assert_eq!(icon.width, 256);\n assert_eq!(icon.rgba[(10 * 256 + 10) * 4 + 3], 0, \"corner is transparent\");\n assert_eq!(icon.rgba[(128 * 256 + 2) * 4 + 3], 255, \"the tile is full bleed\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(icon.width, 256);\n assert_eq!(icon.rgba[(10 * 256 + 10) * 4 + 3], 0, \"corner is transparent\");\n assert_eq!(icon.rgba[(128 * 256 + 2) * 4 + 3], 255, \"the tile is full bleed\");\n }",
|
||
" assert_eq!(icon.rgba[(10 * 256 + 10) * 4 + 3], 0, \"corner is transparent\");\n assert_eq!(icon.rgba[(128 * 256 + 2) * 4 + 3], 255, \"the tile is full bleed\");\n }",
|
||
" assert_eq!(icon.rgba[(128 * 256 + 2) * 4 + 3], 255, \"the tile is full bleed\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/a08f7a2295488c2692f68902835a693322017b64/apps/photocraft/src/app_icon.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-4883",
|
||
"pr": 4883,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked status_bounds_follow_the_actual_selection_and_active_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked status_dimensions_follow_ruler_units_and_document_resolution -- --nocapture"
|
||
],
|
||
"expected": "status bounds follow the actual selection and active layer; status dimensions follow ruler units and document resolution",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked status_bounds_follow_the_actual_selection_and_active_layer -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked status_dimensions_follow_ruler_units_and_document_resolution -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "status_bounds_follow_the_actual_selection_and_active_layer",
|
||
"path": "crates/ui-egui/src/chrome_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked status_bounds_follow_the_actual_selection_and_active_layer -- --nocapture",
|
||
"fixture_and_action_excerpt": " let d = doc();\n let id = d.layers[0].id;\n assert_eq!(status_bounds_text(&d, Some(id)), \"Layer: X 0 Y 0 W 2400 H 1500\");\n assert_eq!(status_bounds_text(&d, None), \"No selection or layer\");\n\n let mut s = photocraft_engine::Session::new();\n s.execute(\"file.new\", json!({\"width\": 120, \"height\": 80})).unwrap();\n s.execute(\"select.all\", json!({})).unwrap();\n let doc = &s.active().unwrap().doc;\n assert_eq!(status_bounds_text(doc, None), \"Selection: X 0 Y 0 W 120 H 80\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(status_bounds_text(&d, Some(id)), \"Layer: X 0 Y 0 W 2400 H 1500\");\n assert_eq!(status_bounds_text(&d, None), \"No selection or layer\");\n\n let mut s = photocraft_engine::Session::new();",
|
||
" assert_eq!(status_bounds_text(&d, None), \"No selection or layer\");\n\n let mut s = photocraft_engine::Session::new();\n s.execute(\"file.new\", json!({\"width\": 120, \"height\": 80})).unwrap();",
|
||
" assert_eq!(status_bounds_text(doc, None), \"Selection: X 0 Y 0 W 120 H 80\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ea500486fb40511d3b4782dfacbb89fbff846d8a/crates/ui-egui/src/chrome_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "status_dimensions_follow_ruler_units_and_document_resolution",
|
||
"path": "crates/ui-egui/src/chrome_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked status_dimensions_follow_ruler_units_and_document_resolution -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_engine::prefs::{PointSize, Unit, UnitsAndRulers};\n let mut d = doc();\n d.resolution_dpi = 300.0;\n for (unit, expected) in [\n (Unit::Pixels, \"2400 px x 1500 px (300 ppi)\"),\n (Unit::Inches, \"8 in x 5 in (300 ppi)\"),\n (Unit::Centimeters, \"20.32 cm x 12.7 cm (300 ppi)\"),\n (Unit::Millimeters, \"203.2 mm x 127 mm (300 ppi)\"),\n (Unit::Points, \"576 pt x 360 pt (300 ppi)\"),\n (Unit::Picas, \"48 pica x 30 pica (300 ppi)\"),\n (Unit::Percent, \"100 % x 100 % (300 ppi)\"),\n ] {",
|
||
"expected_assertions": [
|
||
" assert_eq!(status_info_text_with_units(&d, \"dimensions\", \"\", \"\", &units), expected);\n for (key, _) in STATUS_INFO.iter().filter(|(key, _)| *key != \"dimensions\" && *key != \"coordinates\") {\n assert_eq!(status_info_text_with_units(&d, key, \"Brush Tool\", \"sRGB\", &units), status_info_text(&d, key, \"Brush Tool\", \"sRGB\"));\n }",
|
||
" assert_eq!(status_info_text_with_units(&d, key, \"Brush Tool\", \"sRGB\", &units), status_info_text(&d, key, \"Brush Tool\", \"sRGB\"));\n }\n }\n d.resolution_dpi = 240.0;",
|
||
" assert_eq!(status_info_text_with_units(&d, \"dimensions\", \"\", \"\", &units), \"722.7 pt x 451.7 pt (240 ppi)\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ea500486fb40511d3b4782dfacbb89fbff846d8a/crates/ui-egui/src/chrome_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-4890",
|
||
"pr": 4890,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked scrollbar_visibility_round_trips_and_old_preferences_keep_the_theme_default -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked scrollbar_visibility_applies_in_every_theme_and_survives_theme_changes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked hidden_scrollbars_keep_wheel_scrolling_available -- --nocapture"
|
||
],
|
||
"expected": "scrollbar visibility round trips and old preferences keep the theme default; scrollbar visibility applies in every theme and survives theme changes; hidden scrollbars keep wheel scrolling available",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked scrollbar_visibility_round_trips_and_old_preferences_keep_the_theme_default -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked scrollbar_visibility_applies_in_every_theme_and_survives_theme_changes -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked hidden_scrollbars_keep_wheel_scrolling_available -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "scrollbar_visibility_round_trips_and_old_preferences_keep_the_theme_default",
|
||
"path": "crates/engine/src/prefs/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked scrollbar_visibility_round_trips_and_old_preferences_keep_the_theme_default -- --nocapture",
|
||
"fixture_and_action_excerpt": " let old = serde_json::from_value::<Preferences>(json!({\"interface\": {\"uiFontSize\": \"small\"}})).unwrap();\n assert_eq!(old.interface.scrollbar_visibility, ScrollbarVisibility::Default);\n assert_eq!(choices(\"interface.scrollbarVisibility\"), Some(ScrollbarVisibility::NAMES));\n let mut s = Session::new();\n for mode in ScrollbarVisibility::NAMES {\n s.execute(\"prefs.set\", json!({\"values\": {\"interface.scrollbarVisibility\": mode}})).unwrap();\n let saved = s.prefs().to_json();\n let loaded: Preferences = serde_json::from_value(saved.clone()).unwrap();\n assert_eq!(loaded.interface.scrollbar_visibility, s.prefs().interface.scrollbar_visibility);\n assert_eq!(saved[\"interface\"][\"scrollbarVisibility\"], json!(mode));\n }\n let before = s.prefs().to_json();",
|
||
"expected_assertions": [
|
||
" assert_eq!(old.interface.scrollbar_visibility, ScrollbarVisibility::Default);\n assert_eq!(choices(\"interface.scrollbarVisibility\"), Some(ScrollbarVisibility::NAMES));\n let mut s = Session::new();\n for mode in ScrollbarVisibility::NAMES {",
|
||
" assert_eq!(choices(\"interface.scrollbarVisibility\"), Some(ScrollbarVisibility::NAMES));\n let mut s = Session::new();\n for mode in ScrollbarVisibility::NAMES {\n s.execute(\"prefs.set\", json!({\"values\": {\"interface.scrollbarVisibility\": mode}})).unwrap();",
|
||
" assert_eq!(loaded.interface.scrollbar_visibility, s.prefs().interface.scrollbar_visibility);\n assert_eq!(saved[\"interface\"][\"scrollbarVisibility\"], json!(mode));\n }\n let before = s.prefs().to_json();",
|
||
" assert_eq!(saved[\"interface\"][\"scrollbarVisibility\"], json!(mode));\n }\n let before = s.prefs().to_json();\n assert!(s.execute(\"prefs.set\", json!({\"values\": {\"interface.scrollbarVisibility\": \"sometimes\"}})).is_err());",
|
||
" assert!(s.execute(\"prefs.set\", json!({\"values\": {\"interface.scrollbarVisibility\": \"sometimes\"}})).is_err());\n assert_eq!(s.prefs().to_json(), before);\n s.execute(\"prefs.reset\", json!({\"path\": \"interface.scrollbarVisibility\"})).unwrap();\n assert_eq!(s.prefs().interface.scrollbar_visibility, ScrollbarVisibility::Default);",
|
||
" assert_eq!(s.prefs().to_json(), before);\n s.execute(\"prefs.reset\", json!({\"path\": \"interface.scrollbarVisibility\"})).unwrap();\n assert_eq!(s.prefs().interface.scrollbar_visibility, ScrollbarVisibility::Default);\n}",
|
||
" assert_eq!(s.prefs().interface.scrollbar_visibility, ScrollbarVisibility::Default);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ab84cab7355ac999fb1be226950978bafec39605/crates/engine/src/prefs/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "scrollbar_visibility_applies_in_every_theme_and_survives_theme_changes",
|
||
"path": "crates/ui-egui/src/theme.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked scrollbar_visibility_applies_in_every_theme_and_survives_theme_changes -- --nocapture",
|
||
"fixture_and_action_excerpt": " use photocraft_engine::prefs::ScrollbarVisibility as Mode;\n let ctx = egui::Context::default();\n for kind in ThemeKind::ALL {\n apply(&ctx, kind);\n let original = ctx.global_style().spacing.scroll;\n sync_scrollbars(&ctx, Mode::Default);\n assert_eq!(ctx.global_style().spacing.scroll, original);\n sync_scrollbars(&ctx, Mode::Always);\n assert!(!ctx.global_style().spacing.scroll.floating);\n assert!(ctx.global_style().spacing.scroll.bar_width > 0.0);\n sync_scrollbars(&ctx, Mode::AutoHide);\n assert!(ctx.global_style().spacing.scroll.floating);",
|
||
"expected_assertions": [
|
||
" assert_eq!(ctx.global_style().spacing.scroll, original);\n sync_scrollbars(&ctx, Mode::Always);\n assert!(!ctx.global_style().spacing.scroll.floating);\n assert!(ctx.global_style().spacing.scroll.bar_width > 0.0);",
|
||
" assert!(!ctx.global_style().spacing.scroll.floating);\n assert!(ctx.global_style().spacing.scroll.bar_width > 0.0);\n sync_scrollbars(&ctx, Mode::AutoHide);\n assert!(ctx.global_style().spacing.scroll.floating);",
|
||
" assert!(ctx.global_style().spacing.scroll.bar_width > 0.0);\n sync_scrollbars(&ctx, Mode::AutoHide);\n assert!(ctx.global_style().spacing.scroll.floating);\n assert_eq!(ctx.global_style().spacing.scroll.dormant_handle_opacity, 0.0);",
|
||
" assert!(ctx.global_style().spacing.scroll.floating);\n assert_eq!(ctx.global_style().spacing.scroll.dormant_handle_opacity, 0.0);\n sync_scrollbars(&ctx, Mode::Hidden);\n assert_eq!(ctx.global_style().spacing.scroll.bar_width, 0.0);",
|
||
" assert_eq!(ctx.global_style().spacing.scroll.dormant_handle_opacity, 0.0);\n sync_scrollbars(&ctx, Mode::Hidden);\n assert_eq!(ctx.global_style().spacing.scroll.bar_width, 0.0);\n apply(&ctx, kind);",
|
||
" assert_eq!(ctx.global_style().spacing.scroll.bar_width, 0.0);\n apply(&ctx, kind);\n sync_scrollbars(&ctx, Mode::Hidden);\n assert_eq!(ctx.global_style().spacing.scroll.bar_width, 0.0, \"theme changes retain the saved override\");",
|
||
" assert_eq!(ctx.global_style().spacing.scroll.bar_width, 0.0, \"theme changes retain the saved override\");\n sync_scrollbars(&ctx, Mode::Default);\n assert_eq!(ctx.global_style().spacing.scroll, original);\n }",
|
||
" assert_eq!(ctx.global_style().spacing.scroll, original);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ab84cab7355ac999fb1be226950978bafec39605/crates/ui-egui/src/theme.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "hidden_scrollbars_keep_wheel_scrolling_available",
|
||
"path": "crates/ui-egui/src/theme.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked hidden_scrollbars_keep_wheel_scrolling_available -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(300.0, 120.0)).build_ui_state(\n |ui, offset: &mut f32| {\n let area = egui::ScrollArea::vertical().max_height(100.0).show(ui, |ui| {\n for i in 0..30 {\n ui.label(format!(\"Row {i}\"));\n }\n });\n *offset = area.state.offset.y;\n },\n 0.0,\n );\n sync_scrollbars(&h.ctx, photocraft_engine::prefs::ScrollbarVisibility::Hidden);",
|
||
"expected_assertions": [
|
||
" assert!(*h.state() > 0.0);\n assert_eq!(h.ctx.global_style().spacing.scroll.allocated_width(), 0.0);\n }",
|
||
" assert_eq!(h.ctx.global_style().spacing.scroll.allocated_width(), 0.0);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/ab84cab7355ac999fb1be226950978bafec39605/crates/ui-egui/src/theme.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-4938",
|
||
"pr": 4938,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked dragging_the_title_bar_moves_the_dialog -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_keeps_one_size_on_every_page -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_fits_a_short_screen -- --nocapture"
|
||
],
|
||
"expected": "dragging the title bar moves the dialog; layer style keeps one size on every page; layer style fits a short screen",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked dragging_the_title_bar_moves_the_dialog -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_keeps_one_size_on_every_page -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_fits_a_short_screen -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "dragging_the_title_bar_moves_the_dialog",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked dragging_the_title_bar_moves_the_dialog -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::{Harness, kittest::Queryable};\n\n let app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n let mut harness = Harness::builder().with_size(egui::vec2(1400.0, 1100.0)).build_ui_state(|ui, app| show(app, ui.ctx()), app);\n PhotocraftApp::setup_context(&harness.ctx, crate::theme::ThemeKind::ALL[0]);\n harness.state_mut().ui.open_dialog(DialogKind::LayerStyle, serde_json::Map::new());\n harness.run_steps(3);\n let before = harness.get_by_label(\"Layer Style\").rect();\n\n // Grab the title text itself: it must move the dialog, not select the text.\n let from = before.center();\n harness.hover_at(from);",
|
||
"expected_assertions": [
|
||
" assert!((moved - egui::vec2(-120.0, 80.0)).length() < 1.0, \"dialog moved by {moved:?}\");\n assert_eq!(harness.state().ui.dialogs.len(), 1, \"dragging must not close the dialog\");\n }",
|
||
" assert_eq!(harness.state().ui.dialogs.len(), 1, \"dragging must not close the dialog\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/63b7c921634835259139e4d3e7b9d3c396998b4d/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_style_keeps_one_size_on_every_page",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_style_keeps_one_size_on_every_page -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = layer_style_on_bevel(egui::vec2(1400.0, 900.0));\n let size = frame(&h).size();\n let dialog = h.state().ui.dialogs[0].id;\n for page in [\"blendingOptions\", \"styles\"] {\n h.state_mut().ui.dialog_mut(dialog).expect(\"still open\").fields.insert(\"selected\".into(), json!(page));\n h.run_steps(3);\n assert_eq!(frame(&h).size(), size, \"{page}\");\n }\n let grip = egui::Id::new((\"dialog\", dialog)).with(\"resize\").with(\"__resize_corner\");\n assert!(h.ctx.read_response(grip).is_none(), \"no resize grip\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(frame(&h).size(), size, \"{page}\");\n }\n let grip = egui::Id::new((\"dialog\", dialog)).with(\"resize\").with(\"__resize_corner\");\n assert!(h.ctx.read_response(grip).is_none(), \"no resize grip\");",
|
||
" assert!(h.ctx.read_response(grip).is_none(), \"no resize grip\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/63b7c921634835259139e4d3e7b9d3c396998b4d/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_style_fits_a_short_screen",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_style_fits_a_short_screen -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n\n let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1366.0, 640.0));\n let h = layer_style_on_bevel(screen.size());\n assert!(screen.contains_rect(frame(&h)), \"{:?} fits on {screen:?}\", frame(&h));\n for button in [\"OK\", \"Cancel\"] {\n assert!(screen.contains_rect(h.get_by_label(button).rect()), \"{button} is on screen\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(screen.contains_rect(frame(&h)), \"{:?} fits on {screen:?}\", frame(&h));\n for button in [\"OK\", \"Cancel\"] {\n assert!(screen.contains_rect(h.get_by_label(button).rect()), \"{button} is on screen\");\n }",
|
||
" assert!(screen.contains_rect(h.get_by_label(button).rect()), \"{button} is on screen\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/63b7c921634835259139e4d3e7b9d3c396998b4d/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-5270",
|
||
"pr": 5270,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked gradient_overlay_takes_explicit_stops -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_picker_control_binds_previews_confirms_and_cancels -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked every_exposed_color_field_uses_the_shared_picker_and_only_updates_its_target -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preview_cancel_ok_parent_cancel_and_apply_are_transactional_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked unchanged_ok_preserves_missing_parameters_and_imported_effect_snapshot -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked stale_targets_and_invalid_colors_never_apply_or_leave_preview -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preview_off_and_parent_confirmation_and_cancellation_keep_their_contract -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked eyedropper_edits_only_the_picker_and_invalid_samples_leave_it_unchanged -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked gradient_stop_colors_go_through_the_picker -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ramp_adds_moves_and_deletes_stops -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked presets_delete_and_location -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked stops_round_trip_through_the_field_grammar -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked factory_from_to_become_two_stops -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_fill_of_a_page_never_fails -- --nocapture"
|
||
],
|
||
"expected": "gradient overlay takes explicit stops; layer style picker control binds previews confirms and cancels; every exposed color field uses the shared picker and only updates its target; preview cancel ok parent cancel and apply are transactional at every depth; unchanged ok preserves missing parameters and imported effect snapshot; stale targets and invalid colors never apply or leave preview; preview off and parent confirmation and cancellation keep their contract; eyedropper edits only the picker and invalid samples leave it unchanged; gradient stop colors go through the picker; ramp adds moves and deletes stops; presets delete and location; stops round trip through the field grammar; factory from to become two stops; the fill of a page never fails",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked gradient_overlay_takes_explicit_stops -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_picker_control_binds_previews_confirms_and_cancels -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked every_exposed_color_field_uses_the_shared_picker_and_only_updates_its_target -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preview_cancel_ok_parent_cancel_and_apply_are_transactional_at_every_depth -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked unchanged_ok_preserves_missing_parameters_and_imported_effect_snapshot -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked stale_targets_and_invalid_colors_never_apply_or_leave_preview -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preview_off_and_parent_confirmation_and_cancellation_keep_their_contract -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked eyedropper_edits_only_the_picker_and_invalid_samples_leave_it_unchanged -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked gradient_stop_colors_go_through_the_picker -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked ramp_adds_moves_and_deletes_stops -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked presets_delete_and_location -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked stops_round_trip_through_the_field_grammar -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked factory_from_to_become_two_stops -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked the_fill_of_a_page_never_fails -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "gradient_overlay_takes_explicit_stops",
|
||
"path": "crates/engine/src/layer_style.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked gradient_overlay_takes_explicit_stops -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = session();\n let stops = json!([[0.0, \"#ff0000\"], [0.5, \"#00ff00\"], [1.0, \"#0000ff\"]]);\n s.execute(\"layer.layerStyle.gradientOverlay\", json!({\"stops\": stops, \"opacityStops\": [[0, 100], [1, 50]]})).unwrap();\n let Effect::GradientOverlay { gradient, .. } = &effects(&s)[0] else { panic!() };\n assert_eq!(gradient.stops.len(), 3);\n assert_eq!(gradient.stops[1], (0.5, photocraft_color::Color::rgb(0.0, 1.0, 0.0)));\n assert_eq!(gradient.opacity_stops, vec![(0.0, 1.0), (1.0, 0.5)]);\n // Editing the same overlay: new stops replace the list (sorted), unsorted input is sorted,\n // and a geometry-only edit keeps the three stops.\n s.execute(\"layer.layerStyle.gradientOverlay\", json!({\"stops\": [[1.0, \"#ffffff\"], [0.25, [0.0, 0.0, 0.0]]], \"opacityStops\": []})).unwrap();\n let Effect::GradientOverlay { gradient, .. } = &effects(&s)[0] else { panic!() };\n assert_eq!(gradient.stops.iter().map(|s| s.0).collect::<Vec<_>>(), vec![0.25, 1.0]);",
|
||
"expected_assertions": [
|
||
" assert_eq!(gradient.stops.len(), 3);\n assert_eq!(gradient.stops[1], (0.5, photocraft_color::Color::rgb(0.0, 1.0, 0.0)));\n assert_eq!(gradient.opacity_stops, vec![(0.0, 1.0), (1.0, 0.5)]);\n // Editing the same overlay: new stops replace the list (sorted), unsorted input is sorted,",
|
||
" assert_eq!(gradient.stops[1], (0.5, photocraft_color::Color::rgb(0.0, 1.0, 0.0)));\n assert_eq!(gradient.opacity_stops, vec![(0.0, 1.0), (1.0, 0.5)]);\n // Editing the same overlay: new stops replace the list (sorted), unsorted input is sorted,\n // and a geometry-only edit keeps the three stops.",
|
||
" assert_eq!(gradient.opacity_stops, vec![(0.0, 1.0), (1.0, 0.5)]);\n // Editing the same overlay: new stops replace the list (sorted), unsorted input is sorted,\n // and a geometry-only edit keeps the three stops.\n s.execute(\"layer.layerStyle.gradientOverlay\", json!({\"stops\": [[1.0, \"#ffffff\"], [0.25, [0.0, 0.0, 0.0]]], \"opacityStops\": []})).unwrap();",
|
||
" assert_eq!(gradient.stops.iter().map(|s| s.0).collect::<Vec<_>>(), vec![0.25, 1.0]);\n assert!(gradient.opacity_stops.is_empty(), \"[] means opaque\");\n s.execute(\"layer.layerStyle.gradientOverlay\", json!({\"stops\": stops})).unwrap();\n // The dialog's path: the snapshot plus a geometry edit keeps the three stops.",
|
||
" assert!(gradient.opacity_stops.is_empty(), \"[] means opaque\");\n s.execute(\"layer.layerStyle.gradientOverlay\", json!({\"stops\": stops})).unwrap();\n // The dialog's path: the snapshot plus a geometry edit keeps the three stops.\n let fx = serde_json::to_value(&effects(&s)[0]).unwrap();",
|
||
" assert_eq!((gradient.stops.len(), gradient.angle), (3, 45.0));\n let e = s.execute(\"layer.layerStyle.replace\", json!({\"effects\": [{\"kind\": \"gradientOverlay\", \"params\": {\"stops\": [[0, \"#ff0000\"]]}}]})).unwrap_err();\n assert!(matches!(e, EngineError::BadParams { .. }), \"{e}\");\n // A gradient stroke takes stops too.",
|
||
" assert!(matches!(e, EngineError::BadParams { .. }), \"{e}\");\n // A gradient stroke takes stops too.\n s.execute(\"layer.layerStyle.stroke\", json!({\"size\": 4, \"stops\": [[0, \"#ff0000\"], [0.5, \"#00ff00\"], [1, \"#0000ff\"]]})).unwrap();\n assert!(effects(&s).iter().any(|e| matches!(e, Effect::Stroke(st) if matches!(&st.paint, FxPaint::Gradient(g) if g.stops.len() == 3))));",
|
||
" assert!(effects(&s).iter().any(|e| matches!(e, Effect::Stroke(st) if matches!(&st.paint, FxPaint::Gradient(g) if g.stops.len() == 3))));\n // Malformed lists are errors and change nothing.\n for bad in [\n json!({\"stops\": \"red\"}),",
|
||
" assert!(matches!(e, EngineError::BadParams { .. }), \"{bad}: {e}\");\n }\n let Effect::GradientOverlay { gradient, .. } = &effects(&s)[0] else { panic!() };\n assert_eq!(gradient.stops.len(), 3, \"a refused edit keeps the gradient\");",
|
||
" assert_eq!(gradient.stops.len(), 3, \"a refused edit keeps the gradient\");\n // Positions outside 0..1 are clamped.\n s.execute(\"layer.layerStyle.gradientOverlay\", json!({\"stops\": [[-1, \"#000000\"], [2, \"#ffffff\"]]})).unwrap();\n let Effect::GradientOverlay { gradient, .. } = &effects(&s)[0] else { panic!() };",
|
||
" assert_eq!(gradient.stops.iter().map(|s| s.0).collect::<Vec<_>>(), vec![0.0, 1.0]);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/engine/src/layer_style.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "layer_style_picker_control_binds_previews_confirms_and_cancels",
|
||
"path": "crates/ui-egui/src/control.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_style_picker_control_binds_previews_confirms_and_cancels -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n let ctx = egui::Context::default();\n app.run(\"file.new\", json!({\"width\":16,\"height\":16})).unwrap();\n let parent = call(&mut app, &ctx, \"ui.dialog.open\", json!({\"kind\":\"layerStyle\",\"effect\":\"gradientOverlay\"}))[\"result\"][\"dialog\"].as_u64();\n let parent = parent.unwrap();\n let before = app.ui.dialogs[0].fields.clone();\n // The Gradient Overlay's colours are its stops (#5177): `stop` picks one.\n for stop in [0, 1] {\n let reply = call(&mut app, &ctx, \"ui.dialog.open\", json!({\"kind\":\"colorPicker\",\"parent\":parent,\"effect\":\"fx1\",\"field\":\"stops\",\"stop\":stop}));\n assert_eq!(reply[\"ok\"], true, \"{reply}\");\n let picker = app.ui.dialogs.last().unwrap().id;\n let inspected = call(&mut app, &ctx, \"ui.inspect\", json!({}));",
|
||
"expected_assertions": [
|
||
" assert_eq!(reply[\"ok\"], true, \"{reply}\");\n let picker = app.ui.dialogs.last().unwrap().id;\n let inspected = call(&mut app, &ctx, \"ui.inspect\", json!({}));\n assert!(inspected.to_string().contains(\"__layerStyleColor\"));",
|
||
" assert!(inspected.to_string().contains(\"__layerStyleColor\"));\n assert_eq!(call(&mut app, &ctx, \"ui.dialog.confirm\", json!({\"dialog\":parent}))[\"ok\"], false);\n assert_eq!(call(&mut app, &ctx, \"ui.dialog.set\", json!({\"dialog\":picker,\"field\":\"color\",\"value\":\"#123456\"}))[\"ok\"], true);\n assert_eq!(call(&mut app, &ctx, \"ui.dialog.confirm\", json!({\"dialog\":picker}))[\"ok\"], true);",
|
||
" assert_eq!(call(&mut app, &ctx, \"ui.dialog.confirm\", json!({\"dialog\":parent}))[\"ok\"], false);\n assert_eq!(call(&mut app, &ctx, \"ui.dialog.set\", json!({\"dialog\":picker,\"field\":\"color\",\"value\":\"#123456\"}))[\"ok\"], true);\n assert_eq!(call(&mut app, &ctx, \"ui.dialog.confirm\", json!({\"dialog\":picker}))[\"ok\"], true);\n assert_eq!(app.ui.dialogs[0].fields[\"effects\"][0][\"params\"][\"stops\"][stop][1], \"#123456\");",
|
||
" assert_eq!(call(&mut app, &ctx, \"ui.dialog.set\", json!({\"dialog\":picker,\"field\":\"color\",\"value\":\"#123456\"}))[\"ok\"], true);\n assert_eq!(call(&mut app, &ctx, \"ui.dialog.confirm\", json!({\"dialog\":picker}))[\"ok\"], true);\n assert_eq!(app.ui.dialogs[0].fields[\"effects\"][0][\"params\"][\"stops\"][stop][1], \"#123456\");\n }",
|
||
" assert_eq!(call(&mut app, &ctx, \"ui.dialog.confirm\", json!({\"dialog\":picker}))[\"ok\"], true);\n assert_eq!(app.ui.dialogs[0].fields[\"effects\"][0][\"params\"][\"stops\"][stop][1], \"#123456\");\n }\n assert_ne!(app.ui.dialogs[0].fields, before);",
|
||
" assert_eq!(app.ui.dialogs[0].fields[\"effects\"][0][\"params\"][\"stops\"][stop][1], \"#123456\");\n }\n assert_ne!(app.ui.dialogs[0].fields, before);\n let bad = call(&mut app, &ctx, \"ui.dialog.open\", json!({\"kind\":\"colorPicker\",\"parent\":parent,\"effect\":\"fx1\",\"field\":\"stops\",\"stop\":\"x\"}));",
|
||
" assert_ne!(app.ui.dialogs[0].fields, before);\n let bad = call(&mut app, &ctx, \"ui.dialog.open\", json!({\"kind\":\"colorPicker\",\"parent\":parent,\"effect\":\"fx1\",\"field\":\"stops\",\"stop\":\"x\"}));\n assert_eq!(bad[\"ok\"], false, \"{bad}\");\n let bad = call(&mut app, &ctx, \"ui.dialog.open\", json!({\"kind\":\"colorPicker\",\"parent\":parent,\"effect\":\"fx1\",\"field\":\"stops\",\"stop\":9}));",
|
||
" assert_eq!(bad[\"ok\"], false, \"{bad}\");\n let bad = call(&mut app, &ctx, \"ui.dialog.open\", json!({\"kind\":\"colorPicker\",\"parent\":parent,\"effect\":\"fx1\",\"field\":\"stops\",\"stop\":9}));\n assert_eq!(bad[\"ok\"], false, \"{bad}\");\n call(&mut app, &ctx, \"ui.dialog.open\", json!({\"kind\":\"colorPicker\",\"parent\":parent,\"effect\":\"fx1\",\"field\":\"stops\",\"stop\":1}));",
|
||
" assert_eq!(bad[\"ok\"], false, \"{bad}\");\n call(&mut app, &ctx, \"ui.dialog.open\", json!({\"kind\":\"colorPicker\",\"parent\":parent,\"effect\":\"fx1\",\"field\":\"stops\",\"stop\":1}));\n assert_eq!(call(&mut app, &ctx, \"ui.dialog.cancel\", json!({\"dialog\":parent}))[\"ok\"], true);\n assert!(app.ui.dialogs.is_empty());",
|
||
" assert_eq!(call(&mut app, &ctx, \"ui.dialog.cancel\", json!({\"dialog\":parent}))[\"ok\"], true);\n assert!(app.ui.dialogs.is_empty());\n }",
|
||
" assert!(app.ui.dialogs.is_empty());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/control.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "every_exposed_color_field_uses_the_shared_picker_and_only_updates_its_target",
|
||
"path": "crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked every_exposed_color_field_uses_the_shared_picker_and_only_updates_its_target -- --nocapture",
|
||
"fixture_and_action_excerpt": " for (kind, _) in layer_style::KINDS {\n for (field, _, p) in spec(kind) {\n if !matches!(p, P::Color) {\n continue;\n }\n let mut app = app(8);\n let parent = layer_style::open(&mut app, Some(kind)).unwrap();\n let effect = selected(&app, parent);\n let original = fields(&app, parent);\n let tools = app.session.tools.clone();\n let doc = app.session.active().unwrap().doc.clone();\n let history = app.session.active().unwrap().history.past_len();",
|
||
"expected_assertions": [
|
||
" assert!(color_picker_ui::owns(&fields(&app, picker)));\n assert_eq!(fields(&app, picker)[\"__label\"], \"Color Picker (Layer Style Color)\");\n set_color(&mut app, picker, \"#23a567\");\n let shown = preview_fields(&app, parent, &original);",
|
||
" assert_eq!(fields(&app, picker)[\"__label\"], \"Color Picker (Layer Style Color)\");\n set_color(&mut app, picker, \"#23a567\");\n let shown = preview_fields(&app, parent, &original);\n assert_eq!(super::super::entry(&shown, &effect).unwrap()[\"params\"][field], \"#23a567\");",
|
||
" assert_eq!(super::super::entry(&shown, &effect).unwrap()[\"params\"][field], \"#23a567\");\n assert_eq!(fields(&app, parent), original);\n dialogs::confirm(&mut app, picker).unwrap();\n let mut expected = original;",
|
||
" assert_eq!(fields(&app, parent), original);\n dialogs::confirm(&mut app, picker).unwrap();\n let mut expected = original;\n set_param(&mut expected, &effect, field, json!(\"#23a567\"));",
|
||
" assert_eq!(fields(&app, parent), expected, \"{kind}.{field}\");\n assert!(Arc::ptr_eq(&app.session.active().unwrap().doc, &doc));\n assert_eq!(app.session.active().unwrap().history.past_len(), history);\n assert_eq!(app.session.tools.foreground, tools.foreground);",
|
||
" assert!(Arc::ptr_eq(&app.session.active().unwrap().doc, &doc));\n assert_eq!(app.session.active().unwrap().history.past_len(), history);\n assert_eq!(app.session.tools.foreground, tools.foreground);\n assert_eq!(app.session.tools.background, tools.background);",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), history);\n assert_eq!(app.session.tools.foreground, tools.foreground);\n assert_eq!(app.session.tools.background, tools.background);\n }",
|
||
" assert_eq!(app.session.tools.foreground, tools.foreground);\n assert_eq!(app.session.tools.background, tools.background);\n }\n }",
|
||
" assert_eq!(app.session.tools.background, tools.background);\n }\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "preview_cancel_ok_parent_cancel_and_apply_are_transactional_at_every_depth",
|
||
"path": "crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked preview_cancel_ok_parent_cancel_and_apply_are_transactional_at_every_depth -- --nocapture",
|
||
"fixture_and_action_excerpt": " for depth in [8, 16, 32] {\n let mut app = app(depth);\n let parent = layer_style::open(&mut app, Some(\"colorOverlay\")).unwrap();\n let effect = selected(&app, parent);\n layer_style::add_instance(&mut app.ui.dialog_mut(parent).unwrap().fields, \"stroke\");\n let original = fields(&app, parent);\n let st = app.session.active().unwrap();\n let (doc, history, revision, dirty) = (st.doc.clone(), st.history.past_len(), st.revision, st.is_dirty());\n let picker = open(&mut app, parent, &effect, \"color\", None).unwrap();\n set_color(&mut app, picker, \"#00ff00\");\n let (shown, key) = canvas::display_doc(&mut app, 0);\n assert!(!Arc::ptr_eq(&shown, &doc));",
|
||
"expected_assertions": [
|
||
" assert!(!Arc::ptr_eq(&shown, &doc));\n let again = canvas::display_doc(&mut app, 0);\n assert_eq!(key, again.1);\n assert!(Arc::ptr_eq(&shown, &again.0), \"unchanged preview is cached\");",
|
||
" assert_eq!(key, again.1);\n assert!(Arc::ptr_eq(&shown, &again.0), \"unchanged preview is cached\");\n let pixel = photocraft_compose::flatten(&shown).get(3, 3);\n assert!(pixel[1] > pixel[0] && pixel[1] > pixel[2], \"live preview is green at {depth} bits\");",
|
||
" assert!(Arc::ptr_eq(&shown, &again.0), \"unchanged preview is cached\");\n let pixel = photocraft_compose::flatten(&shown).get(3, 3);\n assert!(pixel[1] > pixel[0] && pixel[1] > pixel[2], \"live preview is green at {depth} bits\");\n let st = app.session.active().unwrap();",
|
||
" assert!(pixel[1] > pixel[0] && pixel[1] > pixel[2], \"live preview is green at {depth} bits\");\n let st = app.session.active().unwrap();\n assert_eq!((st.history.past_len(), st.revision, st.is_dirty()), (history, revision, dirty));\n assert!(Arc::ptr_eq(&st.doc, &doc));",
|
||
" assert_eq!((st.history.past_len(), st.revision, st.is_dirty()), (history, revision, dirty));\n assert!(Arc::ptr_eq(&st.doc, &doc));\n dialogs::cancel(&mut app, picker).unwrap();\n assert_eq!(fields(&app, parent), original);",
|
||
" assert!(Arc::ptr_eq(&st.doc, &doc));\n dialogs::cancel(&mut app, picker).unwrap();\n assert_eq!(fields(&app, parent), original);\n assert_ne!(canvas::display_doc(&mut app, 0).1, key);",
|
||
" assert_eq!(fields(&app, parent), original);\n assert_ne!(canvas::display_doc(&mut app, 0).1, key);\n let picker = open(&mut app, parent, &effect, \"color\", None).unwrap();\n set_color(&mut app, picker, \"#00ff00\");",
|
||
" assert_ne!(canvas::display_doc(&mut app, 0).1, key);\n let picker = open(&mut app, parent, &effect, \"color\", None).unwrap();\n set_color(&mut app, picker, \"#00ff00\");\n dialogs::confirm(&mut app, picker).unwrap();",
|
||
" assert_eq!(app.session.active().unwrap().history.past_len(), history);\n dialogs::cancel(&mut app, parent).unwrap();\n assert!(Arc::ptr_eq(&canvas::display_doc(&mut app, 0).0, &doc));\n let parent = layer_style::open(&mut app, Some(\"colorOverlay\")).unwrap();",
|
||
" assert!(Arc::ptr_eq(&canvas::display_doc(&mut app, 0).0, &doc));\n let parent = layer_style::open(&mut app, Some(\"colorOverlay\")).unwrap();\n let effect = selected(&app, parent);\n let picker = open(&mut app, parent, &effect, \"color\", None).unwrap();",
|
||
" assert!(pixel[1] > pixel[0]);\n app.run(\"edit.undo\", json!({})).unwrap();\n assert_eq!(app.session.active().unwrap().doc.layer(doc.layers[0].id).unwrap().effects.items.len(), 0);\n app.run(\"edit.redo\", json!({})).unwrap();",
|
||
" assert_eq!(app.session.active().unwrap().doc.layer(doc.layers[0].id).unwrap().effects.items.len(), 0);\n app.run(\"edit.redo\", json!({})).unwrap();\n assert_eq!(app.session.active().unwrap().doc.layer(doc.layers[0].id).unwrap().effects, applied.layer(doc.layers[0].id).unwrap().effects);\n }",
|
||
" assert_eq!(app.session.active().unwrap().doc.layer(doc.layers[0].id).unwrap().effects, applied.layer(doc.layers[0].id).unwrap().effects);\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "unchanged_ok_preserves_missing_parameters_and_imported_effect_snapshot",
|
||
"path": "crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked unchanged_ok_preserves_missing_parameters_and_imported_effect_snapshot -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(8);\n app.run(\"layer.layerStyle.stroke\", json!({\"size\":7,\"color\":\"#123456\",\"add\":true})).unwrap();\n app.run(\"layer.layerStyle.stroke\", json!({\"size\":9,\"color\":\"#abcdef\",\"add\":true})).unwrap();\n let parent = layer_style::open(&mut app, Some(\"stroke\")).unwrap();\n let original = fields(&app, parent);\n for effect in [\"fx1\", \"fx2\"] {\n let picker = open(&mut app, parent, effect, \"color\", None).unwrap();\n dialogs::confirm(&mut app, picker).unwrap();\n assert_eq!(fields(&app, parent), original);\n }\n let picker = open(&mut app, parent, \"fx2\", \"color\", None).unwrap();\n set_color(&mut app, picker, \"#223344\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(fields(&app, parent), original);\n }\n let picker = open(&mut app, parent, \"fx2\", \"color\", None).unwrap();\n set_color(&mut app, picker, \"#223344\");",
|
||
" assert_eq!(super::super::entry(¤t, \"fx1\"), super::super::entry(&original, \"fx1\"));\n assert_eq!(super::super::entry(¤t, \"fx2\").unwrap()[\"fx\"], super::super::entry(&original, \"fx2\").unwrap()[\"fx\"]);\n dialogs::cancel(&mut app, parent).unwrap();\n let parent = layer_style::open(&mut app, Some(\"gradientOverlay\")).unwrap();",
|
||
" assert_eq!(super::super::entry(¤t, \"fx2\").unwrap()[\"fx\"], super::super::entry(&original, \"fx2\").unwrap()[\"fx\"]);\n dialogs::cancel(&mut app, parent).unwrap();\n let parent = layer_style::open(&mut app, Some(\"gradientOverlay\")).unwrap();\n let effect = selected(&app, parent);",
|
||
" assert_eq!(fields(&app, parent), original);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "stale_targets_and_invalid_colors_never_apply_or_leave_preview",
|
||
"path": "crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked stale_targets_and_invalid_colors_never_apply_or_leave_preview -- --nocapture",
|
||
"fixture_and_action_excerpt": " for change in [\"document\", \"parent\", \"effect\", \"kind\", \"color\", \"source\", \"malformed\", \"layer\", \"replaced\"] {\n let mut app = app(8);\n let parent = layer_style::open(&mut app, Some(\"colorOverlay\")).unwrap();\n let effect = selected(&app, parent);\n let picker = open(&mut app, parent, &effect, \"color\", None).unwrap();\n set_color(&mut app, picker, \"#00ff00\");\n match change {\n \"document\" => {\n app.run(\"file.new\", json!({\"width\":3,\"height\":3})).unwrap();\n }\n \"parent\" => {\n app.ui.close_dialog(parent);",
|
||
"expected_assertions": [
|
||
" assert!(dialogs::confirm(&mut app, picker).is_err(), \"{change}\");\n assert_eq!(app.ui.dialogs.iter().find(|d| d.id == parent).cloned(), current_parent);\n }\n let mut app = app(8);",
|
||
" assert_eq!(app.ui.dialogs.iter().find(|d| d.id == parent).cloned(), current_parent);\n }\n let mut app = app(8);\n let parent = layer_style::open(&mut app, Some(\"colorOverlay\")).unwrap();",
|
||
" assert!(dialogs::confirm(&mut app, picker).is_err());\n assert_eq!(fields(&app, parent), original);\n let picker = open(&mut app, parent, &effect, \"color\", None).unwrap();\n app.run(\"file.new\", json!({\"width\":3,\"height\":3})).unwrap();",
|
||
" assert_eq!(fields(&app, parent), original);\n let picker = open(&mut app, parent, &effect, \"color\", None).unwrap();\n app.run(\"file.new\", json!({\"width\":3,\"height\":3})).unwrap();\n prune(&mut app);",
|
||
" assert!(!app.ui.dialogs.iter().any(|d| d.id == picker));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "preview_off_and_parent_confirmation_and_cancellation_keep_their_contract",
|
||
"path": "crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked preview_off_and_parent_confirmation_and_cancellation_keep_their_contract -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(8);\n let parent = layer_style::open(&mut app, Some(\"colorOverlay\")).unwrap();\n app.ui.dialog_mut(parent).unwrap().fields.insert(\"preview\".into(), json!(false));\n let effect = selected(&app, parent);\n let original = fields(&app, parent);\n let doc = app.session.active().unwrap().doc.clone();\n let picker = open(&mut app, parent, &effect, \"color\", None).unwrap();\n set_color(&mut app, picker, \"#00ff00\");\n assert!(Arc::ptr_eq(&canvas::display_doc(&mut app, 0).0, &doc));\n assert!(dialogs::confirm(&mut app, parent).is_err());\n assert_eq!(fields(&app, parent), original);\n assert_eq!(app.ui.dialogs.len(), 2);",
|
||
"expected_assertions": [
|
||
" assert!(Arc::ptr_eq(&canvas::display_doc(&mut app, 0).0, &doc));\n assert!(dialogs::confirm(&mut app, parent).is_err());\n assert_eq!(fields(&app, parent), original);\n assert_eq!(app.ui.dialogs.len(), 2);",
|
||
" assert!(dialogs::confirm(&mut app, parent).is_err());\n assert_eq!(fields(&app, parent), original);\n assert_eq!(app.ui.dialogs.len(), 2);\n dialogs::cancel(&mut app, parent).unwrap();",
|
||
" assert_eq!(fields(&app, parent), original);\n assert_eq!(app.ui.dialogs.len(), 2);\n dialogs::cancel(&mut app, parent).unwrap();\n assert!(app.ui.dialogs.is_empty());",
|
||
" assert_eq!(app.ui.dialogs.len(), 2);\n dialogs::cancel(&mut app, parent).unwrap();\n assert!(app.ui.dialogs.is_empty());\n}",
|
||
" assert!(app.ui.dialogs.is_empty());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "eyedropper_edits_only_the_picker_and_invalid_samples_leave_it_unchanged",
|
||
"path": "crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked eyedropper_edits_only_the_picker_and_invalid_samples_leave_it_unchanged -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(8);\n let parent = layer_style::open(&mut app, Some(\"colorOverlay\")).unwrap();\n let effect = selected(&app, parent);\n let original = fields(&app, parent);\n let doc = app.session.active().unwrap().doc.clone();\n let tools = app.session.tools.clone();\n let picker = open(&mut app, parent, &effect, \"color\", None).unwrap();\n color_picker_ui::sample_at(&mut app, 4.0, 4.0);\n assert_eq!(fields(&app, picker)[\"color\"], \"#406080\");\n color_picker_ui::sample_at(&mut app, -100.0, -100.0);\n assert_eq!(fields(&app, picker)[\"color\"], \"#406080\");\n assert_eq!(fields(&app, parent), original);",
|
||
"expected_assertions": [
|
||
" assert_eq!(fields(&app, picker)[\"color\"], \"#406080\");\n color_picker_ui::sample_at(&mut app, -100.0, -100.0);\n assert_eq!(fields(&app, picker)[\"color\"], \"#406080\");\n assert_eq!(fields(&app, parent), original);",
|
||
" assert_eq!(fields(&app, picker)[\"color\"], \"#406080\");\n assert_eq!(fields(&app, parent), original);\n assert!(Arc::ptr_eq(&app.session.active().unwrap().doc, &doc));\n assert_eq!(app.session.tools.foreground, tools.foreground);",
|
||
" assert_eq!(fields(&app, parent), original);\n assert!(Arc::ptr_eq(&app.session.active().unwrap().doc, &doc));\n assert_eq!(app.session.tools.foreground, tools.foreground);\n dialogs::cancel(&mut app, picker).unwrap();",
|
||
" assert!(Arc::ptr_eq(&app.session.active().unwrap().doc, &doc));\n assert_eq!(app.session.tools.foreground, tools.foreground);\n dialogs::cancel(&mut app, picker).unwrap();\n}",
|
||
" assert_eq!(app.session.tools.foreground, tools.foreground);\n dialogs::cancel(&mut app, picker).unwrap();\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "gradient_stop_colors_go_through_the_picker",
|
||
"path": "crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked gradient_stop_colors_go_through_the_picker -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = app(8);\n let parent = layer_style::open(&mut app, Some(\"gradientOverlay\")).unwrap();\n let effect = selected(&app, parent);\n let three = json!([[0.0, \"#ff0000\"], [0.5, \"#00ff00\"], [1.0, \"#0000ff\"]]);\n super::super::set_param(&mut app.ui.dialog_mut(parent).unwrap().fields, &effect, \"stops\", three);\n assert!(open(&mut app, parent, &effect, \"stops\", Some(3)).is_err(), \"no fourth stop\");\n assert!(open(&mut app, parent, &effect, \"stops\", None).is_err(), \"stops is not a plain colour\");\n let picker = open(&mut app, parent, &effect, \"stops\", Some(1)).unwrap();\n set_color(&mut app, picker, \"#123456\");\n let current = fields(&app, parent);\n let shown = preview_fields(&app, parent, ¤t);\n assert_eq!(super::super::entry(&shown, &effect).unwrap()[\"params\"][\"stops\"][1][1], \"#123456\", \"previewed\");",
|
||
"expected_assertions": [
|
||
" assert!(open(&mut app, parent, &effect, \"stops\", Some(3)).is_err(), \"no fourth stop\");\n assert!(open(&mut app, parent, &effect, \"stops\", None).is_err(), \"stops is not a plain colour\");\n let picker = open(&mut app, parent, &effect, \"stops\", Some(1)).unwrap();\n set_color(&mut app, picker, \"#123456\");",
|
||
" assert!(open(&mut app, parent, &effect, \"stops\", None).is_err(), \"stops is not a plain colour\");\n let picker = open(&mut app, parent, &effect, \"stops\", Some(1)).unwrap();\n set_color(&mut app, picker, \"#123456\");\n let current = fields(&app, parent);",
|
||
" assert_eq!(super::super::entry(&shown, &effect).unwrap()[\"params\"][\"stops\"][1][1], \"#123456\", \"previewed\");\n assert_eq!(super::super::entry(&fields(&app, parent), &effect).unwrap()[\"params\"][\"stops\"][1][1], \"#00ff00\", \"not stored yet\");\n dialogs::confirm(&mut app, picker).unwrap();\n let stops = super::super::entry(&fields(&app, parent), &effect).unwrap()[\"params\"][\"stops\"].clone();",
|
||
" assert_eq!(super::super::entry(&fields(&app, parent), &effect).unwrap()[\"params\"][\"stops\"][1][1], \"#00ff00\", \"not stored yet\");\n dialogs::confirm(&mut app, picker).unwrap();\n let stops = super::super::entry(&fields(&app, parent), &effect).unwrap()[\"params\"][\"stops\"].clone();\n assert_eq!(stops, json!([[0.0, \"#ff0000\"], [0.5, \"#123456\"], [1.0, \"#0000ff\"]]));",
|
||
" assert_eq!(stops, json!([[0.0, \"#ff0000\"], [0.5, \"#123456\"], [1.0, \"#0000ff\"]]));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/color_picker/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "ramp_adds_moves_and_deletes_stops",
|
||
"path": "crates/ui-egui/src/layer_style/gradient_field.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked ramp_adds_moves_and_deletes_stops -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut app, parent) = dialog_app();\n let effect = crate::layer_style::effects_of(&app.ui.dialogs[0].fields)[0][\"id\"].as_str().unwrap().to_string();\n set_param(&mut app.ui.dialog_mut(parent).unwrap().fields, &effect, KEY, json!([[0.0, \"#000000\"], [1.0, \"#ffffff\"]]));\n let mut h = harness(app, parent);\n assert!(h.query_by_label(\"Gradient stops\").is_some());\n let (_, bar): (String, Rect) = h.ctx.data(|d| d.get_temp(bar_id())).expect(\"the ramp was drawn\");\n // Add in the middle: a mid grey.\n let mid = pos2(bar.center().x, bar.bottom() + 9.0);\n press(&mut h, mid);\n release(&mut h, mid);\n let stops = stops_in(h.state(), parent);\n assert_eq!(stops.len(), 3, \"{stops:?}\");",
|
||
"expected_assertions": [
|
||
" assert!(h.query_by_label(\"Gradient stops\").is_some());\n let (_, bar): (String, Rect) = h.ctx.data(|d| d.get_temp(bar_id())).expect(\"the ramp was drawn\");\n // Add in the middle: a mid grey.\n let mid = pos2(bar.center().x, bar.bottom() + 9.0);",
|
||
" assert_eq!(stops.len(), 3, \"{stops:?}\");\n assert!((stops[1].0 - 0.5).abs() < 0.02 && (stops[1].1.to_rgb()[0] - 0.5).abs() < 0.06, \"{stops:?}\");\n // Drag it to a quarter.\n let quarter = pos2(bar.left() + bar.width() * 0.25, mid.y);",
|
||
" assert!((stops[1].0 - 0.5).abs() < 0.02 && (stops[1].1.to_rgb()[0] - 0.5).abs() < 0.06, \"{stops:?}\");\n // Drag it to a quarter.\n let quarter = pos2(bar.left() + bar.width() * 0.25, mid.y);\n press(&mut h, mid);",
|
||
" assert_eq!(stops.len(), 3);\n assert!((stops[1].0 - 0.25).abs() < 0.03, \"{stops:?}\");\n // Drag it away: gone.\n let away = pos2(quarter.x, bar.bottom() + 90.0);",
|
||
" assert!((stops[1].0 - 0.25).abs() < 0.03, \"{stops:?}\");\n // Drag it away: gone.\n let away = pos2(quarter.x, bar.bottom() + 90.0);\n press(&mut h, quarter);",
|
||
" assert_eq!(stops.len(), 2, \"{stops:?}\");\n // The last two can't be dragged away.\n let first = pos2(bar.left(), mid.y);\n press(&mut h, first);",
|
||
" assert_eq!(stops_in(h.state(), parent).len(), 2);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/gradient_field.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "presets_delete_and_location",
|
||
"path": "crates/ui-egui/src/layer_style/gradient_field.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked presets_delete_and_location -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut app, parent) = dialog_app();\n let effect = crate::layer_style::effects_of(&app.ui.dialogs[0].fields)[0][\"id\"].as_str().unwrap().to_string();\n let name = app\n .session\n .presets\n .gradients\n .iter()\n .flat_map(|g| g.items.iter())\n .map(|p| p.name.clone())\n .find(|n| n.contains(\"Spectrum\") || n.contains(\"Rainbow\"))\n .or_else(|| app.session.presets.gradients.first().and_then(|g| g.items.first()).map(|p| p.name.clone()))\n .unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(apply_preset(&app, &mut f, &effect, &mut disp, &name), \"{name}\");\n assert!(!apply_preset(&app, &mut f, &effect, &mut disp, \"no such preset\"));\n let stops = stops_of(disp.get(KEY)).unwrap();\n assert!(stops.len() >= 2, \"{name}: {stops:?}\");",
|
||
" assert!(!apply_preset(&app, &mut f, &effect, &mut disp, \"no such preset\"));\n let stops = stops_of(disp.get(KEY)).unwrap();\n assert!(stops.len() >= 2, \"{name}: {stops:?}\");\n app.ui.dialog_mut(parent).unwrap().fields = f;",
|
||
" assert!(stops.len() >= 2, \"{name}: {stops:?}\");\n app.ui.dialog_mut(parent).unwrap().fields = f;\n set_param(&mut app.ui.dialog_mut(parent).unwrap().fields, &effect, KEY, json!([[0.0, \"#ff0000\"], [0.5, \"#00ff00\"], [1.0, \"#0000ff\"]]));\n let mut h = harness(app, parent);",
|
||
" assert_eq!(stops.iter().map(|s| super::super::hex(&s.1)).collect::<Vec<_>>(), [\"#ff0000\", \"#0000ff\"], \"{stops:?}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/gradient_field.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "stops_round_trip_through_the_field_grammar",
|
||
"path": "crates/ui-egui/src/layer_style/gradient_field.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked stops_round_trip_through_the_field_grammar -- --nocapture",
|
||
"fixture_and_action_excerpt": " let stops = vec![(0.0, Color::rgb(1.0, 0.0, 0.0)), (0.5, Color::rgb(0.0, 1.0, 0.0)), (1.0, Color::rgb(0.0, 0.0, 1.0))];\n let v = stops_json(&stops);\n assert_eq!(v, json!([[0.0, \"#ff0000\"], [0.5, \"#00ff00\"], [1.0, \"#0000ff\"]]));\n assert_eq!(stops_of(Some(&v)), Some(stops));\n // Unsorted input is sorted, bad entries are skipped, fewer than two is nothing.\n let v = json!([[1.0, \"#ffffff\"], [\"x\", \"#ff0000\"], [0.25, \"#000000\"], [0.5, 7]]);\n assert_eq!(stops_of(Some(&v)).map(|s| s.iter().map(|x| x.0).collect::<Vec<_>>()), Some(vec![0.25, 1.0]));\n assert_eq!(stops_of(Some(&json!([[0.0, \"#000000\"]]))), None);\n assert_eq!(stops_of(Some(&json!(\"red\"))), None);\n assert_eq!(stops_of(None), None);\n let os = vec![(0.0, 1.0), (1.0, 0.5)];\n assert_eq!(opacity_json(&os), json!([[0.0, 100.0], [1.0, 50.0]]));",
|
||
"expected_assertions": [
|
||
" assert_eq!(v, json!([[0.0, \"#ff0000\"], [0.5, \"#00ff00\"], [1.0, \"#0000ff\"]]));\n assert_eq!(stops_of(Some(&v)), Some(stops));\n // Unsorted input is sorted, bad entries are skipped, fewer than two is nothing.\n let v = json!([[1.0, \"#ffffff\"], [\"x\", \"#ff0000\"], [0.25, \"#000000\"], [0.5, 7]]);",
|
||
" assert_eq!(stops_of(Some(&v)), Some(stops));\n // Unsorted input is sorted, bad entries are skipped, fewer than two is nothing.\n let v = json!([[1.0, \"#ffffff\"], [\"x\", \"#ff0000\"], [0.25, \"#000000\"], [0.5, 7]]);\n assert_eq!(stops_of(Some(&v)).map(|s| s.iter().map(|x| x.0).collect::<Vec<_>>()), Some(vec![0.25, 1.0]));",
|
||
" assert_eq!(stops_of(Some(&v)).map(|s| s.iter().map(|x| x.0).collect::<Vec<_>>()), Some(vec![0.25, 1.0]));\n assert_eq!(stops_of(Some(&json!([[0.0, \"#000000\"]]))), None);\n assert_eq!(stops_of(Some(&json!(\"red\"))), None);\n assert_eq!(stops_of(None), None);",
|
||
" assert_eq!(stops_of(Some(&json!([[0.0, \"#000000\"]]))), None);\n assert_eq!(stops_of(Some(&json!(\"red\"))), None);\n assert_eq!(stops_of(None), None);\n let os = vec![(0.0, 1.0), (1.0, 0.5)];",
|
||
" assert_eq!(stops_of(Some(&json!(\"red\"))), None);\n assert_eq!(stops_of(None), None);\n let os = vec![(0.0, 1.0), (1.0, 0.5)];\n assert_eq!(opacity_json(&os), json!([[0.0, 100.0], [1.0, 50.0]]));",
|
||
" assert_eq!(stops_of(None), None);\n let os = vec![(0.0, 1.0), (1.0, 0.5)];\n assert_eq!(opacity_json(&os), json!([[0.0, 100.0], [1.0, 50.0]]));\n assert_eq!(opacity_of(Some(&opacity_json(&os))), Some(os));",
|
||
" assert_eq!(opacity_json(&os), json!([[0.0, 100.0], [1.0, 50.0]]));\n assert_eq!(opacity_of(Some(&opacity_json(&os))), Some(os));\n assert_eq!(opacity_of(Some(&json!([]))), Some(vec![]), \"[] is opaque\");\n assert_eq!(opacity_of(Some(&json!([[0.0, 100.0]]))), None, \"one stop is not a list\");",
|
||
" assert_eq!(opacity_of(Some(&opacity_json(&os))), Some(os));\n assert_eq!(opacity_of(Some(&json!([]))), Some(vec![]), \"[] is opaque\");\n assert_eq!(opacity_of(Some(&json!([[0.0, 100.0]]))), None, \"one stop is not a list\");\n }",
|
||
" assert_eq!(opacity_of(Some(&json!([]))), Some(vec![]), \"[] is opaque\");\n assert_eq!(opacity_of(Some(&json!([[0.0, 100.0]]))), None, \"one stop is not a list\");\n }",
|
||
" assert_eq!(opacity_of(Some(&json!([[0.0, 100.0]]))), None, \"one stop is not a list\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/gradient_field.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "factory_from_to_become_two_stops",
|
||
"path": "crates/ui-egui/src/layer_style/gradient_field.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked factory_from_to_become_two_stops -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut p = json!({\"from\": \"#ff0000\", \"to\": \"#0000ff\", \"angle\": 90});\n from_to_to_stops(&mut p);\n assert_eq!(p, json!({\"stops\": [[0.0, \"#ff0000\"], [1.0, \"#0000ff\"]], \"opacityStops\": [], \"angle\": 90}));\n let mut p = json!({\"stops\": [[0.0, \"#000000\"], [0.5, \"#ff0000\"], [1.0, \"#ffffff\"]], \"from\": \"#123456\"});\n from_to_to_stops(&mut p);\n assert_eq!(p[\"stops\"].as_array().map(Vec::len), Some(3), \"explicit stops win over From/To\");\n assert!(p.get(\"from\").is_none());\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(p, json!({\"stops\": [[0.0, \"#ff0000\"], [1.0, \"#0000ff\"]], \"opacityStops\": [], \"angle\": 90}));\n let mut p = json!({\"stops\": [[0.0, \"#000000\"], [0.5, \"#ff0000\"], [1.0, \"#ffffff\"]], \"from\": \"#123456\"});\n from_to_to_stops(&mut p);\n assert_eq!(p[\"stops\"].as_array().map(Vec::len), Some(3), \"explicit stops win over From/To\");",
|
||
" assert_eq!(p[\"stops\"].as_array().map(Vec::len), Some(3), \"explicit stops win over From/To\");\n assert!(p.get(\"from\").is_none());\n }",
|
||
" assert!(p.get(\"from\").is_none());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/gradient_field.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "the_fill_of_a_page_never_fails",
|
||
"path": "crates/ui-egui/src/layer_style/gradient_field.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked the_fill_of_a_page_never_fails -- --nocapture",
|
||
"fixture_and_action_excerpt": " for v in [json!({}), json!({\"stops\": \"x\"}), json!({\"stops\": [[0.0, \"#ff0000\"]], \"opacityStops\": [[0.5, 20.0]]}), json!({\"stops\": null})] {\n let Fill::Gradient { stops, opacity_stops, .. } = fill_of(&v) else { panic!(\"{v}\") };\n assert_eq!(stops.len(), 2, \"{v}: the default black-to-white\");\n assert!(opacity_stops.is_empty() || opacity_stops.len() >= 2, \"{v}\");\n }\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(stops.len(), 2, \"{v}: the default black-to-white\");\n assert!(opacity_stops.is_empty() || opacity_stops.len() >= 2, \"{v}\");\n }\n }",
|
||
" assert!(opacity_stops.is_empty() || opacity_stops.len() >= 2, \"{v}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9db1c7ae1d48ce4f31622b5f9029c70c590842f8/crates/ui-egui/src/layer_style/gradient_field.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-5744",
|
||
"pr": 5744,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked torn_off_document_is_not_drawn_again_in_the_main_window -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked tab_reorder_keeps_floating_documents_in_place -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked arrange_layout_only_includes_docked_documents -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked dragging_a_tab_off_the_strip_floats_it_in_a_window -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked views_and_windows_stay_with_their_documents -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked float_in_window_takes_a_document_and_position -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked float_in_window_defaults_to_the_active_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked float_all_in_windows_gives_each_document_its_own_view -- --nocapture"
|
||
],
|
||
"expected": "torn off document is not drawn again in the main window; tab reorder keeps floating documents in place; arrange layout only includes docked documents; dragging a tab off the strip floats it in a window; views and windows stay with their documents; float in window takes a document and position; float in window defaults to the active document; float all in windows gives each document its own view",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked torn_off_document_is_not_drawn_again_in_the_main_window -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked tab_reorder_keeps_floating_documents_in_place -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked arrange_layout_only_includes_docked_documents -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked dragging_a_tab_off_the_strip_floats_it_in_a_window -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked views_and_windows_stay_with_their_documents -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked float_in_window_takes_a_document_and_position -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked float_in_window_defaults_to_the_active_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked float_all_in_windows_gives_each_document_its_own_view -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "torn_off_document_is_not_drawn_again_in_the_main_window",
|
||
"path": "crates/ui-egui/src/canvas.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked torn_off_document_is_not_drawn_again_in_the_main_window -- --nocapture",
|
||
"fixture_and_action_excerpt": " for kind in [crate::theme::ThemeKind::Pro, crate::theme::ThemeKind::Studio] {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 80, \"height\": 60, \"name\": \"floating\"})).unwrap();\n app.run(\"file.new\", json!({\"width\": 80, \"height\": 60, \"name\": \"docked\"})).unwrap();\n app.sync_views();\n let ctx = egui::Context::default();\n crate::menus::invoke(&mut app, &ctx, \"window.arrange.floatInWindow\", json!({\"document\": 0})).unwrap();\n assert!(app.ui.windows[0].floating);\n assert_eq!(app.session.active_index(), Some(0), \"{kind:?}: the floated page remains active\");\n assert_eq!(main_canvas_document(&app), Some(1), \"{kind:?}: the main canvas picks a docked page instead\");\n let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(680.0, 480.0)).build_ui_state(\n |ui, (app, ready): &mut (PhotocraftApp, bool)| {",
|
||
"expected_assertions": [
|
||
" assert!(app.ui.windows[0].floating);\n assert_eq!(app.session.active_index(), Some(0), \"{kind:?}: the floated page remains active\");\n assert_eq!(main_canvas_document(&app), Some(1), \"{kind:?}: the main canvas picks a docked page instead\");\n let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(680.0, 480.0)).build_ui_state(",
|
||
" assert_eq!(app.session.active_index(), Some(0), \"{kind:?}: the floated page remains active\");\n assert_eq!(main_canvas_document(&app), Some(1), \"{kind:?}: the main canvas picks a docked page instead\");\n let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(680.0, 480.0)).build_ui_state(\n |ui, (app, ready): &mut (PhotocraftApp, bool)| {",
|
||
" assert_eq!(main_canvas_document(&app), Some(1), \"{kind:?}: the main canvas picks a docked page instead\");\n let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(680.0, 480.0)).build_ui_state(\n |ui, (app, ready): &mut (PhotocraftApp, bool)| {\n if *ready {",
|
||
" assert_eq!(tabs, Some(vec![1]), \"{kind:?}: only the docked document stays on the main tab strip\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/50b1f6734799cf7b5d45dd84868976afd31aa711/crates/ui-egui/src/canvas.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "tab_reorder_keeps_floating_documents_in_place",
|
||
"path": "crates/ui-egui/src/canvas.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked tab_reorder_keeps_floating_documents_in_place -- --nocapture",
|
||
"fixture_and_action_excerpt": " let visible = [0, 2];\n assert_eq!(move_target_after_filter(&visible, 0, 1, 3), 2);\n assert_eq!(move_target_after_filter(&visible, 2, 0, 3), 0);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(move_target_after_filter(&visible, 0, 1, 3), 2);\n assert_eq!(move_target_after_filter(&visible, 2, 0, 3), 0);\n }",
|
||
" assert_eq!(move_target_after_filter(&visible, 2, 0, 3), 0);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/50b1f6734799cf7b5d45dd84868976afd31aa711/crates/ui-egui/src/canvas.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "arrange_layout_only_includes_docked_documents",
|
||
"path": "crates/ui-egui/src/canvas.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked arrange_layout_only_includes_docked_documents -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n for name in [\"first\", \"floating\", \"last\"] {\n app.run(\"file.new\", json!({\"width\": 80, \"height\": 60, \"name\": name})).unwrap();\n }\n app.ui.view.arrange = \"threeUpStacked\".into();\n crate::menus::invoke(&mut app, &egui::Context::default(), \"window.arrange.floatInWindow\", json!({\"document\": 1})).unwrap();\n let rect = Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(800.0, 600.0));\n let shown: Vec<_> = arranged_cells(&app, rect).unwrap().into_iter().map(|(doc, _)| doc).collect();\n assert_eq!(shown, vec![0, 2]);\n\n crate::menus::invoke(&mut app, &egui::Context::default(), \"window.arrange.floatInWindow\", json!({\"document\": 0})).unwrap();\n crate::menus::invoke(&mut app, &egui::Context::default(), \"window.arrange.floatInWindow\", json!({\"document\": 2})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(shown, vec![0, 2]);\n\n crate::menus::invoke(&mut app, &egui::Context::default(), \"window.arrange.floatInWindow\", json!({\"document\": 0})).unwrap();\n crate::menus::invoke(&mut app, &egui::Context::default(), \"window.arrange.floatInWindow\", json!({\"document\": 2})).unwrap();",
|
||
" assert!(arranged_cells(&app, rect).is_none(), \"the main canvas should be blank when every document is floating\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/50b1f6734799cf7b5d45dd84868976afd31aa711/crates/ui-egui/src/canvas.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "dragging_a_tab_off_the_strip_floats_it_in_a_window",
|
||
"path": "crates/ui-egui/src/canvas.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked dragging_a_tab_off_the_strip_floats_it_in_a_window -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::Queryable;\n let strip = Rect::from_min_size(egui::pos2(0.0, 0.0), egui::vec2(700.0, 26.0));\n assert!(!torn_off(strip, egui::pos2(50.0, 13.0)));\n assert!(!torn_off(strip, egui::pos2(50.0, 26.0 + TEAR_OFF - 1.0)), \"a wobble below the strip still reorders\");\n assert!(torn_off(strip, egui::pos2(50.0, 26.0 + TEAR_OFF + 1.0)));\n assert!(torn_off(strip, egui::pos2(50.0, -TEAR_OFF - 1.0)), \"dragged up, off the window's top\");\n for kind in [crate::theme::ThemeKind::Studio, crate::theme::ThemeKind::Pro] {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n for name in [\"a\", \"b\", \"c\"] {\n app.run(\"file.new\", json!({\"width\": 8, \"height\": 8, \"name\": name})).unwrap();\n }\n app.sync_views();",
|
||
"expected_assertions": [
|
||
" assert!(!torn_off(strip, egui::pos2(50.0, 13.0)));\n assert!(!torn_off(strip, egui::pos2(50.0, 26.0 + TEAR_OFF - 1.0)), \"a wobble below the strip still reorders\");\n assert!(torn_off(strip, egui::pos2(50.0, 26.0 + TEAR_OFF + 1.0)));\n assert!(torn_off(strip, egui::pos2(50.0, -TEAR_OFF - 1.0)), \"dragged up, off the window's top\");",
|
||
" assert!(!torn_off(strip, egui::pos2(50.0, 26.0 + TEAR_OFF - 1.0)), \"a wobble below the strip still reorders\");\n assert!(torn_off(strip, egui::pos2(50.0, 26.0 + TEAR_OFF + 1.0)));\n assert!(torn_off(strip, egui::pos2(50.0, -TEAR_OFF - 1.0)), \"dragged up, off the window's top\");\n for kind in [crate::theme::ThemeKind::Studio, crate::theme::ThemeKind::Pro] {",
|
||
" assert!(torn_off(strip, egui::pos2(50.0, 26.0 + TEAR_OFF + 1.0)));\n assert!(torn_off(strip, egui::pos2(50.0, -TEAR_OFF - 1.0)), \"dragged up, off the window's top\");\n for kind in [crate::theme::ThemeKind::Studio, crate::theme::ThemeKind::Pro] {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());",
|
||
" assert!(torn_off(strip, egui::pos2(50.0, -TEAR_OFF - 1.0)), \"dragged up, off the window's top\");\n for kind in [crate::theme::ThemeKind::Studio, crate::theme::ThemeKind::Pro] {\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n for name in [\"a\", \"b\", \"c\"] {",
|
||
" assert_eq!(names, [\"a\", \"b\", \"c\"], \"{kind:?}: tearing off doesn't reorder\");\n assert_eq!(app.ui.windows.iter().map(|w| w.document).collect::<Vec<_>>(), [1], \"{kind:?}: b floats in its own window\");\n assert_eq!(app.session.active_index(), Some(1), \"{kind:?}: the torn-off document stays active\");\n assert!(app.ui.windows[0].floating, \"{kind:?}: the page belongs exclusively to its floating window\");",
|
||
" assert_eq!(app.ui.windows.iter().map(|w| w.document).collect::<Vec<_>>(), [1], \"{kind:?}: b floats in its own window\");\n assert_eq!(app.session.active_index(), Some(1), \"{kind:?}: the torn-off document stays active\");\n assert!(app.ui.windows[0].floating, \"{kind:?}: the page belongs exclusively to its floating window\");\n }",
|
||
" assert_eq!(app.session.active_index(), Some(1), \"{kind:?}: the torn-off document stays active\");\n assert!(app.ui.windows[0].floating, \"{kind:?}: the page belongs exclusively to its floating window\");\n }\n }",
|
||
" assert!(app.ui.windows[0].floating, \"{kind:?}: the page belongs exclusively to its floating window\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/50b1f6734799cf7b5d45dd84868976afd31aa711/crates/ui-egui/src/canvas.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "views_and_windows_stay_with_their_documents",
|
||
"path": "crates/ui-egui/src/file_open/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked views_and_windows_stay_with_their_documents -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut app, _) = app_with(Vec::new());\n for name in [\"a.psd\", \"b.psd\", \"c.psd\", \"d.psd\"] {\n app.open_bytes(name, b\"x\").unwrap();\n }\n for (i, v) in app.ui.views.iter_mut().enumerate() {\n v.zoom = i as f32 + 1.0;\n }\n app.ui.windows = (0..4)\n .map(|document| crate::state::DocWindow {\n id: document as u64,\n document,\n view: Default::default(),",
|
||
"expected_assertions": [
|
||
" assert_eq!(app.run(\"document.move\", json!({\"document\": 0, \"to\": 3})).unwrap(), json!({\"document\": 3}));\n assert_eq!(doc_names(&app), [\"b.psd\", \"c.psd\", \"d.psd\", \"a.psd\"]);\n assert_eq!(zooms(&app), [2.0, 3.0, 4.0, 1.0]);\n assert_eq!(windows(&app), [(0, 3), (1, 0), (2, 1), (3, 2)]);",
|
||
" assert_eq!(doc_names(&app), [\"b.psd\", \"c.psd\", \"d.psd\", \"a.psd\"]);\n assert_eq!(zooms(&app), [2.0, 3.0, 4.0, 1.0]);\n assert_eq!(windows(&app), [(0, 3), (1, 0), (2, 1), (3, 2)]);\n // Out of range: an error, nothing moves.",
|
||
" assert_eq!(zooms(&app), [2.0, 3.0, 4.0, 1.0]);\n assert_eq!(windows(&app), [(0, 3), (1, 0), (2, 1), (3, 2)]);\n // Out of range: an error, nothing moves.\n assert!(app.run(\"document.move\", json!({\"document\": 7, \"to\": 0})).is_err());",
|
||
" assert_eq!(windows(&app), [(0, 3), (1, 0), (2, 1), (3, 2)]);\n // Out of range: an error, nothing moves.\n assert!(app.run(\"document.move\", json!({\"document\": 7, \"to\": 0})).is_err());\n assert_eq!(zooms(&app), [2.0, 3.0, 4.0, 1.0]);",
|
||
" assert!(app.run(\"document.move\", json!({\"document\": 7, \"to\": 0})).is_err());\n assert_eq!(zooms(&app), [2.0, 3.0, 4.0, 1.0]);\n // Closing a middle tab takes its view and windows with it; the others keep theirs.\n app.run(\"file.close\", json!({\"document\": 1})).unwrap();",
|
||
" assert_eq!(zooms(&app), [2.0, 3.0, 4.0, 1.0]);\n // Closing a middle tab takes its view and windows with it; the others keep theirs.\n app.run(\"file.close\", json!({\"document\": 1})).unwrap();\n assert_eq!(doc_names(&app), [\"b.psd\", \"d.psd\", \"a.psd\"]);",
|
||
" assert_eq!(doc_names(&app), [\"b.psd\", \"d.psd\", \"a.psd\"]);\n assert_eq!(zooms(&app), [2.0, 4.0, 1.0]);\n assert_eq!(windows(&app), [(0, 2), (1, 0), (3, 1)]);\n}",
|
||
" assert_eq!(zooms(&app), [2.0, 4.0, 1.0]);\n assert_eq!(windows(&app), [(0, 2), (1, 0), (3, 1)]);\n}",
|
||
" assert_eq!(windows(&app), [(0, 2), (1, 0), (3, 1)]);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/50b1f6734799cf7b5d45dd84868976afd31aa711/crates/ui-egui/src/file_open/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "float_in_window_takes_a_document_and_position",
|
||
"path": "crates/ui-egui/src/view_cmds/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked float_in_window_takes_a_document_and_position -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut app, ctx) = app_with(3);\n let r = menu(&mut app, &ctx, \"window.arrange.floatInWindow\", json!({\"document\": 1, \"position\": [1950.0, 40.5]})).unwrap();\n let w = app.ui.windows.last().unwrap();\n assert_eq!(r, json!({\"window\": w.id}));\n assert_eq!((w.document, w.position), (1, Some([1950.0, 40.5])));\n assert!(w.floating);\n assert_eq!(app.session.active_index(), Some(1), \"the floated document stays active\");\n let again = menu(&mut app, &ctx, \"window.arrange.floatInWindow\", json!({\"document\": 1})).unwrap();\n assert_eq!(again, r, \"tearing off the same document reuses its window\");\n assert_eq!(app.ui.windows.len(), 1);\n assert_eq!(app.ui.windows[0].position, Some([1950.0, 40.5]));\n for bad in [",
|
||
"expected_assertions": [
|
||
" assert_eq!(r, json!({\"window\": w.id}));\n assert_eq!((w.document, w.position), (1, Some([1950.0, 40.5])));\n assert!(w.floating);\n assert_eq!(app.session.active_index(), Some(1), \"the floated document stays active\");",
|
||
" assert_eq!((w.document, w.position), (1, Some([1950.0, 40.5])));\n assert!(w.floating);\n assert_eq!(app.session.active_index(), Some(1), \"the floated document stays active\");\n let again = menu(&mut app, &ctx, \"window.arrange.floatInWindow\", json!({\"document\": 1})).unwrap();",
|
||
" assert!(w.floating);\n assert_eq!(app.session.active_index(), Some(1), \"the floated document stays active\");\n let again = menu(&mut app, &ctx, \"window.arrange.floatInWindow\", json!({\"document\": 1})).unwrap();\n assert_eq!(again, r, \"tearing off the same document reuses its window\");",
|
||
" assert_eq!(app.session.active_index(), Some(1), \"the floated document stays active\");\n let again = menu(&mut app, &ctx, \"window.arrange.floatInWindow\", json!({\"document\": 1})).unwrap();\n assert_eq!(again, r, \"tearing off the same document reuses its window\");\n assert_eq!(app.ui.windows.len(), 1);",
|
||
" assert_eq!(again, r, \"tearing off the same document reuses its window\");\n assert_eq!(app.ui.windows.len(), 1);\n assert_eq!(app.ui.windows[0].position, Some([1950.0, 40.5]));\n for bad in [",
|
||
" assert_eq!(app.ui.windows.len(), 1);\n assert_eq!(app.ui.windows[0].position, Some([1950.0, 40.5]));\n for bad in [\n json!({\"document\": 3}),",
|
||
" assert_eq!(app.ui.windows[0].position, Some([1950.0, 40.5]));\n for bad in [\n json!({\"document\": 3}),\n json!({\"document\": -1}),",
|
||
" assert!(menu(&mut app, &ctx, \"window.arrange.floatInWindow\", bad.clone()).is_err(), \"{bad}\");\n }\n assert_eq!(app.ui.windows.len(), 1, \"rejected params open no window\");\n app.ui.windows[0].open = false;",
|
||
" assert_eq!(app.ui.windows.len(), 1, \"rejected params open no window\");\n app.ui.windows[0].open = false;\n let reopened = menu(&mut app, &ctx, \"window.arrange.floatInWindow\", json!({\"document\": 1})).unwrap();\n assert_ne!(reopened, r, \"a closed window can be floated again\");",
|
||
" assert_ne!(reopened, r, \"a closed window can be floated again\");\n assert_eq!(app.ui.windows.last().map(|w| (w.document, w.position)), Some((1, None)));\n}",
|
||
" assert_eq!(app.ui.windows.last().map(|w| (w.document, w.position)), Some((1, None)));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/50b1f6734799cf7b5d45dd84868976afd31aa711/crates/ui-egui/src/view_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "float_in_window_defaults_to_the_active_document",
|
||
"path": "crates/ui-egui/src/view_cmds/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked float_in_window_defaults_to_the_active_document -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut app, ctx) = app_with(3);\n app.session.set_active(1);\n let r = menu(&mut app, &ctx, \"window.arrange.floatInWindow\", json!({})).unwrap();\n let window = app.ui.windows.last().unwrap();\n assert_eq!(r, json!({\"window\": window.id}));\n assert_eq!(window.document, 1);\n assert!(window.floating);\n assert_eq!(app.session.active_index(), Some(1));\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(r, json!({\"window\": window.id}));\n assert_eq!(window.document, 1);\n assert!(window.floating);\n assert_eq!(app.session.active_index(), Some(1));",
|
||
" assert_eq!(window.document, 1);\n assert!(window.floating);\n assert_eq!(app.session.active_index(), Some(1));\n}",
|
||
" assert!(window.floating);\n assert_eq!(app.session.active_index(), Some(1));\n}",
|
||
" assert_eq!(app.session.active_index(), Some(1));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/50b1f6734799cf7b5d45dd84868976afd31aa711/crates/ui-egui/src/view_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "float_all_in_windows_gives_each_document_its_own_view",
|
||
"path": "crates/ui-egui/src/view_cmds/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked float_all_in_windows_gives_each_document_its_own_view -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut app, ctx) = app_with(3);\n menu(&mut app, &ctx, \"window.arrange.floatAllInWindows\", json!({})).unwrap();\n assert_eq!(app.ui.windows.iter().map(|w| w.document).collect::<Vec<_>>(), [0, 1, 2]);\n assert!(app.ui.windows.iter().all(|w| w.floating));\n}",
|
||
"expected_assertions": [
|
||
" assert_eq!(app.ui.windows.iter().map(|w| w.document).collect::<Vec<_>>(), [0, 1, 2]);\n assert!(app.ui.windows.iter().all(|w| w.floating));\n}",
|
||
" assert!(app.ui.windows.iter().all(|w| w.floating));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/50b1f6734799cf7b5d45dd84868976afd31aa711/crates/ui-egui/src/view_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-6387",
|
||
"pr": 6387,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked video_frames_to_layers_takes_every_tiff_page -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked video_frames_to_layers_refuses_a_tiff_with_an_incomplete_page_list -- --nocapture"
|
||
],
|
||
"expected": "video frames to layers takes every tiff page; video frames to layers refuses a tiff with an incomplete page list",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked video_frames_to_layers_takes_every_tiff_page -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked video_frames_to_layers_refuses_a_tiff_with_an_incomplete_page_list -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "video_frames_to_layers_takes_every_tiff_page",
|
||
"path": "crates/engine/src/video_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked video_frames_to_layers_takes_every_tiff_page -- --nocapture",
|
||
"fixture_and_action_excerpt": " let dir = tmpdir(\"tiff-pages\");\n let path = format!(\"{dir}/pages.tif\");\n write_tiff(&path, &[(2, 2, 9, 1), (6, 4, 51, 0), (3, 5, 204, 0)]);\n let mut s = session();\n let r = s.execute(\"file.import.videoFramesToLayers\", json!({\"path\": path})).unwrap();\n assert_eq!(r[\"layers\"], 2, \"two pages, the thumbnail left out\");\n let doc = &s.active().unwrap().doc;\n for (name, (w, h), level) in [(\"Frame 1\", (6, 4), 51.0), (\"Frame 2\", (3, 5), 204.0)] {\n let l = doc.layers.iter().find(|l| l.name == name).unwrap_or_else(|| panic!(\"{name}\"));\n let surf = l.surface().unwrap();\n let b = surf.content_bounds();\n assert_eq!((b.width(), b.height()), (w, h), \"{name}\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(r[\"layers\"], 2, \"two pages, the thumbnail left out\");\n let doc = &s.active().unwrap().doc;\n for (name, (w, h), level) in [(\"Frame 1\", (6, 4), 51.0), (\"Frame 2\", (3, 5), 204.0)] {\n let l = doc.layers.iter().find(|l| l.name == name).unwrap_or_else(|| panic!(\"{name}\"));",
|
||
" assert_eq!((b.width(), b.height()), (w, h), \"{name}\");\n let px = surf.read_region(photocraft_geom::Rect::new(b.x0, b.y0, b.x0 + 1, b.y0 + 1));\n assert!((px[0] * 255.0 - level).abs() < 0.6 && px[3] == 1.0, \"{name}: {px:?}\");\n }",
|
||
" assert!((px[0] * 255.0 - level).abs() < 0.6 && px[3] == 1.0, \"{name}: {px:?}\");\n }\n let single = format!(\"{dir}/single.tif\");\n write_tiff(&single, &[(4, 4, 120, 0)]);",
|
||
" assert_eq!(s.execute(\"file.import.videoFramesToLayers\", json!({\"path\": single})).unwrap()[\"layers\"], 1);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bfbbf816025942b74130adf16fb07265817b691/crates/engine/src/video_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "video_frames_to_layers_refuses_a_tiff_with_an_incomplete_page_list",
|
||
"path": "crates/engine/src/video_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked video_frames_to_layers_refuses_a_tiff_with_an_incomplete_page_list -- --nocapture",
|
||
"fixture_and_action_excerpt": " let dir = tmpdir(\"tiff-loop\");\n let path = format!(\"{dir}/loop.tif\");\n write_tiff(&path, &[(2, 2, 51, 0), (2, 2, 204, 0)]);\n // The last directory's next-IFD offset points back to the first directory.\n let mut f = std::fs::read(&path).unwrap();\n let first: [u8; 4] = f[4..8].try_into().unwrap();\n let end = f.len();\n f[end - 4..].copy_from_slice(&first);\n std::fs::write(&path, f).unwrap();\n let mut s = session();\n let before = s.active().unwrap().doc.layers.len();\n let err = s.execute(\"file.import.videoFramesToLayers\", json!({\"path\": path})).unwrap_err().to_string();",
|
||
"expected_assertions": [
|
||
" assert!(err.contains(\"only the first 2 pages\"), \"{err}\");\n assert_eq!(s.active().unwrap().doc.layers.len(), before, \"nothing imported\");\n}",
|
||
" assert_eq!(s.active().unwrap().doc.layers.len(), before, \"nothing imported\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8bfbbf816025942b74130adf16fb07265817b691/crates/engine/src/video_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-6449",
|
||
"pr": 6449,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked cmd_is_not_the_move_tool_for_selection_hand_zoom_pen_shape_or_type_tools -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked cmd_and_alt_with_the_hand_tool_zoom_in_and_out_while_held -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked cmd_mid_pan_or_during_free_transform_is_not_the_hand_tools_zoom -- --nocapture"
|
||
],
|
||
"expected": "cmd is not the move tool for selection hand zoom pen shape or type tools; cmd and alt with the hand tool zoom in and out while held; cmd mid pan or during free transform is not the hand tools zoom",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked cmd_is_not_the_move_tool_for_selection_hand_zoom_pen_shape_or_type_tools -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked cmd_and_alt_with_the_hand_tool_zoom_in_and_out_while_held -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked cmd_mid_pan_or_during_free_transform_is_not_the_hand_tools_zoom -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "cmd_is_not_the_move_tool_for_selection_hand_zoom_pen_shape_or_type_tools",
|
||
"path": "crates/ui-egui/src/hold_keys/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked cmd_is_not_the_move_tool_for_selection_hand_zoom_pen_shape_or_type_tools -- --nocapture",
|
||
"fixture_and_action_excerpt": " for tool in [\n Tool::Hand,\n Tool::RotateView,\n Tool::Zoom,\n Tool::Pen,\n Tool::Rectangle,\n Tool::Type,\n Tool::VerticalType,\n Tool::Crop,\n Tool::PathSelection,\n Tool::DirectSelection,\n Tool::Move,",
|
||
"expected_assertions": [
|
||
" assert!(!cmd_moves(tool), \"{tool:?}\");\n let mut h = harness(tool);\n h.event(Event::ModifiersChanged(platform(Modifiers::COMMAND)));\n h.run_steps(1);",
|
||
" assert_eq!(held_tool(h.state(), &h.ctx), (tool == Tool::Hand).then_some(Temporary::ZoomIn), \"{tool:?}\");\n }\n for tool in [Tool::Brush, Tool::Eraser, Tool::Gradient, Tool::CloneStamp, Tool::Eyedropper, Tool::MagneticLasso, Tool::QuickSelection] {\n assert!(cmd_moves(tool), \"{tool:?}\");",
|
||
" assert!(cmd_moves(tool), \"{tool:?}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/25c38a0b69b7bff31badcdbe2ef9f2ff6aba1c63/crates/ui-egui/src/hold_keys/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "cmd_and_alt_with_the_hand_tool_zoom_in_and_out_while_held",
|
||
"path": "crates/ui-egui/src/hold_keys/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked cmd_and_alt_with_the_hand_tool_zoom_in_and_out_while_held -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness(Tool::Hand);\n let z0 = h.state().ui.views[0].zoom;\n hold_mods(&mut h, Modifiers::COMMAND);\n assert_eq!(held_tool(h.state(), &h.ctx), Some(Temporary::ZoomIn));\n click(&mut h, 200.0, 150.0, Modifiers::COMMAND);\n let z1 = h.state().ui.views[0].zoom;\n assert!(z1 > z0, \"{z0} -> {z1}\");\n hold_mods(&mut h, Modifiers::ALT);\n assert_eq!(held_tool(h.state(), &h.ctx), Some(Temporary::ZoomOut));\n click(&mut h, 200.0, 150.0, Modifiers::ALT);\n let z2 = h.state().ui.views[0].zoom;\n assert!(z2 < z1, \"{z1} -> {z2}\");",
|
||
"expected_assertions": [
|
||
" assert_eq!(held_tool(h.state(), &h.ctx), Some(Temporary::ZoomIn));\n click(&mut h, 200.0, 150.0, Modifiers::COMMAND);\n let z1 = h.state().ui.views[0].zoom;\n assert!(z1 > z0, \"{z0} -> {z1}\");",
|
||
" assert!(z1 > z0, \"{z0} -> {z1}\");\n hold_mods(&mut h, Modifiers::ALT);\n assert_eq!(held_tool(h.state(), &h.ctx), Some(Temporary::ZoomOut));\n click(&mut h, 200.0, 150.0, Modifiers::ALT);",
|
||
" assert_eq!(held_tool(h.state(), &h.ctx), Some(Temporary::ZoomOut));\n click(&mut h, 200.0, 150.0, Modifiers::ALT);\n let z2 = h.state().ui.views[0].zoom;\n assert!(z2 < z1, \"{z1} -> {z2}\");",
|
||
" assert!(z2 < z1, \"{z1} -> {z2}\");\n hold_mods(&mut h, Modifiers::COMMAND | Modifiers::ALT);\n assert_eq!(held_tool(h.state(), &h.ctx), Some(Temporary::ZoomOut), \"⌥ turns ⌘'s Zoom In around\");\n hold_mods(&mut h, Modifiers::NONE);",
|
||
" assert_eq!(held_tool(h.state(), &h.ctx), Some(Temporary::ZoomOut), \"⌥ turns ⌘'s Zoom In around\");\n hold_mods(&mut h, Modifiers::NONE);\n assert_eq!(held_tool(h.state(), &h.ctx), None);\n // Released: a drag pans again.",
|
||
" assert_eq!(held_tool(h.state(), &h.ctx), None);\n // Released: a drag pans again.\n let (center, zoom) = (h.state().ui.views[0].center, h.state().ui.views[0].zoom);\n drag_with(&mut h, Modifiers::NONE, 200.0, 150.0, 260.0, 190.0);",
|
||
" assert_ne!(h.state().ui.views[0].center, center, \"the Hand pans\");\n assert_eq!(h.state().ui.views[0].zoom, zoom);\n assert_eq!(h.state().ui.tool, Tool::Hand);\n}",
|
||
" assert_eq!(h.state().ui.views[0].zoom, zoom);\n assert_eq!(h.state().ui.tool, Tool::Hand);\n}",
|
||
" assert_eq!(h.state().ui.tool, Tool::Hand);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/25c38a0b69b7bff31badcdbe2ef9f2ff6aba1c63/crates/ui-egui/src/hold_keys/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "cmd_mid_pan_or_during_free_transform_is_not_the_hand_tools_zoom",
|
||
"path": "crates/ui-egui/src/hold_keys/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked cmd_mid_pan_or_during_free_transform_is_not_the_hand_tools_zoom -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut h = harness(Tool::Hand);\n let z0 = h.state().ui.views[0].zoom;\n press_at(&mut h, 200.0, 150.0);\n hold_mods(&mut h, Modifiers::COMMAND);\n let center = h.state().ui.views[0].center;\n move_to(&mut h, 300.0, 150.0);\n assert_ne!(h.state().ui.views[0].center, center, \"the drag kept panning after ⌘ went down\");\n release(&mut h, 300.0, 150.0, Modifiers::COMMAND);\n hold_mods(&mut h, Modifiers::NONE);\n assert_eq!(h.state().ui.views[0].zoom, z0, \"no zoom\");\n\n with_layer(&mut h);",
|
||
"expected_assertions": [
|
||
" assert_ne!(h.state().ui.views[0].center, center, \"the drag kept panning after ⌘ went down\");\n release(&mut h, 300.0, 150.0, Modifiers::COMMAND);\n hold_mods(&mut h, Modifiers::NONE);\n assert_eq!(h.state().ui.views[0].zoom, z0, \"no zoom\");",
|
||
" assert_eq!(h.state().ui.views[0].zoom, z0, \"no zoom\");\n\n with_layer(&mut h);\n let ctx = h.ctx.clone();",
|
||
" assert!(h.state().ui.transform.is_some());\n hold_mods(&mut h, Modifiers::COMMAND);\n assert_eq!(held_tool(h.state(), &h.ctx), None);\n hold_mods(&mut h, Modifiers::NONE);",
|
||
" assert_eq!(held_tool(h.state(), &h.ctx), None);\n hold_mods(&mut h, Modifiers::NONE);\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/25c38a0b69b7bff31badcdbe2ef9f2ff6aba1c63/crates/ui-egui/src/hold_keys/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-7255",
|
||
"pr": 7255,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked trim_and_duplicate_merged_on_too_large_document_fail_gracefully_without_panic -- --nocapture"
|
||
],
|
||
"expected": "trim and duplicate merged on too large document fail gracefully without panic",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked trim_and_duplicate_merged_on_too_large_document_fail_gracefully_without_panic -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "trim_and_duplicate_merged_on_too_large_document_fail_gracefully_without_panic",
|
||
"path": "crates/engine/src/image_cmds.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked trim_and_duplicate_merged_on_too_large_document_fail_gracefully_without_panic -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut s = Session::new();\n s.execute(\"file.new\", json!({\"width\": 40000, \"height\": 30000, \"background\": \"transparent\"})).unwrap();\n let initial_layers = doc(&s).layers.len();\n let initial_bounds = doc(&s).bounds();\n let initial_rev = s.active().unwrap().revision;\n let initial_docs = s.documents().len();\n\n let trim_res = s.execute(\"image.trim\", json!({\"basedOn\": \"topLeft\"}));\n assert!(trim_res.is_err(), \"trim on too-large document must return error\");\n let err = trim_res.unwrap_err().to_string();\n assert!(err.contains(\"too large to trim\"), \"error should explain document is too large: {err}\");\n assert_eq!(doc(&s).layers.len(), initial_layers, \"layer count unchanged after failed trim\");",
|
||
"expected_assertions": [
|
||
" assert!(trim_res.is_err(), \"trim on too-large document must return error\");\n let err = trim_res.unwrap_err().to_string();\n assert!(err.contains(\"too large to trim\"), \"error should explain document is too large: {err}\");\n assert_eq!(doc(&s).layers.len(), initial_layers, \"layer count unchanged after failed trim\");",
|
||
" assert!(err.contains(\"too large to trim\"), \"error should explain document is too large: {err}\");\n assert_eq!(doc(&s).layers.len(), initial_layers, \"layer count unchanged after failed trim\");\n assert_eq!(doc(&s).bounds(), initial_bounds, \"canvas size unchanged after failed trim\");\n assert_eq!(s.active().unwrap().revision, initial_rev, \"revision unchanged after failed trim\");",
|
||
" assert_eq!(doc(&s).layers.len(), initial_layers, \"layer count unchanged after failed trim\");\n assert_eq!(doc(&s).bounds(), initial_bounds, \"canvas size unchanged after failed trim\");\n assert_eq!(s.active().unwrap().revision, initial_rev, \"revision unchanged after failed trim\");\n",
|
||
" assert_eq!(doc(&s).bounds(), initial_bounds, \"canvas size unchanged after failed trim\");\n assert_eq!(s.active().unwrap().revision, initial_rev, \"revision unchanged after failed trim\");\n\n let dup_res = s.execute(\"image.duplicate\", json!({\"mergedOnly\": true}));",
|
||
" assert_eq!(s.active().unwrap().revision, initial_rev, \"revision unchanged after failed trim\");\n\n let dup_res = s.execute(\"image.duplicate\", json!({\"mergedOnly\": true}));\n assert!(dup_res.is_err(), \"duplicate merged on too-large document must return error\");",
|
||
" assert!(dup_res.is_err(), \"duplicate merged on too-large document must return error\");\n let dup_err = dup_res.unwrap_err().to_string();\n assert!(dup_err.contains(\"too large to duplicate merged\"), \"error should explain document is too large: {dup_err}\");\n assert_eq!(s.documents().len(), initial_docs, \"document count unchanged after failed duplicate\");",
|
||
" assert!(dup_err.contains(\"too large to duplicate merged\"), \"error should explain document is too large: {dup_err}\");\n assert_eq!(s.documents().len(), initial_docs, \"document count unchanged after failed duplicate\");\n assert_eq!(doc(&s).layers.len(), initial_layers, \"layer count unchanged after failed duplicate\");\n assert_eq!(doc(&s).bounds(), initial_bounds, \"canvas size unchanged after failed duplicate\");",
|
||
" assert_eq!(s.documents().len(), initial_docs, \"document count unchanged after failed duplicate\");\n assert_eq!(doc(&s).layers.len(), initial_layers, \"layer count unchanged after failed duplicate\");\n assert_eq!(doc(&s).bounds(), initial_bounds, \"canvas size unchanged after failed duplicate\");\n assert_eq!(s.active().unwrap().revision, initial_rev, \"revision unchanged after failed duplicate\");",
|
||
" assert_eq!(doc(&s).layers.len(), initial_layers, \"layer count unchanged after failed duplicate\");\n assert_eq!(doc(&s).bounds(), initial_bounds, \"canvas size unchanged after failed duplicate\");\n assert_eq!(s.active().unwrap().revision, initial_rev, \"revision unchanged after failed duplicate\");\n }",
|
||
" assert_eq!(doc(&s).bounds(), initial_bounds, \"canvas size unchanged after failed duplicate\");\n assert_eq!(s.active().unwrap().revision, initial_rev, \"revision unchanged after failed duplicate\");\n }",
|
||
" assert_eq!(s.active().unwrap().revision, initial_rev, \"revision unchanged after failed duplicate\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/1b810052bc3a876c1eaf1a8766870ffdba9f8a80/crates/engine/src/image_cmds.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-8931",
|
||
"pr": 8931,
|
||
"subsystem": "Compositing and filters",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-algo --locked the_description_is_the_cpus_blur -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_impulse_spreads_no_further_than_the_reach -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked output_depends_only_on_the_input_region -- --nocapture"
|
||
],
|
||
"expected": "the description is the cpus blur; an impulse spreads no further than the reach; output depends only on the input region",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-algo --locked the_description_is_the_cpus_blur -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked an_impulse_spreads_no_further_than_the_reach -- --nocapture",
|
||
"cargo test -p photocraft-algo --locked output_depends_only_on_the_input_region -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "the_description_is_the_cpus_blur",
|
||
"path": "crates/algo/src/separable.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked the_description_is_the_cpus_blur -- --nocapture",
|
||
"fixture_and_action_excerpt": " for radius in RADII {\n let params = FilterParams::GaussianBlur { radius };\n let blur = Separable::of(¶ms).unwrap();\n match &blur {\n Separable::Kernel(k) => {\n assert!(radius <= 4.0, \"radius {radius}\");\n assert_eq!(k, &blur::gaussian_kernel(radius));\n assert_eq!(k.len() % 2, 1);\n assert!((k.iter().sum::<f32>() - 1.0).abs() < 1e-5);\n }\n Separable::Boxes(b) => {\n assert!(radius > 4.0, \"radius {radius}\");",
|
||
"expected_assertions": [
|
||
" assert!(radius <= 4.0, \"radius {radius}\");\n assert_eq!(k, &blur::gaussian_kernel(radius));\n assert_eq!(k.len() % 2, 1);\n assert!((k.iter().sum::<f32>() - 1.0).abs() < 1e-5);",
|
||
" assert_eq!(k, &blur::gaussian_kernel(radius));\n assert_eq!(k.len() % 2, 1);\n assert!((k.iter().sum::<f32>() - 1.0).abs() < 1e-5);\n }",
|
||
" assert_eq!(k.len() % 2, 1);\n assert!((k.iter().sum::<f32>() - 1.0).abs() < 1e-5);\n }\n Separable::Boxes(b) => {",
|
||
" assert!((k.iter().sum::<f32>() - 1.0).abs() < 1e-5);\n }\n Separable::Boxes(b) => {\n assert!(radius > 4.0, \"radius {radius}\");",
|
||
" assert!(radius > 4.0, \"radius {radius}\");\n assert_eq!(Some(b.clone()), blur::box_widths(¶ms));\n assert!(b.iter().all(|w| w % 2 == 1));\n }",
|
||
" assert_eq!(Some(b.clone()), blur::box_widths(¶ms));\n assert!(b.iter().all(|w| w % 2 == 1));\n }\n }",
|
||
" assert!(b.iter().all(|w| w % 2 == 1));\n }\n }\n let Halo::Radius(halo) = params.halo() else { panic!(\"a Gaussian has a radius halo\") };",
|
||
" assert!(blur.reach() <= halo, \"radius {radius}: reach {} past the halo {halo}\", blur.reach());\n }\n assert_eq!(Separable::of(&FilterParams::BoxBlur { radius: 9.0 }), None, \"not a Gaussian (yet)\");\n assert_eq!(Separable::Boxes(vec![usize::MAX, 3]).reach(), i32::MAX, \"saturates\");",
|
||
" assert_eq!(Separable::of(&FilterParams::BoxBlur { radius: 9.0 }), None, \"not a Gaussian (yet)\");\n assert_eq!(Separable::Boxes(vec![usize::MAX, 3]).reach(), i32::MAX, \"saturates\");\n }",
|
||
" assert_eq!(Separable::Boxes(vec![usize::MAX, 3]).reach(), i32::MAX, \"saturates\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d42dd4c6302c77c1f9dc46b7b53ffa5eb0047a13/crates/algo/src/separable.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "an_impulse_spreads_no_further_than_the_reach",
|
||
"path": "crates/algo/src/separable.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked an_impulse_spreads_no_further_than_the_reach -- --nocapture",
|
||
"fixture_and_action_excerpt": " for radius in RADII {\n let params = FilterParams::GaussianBlur { radius };\n let reach = Separable::of(¶ms).unwrap().reach();\n let fmt = PixelFormat::new(ColorMode::Rgb, SampleType::F32, true);\n let size = 2 * reach + 41;\n let canvas = Rect::new(0, 0, size, size);\n let mut s = Surface::new(fmt);\n let dot = Rect::new(size / 2, size / 2, size / 2 + 1, size / 2 + 1);\n s.fill_rect(dot, &[1.0, 1.0, 1.0, 1.0]);\n let out = crate::apply_in_with(&s, ¶ms, canvas, canvas, None, canvas, &Interrupt::NONE).unwrap();\n let mut px = Vec::new();\n out.read_region_into(canvas, &mut px);",
|
||
"expected_assertions": [
|
||
" assert!(dot.inflate(reach).contains_rect(&touched), \"radius {radius}: {touched:?} past the reach {reach}\");\n if matches!(Separable::of(¶ms), Some(Separable::Kernel(_))) {\n assert_eq!(touched, dot.inflate(reach), \"radius {radius}\");\n }",
|
||
" assert_eq!(touched, dot.inflate(reach), \"radius {radius}\");\n }\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d42dd4c6302c77c1f9dc46b7b53ffa5eb0047a13/crates/algo/src/separable.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "output_depends_only_on_the_input_region",
|
||
"path": "crates/algo/src/separable.rs",
|
||
"package": "photocraft-algo",
|
||
"command": "cargo test -p photocraft-algo --locked output_depends_only_on_the_input_region -- --nocapture",
|
||
"fixture_and_action_excerpt": " let fmt = PixelFormat::new(ColorMode::Rgb, SampleType::F32, true);\n let extent = Rect::new(0, 0, 300, 200);\n let noise = |seed: u32| {\n let mut s = Surface::new(fmt);\n for y in 0..200 {\n for x in 0..300 {\n let h = (x as u32).wrapping_mul(73_856_093) ^ (y as u32).wrapping_mul(19_349_663) ^ seed;\n let v = (h % 1000) as f32 / 999.0;\n s.fill_rect(Rect::new(x, y, x + 1, y + 1), &[v, 1.0 - v, (h % 7) as f32 / 6.0, (h % 5) as f32 / 4.0]);\n }\n }\n s",
|
||
"expected_assertions": [
|
||
" assert!(extent.contains_rect(&input) && input.contains_rect(&out));\n // Everything outside the input region replaced by other pixels.\n let mut b = noise(2);\n let mut inside = Vec::new();",
|
||
" assert_eq!(blur(&a), blur(&b), \"radius {radius}, {out:?}\");\n }\n }\n assert_eq!(OperatorRegion { reach: 5, extent }.input(Rect::EMPTY), Rect::EMPTY);",
|
||
" assert_eq!(OperatorRegion { reach: 5, extent }.input(Rect::EMPTY), Rect::EMPTY);\n assert_eq!(OperatorRegion { reach: 5, extent }.input(Rect::new(400, 400, 410, 410)), Rect::EMPTY, \"out of reach of the extent\");\n assert_eq!(OperatorRegion { reach: -3, extent }.input(Rect::new(10, 10, 20, 20)), Rect::new(10, 10, 20, 20));\n assert_eq!(edge_extent(extent, Rect::new(-10, 50, 20, 60)), Rect::new(-10, 0, 300, 200));",
|
||
" assert_eq!(OperatorRegion { reach: 5, extent }.input(Rect::new(400, 400, 410, 410)), Rect::EMPTY, \"out of reach of the extent\");\n assert_eq!(OperatorRegion { reach: -3, extent }.input(Rect::new(10, 10, 20, 20)), Rect::new(10, 10, 20, 20));\n assert_eq!(edge_extent(extent, Rect::new(-10, 50, 20, 60)), Rect::new(-10, 0, 300, 200));\n }",
|
||
" assert_eq!(OperatorRegion { reach: -3, extent }.input(Rect::new(10, 10, 20, 20)), Rect::new(10, 10, 20, 20));\n assert_eq!(edge_extent(extent, Rect::new(-10, 50, 20, 60)), Rect::new(-10, 0, 300, 200));\n }",
|
||
" assert_eq!(edge_extent(extent, Rect::new(-10, 50, 20, 60)), Rect::new(-10, 0, 300, 200));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/d42dd4c6302c77c1f9dc46b7b53ffa5eb0047a13/crates/algo/src/separable.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9004",
|
||
"pr": 9004,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Open a synthetic layered document with Move tool; use the supported themes and display scales.",
|
||
"action": "Inspect Move alignment icons and compare screenshots to the reviewed icon geometry in this PR.",
|
||
"expected": "Icons use the enlarged reviewed geometry, remain legible and do not clip or shift adjacent controls.",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": ""
|
||
},
|
||
{
|
||
"id": "PR-9015",
|
||
"pr": 9015,
|
||
"subsystem": "Platform and reliability",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p xtask --locked rejects_numeric_prerelease_identifiers_with_leading_zeroes -- --nocapture"
|
||
],
|
||
"expected": "rejects numeric prerelease identifiers with leading zeroes",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p xtask --locked rejects_numeric_prerelease_identifiers_with_leading_zeroes -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "rejects_numeric_prerelease_identifiers_with_leading_zeroes",
|
||
"path": "xtask/src/version.rs",
|
||
"package": "xtask",
|
||
"command": "cargo test -p xtask --locked rejects_numeric_prerelease_identifiers_with_leading_zeroes -- --nocapture",
|
||
"fixture_and_action_excerpt": " for version in [\"1.0.0-01\", \"1.0.0-rc.01\", \"1.0.0-00.1\"] {\n assert!(validate(version).is_err(), \"validator accepted invalid version {version}\");\n assert!(replace(MANIFEST, version).is_err(), \"accepted invalid version {version}\");\n }\n for version in [\"1.0.0-0\", \"1.0.0-rc.0\", \"1.0.0-01a\", \"1.0.0-01-2\"] {\n let updated = replace(MANIFEST, version).expect(\"valid prerelease\");\n assert_eq!(read(&updated).unwrap(), version);\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(validate(version).is_err(), \"validator accepted invalid version {version}\");\n assert!(replace(MANIFEST, version).is_err(), \"accepted invalid version {version}\");\n }\n for version in [\"1.0.0-0\", \"1.0.0-rc.0\", \"1.0.0-01a\", \"1.0.0-01-2\"] {",
|
||
" assert!(replace(MANIFEST, version).is_err(), \"accepted invalid version {version}\");\n }\n for version in [\"1.0.0-0\", \"1.0.0-rc.0\", \"1.0.0-01a\", \"1.0.0-01-2\"] {\n let updated = replace(MANIFEST, version).expect(\"valid prerelease\");",
|
||
" assert_eq!(read(&updated).unwrap(), version);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/afb4364a8795c42e6353762891b4890d878f9a68/xtask/src/version.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9172",
|
||
"pr": 9172,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-engine --locked new_gradient_fill_layer_defaults_to_foreground_to_transparent -- --nocapture"
|
||
],
|
||
"expected": "new gradient fill layer defaults to foreground to transparent",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-engine --locked new_gradient_fill_layer_defaults_to_foreground_to_transparent -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "new_gradient_fill_layer_defaults_to_foreground_to_transparent",
|
||
"path": "crates/engine/src/gradient_fill_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked new_gradient_fill_layer_defaults_to_foreground_to_transparent -- --nocapture",
|
||
"fixture_and_action_excerpt": " // #8708: Photoshop's Layer › New Fill Layer › Gradient… starts from Foreground to\n // Transparent: the foreground at both ends, its opacity 100% to 0%. A `to` colour keeps a\n // two-colour gradient.\n let mut s = session(8, \"transparent\");\n s.tools.foreground = [0.2, 0.4, 0.6, 1.0];\n s.tools.background = [1.0, 1.0, 1.0, 1.0];\n s.execute(\"layer.newFillLayer.gradient\", json!({})).unwrap();\n let Fill::Gradient { stops, opacity_stops, .. } = active_fill(&s) else { panic!(\"not a gradient\") };\n let fg = Color::rgba(0.2, 0.4, 0.6, 1.0);\n assert_eq!(stops, vec![(0.0, fg), (1.0, fg)]);\n assert_eq!(opacity_stops, vec![(0.0, 1.0), (1.0, 0.0)]);\n s.execute(\"layer.newFillLayer.gradient\", json!({\"to\": \"#ff0000\"})).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(stops, vec![(0.0, fg), (1.0, fg)]);\n assert_eq!(opacity_stops, vec![(0.0, 1.0), (1.0, 0.0)]);\n s.execute(\"layer.newFillLayer.gradient\", json!({\"to\": \"#ff0000\"})).unwrap();\n let Fill::Gradient { stops, opacity_stops, .. } = active_fill(&s) else { panic!(\"not a gradient\") };",
|
||
" assert_eq!(opacity_stops, vec![(0.0, 1.0), (1.0, 0.0)]);\n s.execute(\"layer.newFillLayer.gradient\", json!({\"to\": \"#ff0000\"})).unwrap();\n let Fill::Gradient { stops, opacity_stops, .. } = active_fill(&s) else { panic!(\"not a gradient\") };\n assert_eq!(stops[1].1, Color::rgba(1.0, 0.0, 0.0, 1.0));",
|
||
" assert_eq!(stops[1].1, Color::rgba(1.0, 0.0, 0.0, 1.0));\n assert!(opacity_stops.is_empty());\n}",
|
||
" assert!(opacity_stops.is_empty());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/8ebb04999d25790f71f9bd88f7a268a6a2754aec/crates/engine/src/gradient_fill_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9282",
|
||
"pr": 9282,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked adjustment_preset_menus_load_presets_and_read_custom_after_an_edit -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked properties_preset_menus_load_every_setting_in_one_step -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preset_menus_say_they_are_photocrafts_own -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked presets_apply_and_are_recognised -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked presets_give_their_looks -- --nocapture"
|
||
],
|
||
"expected": "adjustment preset menus load presets and read custom after an edit; properties preset menus load every setting in one step; preset menus say they are photocrafts own; presets apply and are recognised; presets give their looks",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked adjustment_preset_menus_load_presets_and_read_custom_after_an_edit -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked properties_preset_menus_load_every_setting_in_one_step -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked preset_menus_say_they_are_photocrafts_own -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked presets_apply_and_are_recognised -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked presets_give_their_looks -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "adjustment_preset_menus_load_presets_and_read_custom_after_an_edit",
|
||
"path": "crates/ui-egui/src/adjust_dialog.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked adjustment_preset_menus_load_presets_and_read_custom_after_an_edit -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::{NodeT, Queryable};\n for (kind, label, key) in [\n (\"levels\", \"Increase Contrast 2\", \"inBlack\"),\n (\"exposure\", \"Plus 1.0\", \"exposure\"),\n (\"blackWhite\", \"Red Filter\", \"reds\"),\n (\"channelMixer\", \"Black & White with Red Filter (RGB)\", \"monochrome\"),\n ] {\n let mut h = Harness::builder().with_size(egui::vec2(1200.0, 900.0)).build_ui_state(|ui, app| crate::dialogs::show(app, ui.ctx()), app_with_image());\n PhotocraftApp::setup_context(&h.ctx, crate::theme::ThemeKind::ALL[0]);\n let id = open(h.state_mut(), &format!(\"image.adjustments.{kind}\")).unwrap();\n h.run_steps(4);\n let preset = |h: &Harness<'_, PhotocraftApp>| {",
|
||
"expected_assertions": [
|
||
" assert_eq!(preset(&h).as_deref(), Some(\"Default\"), \"{kind} opens on Default\");\n h.query_all_by_role(egui::accesskit::Role::ComboBox).next().unwrap().click();\n h.run_steps(2);\n h.get_by_label(label).click();",
|
||
" assert_eq!(preset(&h).as_deref(), Some(label), \"{kind}: the menu shows the preset\");\n let want = crate::adjust_presets::presets(kind, false)\n .iter()\n .find(|p| p.label == label)",
|
||
" assert_eq!(fields[k], *v, \"{kind}: the preset's `{k}` is loaded\");\n }\n assert_eq!(fields[key], want[key]);\n let edit = match kind {",
|
||
" assert_eq!(fields[key], want[key]);\n let edit = match kind {\n \"levels\" => (\"gamma\", json!(1.37)),\n \"exposure\" => (\"offset\", json!(0.05)),",
|
||
" assert_eq!(preset(&h).as_deref(), Some(\"Custom\"), \"{kind}: an edit is Custom\");\n crate::dialogs::confirm(h.state_mut(), id).unwrap();\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/20803d1f15900ed6ecc7b5c79b4c68f6c3d6dcce/crates/ui-egui/src/adjust_dialog.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "properties_preset_menus_load_every_setting_in_one_step",
|
||
"path": "crates/ui-egui/src/adjust_editors_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked properties_preset_menus_load_every_setting_in_one_step -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::kittest::NodeT;\n for (kind, label) in\n [(\"levels\", \"Increase Contrast 2\"), (\"exposure\", \"Plus 1.0\"), (\"blackWhite\", \"Red Filter\"), (\"channelMixer\", \"Black & White with Red Filter (RGB)\")]\n {\n let mut h = app_harness(kind, \"rgb\", 8);\n let steps = h.state().session.active().unwrap().history.past_len();\n let menu = h\n .query_all_by_role(egui::accesskit::Role::ComboBox)\n .find(|n| n.accesskit_node().value().as_deref() == Some(\"Default\"))\n .unwrap_or_else(|| panic!(\"{kind}: the Preset menu, at Default\"));\n menu.click();\n h.run_steps(2);",
|
||
"expected_assertions": [
|
||
" assert_eq!(got[k], *v, \"{kind}: the layer's `{k}`\");\n }\n assert_eq!(h.state().session.active().unwrap().history.past_len(), steps + 1, \"{kind}: one step\");\n }",
|
||
" assert_eq!(h.state().session.active().unwrap().history.past_len(), steps + 1, \"{kind}: one step\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/20803d1f15900ed6ecc7b5c79b4c68f6c3d6dcce/crates/ui-egui/src/adjust_editors_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "preset_menus_say_they_are_photocrafts_own",
|
||
"path": "crates/ui-egui/src/adjust_editors_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked preset_menus_say_they_are_photocrafts_own -- --nocapture",
|
||
"fixture_and_action_excerpt": " for kind in [\"levels\", \"exposure\", \"blackWhite\", \"channelMixer\"] {\n let mut h = app_harness(kind, \"rgb\", 8);\n let caption = h.get_by_label(\"PhotoCraft Preset:\");\n caption.hover();\n h.run_steps(30);\n assert!(h.query_by_label_contains(\"not Photoshop's presets\").is_some(), \"{kind}: the caption explains the presets are PhotoCraft's own\");\n }\n}",
|
||
"expected_assertions": [
|
||
" assert!(h.query_by_label_contains(\"not Photoshop's presets\").is_some(), \"{kind}: the caption explains the presets are PhotoCraft's own\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/20803d1f15900ed6ecc7b5c79b4c68f6c3d6dcce/crates/ui-egui/src/adjust_editors_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "presets_apply_and_are_recognised",
|
||
"path": "crates/ui-egui/src/adjust_presets.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked presets_apply_and_are_recognised -- --nocapture",
|
||
"fixture_and_action_excerpt": " for kind in [\"levels\", \"exposure\", \"blackWhite\", \"channelMixer\"] {\n let all = presets(kind, false);\n assert!(all.len() >= 5 && all[0].id == \"default\", \"{kind}\");\n for p in all {\n let s = settings(kind, p, false).unwrap_or_else(|| panic!(\"{kind} {}: valid params\", p.id));\n assert_eq!(matching(kind, &s, false).map(|m| m.id), Some(p.id), \"{kind} {}\", p.id);\n }\n let distinct: std::collections::HashSet<String> = all.iter().map(|p| settings(kind, p, false).unwrap().to_string()).collect();\n assert_eq!(distinct.len(), all.len(), \"{kind}: no two presets are the same\");\n assert_eq!(matching(kind, &json!({}), false).map(|p| p.id), Some(\"default\"), \"{kind}: untouched is Default\");\n }\n let mut v = settings(\"levels\", &LEVELS[3], false).unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(all.len() >= 5 && all[0].id == \"default\", \"{kind}\");\n for p in all {\n let s = settings(kind, p, false).unwrap_or_else(|| panic!(\"{kind} {}: valid params\", p.id));\n assert_eq!(matching(kind, &s, false).map(|m| m.id), Some(p.id), \"{kind} {}\", p.id);",
|
||
" assert_eq!(matching(kind, &s, false).map(|m| m.id), Some(p.id), \"{kind} {}\", p.id);\n }\n let distinct: std::collections::HashSet<String> = all.iter().map(|p| settings(kind, p, false).unwrap().to_string()).collect();\n assert_eq!(distinct.len(), all.len(), \"{kind}: no two presets are the same\");",
|
||
" assert_eq!(distinct.len(), all.len(), \"{kind}: no two presets are the same\");\n assert_eq!(matching(kind, &json!({}), false).map(|p| p.id), Some(\"default\"), \"{kind}: untouched is Default\");\n }\n let mut v = settings(\"levels\", &LEVELS[3], false).unwrap();",
|
||
" assert_eq!(matching(kind, &json!({}), false).map(|p| p.id), Some(\"default\"), \"{kind}: untouched is Default\");\n }\n let mut v = settings(\"levels\", &LEVELS[3], false).unwrap();\n v[\"gamma\"] = json!(1.37);",
|
||
" assert!(matching(\"levels\", &v, false).is_none(), \"an edit is Custom\");\n assert!(presets(\"blackWhite\", true).is_empty() && presets(\"channelMixer\", true).is_empty(), \"colour presets need colour\");\n assert_eq!(presets(\"levels\", true).len(), LEVELS.len());\n }",
|
||
" assert!(presets(\"blackWhite\", true).is_empty() && presets(\"channelMixer\", true).is_empty(), \"colour presets need colour\");\n assert_eq!(presets(\"levels\", true).len(), LEVELS.len());\n }",
|
||
" assert_eq!(presets(\"levels\", true).len(), LEVELS.len());\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/20803d1f15900ed6ecc7b5c79b4c68f6c3d6dcce/crates/ui-egui/src/adjust_presets.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "presets_give_their_looks",
|
||
"path": "crates/ui-egui/src/adjust_presets.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked presets_give_their_looks -- --nocapture",
|
||
"fixture_and_action_excerpt": " let lv = |id: &str| settings(\"levels\", LEVELS.iter().find(|p| p.id == id).unwrap(), false).unwrap();\n let span = |v: &Value| v[\"inWhite\"].as_f64().unwrap() - v[\"inBlack\"].as_f64().unwrap();\n assert!(span(&lv(\"increaseContrast1\")) > span(&lv(\"increaseContrast2\")) && span(&lv(\"increaseContrast2\")) > span(&lv(\"increaseContrast3\")));\n assert!(lv(\"midtonesBrighter\")[\"gamma\"].as_f64().unwrap() > 1.0 && lv(\"midtonesDarker\")[\"gamma\"].as_f64().unwrap() < 1.0);\n let bw = |id: &str| settings(\"blackWhite\", BLACK_WHITE.iter().find(|p| p.id == id).unwrap(), false).unwrap();\n let w = |v: &Value, k: &str| v[k].as_f64().unwrap();\n assert!(w(&bw(\"redFilter\"), \"reds\") > w(&bw(\"redFilter\"), \"cyans\"), \"a red filter lightens reds over cyans\");\n assert!(w(&bw(\"blueFilter\"), \"blues\") > w(&bw(\"blueFilter\"), \"yellows\"), \"a blue filter lightens blues over yellows\");\n assert!(\n w(&bw(\"highContrastRedFilter\"), \"reds\") - w(&bw(\"highContrastRedFilter\"), \"blues\") > w(&bw(\"redFilter\"), \"reds\") - w(&bw(\"redFilter\"), \"blues\")\n );\n let ex = |id: &str| settings(\"exposure\", EXPOSURE.iter().find(|p| p.id == id).unwrap(), false).unwrap()[\"exposure\"].as_f64().unwrap();",
|
||
"expected_assertions": [
|
||
" assert!(span(&lv(\"increaseContrast1\")) > span(&lv(\"increaseContrast2\")) && span(&lv(\"increaseContrast2\")) > span(&lv(\"increaseContrast3\")));\n assert!(lv(\"midtonesBrighter\")[\"gamma\"].as_f64().unwrap() > 1.0 && lv(\"midtonesDarker\")[\"gamma\"].as_f64().unwrap() < 1.0);\n let bw = |id: &str| settings(\"blackWhite\", BLACK_WHITE.iter().find(|p| p.id == id).unwrap(), false).unwrap();\n let w = |v: &Value, k: &str| v[k].as_f64().unwrap();",
|
||
" assert!(lv(\"midtonesBrighter\")[\"gamma\"].as_f64().unwrap() > 1.0 && lv(\"midtonesDarker\")[\"gamma\"].as_f64().unwrap() < 1.0);\n let bw = |id: &str| settings(\"blackWhite\", BLACK_WHITE.iter().find(|p| p.id == id).unwrap(), false).unwrap();\n let w = |v: &Value, k: &str| v[k].as_f64().unwrap();\n assert!(w(&bw(\"redFilter\"), \"reds\") > w(&bw(\"redFilter\"), \"cyans\"), \"a red filter lightens reds over cyans\");",
|
||
" assert!(w(&bw(\"redFilter\"), \"reds\") > w(&bw(\"redFilter\"), \"cyans\"), \"a red filter lightens reds over cyans\");\n assert!(w(&bw(\"blueFilter\"), \"blues\") > w(&bw(\"blueFilter\"), \"yellows\"), \"a blue filter lightens blues over yellows\");\n assert!(\n w(&bw(\"highContrastRedFilter\"), \"reds\") - w(&bw(\"highContrastRedFilter\"), \"blues\") > w(&bw(\"redFilter\"), \"reds\") - w(&bw(\"redFilter\"), \"blues\")",
|
||
" assert!(w(&bw(\"blueFilter\"), \"blues\") > w(&bw(\"blueFilter\"), \"yellows\"), \"a blue filter lightens blues over yellows\");\n assert!(\n w(&bw(\"highContrastRedFilter\"), \"reds\") - w(&bw(\"highContrastRedFilter\"), \"blues\") > w(&bw(\"redFilter\"), \"reds\") - w(&bw(\"redFilter\"), \"blues\")\n );",
|
||
" assert!(\n w(&bw(\"highContrastRedFilter\"), \"reds\") - w(&bw(\"highContrastRedFilter\"), \"blues\") > w(&bw(\"redFilter\"), \"reds\") - w(&bw(\"redFilter\"), \"blues\")\n );\n let ex = |id: &str| settings(\"exposure\", EXPOSURE.iter().find(|p| p.id == id).unwrap(), false).unwrap()[\"exposure\"].as_f64().unwrap();",
|
||
" assert_eq!([ex(\"minus2\"), ex(\"minus1\"), ex(\"plus1\"), ex(\"plus2\")], [-2.0, -1.0, 1.0, 2.0]);\n for p in &CHANNEL_MIXER[1..] {\n let s = settings(\"channelMixer\", p, false).unwrap();\n assert_eq!(s[\"monochrome\"], json!(true), \"{}\", p.id);",
|
||
" assert_eq!(s[\"monochrome\"], json!(true), \"{}\", p.id);\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/20803d1f15900ed6ecc7b5c79b4c68f6c3d6dcce/crates/ui-egui/src/adjust_presets.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9354",
|
||
"pr": 9354,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked screen_mode_button_is_inert_without_a_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked long_press_screen_mode_opens_the_modes_without_cycling -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked full_screen_modes_need_a_document -- --nocapture"
|
||
],
|
||
"expected": "screen mode button is inert without a document; long press screen mode opens the modes without cycling; full screen modes need a document",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked screen_mode_button_is_inert_without_a_document -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked long_press_screen_mode_opens_the_modes_without_cycling -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked full_screen_modes_need_a_document -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "screen_mode_button_is_inert_without_a_document",
|
||
"path": "crates/ui-egui/src/panels.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked screen_mode_button_is_inert_without_a_document -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", serde_json::json!({\"width\": 64, \"height\": 48})).unwrap();\n let ctx = egui::Context::default();\n PhotocraftApp::setup_context(&ctx, crate::theme::ThemeKind::ALL[0]);\n frame(&mut app, &ctx, 0.0, vec![]);\n frame(&mut app, &ctx, 0.1, vec![]);\n let bx = if Tokens::get(&ctx).pro { 30.0 } else { 36.0 };\n // Found while a document makes it clickable: the toolbar's last button.\n let at = ctx\n .viewport(|v| {\n v.prev_pass\n .widgets",
|
||
"expected_assertions": [
|
||
" assert_eq!(crate::view_cmds::is_enabled(&app, \"view.screenMode.cycle\"), Some(false));\n let pointer = |pressed| egui::Event::PointerButton { pos: at, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() };\n let mut sent = Vec::new();\n for (t, events) in [(2.0, vec![egui::Event::PointerMoved(at), pointer(true)]), (2.1, vec![pointer(false)]), (2.15, vec![])] {",
|
||
" assert!(!sent.iter().any(|c| matches!(c, egui::ViewportCommand::Fullscreen(_))), \"no screen mode change was sent: {sent:?}\");\n assert_eq!(app.ui.view.screen_mode, \"standard\");\n }",
|
||
" assert_eq!(app.ui.view.screen_mode, \"standard\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/41eb1de5cff17f5f5b9c22913e48b71565b56a2a/crates/ui-egui/src/panels.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "long_press_screen_mode_opens_the_modes_without_cycling",
|
||
"path": "crates/ui-egui/src/panels.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked long_press_screen_mode_opens_the_modes_without_cycling -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n // A document open: Full Screen Mode needs one (#9349), so without it a click can't cycle.\n app.run(\"file.new\", serde_json::json!({\"width\": 64, \"height\": 48})).unwrap();\n let ctx = egui::Context::default();\n PhotocraftApp::setup_context(&ctx, crate::theme::ThemeKind::ALL[0]);\n frame(&mut app, &ctx, 0.0, vec![]);\n frame(&mut app, &ctx, 0.1, vec![]);\n let bx = if Tokens::get(&ctx).pro { 30.0 } else { 36.0 };\n // The toolbar's last button: Change Screen Mode, after Quick Mask.\n let at = ctx\n .viewport(|v| {\n v.prev_pass",
|
||
"expected_assertions": [
|
||
" assert!(standard(&app));\n // Hold, then release: the list opens and stays open, and the mode is unchanged.\n frame(&mut app, &ctx, 1.0, vec![egui::Event::PointerMoved(at), pointer(at, true)]);\n frame(&mut app, &ctx, 1.2, vec![]);",
|
||
" assert!(!menu_open(&ctx), \"not before the hold time\");\n frame(&mut app, &ctx, 1.4, vec![]);\n assert!(menu_open(&ctx), \"open while still held\");\n frame(&mut app, &ctx, 1.5, vec![pointer(at, false)]);",
|
||
" assert!(menu_open(&ctx), \"open while still held\");\n frame(&mut app, &ctx, 1.5, vec![pointer(at, false)]);\n frame(&mut app, &ctx, 1.55, vec![]);\n assert!(menu_open(&ctx), \"the release keeps it open\");",
|
||
" assert!(menu_open(&ctx), \"the release keeps it open\");\n assert!(standard(&app), \"the release doesn't cycle the mode\");\n // Escape closes it; a plain click cycles the mode and opens nothing.\n frame(",
|
||
" assert!(standard(&app), \"the release doesn't cycle the mode\");\n // Escape closes it; a plain click cycles the mode and opens nothing.\n frame(\n &mut app,",
|
||
" assert!(!menu_open(&ctx));\n frame(&mut app, &ctx, 3.0, vec![egui::Event::PointerMoved(at), pointer(at, true)]);\n frame(&mut app, &ctx, 3.1, vec![pointer(at, false)]);\n frame(&mut app, &ctx, 3.15, vec![]);",
|
||
" assert!(!standard(&app), \"a click cycles\");\n assert!(!menu_open(&ctx));\n // Right-click opens it too.\n let secondary = |pressed| egui::Event::PointerButton { pos: at, button: egui::PointerButton::Secondary, pressed, modifiers: Default::default() };",
|
||
" assert!(!menu_open(&ctx));\n // Right-click opens it too.\n let secondary = |pressed| egui::Event::PointerButton { pos: at, button: egui::PointerButton::Secondary, pressed, modifiers: Default::default() };\n frame(&mut app, &ctx, 4.0, vec![secondary(true)]);",
|
||
" assert!(menu_open(&ctx));\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/41eb1de5cff17f5f5b9c22913e48b71565b56a2a/crates/ui-egui/src/panels.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "full_screen_modes_need_a_document",
|
||
"path": "crates/ui-egui/src/view_cmds/tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked full_screen_modes_need_a_document -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut app, ctx) = app_with(0);\n for id in [\"view.screenMode.fullScreen\", \"view.screenMode.fullScreenWithMenuBar\", \"view.screenMode.cycle\"] {\n assert_eq!(is_enabled(&app, id), Some(false), \"{id} without a document\");\n }\n // #9354 review: run anyway (the toolbar list, automation), they are refused and Standard stays.\n for id in [\"view.screenMode.fullScreen\", \"view.screenMode.fullScreenWithMenuBar\"] {\n assert!(menu(&mut app, &ctx, id, json!({})).is_err(), \"{id} is refused without a document\");\n assert_eq!(app.ui.view.screen_mode, \"standard\", \"{id}\");\n }\n assert_eq!(is_enabled(&app, \"view.screenMode.standard\"), Some(true));\n let (mut with_doc, _) = app_with(1);\n for id in [\"view.screenMode.fullScreen\", \"view.screenMode.fullScreenWithMenuBar\", \"view.screenMode.cycle\"] {",
|
||
"expected_assertions": [
|
||
" assert_eq!(is_enabled(&app, id), Some(false), \"{id} without a document\");\n }\n // #9354 review: run anyway (the toolbar list, automation), they are refused and Standard stays.\n for id in [\"view.screenMode.fullScreen\", \"view.screenMode.fullScreenWithMenuBar\"] {",
|
||
" assert!(menu(&mut app, &ctx, id, json!({})).is_err(), \"{id} is refused without a document\");\n assert_eq!(app.ui.view.screen_mode, \"standard\", \"{id}\");\n }\n assert_eq!(is_enabled(&app, \"view.screenMode.standard\"), Some(true));",
|
||
" assert_eq!(app.ui.view.screen_mode, \"standard\", \"{id}\");\n }\n assert_eq!(is_enabled(&app, \"view.screenMode.standard\"), Some(true));\n let (mut with_doc, _) = app_with(1);",
|
||
" assert_eq!(is_enabled(&app, \"view.screenMode.standard\"), Some(true));\n let (mut with_doc, _) = app_with(1);\n for id in [\"view.screenMode.fullScreen\", \"view.screenMode.fullScreenWithMenuBar\", \"view.screenMode.cycle\"] {\n assert_eq!(is_enabled(&with_doc, id), Some(true), \"{id} with a document\");",
|
||
" assert_eq!(is_enabled(&with_doc, id), Some(true), \"{id} with a document\");\n }\n // The last document closed in Full Screen Mode: back to Standard.\n menu(&mut with_doc, &ctx, \"view.screenMode.fullScreen\", json!({})).unwrap();",
|
||
" assert_eq!(with_doc.ui.view.screen_mode, \"fullScreen\", \"a document is still open\");\n with_doc.run(\"file.close\", json!({\"save\": false})).unwrap();\n assert!(with_doc.session.documents().is_empty());\n leave_full_screen_without_document(&mut with_doc, &ctx);",
|
||
" assert!(with_doc.session.documents().is_empty());\n leave_full_screen_without_document(&mut with_doc, &ctx);\n assert_eq!(with_doc.ui.view.screen_mode, \"standard\");\n // A full screen mode reached anyway (automation) with no document drops back the same way.",
|
||
" assert_eq!(with_doc.ui.view.screen_mode, \"standard\");\n // A full screen mode reached anyway (automation) with no document drops back the same way.\n app.ui.view.screen_mode = \"fullScreenWithMenuBar\".into();\n assert_eq!(is_enabled(&app, \"view.screenMode.cycle\"), Some(true), \"Cycle can still leave it\");",
|
||
" assert_eq!(is_enabled(&app, \"view.screenMode.cycle\"), Some(true), \"Cycle can still leave it\");\n // #9354 review: and Cycle itself goes straight back to Standard, not on to Full Screen.\n menu(&mut app, &ctx, \"view.screenMode.cycle\", json!({})).unwrap();\n assert_eq!(app.ui.view.screen_mode, \"standard\", \"Cycle without a document returns to Standard\");",
|
||
" assert_eq!(app.ui.view.screen_mode, \"standard\", \"Cycle without a document returns to Standard\");\n app.ui.view.screen_mode = \"fullScreenWithMenuBar\".into();\n leave_full_screen_without_document(&mut app, &ctx);\n assert_eq!(app.ui.view.screen_mode, \"standard\");",
|
||
" assert_eq!(app.ui.view.screen_mode, \"standard\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/41eb1de5cff17f5f5b9c22913e48b71565b56a2a/crates/ui-egui/src/view_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9418",
|
||
"pr": 9418,
|
||
"subsystem": "File fidelity and colour",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-cms --locked three_dl_without_a_header_reads_low_nodes_as_12_bit -- --nocapture",
|
||
"cargo test -p photocraft-cms --locked three_dl_mesh_three_point_shaper_is_not_a_node -- --nocapture",
|
||
"cargo test -p photocraft-cms --locked three_dl_mesh_declares_the_output_depth -- --nocapture",
|
||
"cargo test -p photocraft-cms --locked three_dl_mesh_header_mismatch_is_rejected -- --nocapture",
|
||
"cargo test -p photocraft-cms --locked three_dl_malformed_mesh_header_falls_back_to_inference -- --nocapture",
|
||
"cargo test -p photocraft-cms --locked three_dl_mesh_uses_declared_range_for_small_integer_codes -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked color_lookup_mesh_3dl_honours_the_header -- --nocapture"
|
||
],
|
||
"expected": "three dl without a header reads low nodes as 12 bit; three dl mesh three point shaper is not a node; three dl mesh declares the output depth; three dl mesh header mismatch is rejected; three dl malformed mesh header falls back to inference; three dl mesh uses declared range for small integer codes; color lookup mesh 3dl honours the header",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-cms --locked three_dl_without_a_header_reads_low_nodes_as_12_bit -- --nocapture",
|
||
"cargo test -p photocraft-cms --locked three_dl_mesh_three_point_shaper_is_not_a_node -- --nocapture",
|
||
"cargo test -p photocraft-cms --locked three_dl_mesh_declares_the_output_depth -- --nocapture",
|
||
"cargo test -p photocraft-cms --locked three_dl_mesh_header_mismatch_is_rejected -- --nocapture",
|
||
"cargo test -p photocraft-cms --locked three_dl_malformed_mesh_header_falls_back_to_inference -- --nocapture",
|
||
"cargo test -p photocraft-cms --locked three_dl_mesh_uses_declared_range_for_small_integer_codes -- --nocapture",
|
||
"cargo test -p photocraft-engine --locked color_lookup_mesh_3dl_honours_the_header -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "three_dl_without_a_header_reads_low_nodes_as_12_bit",
|
||
"path": "crates/cms/src/lutfile.rs",
|
||
"package": "photocraft-cms",
|
||
"command": "cargo test -p photocraft-cms --locked three_dl_without_a_header_reads_low_nodes_as_12_bit -- --nocapture",
|
||
"fixture_and_action_excerpt": " let table = |peak: u32| -> String {\n let mut text = String::from(\"0 1023\\n\");\n for i in 0..8 {\n let on = |bit: u32| if i & bit != 0 { peak } else { 0 };\n text.push_str(&format!(\"{} {} {}\\n\", on(4), on(2), on(1)));\n }\n text\n };\n for peak in [255, 1023, 4095] {\n let white = parse_3dl(&table(peak)).unwrap().data[21..24].to_vec();\n assert_eq!(white, [peak as f32 / 4095.0; 3], \"peak {peak}\");\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(white, [peak as f32 / 4095.0; 3], \"peak {peak}\");\n }\n // A header keeps the inferred 10-bit depth. The bare `3DMESH` magic is a header without a\n // cube declaration; `Mesh 1 10` would declare a 3³ cube and refuse this 2³ table (#9078).",
|
||
" assert_eq!(white, [1.0; 3]);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/da4b838e54f6073cda4798fa7b63b3b7214aaf93/crates/cms/src/lutfile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "three_dl_mesh_three_point_shaper_is_not_a_node",
|
||
"path": "crates/cms/src/lutfile.rs",
|
||
"package": "photocraft-cms",
|
||
"command": "cargo test -p photocraft-cms --locked three_dl_mesh_three_point_shaper_is_not_a_node -- --nocapture",
|
||
"fixture_and_action_excerpt": " // #9078: Photoshop loads a 3³ cube whose shaper line has three values; counting it as a\n // 28th node rejected the whole file.\n let l = parse_3dl(&mesh_3dl(1, 12, 3, 4095.0, true)).unwrap();\n assert_eq!(l.size, 3);\n assert_eq!(l.data.len(), 3 * 3 * 3 * 3);\n // The inverse identity: node (0,0,0) is full, node (2,2,2) black.\n assert!((l.data[0] - 1.0).abs() < 1e-6 && (l.data[1] - 1.0).abs() < 1e-6 && (l.data[2] - 1.0).abs() < 1e-6);\n let last = &l.data[l.data.len() - 3..];\n assert_eq!(last, [0.0, 0.0, 0.0]);\n // The same 27 nodes without the shaper row still load (the node-only control).\n assert_eq!(parse_3dl(&mesh_3dl(1, 12, 3, 4095.0, false)).unwrap().data, l.data);\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(l.size, 3);\n assert_eq!(l.data.len(), 3 * 3 * 3 * 3);\n // The inverse identity: node (0,0,0) is full, node (2,2,2) black.\n assert!((l.data[0] - 1.0).abs() < 1e-6 && (l.data[1] - 1.0).abs() < 1e-6 && (l.data[2] - 1.0).abs() < 1e-6);",
|
||
" assert_eq!(l.data.len(), 3 * 3 * 3 * 3);\n // The inverse identity: node (0,0,0) is full, node (2,2,2) black.\n assert!((l.data[0] - 1.0).abs() < 1e-6 && (l.data[1] - 1.0).abs() < 1e-6 && (l.data[2] - 1.0).abs() < 1e-6);\n let last = &l.data[l.data.len() - 3..];",
|
||
" assert!((l.data[0] - 1.0).abs() < 1e-6 && (l.data[1] - 1.0).abs() < 1e-6 && (l.data[2] - 1.0).abs() < 1e-6);\n let last = &l.data[l.data.len() - 3..];\n assert_eq!(last, [0.0, 0.0, 0.0]);\n // The same 27 nodes without the shaper row still load (the node-only control).",
|
||
" assert_eq!(last, [0.0, 0.0, 0.0]);\n // The same 27 nodes without the shaper row still load (the node-only control).\n assert_eq!(parse_3dl(&mesh_3dl(1, 12, 3, 4095.0, false)).unwrap().data, l.data);\n }",
|
||
" assert_eq!(parse_3dl(&mesh_3dl(1, 12, 3, 4095.0, false)).unwrap().data, l.data);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/da4b838e54f6073cda4798fa7b63b3b7214aaf93/crates/cms/src/lutfile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "three_dl_mesh_declares_the_output_depth",
|
||
"path": "crates/cms/src/lutfile.rs",
|
||
"package": "photocraft-cms",
|
||
"command": "cargo test -p photocraft-cms --locked three_dl_mesh_declares_the_output_depth -- --nocapture",
|
||
"fixture_and_action_excerpt": " // #9073: identical node codes divide by the declared range, not by the largest value.\n let mut text_10 = String::new();\n let mut text_12 = String::new();\n for (n_bits, out_bits, dst) in [(2, 10, &mut text_10), (2, 12, &mut text_12)] {\n // A 5³ identity scaled to 10-bit codes (max 1023).\n *dst = format!(\"3DMESH\\nMesh {n_bits} {out_bits}\\n0 256 512 768 1023\\n\");\n for r in 0..5 {\n for g in 0..5 {\n for b in 0..5 {\n dst.push_str(&format!(\"{} {} {}\\n\", r * 255, g * 255, b * 255));\n }\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(white_10.size, 5);\n let last_10 = &white_10.data[white_10.data.len() - 3..];\n let last_12 = &white_12.data[white_12.data.len() - 3..];\n assert!((last_10[0] - 1020.0 / 1023.0).abs() < 1e-6, \"{last_10:?}\");",
|
||
" assert!((last_10[0] - 1020.0 / 1023.0).abs() < 1e-6, \"{last_10:?}\");\n // 1020/4095 ≈ 0.249: white renders grey, as Photoshop measures it.\n assert!((last_12[0] - 1020.0 / 4095.0).abs() < 1e-6, \"{last_12:?}\");\n }",
|
||
" assert!((last_12[0] - 1020.0 / 4095.0).abs() < 1e-6, \"{last_12:?}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/da4b838e54f6073cda4798fa7b63b3b7214aaf93/crates/cms/src/lutfile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "three_dl_mesh_header_mismatch_is_rejected",
|
||
"path": "crates/cms/src/lutfile.rs",
|
||
"package": "photocraft-cms",
|
||
"command": "cargo test -p photocraft-cms --locked three_dl_mesh_header_mismatch_is_rejected -- --nocapture",
|
||
"fixture_and_action_excerpt": " // A Mesh header that disagrees with the row count is refused, not silently re-inferred.\n assert!(parse_3dl(\"3DMESH\\nMesh 1 12\\n0 0 0\\n0 0 1\\n\").is_err());\n // A node beyond the declared range is a wrong declaration: the old inference from the\n // largest value keeps the file loading as it did before the header was honoured.\n let mut text = String::from(\"3DMESH\\nMesh 1 10\\n\");\n for r in 0..3 {\n for g in 0..3 {\n for b in 0..3 {\n text.push_str(&format!(\"{} {} {}\\n\", r * 2047, g * 2047, b * 2047));\n }\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!(parse_3dl(\"3DMESH\\nMesh 1 12\\n0 0 0\\n0 0 1\\n\").is_err());\n // A node beyond the declared range is a wrong declaration: the old inference from the\n // largest value keeps the file loading as it did before the header was honoured.\n let mut text = String::from(\"3DMESH\\nMesh 1 10\\n\");",
|
||
" assert!((last[0] - 4094.0 / 4095.0).abs() < 1e-6, \"{last:?}\");\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/da4b838e54f6073cda4798fa7b63b3b7214aaf93/crates/cms/src/lutfile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "three_dl_malformed_mesh_header_falls_back_to_inference",
|
||
"path": "crates/cms/src/lutfile.rs",
|
||
"package": "photocraft-cms",
|
||
"command": "cargo test -p photocraft-cms --locked three_dl_malformed_mesh_header_falls_back_to_inference -- --nocapture",
|
||
"fixture_and_action_excerpt": " // A `Mesh` line that is not exactly two integer fields is not a declaration: it is\n // ignored and the table is inferred as if headerless, rather than recovering numbers\n // from the wrong positions (#9078). A 2³ cube would otherwise be read as a 3³ cube.\n for header in [\"Mesh invalid 1 12\", \"Mesh 1 12 13\", \"Mesh 1 x\", \"Mesh 1\"] {\n let mut text = format!(\"3DMESH\\n{header}\\n\");\n for r in 0..2 {\n for g in 0..2 {\n for b in 0..2 {\n text.push_str(&format!(\"{} {} {}\\n\", r * 1023, g * 1023, b * 1023));\n }\n }\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(l.size, 2, \"{header}\");\n assert_eq!(l.data, LutFile::identity(2).data, \"{header}\");\n }\n }",
|
||
" assert_eq!(l.data, LutFile::identity(2).data, \"{header}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/da4b838e54f6073cda4798fa7b63b3b7214aaf93/crates/cms/src/lutfile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "three_dl_mesh_uses_declared_range_for_small_integer_codes",
|
||
"path": "crates/cms/src/lutfile.rs",
|
||
"package": "photocraft-cms",
|
||
"command": "cargo test -p photocraft-cms --locked three_dl_mesh_uses_declared_range_for_small_integer_codes -- --nocapture",
|
||
"fixture_and_action_excerpt": " // #9073: under a valid `Mesh` declaration the node codes are integers in the declared\n // range, so a max value of 1 is 1/4095 of full output — not full output itself.\n let mut text = String::from(\"3DMESH\\nMesh 1 12\\n\");\n for r in 0..3 {\n for g in 0..3 {\n for b in 0..3 {\n let v = u8::from(r == 0 && g == 0 && b == 0);\n text.push_str(&format!(\"{v} {v} {v}\\n\"));\n }\n }\n }\n let l = parse_3dl(&text).unwrap();",
|
||
"expected_assertions": [
|
||
" assert_eq!(l.size, 3);\n // blue fastest: node (0,0,0) is the first entry, code 1 → 1/4095.\n assert!((l.data[0] - 1.0 / 4095.0).abs() < 1e-6, \"{:?}\", &l.data[0..3]);\n assert!(l.data[3..].iter().all(|&v| v == 0.0), \"{:?}\", l.data);",
|
||
" assert!((l.data[0] - 1.0 / 4095.0).abs() < 1e-6, \"{:?}\", &l.data[0..3]);\n assert!(l.data[3..].iter().all(|&v| v == 0.0), \"{:?}\", l.data);\n }",
|
||
" assert!(l.data[3..].iter().all(|&v| v == 0.0), \"{:?}\", l.data);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/da4b838e54f6073cda4798fa7b63b3b7214aaf93/crates/cms/src/lutfile.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "color_lookup_mesh_3dl_honours_the_header",
|
||
"path": "crates/engine/src/adjust_cmds/tests.rs",
|
||
"package": "photocraft-engine",
|
||
"command": "cargo test -p photocraft-engine --locked color_lookup_mesh_3dl_honours_the_header -- --nocapture",
|
||
"fixture_and_action_excerpt": " // #9078 / #9073: a Lustre .3dl whose `Mesh <inBits> <outBits>` line declares the cube edge\n // (2^inBits + 1) and the output range (up to 2^outBits - 1). The three-value shaper row used\n // to be counted as a 28th node (\"28 rows is not a cube\"), and 10-bit codes under a 12-bit\n // declaration divided by the inferred 1023 instead of the declared 4095.\n let mut lut = String::from(\"3DMESH\\nMesh 1 12\\n0 512 1023\\n\");\n for r in 0..3 {\n for g in 0..3 {\n for b in 0..3 {\n let v = [r, g, b].map(|c| (4095.0 - 4095.0 * c as f64 / 2.0).round() as i32);\n lut.push_str(&format!(\"{} {} {}\\n\", v[0], v[1], v[2]));\n }\n }",
|
||
"expected_assertions": [
|
||
" assert!((after[c] * 255.0 - want).abs() <= 1.0, \"channel {c}: {after:?}\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/da4b838e54f6073cda4798fa7b63b3b7214aaf93/crates/engine/src/adjust_cmds/tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9481",
|
||
"pr": 9481,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked new_effects_start_from_the_made_default -- --nocapture"
|
||
],
|
||
"expected": "new effects start from the made default",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked new_effects_start_from_the_made_default -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "new_effects_start_from_the_made_default",
|
||
"path": "crates/ui-egui/src/layer_style.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked new_effects_start_from_the_made_default -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", json!({\"width\": 32, \"height\": 32})).unwrap();\n app.run(\"layer.new.layer\", json!({})).unwrap();\n app.run(\"layer.layerStyle.makeDefault\", json!({\"kind\": \"stroke\", \"params\": {\"size\": 7, \"position\": \"outside\"}})).unwrap();\n\n let id = open(&mut app, Some(\"stroke\")).unwrap();\n let mut f = app.ui.dialogs.iter().find(|d| d.id == id).unwrap().fields.clone();\n add_instance(&mut f, \"stroke\");\n add_instance(&mut f, \"dropShadow\");\n let fx = effects_of(&f);\n let strokes: Vec<_> = fx.iter().filter(|e| e[\"kind\"] == json!(\"stroke\")).collect();\n assert_eq!(strokes.len(), 2);",
|
||
"expected_assertions": [
|
||
" assert_eq!(strokes.len(), 2);\n for e in strokes {\n assert_eq!((&e[\"params\"][\"size\"], &e[\"params\"][\"position\"]), (&json!(7), &json!(\"outside\")));\n assert_eq!(e[\"params\"][\"opacity\"], defaults(\"stroke\")[\"opacity\"], \"unsaved keys keep the factory value\");",
|
||
" assert_eq!((&e[\"params\"][\"size\"], &e[\"params\"][\"position\"]), (&json!(7), &json!(\"outside\")));\n assert_eq!(e[\"params\"][\"opacity\"], defaults(\"stroke\")[\"opacity\"], \"unsaved keys keep the factory value\");\n }\n let shadow = fx.iter().find(|e| e[\"kind\"] == json!(\"dropShadow\")).unwrap();",
|
||
" assert_eq!(e[\"params\"][\"opacity\"], defaults(\"stroke\")[\"opacity\"], \"unsaved keys keep the factory value\");\n }\n let shadow = fx.iter().find(|e| e[\"kind\"] == json!(\"dropShadow\")).unwrap();\n assert_eq!(shadow[\"params\"][\"size\"], defaults(\"dropShadow\")[\"size\"]);",
|
||
" assert_eq!(shadow[\"params\"][\"size\"], defaults(\"dropShadow\")[\"size\"]);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/7937adff961027154d795b8905e821244ae4f929/crates/ui-egui/src/layer_style.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9504",
|
||
"pr": 9504,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked cmd_z_is_recorded_while_capturing_and_undoes_otherwise -- --nocapture"
|
||
],
|
||
"expected": "cmd z is recorded while capturing and undoes otherwise",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked cmd_z_is_recorded_while_capturing_and_undoes_otherwise -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "cmd_z_is_recorded_while_capturing_and_undoes_otherwise",
|
||
"path": "crates/ui-egui/src/shortcut_capture_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked cmd_z_is_recorded_while_capturing_and_undoes_otherwise -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut h, id) = dialog(1.0, \"edit.search\", \"search…\");\n capture(&mut h, &crate::shortcuts::pretty(\"Cmd+F\"), Key::ControlLeft, Modifiers::COMMAND, Key::Z);\n assert_eq!(field(&h, id, \"overrides\")[\"edit.search\"], json!(\"Cmd+Z\"));\n assert_eq!(field(&h, id, \"capture\"), json!(false));\n key(&mut h, Key::Z, true, Modifiers::COMMAND);\n h.run_steps(2);\n assert_ne!(field(&h, id, \"overrides\")[\"edit.search\"], json!(\"Cmd+Z\"), \"⌘Z outside a capture undoes the change\");\n assert_eq!(field(&h, id, \"capture\"), json!(false), \"and doesn't wait for keys again\");\n // CodeRabbit on #9504: clearing the restored capture isn't a new edit, so Redo still works.\n h.run_steps(2);\n key(&mut h, Key::Z, true, Modifiers::COMMAND | Modifiers::SHIFT);\n h.run_steps(2);",
|
||
"expected_assertions": [
|
||
" assert_eq!(field(&h, id, \"overrides\")[\"edit.search\"], json!(\"Cmd+Z\"));\n assert_eq!(field(&h, id, \"capture\"), json!(false));\n key(&mut h, Key::Z, true, Modifiers::COMMAND);\n h.run_steps(2);",
|
||
" assert_eq!(field(&h, id, \"capture\"), json!(false));\n key(&mut h, Key::Z, true, Modifiers::COMMAND);\n h.run_steps(2);\n assert_ne!(field(&h, id, \"overrides\")[\"edit.search\"], json!(\"Cmd+Z\"), \"⌘Z outside a capture undoes the change\");",
|
||
" assert_ne!(field(&h, id, \"overrides\")[\"edit.search\"], json!(\"Cmd+Z\"), \"⌘Z outside a capture undoes the change\");\n assert_eq!(field(&h, id, \"capture\"), json!(false), \"and doesn't wait for keys again\");\n // CodeRabbit on #9504: clearing the restored capture isn't a new edit, so Redo still works.\n h.run_steps(2);",
|
||
" assert_eq!(field(&h, id, \"capture\"), json!(false), \"and doesn't wait for keys again\");\n // CodeRabbit on #9504: clearing the restored capture isn't a new edit, so Redo still works.\n h.run_steps(2);\n key(&mut h, Key::Z, true, Modifiers::COMMAND | Modifiers::SHIFT);",
|
||
" assert_eq!(field(&h, id, \"overrides\")[\"edit.search\"], json!(\"Cmd+Z\"), \"⇧⌘Z redoes the recorded shortcut\");\n assert_eq!(field(&h, id, \"capture\"), json!(false));\n}",
|
||
" assert_eq!(field(&h, id, \"capture\"), json!(false));\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/993c9ed167c6acd9bc8f87c6cff6e2c7abba17a8/crates/ui-egui/src/shortcut_capture_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9517",
|
||
"pr": 9517,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_buttons_stay_on_a_short_window -- --nocapture"
|
||
],
|
||
"expected": "layer style buttons stay on a short window",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked layer_style_buttons_stay_on_a_short_window -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "layer_style_buttons_stay_on_a_short_window",
|
||
"path": "crates/ui-egui/src/dialogs.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_style_buttons_stay_on_a_short_window -- --nocapture",
|
||
"fixture_and_action_excerpt": " use egui_kittest::{Harness, kittest::Queryable};\n\n let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.run(\"file.new\", serde_json::json!({\"width\": 64, \"height\": 64})).unwrap();\n app.run(\"layer.new.layer\", serde_json::json!({})).unwrap();\n let mut h = Harness::builder().with_size(egui::vec2(1435.0, 858.0)).build_ui_state(|ui, app| show(app, ui.ctx()), app);\n PhotocraftApp::setup_context(&h.ctx, crate::theme::ThemeKind::ALL[0]);\n crate::layer_style::open(h.state_mut(), Some(\"bevelEmboss\")).unwrap();\n h.run_steps(4);\n for label in [\"OK\", \"Cancel\"] {\n let r = h.get_by_label(label).rect();\n assert!(r.bottom() <= 858.0, \"{label} is off the window: {r:?}\");",
|
||
"expected_assertions": [
|
||
" assert!(r.bottom() <= 858.0, \"{label} is off the window: {r:?}\");\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/81b434c6149732eadc94e0465fea81bd075facd4/crates/ui-egui/src/dialogs.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9597",
|
||
"pr": 9597,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked layer_rows_do_not_move_when_no_layer_is_selected -- --nocapture"
|
||
],
|
||
"expected": "layer rows do not move when no layer is selected",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked layer_rows_do_not_move_when_no_layer_is_selected -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "layer_rows_do_not_move_when_no_layer_is_selected",
|
||
"path": "crates/ui-egui/src/layer_pct_slider_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked layer_rows_do_not_move_when_no_layer_is_selected -- --nocapture",
|
||
"fixture_and_action_excerpt": " for theme in [crate::theme::ThemeKind::Studio, crate::theme::ThemeKind::Classic, crate::theme::ThemeKind::ProMedium] {\n let mut h = harness();\n PhotocraftApp::setup_context(&h.ctx, theme);\n h.run_steps(4);\n let row_top = |h: &Harness<'_, PhotocraftApp>| by_role(h, \"Paint\", Role::Button).map(|r| r.top());\n let selected = row_top(&h);\n h.state_mut().session.execute(\"select.deselectLayers\", json!({})).unwrap();\n h.run_steps(4);\n let none = row_top(&h);\n assert!(selected.is_some(), \"{theme:?}: the layer row\");\n assert_eq!(none, selected, \"{theme:?}: the row moved with no layer selected\");\n }",
|
||
"expected_assertions": [
|
||
" assert!(selected.is_some(), \"{theme:?}: the layer row\");\n assert_eq!(none, selected, \"{theme:?}: the row moved with no layer selected\");\n }\n}",
|
||
" assert_eq!(none, selected, \"{theme:?}: the row moved with no layer selected\");\n }\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/9429df26b371c04c2afa65228a60ded739b5fbc2/crates/ui-egui/src/layer_pct_slider_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9598",
|
||
"pr": 9598,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked twirl_counterclockwise_has_its_own_mirrored_icon -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked alt_reversed_twirl_survives_replay_undo_and_redo -- --nocapture"
|
||
],
|
||
"expected": "twirl counterclockwise has its own mirrored icon; alt reversed twirl survives replay undo and redo",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked twirl_counterclockwise_has_its_own_mirrored_icon -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked alt_reversed_twirl_survives_replay_undo_and_redo -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "twirl_counterclockwise_has_its_own_mirrored_icon",
|
||
"path": "crates/ui-egui/src/liquify_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked twirl_counterclockwise_has_its_own_mirrored_icon -- --nocapture",
|
||
"fixture_and_action_excerpt": " assert_eq!(tool_icon(LiquifyTool::TwirlCcw), \"rotate-ccw\");\n let svg = |name: &str| crate::icon_data::ICONS.iter().find(|(n, _)| *n == name).map(|(_, b)| String::from_utf8_lossy(b).into_owned());\n let (cw, ccw) = (svg(\"rotate-cw\").unwrap(), svg(\"rotate-ccw\").expect(\"the rotate-ccw icon\"));\n assert!(ccw.contains(\"M3 12a9 9 0 1 0 9-9\") && cw.contains(\"M21 12a9 9 0 1 1-9-9\"), \"mirror images\");\n for t in [LiquifyTool::ForwardWarp, LiquifyTool::TwirlCw, LiquifyTool::TwirlCcw, LiquifyTool::Pucker, LiquifyTool::Bloat] {\n assert!(svg(tool_icon(t)).is_some(), \"{t:?}: {}\", tool_icon(t));\n }\n }",
|
||
"expected_assertions": [
|
||
" assert_eq!(tool_icon(LiquifyTool::TwirlCcw), \"rotate-ccw\");\n let svg = |name: &str| crate::icon_data::ICONS.iter().find(|(n, _)| *n == name).map(|(_, b)| String::from_utf8_lossy(b).into_owned());\n let (cw, ccw) = (svg(\"rotate-cw\").unwrap(), svg(\"rotate-ccw\").expect(\"the rotate-ccw icon\"));\n assert!(ccw.contains(\"M3 12a9 9 0 1 0 9-9\") && cw.contains(\"M21 12a9 9 0 1 1-9-9\"), \"mirror images\");",
|
||
" assert!(ccw.contains(\"M3 12a9 9 0 1 0 9-9\") && cw.contains(\"M21 12a9 9 0 1 1-9-9\"), \"mirror images\");\n for t in [LiquifyTool::ForwardWarp, LiquifyTool::TwirlCw, LiquifyTool::TwirlCcw, LiquifyTool::Pucker, LiquifyTool::Bloat] {\n assert!(svg(tool_icon(t)).is_some(), \"{t:?}: {}\", tool_icon(t));\n }",
|
||
" assert!(svg(tool_icon(t)).is_some(), \"{t:?}: {}\", tool_icon(t));\n }\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/47aea89e9220b996f0d5a0d2bb8b5938100b4ad1/crates/ui-egui/src/liquify_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "alt_reversed_twirl_survives_replay_undo_and_redo",
|
||
"path": "crates/ui-egui/src/liquify_ui.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked alt_reversed_twirl_survives_replay_undo_and_redo -- --nocapture",
|
||
"fixture_and_action_excerpt": " let ctx = egui::Context::default();\n let mut app = app_with_layer();\n open(&mut app, &ctx).unwrap();\n control(&mut app, &json!({\"tool\": \"twirlCw\", \"size\": 36, \"rate\": 80})).unwrap();\n\n // Releasing Alt while dragging must not change the tool recorded at pointer-down.\n pointer(&mut app, ToolEvent::Down { x: 53.0, y: 40.0, pressure: 1.0 }, egui::Modifiers::ALT);\n pointer(&mut app, ToolEvent::Move { x: 58.0, y: 41.0, pressure: 1.0 }, egui::Modifiers::NONE);\n pointer(&mut app, ToolEvent::Up { x: 58.0, y: 41.0 }, egui::Modifiers::NONE);\n let d = app.distort.liquify.as_ref().unwrap();\n assert_eq!(d.opts.tool, LiquifyTool::TwirlCw, \"Alt must not change the selected tool\");\n assert_eq!(d.strokes.len(), 1);",
|
||
"expected_assertions": [
|
||
" assert_eq!(d.opts.tool, LiquifyTool::TwirlCw, \"Alt must not change the selected tool\");\n assert_eq!(d.strokes.len(), 1);\n assert_eq!(d.strokes[0].tool, LiquifyTool::TwirlCcw);\n assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);",
|
||
" assert_eq!(d.strokes.len(), 1);\n assert_eq!(d.strokes[0].tool, LiquifyTool::TwirlCcw);\n assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n",
|
||
" assert_eq!(d.strokes[0].tool, LiquifyTool::TwirlCcw);\n assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n\n // A following stroke without Alt records the original tool.",
|
||
" assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n\n // A following stroke without Alt records the original tool.\n pointer(&mut app, ToolEvent::Down { x: 70.0, y: 40.0, pressure: 1.0 }, egui::Modifiers::NONE);",
|
||
" assert_eq!(d.strokes.len(), 2);\n assert_eq!(d.strokes[1].tool, LiquifyTool::TwirlCw);\n assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n",
|
||
" assert_eq!(d.strokes[1].tool, LiquifyTool::TwirlCw);\n assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n\n control(&mut app, &json!({\"undo\": true})).unwrap();",
|
||
" assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n\n control(&mut app, &json!({\"undo\": true})).unwrap();\n let d = app.distort.liquify.as_ref().unwrap();",
|
||
" assert_eq!(d.strokes.len(), 1);\n assert_eq!(d.strokes[0].tool, LiquifyTool::TwirlCcw);\n assert_eq!(d.redo[0].tool, LiquifyTool::TwirlCw);\n assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);",
|
||
" assert_eq!(d.strokes[0].tool, LiquifyTool::TwirlCcw);\n assert_eq!(d.redo[0].tool, LiquifyTool::TwirlCw);\n assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n",
|
||
" assert_eq!(d.redo[0].tool, LiquifyTool::TwirlCw);\n assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n\n control(&mut app, &json!({\"redo\": true})).unwrap();",
|
||
" assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n\n control(&mut app, &json!({\"redo\": true})).unwrap();\n let d = app.distort.liquify.as_ref().unwrap();",
|
||
" assert_eq!(d.strokes.len(), 2);\n assert!(d.redo.is_empty());\n assert_eq!(d.strokes[0].tool, LiquifyTool::TwirlCcw);\n assert_eq!(d.strokes[1].tool, LiquifyTool::TwirlCw);",
|
||
" assert!(d.redo.is_empty());\n assert_eq!(d.strokes[0].tool, LiquifyTool::TwirlCcw);\n assert_eq!(d.strokes[1].tool, LiquifyTool::TwirlCw);\n assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);",
|
||
" assert_eq!(d.strokes[0].tool, LiquifyTool::TwirlCcw);\n assert_eq!(d.strokes[1].tool, LiquifyTool::TwirlCw);\n assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n }",
|
||
" assert_eq!(d.strokes[1].tool, LiquifyTool::TwirlCw);\n assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n }",
|
||
" assert_eq!(LiquifyField::from_strokes(d.canvas, d.cell, &d.strokes), d.field);\n }"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/47aea89e9220b996f0d5a0d2bb8b5938100b4ad1/crates/ui-egui/src/liquify_ui.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
},
|
||
{
|
||
"id": "PR-9606",
|
||
"pr": 9606,
|
||
"subsystem": "UI and workflow",
|
||
"fixture_setup": "Use the exact synthetic/temporary fixtures constructed by the listed changed regressions; source links and setup excerpts are retained below.",
|
||
"action": [
|
||
"cargo test -p photocraft-ui-egui --locked color_panel_options_survive_a_restart -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked an_outside_preference_change_reaches_the_live_panel -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked dragging_the_splitter_resizes_and_survives_a_ui_state_round_trip -- --nocapture"
|
||
],
|
||
"expected": "color panel options survive a restart; an outside preference change reaches the live panel; dragging the splitter resizes and survives a ui state round trip",
|
||
"status": "NOT RUN",
|
||
"actual": "",
|
||
"evidence": "",
|
||
"tester": "",
|
||
"test_commands": [
|
||
"cargo test -p photocraft-ui-egui --locked color_panel_options_survive_a_restart -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked an_outside_preference_change_reaches_the_live_panel -- --nocapture",
|
||
"cargo test -p photocraft-ui-egui --locked dragging_the_splitter_resizes_and_survives_a_ui_state_round_trip -- --nocapture"
|
||
],
|
||
"source_regressions": [
|
||
{
|
||
"name": "color_panel_options_survive_a_restart",
|
||
"path": "crates/ui-egui/src/color_panel_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked color_panel_options_survive_a_restart -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut first = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n first.ui.color_panel.mode = ColorPanelMode::HsbSliders;\n first.ui.color_panel.ramp = ColorRamp::GrayscaleRamp;\n crate::color_panel_ui::persist(&mut first);\n let saved = first.session.prefs().clone();\n\n let mut next = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n next.session.prefs.edit(|p| *p = saved);\n crate::color_panel_ui::restore(&mut next);\n assert_eq!((next.ui.color_panel.mode, next.ui.color_panel.ramp), (ColorPanelMode::HsbSliders, ColorRamp::GrayscaleRamp));\n\n let mut fresh = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());",
|
||
"expected_assertions": [
|
||
" assert_eq!((next.ui.color_panel.mode, next.ui.color_panel.ramp), (ColorPanelMode::HsbSliders, ColorRamp::GrayscaleRamp));\n\n let mut fresh = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n crate::color_panel_ui::restore(&mut fresh);",
|
||
" assert_eq!(fresh.ui.color_panel.mode, ColorPanelMode::HueCube, \"no saved options: the default\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/6cc516a3d20120b678040050d95ccadc8d1dfd3f/crates/ui-egui/src/color_panel_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "an_outside_preference_change_reaches_the_live_panel",
|
||
"path": "crates/ui-egui/src/color_panel_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked an_outside_preference_change_reaches_the_live_panel -- --nocapture",
|
||
"fixture_and_action_excerpt": " let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());\n app.ui.color_panel.mode = ColorPanelMode::HsbSliders;\n crate::color_panel_ui::persist(&mut app);\n // As prefs.set or a reset to defaults would: the stored options change under the panel.\n let mut other = app.ui.color_panel;\n other.mode = ColorPanelMode::GrayscaleSlider;\n app.session.prefs.edit(|p| p.color_panel = serde_json::to_value(other).unwrap());\n crate::color_panel_ui::persist(&mut app);\n assert_eq!(app.ui.color_panel.mode, ColorPanelMode::GrayscaleSlider, \"the live panel follows the preference\");\n let stored: crate::state::ColorPanelState = serde_json::from_value(app.session.prefs().color_panel.clone()).unwrap();\n assert_eq!(stored.mode, ColorPanelMode::GrayscaleSlider, \"and the preference isn't overwritten\");\n // A reset to defaults clears the stored options: the panel goes back to its defaults too.",
|
||
"expected_assertions": [
|
||
" assert_eq!(app.ui.color_panel.mode, ColorPanelMode::GrayscaleSlider, \"the live panel follows the preference\");\n let stored: crate::state::ColorPanelState = serde_json::from_value(app.session.prefs().color_panel.clone()).unwrap();\n assert_eq!(stored.mode, ColorPanelMode::GrayscaleSlider, \"and the preference isn't overwritten\");\n // A reset to defaults clears the stored options: the panel goes back to its defaults too.",
|
||
" assert_eq!(stored.mode, ColorPanelMode::GrayscaleSlider, \"and the preference isn't overwritten\");\n // A reset to defaults clears the stored options: the panel goes back to its defaults too.\n app.session.prefs.edit(|p| p.color_panel = serde_json::Value::Null);\n crate::color_panel_ui::persist(&mut app);",
|
||
" assert_eq!(app.ui.color_panel.mode, ColorPanelMode::HueCube, \"reset: the default mode\");\n crate::color_panel_ui::persist(&mut app);\n assert_eq!(app.ui.color_panel.mode, ColorPanelMode::HueCube, \"and it stays reset\");\n}",
|
||
" assert_eq!(app.ui.color_panel.mode, ColorPanelMode::HueCube, \"and it stays reset\");\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/6cc516a3d20120b678040050d95ccadc8d1dfd3f/crates/ui-egui/src/color_panel_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
},
|
||
{
|
||
"name": "dragging_the_splitter_resizes_and_survives_a_ui_state_round_trip",
|
||
"path": "crates/ui-egui/src/dock_tests.rs",
|
||
"package": "photocraft-ui-egui",
|
||
"command": "cargo test -p photocraft-ui-egui --locked dragging_the_splitter_resizes_and_survives_a_ui_state_round_trip -- --nocapture",
|
||
"fixture_and_action_excerpt": " let (mut app, _, _) = app_with_layers();\n // CodeRabbit on #9606: the Color panel's options ride the same frames and preferences.\n app.ui.color_panel.mode = crate::state::ColorPanelMode::HsbSliders;\n let mut h = harness(app, vec2(1200.0, 800.0), ThemeKind::ProMedium);\n let props = rect_of(&h, Group::Properties);\n let color = rect_of(&h, Group::Color);\n let split = probe::hit_rect(&h.ctx, &craft_ui::docking::Hit::Divider(craft_ui::docking::Divider::Group(\"properties\".into())))\n .expect(\"divider below Properties\")\n .center();\n // Less than Properties has above its minimum, so the groups above don't give way.\n drag(&mut h, split, split - vec2(0.0, 40.0));\n let props2 = rect_of(&h, Group::Properties);",
|
||
"expected_assertions": [
|
||
" assert!((props2.height() - (props.height() - 40.0)).abs() < 2.0, \"{props:?} -> {props2:?}\");\n assert_eq!(rect_of(&h, Group::Color), color, \"the group above keeps its place\");\n\n // Save and restore the UI state (what `ui.inspect` / `ui.set` and workspaces carry).",
|
||
" assert_eq!(rect_of(&h, Group::Color), color, \"the group above keeps its place\");\n\n // Save and restore the UI state (what `ui.inspect` / `ui.set` and workspaces carry).\n let saved = serde_json::to_value(&h.state().ui).unwrap();",
|
||
" assert_eq!(drawn(&h2).0, drawn(&h).0);\n\n // Remembered in the preferences once the mouse is up, and restored at the next launch.\n let prefs = h.state().session.prefs_to_json();",
|
||
" assert!(app3.ui.docking.is_some());\n assert_eq!(app3.ui.docking.as_ref().map(|w| &w.layout), h.state().ui.docking.as_ref().map(|w| &w.layout));\n crate::color_panel_ui::restore(&mut app3);\n assert_eq!(app3.ui.color_panel.mode, crate::state::ColorPanelMode::HsbSliders, \"the Color panel's mode too\");",
|
||
" assert_eq!(app3.ui.docking.as_ref().map(|w| &w.layout), h.state().ui.docking.as_ref().map(|w| &w.layout));\n crate::color_panel_ui::restore(&mut app3);\n assert_eq!(app3.ui.color_panel.mode, crate::state::ColorPanelMode::HsbSliders, \"the Color panel's mode too\");\n // …unless Remember Workspace Changes is off.",
|
||
" assert_eq!(app3.ui.color_panel.mode, crate::state::ColorPanelMode::HsbSliders, \"the Color panel's mode too\");\n // …unless Remember Workspace Changes is off.\n let mut s3 = photocraft_engine::Session::new();\n s3.load_prefs_json(&prefs).unwrap();",
|
||
" assert!(app4.ui.docking.is_none());\n assert_eq!(app4.ui.dock, DockLayout::default());\n}",
|
||
" assert_eq!(app4.ui.dock, DockLayout::default());\n}"
|
||
],
|
||
"reviewed_source": "https://github.com/storytold/photocraft/blob/6cc516a3d20120b678040050d95ccadc8d1dfd3f/crates/ui-egui/src/dock_tests.rs",
|
||
"ignored_requires_explicit_execution": false
|
||
}
|
||
],
|
||
"tested_sha": ""
|
||
}
|
||
]
|
||
}
|