use super::*;
use crate::model::HistoryEntry;
fn history(id: &str) -> HistoryEntry {
HistoryEntry {
id: id.to_owned(),
..Default::default()
}
}
fn chain1_clips() -> Vec<Clip> {
vec![
Clip {
id: "40068b49".into(),
title: "Zac and the Sea Eagles (Lullaby Version)".into(),
clip_type: "upsample".into(),
task: "upsample".into(),
is_remix: true,
upsample_clip_id: "52962dae".into(),
edited_clip_id: "52962dae".into(),
..Default::default()
},
Clip {
id: "52962dae".into(),
title: "Zac and the Sea Eagles (Edit) (Remastered)".into(),
clip_type: "gen".into(),
task: "cover".into(),
is_remix: true,
cover_clip_id: "536e1b92".into(),
edited_clip_id: "536e1b92".into(),
..Default::default()
},
Clip {
id: "536e1b92".into(),
title: "Zac and the Sea Eagles (Edit) (Remastered)".into(),
clip_type: "upsample".into(),
task: "upsample".into(),
is_remix: true,
upsample_clip_id: "b9f27ee1".into(),
edited_clip_id: "b9f27ee1".into(),
..Default::default()
},
Clip {
id: "b9f27ee1".into(),
title: "Zac and the Sea Eagles (Edit)".into(),
clip_type: "gen".into(),
task: "cover".into(),
is_remix: true,
cover_clip_id: "c1997d52".into(),
edited_clip_id: "c1997d52".into(),
..Default::default()
},
Clip {
id: "c1997d52".into(),
title: "Zac and the Sea Eagles (Rework)".into(),
clip_type: "edit_v3_export".into(),
edited_clip_id: "dfb59a04".into(),
..Default::default()
},
Clip {
id: "dfb59a04".into(),
title: "Zac and the Sea Eagles".into(),
clip_type: "gen".into(),
..Default::default()
},
]
}
#[test]
fn edge_type_labels_read_naturally() {
assert_eq!(EdgeType::Cover.label(), "Cover of");
assert_eq!(EdgeType::Remaster.label(), "Remaster of");
assert_eq!(EdgeType::SpeedEdit.label(), "Speed-edited from");
assert_eq!(EdgeType::Edit.label(), "Edited from");
assert_eq!(EdgeType::Extend.label(), "Extended from");
assert_eq!(EdgeType::SectionReplace.label(), "Section replaced from");
assert_eq!(EdgeType::Stitch.label(), "Stitched from");
assert_eq!(EdgeType::Derived.label(), "Derived from");
assert_eq!(EdgeType::Uploaded.label(), "Uploaded");
}
#[test]
fn classifies_remaster_cover_edit_and_root_across_chain1() {
let clips = chain1_clips();
assert_eq!(edge_type(&clips[0]), Some(EdgeType::Remaster));
assert_eq!(
immediate_parent(&clips[0]),
Some(("52962dae".into(), EdgeType::Remaster))
);
assert_eq!(edge_type(&clips[1]), Some(EdgeType::Cover));
assert_eq!(
immediate_parent(&clips[1]),
Some(("536e1b92".into(), EdgeType::Cover))
);
assert_eq!(edge_type(&clips[4]), Some(EdgeType::Edit));
assert_eq!(
immediate_parent(&clips[4]),
Some(("dfb59a04".into(), EdgeType::Edit))
);
assert_eq!(edge_type(&clips[5]), None);
assert_eq!(immediate_parent(&clips[5]), None);
}
#[test]
fn classifies_speed_edit_from_speed_pointer_without_edited() {
let clip = Clip {
id: "6e5193b1".into(),
title: "Go Xavi Go, Fast. (Drum n' Bass Version)".into(),
clip_type: "edit_speed".into(),
is_remix: true,
speed_clip_id: "2b69882c".into(),
..Default::default()
};
assert_eq!(edge_type(&clip), Some(EdgeType::SpeedEdit));
assert_eq!(
immediate_parent(&clip),
Some(("2b69882c".into(), EdgeType::SpeedEdit))
);
}
#[test]
fn empty_task_gen_is_a_root() {
let clip = Clip {
id: "b4f16694".into(),
title: "Go Xavi Go, Fast.".into(),
clip_type: "gen".into(),
task: String::new(),
..Default::default()
};
assert_eq!(edge_type(&clip), None);
assert_eq!(immediate_parent(&clip), None);
}
#[test]
fn classifies_extend_from_history_head() {
let clip = Clip {
id: "9a3dcb67".into(),
title: "Extended".into(),
clip_type: "gen".into(),
task: "extend".into(),
edited_clip_id: "0a3c311a".into(),
history: vec![HistoryEntry {
id: "0a3c311a".into(),
continue_at: Some(115.35),
..Default::default()
}],
..Default::default()
};
assert_eq!(edge_type(&clip), Some(EdgeType::Extend));
assert_eq!(
immediate_parent(&clip),
Some(("0a3c311a".into(), EdgeType::Extend))
);
}
#[test]
fn classifies_infill_with_override_history_precedence() {
let clip = Clip {
id: "c0ce5c48".into(),
title: "Section replaced".into(),
clip_type: "gen".into(),
task: "infill".into(),
edited_clip_id: "cf37e05f".into(),
override_history_clip_id: "d3d28e59".into(),
override_future_clip_id: "ea88571e".into(),
history: vec![HistoryEntry {
id: "cf37e05f".into(),
infill: true,
infill_start_s: Some(20.4),
infill_end_s: Some(24.92),
..Default::default()
}],
..Default::default()
};
assert_eq!(edge_type(&clip), Some(EdgeType::SectionReplace));
assert_eq!(
immediate_parent(&clip),
Some(("d3d28e59".into(), EdgeType::SectionReplace))
);
}
#[test]
fn fixed_infill_is_also_section_replace() {
let clip = Clip {
task: "fixed_infill".into(),
override_history_clip_id: "past".into(),
edited_clip_id: "edited".into(),
..Default::default()
};
assert_eq!(edge_type(&clip), Some(EdgeType::SectionReplace));
assert_eq!(
immediate_parent(&clip),
Some(("past".into(), EdgeType::SectionReplace))
);
}
#[test]
fn classifies_stitch_from_concat_base() {
let clip = Clip {
id: "43ba1ce3".into(),
title: "Stitched".into(),
clip_type: "concat".into(),
concat_history: vec![
HistoryEntry {
id: "ead64fbe".into(),
continue_at: Some(149.19),
..Default::default()
},
history("da47b824"),
],
..Default::default()
};
assert_eq!(edge_type(&clip), Some(EdgeType::Stitch));
assert_eq!(
immediate_parent(&clip),
Some(("ead64fbe".into(), EdgeType::Stitch))
);
}
#[test]
fn inherited_concat_history_without_concat_type_is_not_a_stitch() {
let clip = Clip {
clip_type: "gen".into(),
concat_history: vec![history("base"), history("second")],
..Default::default()
};
assert_eq!(edge_type(&clip), None);
assert_eq!(immediate_parent(&clip), None);
}
#[test]
fn cover_of_a_stitch_classifies_as_cover_not_stitch() {
let clip = Clip {
id: "cov".into(),
title: "Cover of a stitch".into(),
clip_type: "gen".into(),
task: "cover".into(),
cover_clip_id: "stitch-parent".into(),
edited_clip_id: "stitch-parent".into(),
concat_history: vec![history("inherited-base"), history("inherited-seg")],
..Default::default()
};
assert_eq!(edge_type(&clip), Some(EdgeType::Cover));
assert_eq!(
immediate_parent(&clip),
Some(("stitch-parent".into(), EdgeType::Cover))
);
}
#[test]
fn upload_is_a_root() {
let clip = Clip {
id: "4770ef56".into(),
title: "Uploaded audio".into(),
clip_type: "upload".into(),
..Default::default()
};
assert_eq!(edge_type(&clip), None);
assert_eq!(immediate_parent(&clip), None);
}
#[test]
fn edited_only_clip_is_derived() {
let clip = Clip {
clip_type: "gen".into(),
task: "chop_sample_condition".into(),
edited_clip_id: "parent-x".into(),
..Default::default()
};
assert_eq!(edge_type(&clip), Some(EdgeType::Derived));
assert_eq!(
immediate_parent(&clip),
Some(("parent-x".into(), EdgeType::Derived))
);
}
#[test]
fn unmarked_clip_without_pointer_is_a_root() {
let clip = Clip {
clip_type: "gen".into(),
task: "chop_sample_condition".into(),
..Default::default()
};
assert_eq!(edge_type(&clip), None);
assert_eq!(immediate_parent(&clip), None);
}
#[test]
fn is_remix_does_not_change_classification() {
let base = Clip {
clip_type: "gen".into(),
task: "cover".into(),
cover_clip_id: "root-1".into(),
edited_clip_id: "root-1".into(),
..Default::default()
};
let mut with_flag = base.clone();
with_flag.is_remix = true;
let mut without_flag = base;
without_flag.is_remix = false;
assert_eq!(edge_type(&with_flag), edge_type(&without_flag));
assert_eq!(
immediate_parent(&with_flag),
immediate_parent(&without_flag)
);
assert_eq!(edge_type(&with_flag), Some(EdgeType::Cover));
assert_eq!(
immediate_parent(&with_flag),
Some(("root-1".into(), EdgeType::Cover))
);
}
#[test]
fn zero_uuid_cover_falls_back_to_edited() {
let clip = Clip {
clip_type: "gen".into(),
task: "cover".into(),
cover_clip_id: ZERO_UUID.into(),
edited_clip_id: "real-parent".into(),
..Default::default()
};
assert_eq!(
immediate_parent(&clip),
Some(("real-parent".into(), EdgeType::Cover))
);
}
#[test]
fn m_prefix_is_stripped_from_history_and_concat_ids() {
let extend = Clip {
clip_type: "gen".into(),
task: "extend".into(),
history: vec![history("m_abc123")],
..Default::default()
};
assert_eq!(
immediate_parent(&extend),
Some(("abc123".into(), EdgeType::Extend))
);
let stitch = Clip {
clip_type: "concat".into(),
concat_history: vec![history("m_base"), history("m_second")],
..Default::default()
};
let edges = lineage_edges(&stitch);
assert_eq!(edges[0].parent_id, "base");
assert_eq!(edges[1].parent_id, "second");
assert_eq!(edges[1].role, EdgeRole::Secondary);
}
#[test]
fn lineage_edges_of_a_root_is_empty() {
let clip = Clip {
clip_type: "gen".into(),
..Default::default()
};
assert!(lineage_edges(&clip).is_empty());
}
#[test]
fn lineage_edges_records_stitch_secondaries_in_order() {
let clip = Clip {
clip_type: "concat".into(),
concat_history: vec![history("base"), history("seg1"), history("seg2")],
..Default::default()
};
let edges = lineage_edges(&clip);
assert_eq!(
edges,
vec![
Edge {
parent_id: "base".into(),
edge_type: EdgeType::Stitch,
role: EdgeRole::Primary,
ordinal: 0,
source_field: "concat_history",
},
Edge {
parent_id: "seg1".into(),
edge_type: EdgeType::Stitch,
role: EdgeRole::Secondary,
ordinal: 1,
source_field: "concat_history",
},
Edge {
parent_id: "seg2".into(),
edge_type: EdgeType::Stitch,
role: EdgeRole::Secondary,
ordinal: 2,
source_field: "concat_history",
},
]
);
}
#[test]
fn lineage_edges_emits_secondaries_when_the_primary_is_absent() {
let clip = Clip {
clip_type: "concat".into(),
concat_history: vec![history(""), history("seg1"), history("seg2")],
..Default::default()
};
let edges = lineage_edges(&clip);
assert_eq!(
edges,
vec![
Edge {
parent_id: "seg1".into(),
edge_type: EdgeType::Stitch,
role: EdgeRole::Secondary,
ordinal: 1,
source_field: "concat_history",
},
Edge {
parent_id: "seg2".into(),
edge_type: EdgeType::Stitch,
role: EdgeRole::Secondary,
ordinal: 2,
source_field: "concat_history",
},
],
"secondaries survive an empty primary base segment"
);
}
#[test]
fn lineage_edges_records_infill_future_as_secondary() {
let clip = Clip {
task: "infill".into(),
override_history_clip_id: "past".into(),
override_future_clip_id: "future".into(),
..Default::default()
};
let edges = lineage_edges(&clip);
assert_eq!(edges[0].parent_id, "past");
assert_eq!(edges[0].role, EdgeRole::Primary);
assert_eq!(edges[0].source_field, "override_history_clip_id");
assert_eq!(
edges[1],
Edge {
parent_id: "future".into(),
edge_type: EdgeType::SectionReplace,
role: EdgeRole::Secondary,
ordinal: 1,
source_field: "override_future_clip_id",
}
);
}
fn clip_root(id: &str, handle: &str) -> crate::model::ClipRoot {
crate::model::ClipRoot {
id: id.to_owned(),
handle: handle.to_owned(),
..Default::default()
}
}
#[test]
fn attribution_edges_map_clip_roots_in_order() {
let clip = Clip {
id: "child".into(),
handle: "me".into(),
clip_attribution_type: "remix".into(),
clip_roots: vec![
clip_root("own-root", "me"),
clip_root("foreign-root", "stranger"),
],
..Default::default()
};
let edges = attribution_edges(&clip);
assert_eq!(edges.len(), 2);
assert_eq!(
edges[0],
AttributionEdge {
parent_id: "own-root".into(),
edge_slug: "remix".into(),
role: EdgeRole::Secondary,
ordinal: 0,
source_field: "clip_roots",
same_owner: true,
}
);
assert_eq!(edges[1].parent_id, "foreign-root");
assert_eq!(edges[1].ordinal, 1);
assert!(
!edges[1].same_owner,
"a differently-handled root is foreign, and still emits an edge"
);
}
#[test]
fn attribution_edges_are_empty_without_clip_roots() {
let clip = Clip {
id: "child".into(),
handle: "me".into(),
..Default::default()
};
assert!(attribution_edges(&clip).is_empty());
}
#[test]
fn attribution_edges_same_owner_is_fail_closed() {
let matched = Clip {
handle: "me".into(),
clip_roots: vec![clip_root("r", "me")],
..Default::default()
};
assert!(attribution_edges(&matched)[0].same_owner);
let clip_blank = Clip {
handle: "".into(),
clip_roots: vec![clip_root("r", "me")],
..Default::default()
};
assert!(
!attribution_edges(&clip_blank)[0].same_owner,
"an empty clip handle is fail-closed to foreign"
);
let root_blank = Clip {
handle: "me".into(),
clip_roots: vec![clip_root("r", " ")],
..Default::default()
};
assert!(
!attribution_edges(&root_blank)[0].same_owner,
"a whitespace-only root handle is fail-closed to foreign"
);
}
#[test]
fn attribution_edges_skip_a_root_with_no_id_and_keep_contiguous_ordinals() {
let clip = Clip {
handle: "me".into(),
clip_attribution_type: "remix".into(),
clip_roots: vec![
clip_root("", "me"),
clip_root(ZERO_UUID, "me"),
clip_root("real-root", "me"),
],
..Default::default()
};
let edges = attribution_edges(&clip);
assert_eq!(edges.len(), 1, "empty and sentinel root ids are dropped");
assert_eq!(edges[0].parent_id, "real-root");
assert_eq!(edges[0].ordinal, 0, "ordinals stay contiguous after a skip");
}
fn resolution_with(roots: Vec<(&str, RootInfo)>) -> Resolution {
Resolution {
roots: roots
.into_iter()
.map(|(id, info)| (id.to_owned(), info))
.collect(),
gap_filled: Vec::new(),
bridges: Vec::new(),
}
}
#[test]
fn context_for_a_root_uses_its_own_id_and_title() {
let root = Clip {
id: "root-1".into(),
title: "Original".into(),
..Default::default()
};
let resolution = resolution_with(vec![(
"root-1",
RootInfo {
root_id: "root-1".into(),
root_title: "Original".into(),
status: ResolveStatus::Resolved,
},
)]);
let ctx = LineageContext::for_clip(&root, &resolution);
assert_eq!(ctx.root_id, "root-1");
assert_eq!(ctx.root_title, "Original");
assert_eq!(ctx.parent_id, "");
assert_eq!(ctx.edge_type, None);
assert_eq!(ctx.album("Original"), "Original");
}
#[test]
fn context_for_a_remix_carries_root_and_parent() {
let child = Clip {
id: "child-1".into(),
title: "Remix".into(),
clip_type: "gen".into(),
task: "cover".into(),
cover_clip_id: "root-1".into(),
edited_clip_id: "root-1".into(),
..Default::default()
};
let resolution = resolution_with(vec![(
"child-1",
RootInfo {
root_id: "root-1".into(),
root_title: "Original".into(),
status: ResolveStatus::Resolved,
},
)]);
let ctx = LineageContext::for_clip(&child, &resolution);
assert_eq!(ctx.root_id, "root-1");
assert_eq!(ctx.root_title, "Original");
assert_eq!(ctx.parent_id, "root-1");
assert_eq!(ctx.edge_type, Some(EdgeType::Cover));
assert_eq!(ctx.album("Remix"), "Original");
}
#[test]
fn context_absent_from_resolution_is_its_own_root() {
let clip = Clip {
id: "lonely".into(),
title: "Solo".into(),
..Default::default()
};
let ctx = LineageContext::for_clip(&clip, &resolution_with(vec![]));
assert_eq!(ctx.root_id, "lonely");
assert_eq!(ctx.root_title, "Solo");
assert_eq!(ctx.status, ResolveStatus::Resolved);
assert_eq!(ctx.album("Solo"), "Solo");
}
#[test]
fn album_falls_back_to_own_title_when_root_title_is_empty() {
let ctx = LineageContext {
root_id: "outside".into(),
root_title: String::new(),
root_date: String::new(),
parent_id: "outside".into(),
edge_type: Some(EdgeType::Cover),
status: ResolveStatus::External,
track: 0,
track_total: 0,
};
assert_eq!(ctx.album("My Title"), "My Title");
}
#[test]
fn own_root_has_no_parent() {
let clip = Clip {
id: "solo".into(),
title: "Solo".into(),
..Default::default()
};
let ctx = LineageContext::own_root(&clip);
assert_eq!(ctx.root_id, "solo");
assert_eq!(ctx.parent_id, "");
assert_eq!(ctx.edge_type, None);
}
#[test]
fn year_prefers_the_root_year_over_the_clips_own() {
let ctx = LineageContext {
root_id: "root-1".into(),
root_title: "Origin".into(),
root_date: "2023-12-30T23:00:00Z".into(),
parent_id: "root-1".into(),
edge_type: Some(EdgeType::Extend),
status: ResolveStatus::Resolved,
track: 0,
track_total: 0,
};
assert_eq!(ctx.year("2024-01-02T08:00:00Z"), "2023");
}
#[test]
fn year_falls_back_to_own_when_the_root_date_is_unavailable() {
let ctx = LineageContext {
root_id: "outside".into(),
root_title: String::new(),
root_date: String::new(),
parent_id: "outside".into(),
edge_type: Some(EdgeType::Cover),
status: ResolveStatus::External,
track: 0,
track_total: 0,
};
assert_eq!(ctx.year("2024-07-01T00:00:00Z"), "2024");
}
#[test]
fn own_root_tags_its_own_year() {
let clip = Clip {
id: "solo".into(),
title: "Solo".into(),
created_at: "2022-05-06T12:00:00Z".into(),
..Default::default()
};
let ctx = LineageContext::own_root(&clip);
assert_eq!(ctx.root_date, "2022-05-06T12:00:00Z");
assert_eq!(ctx.year(&clip.created_at), "2022");
}
#[test]
fn year_is_empty_when_no_date_is_known() {
let clip = Clip::default();
let ctx = LineageContext::own_root(&clip);
assert_eq!(ctx.year(&clip.created_at), "");
}