diff options
Diffstat (limited to 'rust/crates/timeline/tests/split.rs')
| -rw-r--r-- | rust/crates/timeline/tests/split.rs | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/rust/crates/timeline/tests/split.rs b/rust/crates/timeline/tests/split.rs new file mode 100644 index 00000000..ee9d4558 --- /dev/null +++ b/rust/crates/timeline/tests/split.rs @@ -0,0 +1,187 @@ +use scene::{ + BaseTimelineElement, Element, ElementRef, ParamValue, ParamValues, RetimeConfig, SceneTracks, + Track, VideoElement, +}; +use time::MediaTime; +use timeline::split::{RetainSide, split_elements}; + +fn seconds(value: f64) -> MediaTime { + MediaTime::from_seconds_f64(value).unwrap() +} + +fn build_video_element(id: &str, duration: MediaTime, retime: Option<RetimeConfig>) -> Element { + Element::Video(VideoElement { + base: BaseTimelineElement { + id: id.to_string(), + name: id.to_string(), + start_time: MediaTime::ZERO, + duration, + trim_start: MediaTime::ZERO, + trim_end: MediaTime::ZERO, + source_duration: None, + animations: None, + params: ParamValues::from([ + ("transform.positionX".to_string(), ParamValue::Number(0.0)), + ("transform.positionY".to_string(), ParamValue::Number(0.0)), + ("transform.scaleX".to_string(), ParamValue::Number(1.0)), + ("transform.scaleY".to_string(), ParamValue::Number(1.0)), + ("transform.rotate".to_string(), ParamValue::Number(0.0)), + ("opacity".to_string(), ParamValue::Number(1.0)), + ]), + }, + media_id: format!("media-{id}"), + is_source_audio_enabled: None, + hidden: None, + retime, + effects: None, + masks: None, + }) +} + +fn seed_tracks(element: Element) -> (SceneTracks, ElementRef) { + let reference = ElementRef { + track_id: "main-track".to_string(), + element_id: element.base().id.clone(), + }; + ( + SceneTracks { + overlay: Vec::new(), + main: Track::Video { + id: "main-track".to_string(), + name: "Main Track".to_string(), + elements: vec![element], + muted: false, + hidden: false, + }, + audio: Vec::new(), + }, + reference, + ) +} + +#[test] +fn split_produces_left_and_right_halves_with_shifted_trims() { + let (tracks, reference) = seed_tracks(build_video_element("video-1", seconds(10.0), None)); + + let result = split_elements(&tracks, &[reference], seconds(4.0), RetainSide::Both); + + assert_eq!(result.right_side_elements.len(), 1); + let elements = result.tracks.main.elements(); + assert_eq!(elements.len(), 2); + + let left = &elements[0]; + assert_eq!(left.base().id, "video-1"); + assert_eq!(left.base().name, "video-1 (left)"); + assert_eq!(left.base().start_time, MediaTime::ZERO); + assert_eq!(left.base().duration, seconds(4.0)); + assert_eq!(left.base().trim_start, MediaTime::ZERO); + assert_eq!(left.base().trim_end, seconds(6.0)); + + let right = &elements[1]; + assert_eq!(right.base().id, result.right_side_elements[0].element_id); + assert_eq!(right.base().name, "video-1 (right)"); + assert_eq!(right.base().start_time, seconds(4.0)); + assert_eq!(right.base().duration, seconds(6.0)); + assert_eq!(right.base().trim_start, seconds(4.0)); + assert_eq!(right.base().trim_end, MediaTime::ZERO); +} + +#[test] +fn split_scales_source_spans_by_the_retime_rate() { + let retime = RetimeConfig { + rate: 2.0, + maintain_pitch: None, + }; + let (tracks, reference) = + seed_tracks(build_video_element("video-1", seconds(10.0), Some(retime))); + + let result = split_elements(&tracks, &[reference], seconds(4.0), RetainSide::Both); + + let elements = result.tracks.main.elements(); + let left = &elements[0]; + let right = &elements[1]; + assert_eq!(left.base().trim_end, seconds(12.0)); + assert_eq!(right.base().trim_start, seconds(8.0)); + assert_eq!( + left.base().trim_start + left.base().duration * 2 + left.base().trim_end, + right.base().trim_start + right.base().duration * 2 + right.base().trim_end + ); + assert_eq!(timeline::element_retime(left), Some(retime)); + assert_eq!(timeline::element_retime(right), Some(retime)); +} + +#[test] +fn retain_left_keeps_only_the_left_half() { + let (tracks, reference) = seed_tracks(build_video_element("video-1", seconds(10.0), None)); + + let result = split_elements(&tracks, &[reference], seconds(4.0), RetainSide::Left); + + assert_eq!(result.right_side_elements.len(), 0); + let elements = result.tracks.main.elements(); + assert_eq!(elements.len(), 1); + assert_eq!(elements[0].base().id, "video-1"); + assert_eq!(elements[0].base().duration, seconds(4.0)); + assert_eq!(elements[0].base().trim_end, seconds(6.0)); +} + +#[test] +fn retain_right_keeps_only_the_right_half_with_a_new_id() { + let (tracks, reference) = seed_tracks(build_video_element("video-1", seconds(10.0), None)); + + let result = split_elements(&tracks, &[reference], seconds(4.0), RetainSide::Right); + + assert_eq!(result.right_side_elements.len(), 1); + let elements = result.tracks.main.elements(); + assert_eq!(elements.len(), 1); + let right = &elements[0]; + assert_ne!(right.base().id, "video-1"); + assert_eq!(right.base().id, result.right_side_elements[0].element_id); + assert_eq!(right.base().start_time, seconds(4.0)); + assert_eq!(right.base().duration, seconds(6.0)); + assert_eq!(right.base().trim_start, seconds(4.0)); +} + +#[test] +fn split_outside_the_element_bounds_is_a_no_op() { + let (tracks, reference) = seed_tracks(build_video_element("video-1", seconds(10.0), None)); + + for split_time in [MediaTime::ZERO, seconds(10.0), seconds(12.0)] { + let result = split_elements( + &tracks, + std::slice::from_ref(&reference), + split_time, + RetainSide::Both, + ); + assert_eq!(result.right_side_elements.len(), 0); + assert_eq!(result.tracks.main.elements().len(), 1); + assert_eq!( + result.tracks.main.elements()[0].base().duration, + seconds(10.0) + ); + } +} + +#[test] +fn shifting_the_right_side_and_inserting_into_the_gap_keeps_layout_consistent() { + let (tracks, reference) = seed_tracks(build_video_element("video-1", seconds(10.0), None)); + + let result = split_elements(&tracks, &[reference], seconds(4.0), RetainSide::Both); + let right_ref = result.right_side_elements[0].clone(); + + let shifted = timeline::update_element_in_scene_tracks( + &result.tracks, + &right_ref.track_id, + &right_ref.element_id, + |element| { + let mut next = element.clone(); + next.base_mut().start_time = element.base().start_time + seconds(3.0); + next + }, + None, + ); + + let elements = shifted.main.elements(); + assert_eq!(elements[0].base().duration, seconds(4.0)); + assert_eq!(elements[1].base().start_time, seconds(7.0)); + assert_eq!(elements[1].base().duration, seconds(6.0)); +} |
