mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-19 03:15:19 +02:00
* Tests: bad-layer-id checks use an id that can't exist (#3343) Layer ids come from one process-wide counter (shared with document and smart-object ids, and bumped by ensure_ids_above on file loads). A full `cargo test` run passes ids like 9999, so a layer a test just created can get the "bad" id, the command succeeds and the assertion fails at random (seen on CI in type_extra_cmds::tests::vertical_orientation_renders_columns_inside_the_canvas). Use u64::MAX, which the counter never reaches, for every "no such layer" sentinel in the engine and ui-egui tests. Test-only change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tests: use u64::MAX for bad-layer-id sentinels added on main since (#3343) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
75 lines
3.6 KiB
Rust
75 lines
3.6 KiB
Rust
//! A command that documents `"layer":id` checks its precondition on that layer, not on whichever
|
|
//! layer happens to be active (#466 for smart filters, generalised): a script, action or agent can
|
|
//! Replace Contents or Rasterize a smart object while another layer is selected.
|
|
|
|
use photocraft_doc::{LayerContent, LayerId};
|
|
use photocraft_engine::{EngineError, Session};
|
|
use photocraft_geom::Rect;
|
|
use serde_json::json;
|
|
|
|
/// A smart object (blue) under a plain pixel layer, which is active.
|
|
fn session() -> (Session, u64, u64) {
|
|
let mut s = Session::new();
|
|
s.execute("file.new", json!({"width": 8, "height": 6})).unwrap();
|
|
s.execute("layer.new.layer", json!({})).unwrap();
|
|
s.edit("paint", |doc, active| {
|
|
doc.layer_mut(active.unwrap()).unwrap().surface_mut().unwrap().fill_rect(Rect::new(0, 0, 8, 6), &[0.0, 0.0, 1.0, 1.0]);
|
|
Ok(())
|
|
})
|
|
.unwrap();
|
|
let so = s.execute("layer.smartObjects.convertToSmartObject", json!({})).unwrap()["layer"].as_u64().unwrap();
|
|
let pixels = s.execute("layer.new.layer", json!({})).unwrap()["layer"].as_u64().unwrap();
|
|
(s, so, pixels)
|
|
}
|
|
|
|
fn active(s: &Session) -> u64 {
|
|
s.active().unwrap().active_layer.unwrap().0
|
|
}
|
|
|
|
fn kind(s: &Session, id: u64) -> &'static str {
|
|
s.active().unwrap().doc.layer(LayerId(id)).unwrap().content.kind_name()
|
|
}
|
|
|
|
#[test]
|
|
fn smart_object_commands_act_on_a_named_layer_while_another_is_active() {
|
|
let (mut s, so, pixels) = session();
|
|
assert_eq!(active(&s), pixels);
|
|
// Without "layer" the active pixel layer decides, as the menus show.
|
|
assert!(!s.is_enabled("layer.smartObjects.replaceContents"));
|
|
// Replace Contents on the named smart object.
|
|
let dir = std::env::temp_dir().join(format!("pcraft-explicit-layer-{}", std::process::id()));
|
|
std::fs::create_dir_all(&dir).unwrap();
|
|
let png = dir.join("red.png");
|
|
let red = photocraft_doc::Document::with_background(
|
|
"r",
|
|
photocraft_geom::Size::new(8, 6),
|
|
photocraft_color::ColorMode::Rgb,
|
|
photocraft_color::SampleType::U8,
|
|
photocraft_color::Color::rgba(1.0, 0.0, 0.0, 1.0),
|
|
);
|
|
std::fs::write(&png, photocraft_io::export(&red, "png", &Default::default()).unwrap().bytes).unwrap();
|
|
s.execute("layer.smartObjects.replaceContents", json!({"layer": so, "path": png.to_str().unwrap()})).unwrap();
|
|
std::fs::remove_dir_all(&dir).ok();
|
|
let LayerContent::Smart(sm) = &s.active().unwrap().doc.layer(LayerId(so)).unwrap().content else { panic!("smart object") };
|
|
assert_eq!(sm.cache.as_ref().unwrap().rgba(2, 2), [1.0, 0.0, 0.0, 1.0], "the named smart object was replaced");
|
|
assert_eq!(active(&s), pixels, "the active layer stays");
|
|
// Rasterize it, still without selecting it.
|
|
s.execute("layer.rasterize.smartObject", json!({"layer": so})).unwrap();
|
|
assert_eq!(kind(&s, so), "Pixel");
|
|
assert_eq!(active(&s), pixels);
|
|
}
|
|
|
|
#[test]
|
|
fn a_named_layer_of_the_wrong_kind_or_that_does_not_exist_is_refused() {
|
|
let (mut s, _so, pixels) = session();
|
|
let before = s.active().unwrap().doc.clone();
|
|
// The named layer is checked: a pixel layer is not a smart object.
|
|
let r = s.execute("layer.smartObjects.rasterize", json!({"layer": pixels}));
|
|
assert!(matches!(r, Err(EngineError::Disabled(..))), "{r:?}");
|
|
// A layer that doesn't exist falls back to the active layer's check, and still fails.
|
|
assert!(s.execute("layer.smartObjects.rasterize", json!({"layer": u64::MAX})).is_err());
|
|
assert!(s.execute("layer.smartObjects.rasterize", json!({"layer": "nope"})).is_err());
|
|
assert_eq!(s.active().unwrap().doc, before);
|
|
assert_eq!(active(&s), pixels);
|
|
}
|