use tellers_timeline_core::{Item, MediaReference, Timeline};
fn timeline_json(schema: &str, extra_fields: &str) -> String {
format!(
r#"{{
"OTIO_SCHEMA": "Timeline.1",
"name": "SEQ",
"tracks": {{
"OTIO_SCHEMA": "Stack.1",
"name": "tracks",
"children": [{{
"OTIO_SCHEMA": "Track.1",
"name": "V1",
"kind": "Video",
"children": [{{
"OTIO_SCHEMA": "Clip.2",
"name": "A001C001",
"active_media_reference_key": "DEFAULT_MEDIA",
"media_references": {{
"DEFAULT_MEDIA": {{
"OTIO_SCHEMA": "{schema}",
"name": "A001C001",
{extra_fields}
"metadata": {{ "media_id": "asset-1" }}
}}
}},
"source_range": {{
"OTIO_SCHEMA": "TimeRange.1",
"start_time": {{
"OTIO_SCHEMA": "RationalTime.1",
"rate": 25.0, "value": 0.0
}},
"duration": {{
"OTIO_SCHEMA": "RationalTime.1",
"rate": 25.0, "value": 100.0
}}
}}
}}]
}}]
}}
}}"#
)
}
fn only_reference(timeline: &Timeline) -> &MediaReference {
let track = &timeline.tracks.children[0];
let Item::Clip(clip) = &track.items[0] else {
panic!("expected a clip");
};
clip.media_references
.values()
.next()
.expect("clip keeps its media reference")
}
#[test]
fn missing_reference_parses_as_an_empty_external_reference() {
let json = timeline_json("MissingReference.1", "");
let timeline: Timeline = serde_json::from_str(&json).expect("MissingReference is accepted");
match only_reference(&timeline) {
MediaReference::ExternalReference { target_url, .. } => {
assert_eq!(target_url, "", "no media to point at yet");
}
other => panic!("expected an external reference, got {other:?}"),
}
}
#[test]
fn missing_reference_keeps_the_metadata_that_links_it_to_an_asset() {
let json = timeline_json("MissingReference.1", "");
let timeline: Timeline = serde_json::from_str(&json).unwrap();
let MediaReference::ExternalReference { metadata, .. } = only_reference(&timeline) else {
panic!("expected an external reference");
};
assert_eq!(metadata["media_id"], "asset-1");
}
#[test]
fn missing_reference_re_serializes_as_an_external_reference() {
let json = timeline_json("MissingReference.1", "");
let timeline: Timeline = serde_json::from_str(&json).unwrap();
let out = serde_json::to_string(&timeline).unwrap();
assert!(out.contains("ExternalReference.1"));
assert!(!out.contains("MissingReference.1"));
}
#[test]
fn an_ordinary_external_reference_is_untouched() {
let json = timeline_json("ExternalReference.1", r#""target_url": "s3://bucket/a.mxf","#);
let timeline: Timeline = serde_json::from_str(&json).unwrap();
match only_reference(&timeline) {
MediaReference::ExternalReference { target_url, .. } => {
assert_eq!(target_url, "s3://bucket/a.mxf");
}
other => panic!("expected an external reference, got {other:?}"),
}
}
#[test]
fn a_genuinely_unknown_reference_schema_is_still_rejected() {
let json = timeline_json("SomeFutureReference.1", "");
let result: Result<Timeline, _> = serde_json::from_str(&json);
assert!(
result.is_err(),
"only MissingReference is aliased; anything else should still fail loudly"
);
}
#[test]
fn image_sequence_reference_is_still_rejected() {
let json = timeline_json("ImageSequenceReference.1", "");
let result: Result<Timeline, _> = serde_json::from_str(&json);
assert!(result.is_err());
}