summaryrefslogtreecommitdiff
path: root/rust/crates/commands/tests/freeze_frame.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/crates/commands/tests/freeze_frame.rs')
-rw-r--r--rust/crates/commands/tests/freeze_frame.rs155
1 files changed, 155 insertions, 0 deletions
diff --git a/rust/crates/commands/tests/freeze_frame.rs b/rust/crates/commands/tests/freeze_frame.rs
new file mode 100644
index 00000000..614b73f7
--- /dev/null
+++ b/rust/crates/commands/tests/freeze_frame.rs
@@ -0,0 +1,155 @@
+mod common;
+
+use commands::{
+ BatchCommand, Command, InsertElementCommand, InsertElementPlacement, RetainSide,
+ ShiftSplitRemainderCommand, SplitElementsCommand,
+};
+use common::{
+ FREEZE_SECONDS, SPLIT_SECONDS, VIDEO_SECONDS, build_freeze_image_element, seconds,
+ seed_project_with_video,
+};
+use scene::{Element, ElementRef, Project};
+use time::MediaTime;
+
+fn build_freeze_batch(track_id: &str) -> BatchCommand {
+ let split = SplitElementsCommand::new(
+ vec![ElementRef {
+ track_id: track_id.to_string(),
+ element_id: "video-1".to_string(),
+ }],
+ seconds(SPLIT_SECONDS),
+ RetainSide::Both,
+ );
+ let right_side = split.right_side_handle();
+ let shift = ShiftSplitRemainderCommand::new(
+ right_side,
+ seconds(SPLIT_SECONDS) + seconds(FREEZE_SECONDS),
+ );
+ let insert = InsertElementCommand::new(
+ build_freeze_image_element(),
+ InsertElementPlacement::Explicit {
+ track_id: track_id.to_string(),
+ },
+ );
+ BatchCommand::new(vec![Box::new(split), Box::new(shift), Box::new(insert)])
+}
+
+fn sorted_main_elements(project: &Project) -> Vec<Element> {
+ let scene = project
+ .scenes
+ .iter()
+ .find(|scene| scene.id == project.current_scene_id)
+ .expect("active scene");
+ let mut elements = scene.tracks.main.elements().to_vec();
+ elements.sort_by_key(|element| element.base().start_time);
+ elements
+}
+
+fn element_type_name(element: &Element) -> &'static str {
+ match element {
+ Element::Video(_) => "video",
+ Element::Image(_) => "image",
+ Element::Text(_) => "text",
+ Element::Audio(_) => "audio",
+ Element::Sticker(_) => "sticker",
+ Element::Graphic(_) => "graphic",
+ Element::Effect(_) => "effect",
+ }
+}
+
+#[test]
+fn splits_shifts_right_side_and_inserts_into_gap() {
+ let (mut project, track_id) = seed_project_with_video();
+
+ build_freeze_batch(&track_id)
+ .execute(&mut project)
+ .expect("execute");
+
+ let elements = sorted_main_elements(&project);
+ let type_names: Vec<&str> = elements.iter().map(element_type_name).collect();
+ assert_eq!(type_names, ["video", "image", "video"]);
+
+ let [left, image, right] = &elements[..] else {
+ panic!("expected three elements");
+ };
+ assert_eq!(left.base().start_time, MediaTime::ZERO);
+ assert_eq!(left.base().duration, seconds(SPLIT_SECONDS));
+ assert_eq!(image.base().start_time, seconds(SPLIT_SECONDS));
+ assert_eq!(image.base().duration, seconds(FREEZE_SECONDS));
+ assert_eq!(
+ right.base().start_time,
+ seconds(SPLIT_SECONDS) + seconds(FREEZE_SECONDS)
+ );
+ assert_eq!(
+ right.base().duration,
+ seconds(VIDEO_SECONDS - SPLIT_SECONDS)
+ );
+}
+
+#[test]
+fn undo_restores_original_element_as_single_step() {
+ let (mut project, track_id) = seed_project_with_video();
+ let mut batch = build_freeze_batch(&track_id);
+
+ batch.execute(&mut project).expect("execute");
+ batch.undo(&mut project);
+
+ let scene = project
+ .scenes
+ .iter()
+ .find(|scene| scene.id == project.current_scene_id)
+ .expect("active scene");
+ let elements = scene.tracks.main.elements();
+ assert_eq!(elements.len(), 1);
+ assert_eq!(elements[0].base().id, "video-1");
+ assert_eq!(elements[0].base().start_time, MediaTime::ZERO);
+ assert_eq!(elements[0].base().duration, seconds(VIDEO_SECONDS));
+}
+
+#[test]
+fn redo_after_undo_reapplies_shift_to_resplit_elements() {
+ let (mut project, track_id) = seed_project_with_video();
+ let mut batch = build_freeze_batch(&track_id);
+
+ batch.execute(&mut project).expect("execute");
+ batch.undo(&mut project);
+ batch.redo(&mut project).expect("redo");
+
+ let elements = sorted_main_elements(&project);
+ let type_names: Vec<&str> = elements.iter().map(element_type_name).collect();
+ assert_eq!(type_names, ["video", "image", "video"]);
+
+ let right = elements.last().expect("right element");
+ assert!(matches!(right, Element::Video(_)));
+ assert_eq!(
+ right.base().start_time,
+ seconds(SPLIT_SECONDS) + seconds(FREEZE_SECONDS)
+ );
+}
+
+#[test]
+fn no_op_when_split_produces_no_right_side() {
+ let (mut project, track_id) = seed_project_with_video();
+
+ let split = SplitElementsCommand::new(
+ vec![ElementRef {
+ track_id: track_id.to_string(),
+ element_id: "video-1".to_string(),
+ }],
+ MediaTime::ZERO,
+ RetainSide::Both,
+ );
+ let right_side = split.right_side_handle();
+ let shift = ShiftSplitRemainderCommand::new(right_side, seconds(FREEZE_SECONDS));
+ let mut batch = BatchCommand::new(vec![Box::new(split), Box::new(shift)]);
+
+ batch.execute(&mut project).expect("execute");
+ batch.undo(&mut project);
+
+ let scene = project
+ .scenes
+ .iter()
+ .find(|scene| scene.id == project.current_scene_id)
+ .expect("active scene");
+ assert_eq!(scene.tracks.main.elements().len(), 1);
+}