effectcraft/crates/engine/src/tests_timeline_interchange.rs

67 lines
3.8 KiB
Rust

//! File ▸ Import / Export ▸ Adobe Premiere Pro Project… (timeline interchange) through the command
//! registry, without media decoding (pixels: `crates/host/tests/timeline_interop.rs`).
use serde_json::json;
use crate::Session;
use crate::project::{ItemId, ItemKind, LayerSource};
fn tmp(name: &str) -> String {
let d = std::env::temp_dir().join(format!("effectcraft-timeline-tests-{}", std::process::id()));
std::fs::create_dir_all(&d).unwrap();
d.join(name).to_string_lossy().to_string()
}
#[test]
fn export_and_reimport_timeline_commands() {
let mut s = Session::default();
s.execute("comp.new", json!({"name": "Main", "width": 320, "height": 180, "frameRate": 25, "duration": 2})).unwrap();
let full = s.execute("layer.newSolid", json!({"color": "#ff8000"})).unwrap()["layer"].as_u64().unwrap();
s.execute("prop.set", json!({"layer": full, "path": "transform/opacity", "value": 40})).unwrap();
s.execute("layer.newSolid", json!({"color": "#0080ff", "width": 50, "height": 50})).unwrap();
s.execute("layer.newNull", json!({})).unwrap();
let main = s.active_comp_id().unwrap().0;
for (ext, format) in [("xml", "xml"), ("fcpxml", "fcpxml"), ("otio", "otio")] {
let path = tmp(&format!("Main.{ext}"));
// No exporter in a bare session: the small solid can't be pre-rendered and is left out.
let r = s.execute_checked("file.exportTimeline", json!({"comp": main, "path": path})).unwrap();
assert_eq!(r["format"], format);
// Only Final Cut Pro XML carries colour mattes; the other formats would pre-render solids.
assert_eq!(r["videoTracks"], if format == "xml" { 1 } else { 0 }, "{r}");
assert!(r["warnings"].as_array().unwrap().iter().any(|w| w.as_str().unwrap().contains("pre-render")), "{r}");
let r = s.execute_checked("file.importTimeline", json!({"path": path})).unwrap();
assert_eq!(r["format"], format);
let cid = ItemId(r["comps"][0].as_u64().unwrap());
assert_eq!(s.active_comp_id(), Some(cid));
let c = s.project.comp(cid).unwrap();
assert_eq!((c.width, c.height), (320, 180));
if format != "xml" {
assert!(c.layers.is_empty());
continue;
}
assert_eq!(c.layers.len(), 1);
let l = &c.layers[0];
let LayerSource::Solid { item } = l.source else { panic!("{:?}", l.source) };
let ItemKind::Solid(sol) = &s.project.item(item).unwrap().kind else { panic!() };
assert!((sol.color[0] - 1.0).abs() < 0.01 && (sol.color[2]).abs() < 0.01, "{:?}", sol.color);
assert!((l.transform().unwrap().get("opacity").unwrap().value.as_f64() - 40.0).abs() < 1e-6);
let folder = ItemId(r["folder"].as_u64().unwrap());
assert_eq!(s.project.item(folder).unwrap().name, format!("Main.{ext}"));
}
// A path without an extension gets the format's.
let r = s.execute_checked("file.exportTimeline", json!({"comp": main, "path": tmp("NoExt"), "format": "otio", "prerender": "none"})).unwrap();
assert!(r["path"].as_str().unwrap().ends_with("NoExt.otio"));
assert!(s.execute_checked("file.exportTimeline", json!({"path": tmp("x.xml"), "prerender": "sometimes"})).is_err());
assert!(s.execute_checked("file.importTimeline", json!({"path": "/nope/a.prproj"})).is_err());
let formats = s.execute("file.timelineFormats", json!({})).unwrap();
assert_eq!(formats.as_array().unwrap().len(), 6);
}
#[test]
fn premiere_menu_entries_keep_after_effects_labels() {
let entries = crate::menus::entries();
let find = |cmd: &str| entries.iter().find(|(_, e)| e.command == cmd).map(|(p, e)| (p.join(" > "), e.label.clone()));
assert_eq!(find("file.exportTimeline"), Some(("File > Export".into(), "Adobe Premiere Pro Project...".into())));
assert_eq!(find("file.importTimeline"), Some(("File > Import".into(), "Adobe Premiere Pro Project...".into())));
}