Files
effectcraft/crates/engine/src/tests_key_metadata_order.rs
T

114 lines
4.8 KiB
Rust

//! Key attributes preserve the order used by the next stagger gesture.
use std::sync::Arc;
use effectcraft_keyframe::Interp;
use effectcraft_project::LayerId;
use serde_json::json;
use crate::{KeyRef, Session, time::FrameRate};
fn setup() -> (Session, u64) {
let mut s = Session::default();
s.execute_checked("comp.new", json!({"width": 64, "height": 64, "frameRate": 30, "duration": 4})).unwrap();
let layer = s.execute_checked("layer.newSolid", json!({"name": "Box", "color": "#fff"})).unwrap()["layer"].as_u64().unwrap();
(s, layer)
}
fn add(s: &mut Session, layer: u64, path: &str, time: i64, value: serde_json::Value) {
s.execute_checked("prop.addKey", json!({"layer": layer, "path": path, "time": time, "value": value})).unwrap();
}
fn uid(s: &Session, layer: u64, path: &str) -> u64 {
s.active_comp().unwrap().layer(LayerId(layer)).unwrap().props.prop(path).unwrap().uid
}
fn key(layer: u64, prop: u64, frame: i64) -> KeyRef {
KeyRef { layer: LayerId(layer), prop, time: FrameRate::FPS_30.tick_of(frame) }
}
#[test]
fn easing_preserves_interleaved_layer_and_property_order_with_one_undo() {
let (mut s, first) = setup();
let second = s.execute_checked("layer.newSolid", json!({"name": "Other", "color": "#fff"})).unwrap()["layer"].as_u64().unwrap();
for layer in [first, second] {
for time in [0, 1] {
add(&mut s, layer, "transform/opacity", time, json!(time * 25));
}
}
add(&mut s, first, "transform/position", 1, json!([10, 20]));
let a = uid(&s, first, "transform/opacity");
let b = uid(&s, second, "transform/opacity");
let position = uid(&s, first, "transform/position");
s.execute_checked(
"keys.select",
json!({"keys": [
{"layer": second, "prop": b, "time": 1},
{"layer": first, "prop": position, "time": 1},
{"layer": first, "prop": a, "time": 0},
{"layer": second, "prop": b, "time": 0}
]}),
)
.unwrap();
let order = s.state.selected_keys.clone();
let before = s.project.clone();
s.history.clear();
s.execute_checked("keys.easyEase", json!({})).unwrap();
assert_eq!(s.state.selected_keys, order);
assert_eq!(s.history.undo.len(), 1);
for selected in &order {
let keys = &s.active_comp().unwrap().layer(selected.layer).unwrap().props.find(selected.prop).unwrap().keys;
assert_eq!(keys.iter().find(|k| k.time == selected.time).unwrap().out_interp, Interp::Bezier);
}
s.execute_checked("edit.undo", json!({})).unwrap();
assert!(Arc::ptr_eq(&s.project, &before));
assert_eq!(s.state.selected_keys, order);
}
#[test]
fn roving_keeps_the_selected_key_identity_and_arbitrary_order() {
let (mut s, layer) = setup();
for (time, x) in [(0, 0), (1, 25), (2, 100)] {
add(&mut s, layer, "transform/position", time, json!([x, 0]));
}
let prop = uid(&s, layer, "transform/position");
s.execute_checked(
"keys.select",
json!({"keys": [
{"layer": layer, "prop": prop, "time": 1},
{"layer": layer, "prop": prop, "time": 2},
{"layer": layer, "prop": prop, "time": 0}
]}),
)
.unwrap();
s.execute_checked("keys.interpolation", json!({"roving": true})).unwrap();
assert_eq!(s.state.selected_keys, vec![key(layer, prop, 15), key(layer, prop, 60), key(layer, prop, 0)]);
let position = s.active_comp().unwrap().layer(LayerId(layer)).unwrap().props.find(prop).unwrap();
assert_eq!(position.keys[1].value.as_vec2(), [25.0, 0.0]);
assert_eq!(position.keys[1].time, FrameRate::FPS_30.tick_of(15));
assert!(position.keys[1].roving);
assert!(!position.keys[0].roving && !position.keys[2].roving);
}
#[test]
fn attribute_edit_deduplicates_legacy_refs_and_drops_stale_refs_without_snapping() {
let (mut s, layer) = setup();
for time in [0, 1] {
add(&mut s, layer, "transform/opacity", time, json!(20));
}
let prop = uid(&s, layer, "transform/opacity");
let first = key(layer, prop, 0);
let second = key(layer, prop, 30);
s.state.selected_keys = vec![second, key(layer, prop, 10), first, second, key(layer, u64::MAX, 0), first, key(u64::MAX, prop, 0)];
s.history.clear();
let result = s.execute_checked("keys.toggleHold", json!({})).unwrap();
assert_eq!(result, json!(2));
assert_eq!(s.state.selected_keys, vec![second, first]);
assert_eq!(s.history.undo.len(), 1);
let opacity = s.active_comp().unwrap().layer(LayerId(layer)).unwrap().props.find(prop).unwrap();
assert!(opacity.keys.iter().all(|k| k.out_interp == Interp::Hold));
s.execute_checked("edit.undo", json!({})).unwrap();
let opacity = s.active_comp().unwrap().layer(LayerId(layer)).unwrap().props.find(prop).unwrap();
assert!(opacity.keys.iter().all(|k| k.out_interp == Interp::Linear));
}