mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-26 10:57:20 -06:00
`ui.dialog.set` can store any JSON in the dialog's `__variables` field, and the Define and Data Sets pages write fields into its entries (`d["name"] = …`, `set["name"] = …`), which panics when an entry is a number or a string. The dialog now normalizes the state each frame, keeping only object entries in `defs`, `dataSets` and each set's `values`.
92 lines
3.6 KiB
Rust
92 lines
3.6 KiB
Rust
use egui_kittest::Harness;
|
|
use egui_kittest::kittest::Queryable;
|
|
use photocraft_ui_egui::PhotocraftApp;
|
|
use photocraft_ui_egui::state::DialogKind;
|
|
use serde_json::{Map, json};
|
|
|
|
fn app_with_variables_dialog(cur: u64) -> PhotocraftApp {
|
|
let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), photocraft_ui_egui::Services::default());
|
|
app.run("file.new", json!({"width": 64, "height": 64})).unwrap();
|
|
app.run("layer.new.layer", json!({})).unwrap();
|
|
let state = json!({
|
|
"defs": [{
|
|
"name": "v1",
|
|
"layer": 0,
|
|
"type": "visibility",
|
|
"method": "fit",
|
|
"align": "center",
|
|
"clip": false
|
|
}],
|
|
"dataSets": [{"name": "A", "values": []}]
|
|
});
|
|
let mut fields = Map::new();
|
|
fields.insert("__variables".into(), state);
|
|
fields.insert("__page".into(), json!("dataSets"));
|
|
fields.insert("__cur".into(), json!(cur));
|
|
app.ui.open_dialog(DialogKind::Command, fields);
|
|
app
|
|
}
|
|
|
|
fn harness(app: PhotocraftApp) -> Harness<'static, PhotocraftApp> {
|
|
let mut h = Harness::builder().with_size(egui::vec2(900.0, 700.0)).build_ui_state(
|
|
|ui, app: &mut PhotocraftApp| {
|
|
let ctx = ui.ctx().clone();
|
|
if !ctx.fonts(|f| f.families().contains(&egui::FontFamily::Name("medium".into()))) {
|
|
return;
|
|
}
|
|
photocraft_ui_egui::dialogs::show(app, &ctx);
|
|
},
|
|
app,
|
|
);
|
|
PhotocraftApp::setup_context(&h.ctx, photocraft_ui_egui::theme::ThemeKind::ALL[0]);
|
|
h.run_steps(3);
|
|
h
|
|
}
|
|
|
|
#[test]
|
|
fn out_of_range_data_set_index_does_not_overflow_during_render() {
|
|
let mut h = harness(app_with_variables_dialog(u64::MAX));
|
|
h.run_steps(2);
|
|
}
|
|
|
|
#[test]
|
|
fn out_of_range_data_set_index_is_clamped_before_delete() {
|
|
let mut h = harness(app_with_variables_dialog(999));
|
|
h.get_by_label("Delete").click();
|
|
h.run_steps(2);
|
|
}
|
|
|
|
/// `ui.dialog.set` can store any JSON in `__variables`; the editors write into its entries.
|
|
fn app_with_malformed_variables(page: &str) -> PhotocraftApp {
|
|
let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), photocraft_ui_egui::Services::default());
|
|
app.run("file.new", json!({"width": 64, "height": 64})).unwrap();
|
|
app.run("layer.new.layer", json!({})).unwrap();
|
|
let mut fields = Map::new();
|
|
fields.insert(
|
|
"__variables".into(),
|
|
json!({"defs": [42, {"name": "v1", "layer": 0, "type": "textReplacement"}], "dataSets": ["bad", {"name": "A", "values": [7, "x"]}, {"name": "B", "values": "nope"}]}),
|
|
);
|
|
fields.insert("__page".into(), json!(page));
|
|
app.ui.open_dialog(DialogKind::Command, fields);
|
|
app
|
|
}
|
|
|
|
fn type_into_first_text_field(h: &mut Harness<'static, PhotocraftApp>) {
|
|
h.query_all_by_role(egui::accesskit::Role::TextInput).next().expect("a text field").click();
|
|
h.run_steps(2);
|
|
h.query_all_by_role(egui::accesskit::Role::TextInput).next().expect("a text field").type_text("z");
|
|
h.run_steps(2);
|
|
}
|
|
|
|
#[test]
|
|
fn malformed_variable_entries_are_dropped_before_an_edit() {
|
|
for page in ["define", "dataSets"] {
|
|
let mut h = harness(app_with_malformed_variables(page));
|
|
type_into_first_text_field(&mut h);
|
|
let state = &h.state().ui.dialogs.last().unwrap().fields["__variables"];
|
|
assert_eq!(state["defs"].as_array().unwrap().len(), 1, "{page}: {state}");
|
|
assert_eq!(state["dataSets"].as_array().unwrap().len(), 2, "{page}: {state}");
|
|
assert!(state["dataSets"].as_array().unwrap().iter().all(|s| s["values"].as_array().unwrap().iter().all(|v| v.is_object())), "{page}: {state}");
|
|
}
|
|
}
|