87 lines
3.6 KiB
Rust
87 lines
3.6 KiB
Rust
//! Primitive evaluation and combined resource boundaries.
|
|
|
|
use notescraft_lottie::{Animation, Error, Item};
|
|
use serde_json::{Value, json};
|
|
|
|
fn fixture() -> Value {
|
|
serde_json::from_str(include_str!("fixtures/stroke.json")).expect("valid fixture")
|
|
}
|
|
|
|
#[test]
|
|
fn rounded_rectangle_and_ellipse_emit_closed_pixel_contours() {
|
|
for primitive in [
|
|
json!({"ty":"rc","p":{"a":0,"k":[12,12]},"s":{"a":0,"k":[20,10]},"r":{"a":0,"k":2}}),
|
|
json!({"ty":"el","p":{"a":0,"k":[12,12]},"s":{"a":0,"k":[20,10]}}),
|
|
] {
|
|
let mut input = fixture();
|
|
input["layers"][0]["shapes"][0] = primitive;
|
|
let animation = Animation::parse(&input.to_string()).expect("primitive");
|
|
let frame = animation.frame_at(0.0);
|
|
let Some(Item::Stroke(stroke)) = frame.items.first() else { panic!("stroke") };
|
|
let line = stroke.polylines.first().expect("contour");
|
|
assert!(line.closed);
|
|
assert!(line.points.len() > 8);
|
|
assert!(line.points.iter().all(|[x, y]| (2.0..=22.0).contains(x) && (7.0..=17.0).contains(y)));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn animated_ellipse_size_and_position_interpolate() {
|
|
let mut input = fixture();
|
|
input["layers"][0]["shapes"][0] = json!({
|
|
"ty":"el",
|
|
"p":{"a":1,"k":[{"t":0,"s":[10,10]},{"t":10,"s":[20,20]}]},
|
|
"s":{"a":1,"k":[{"t":0,"s":[10,10]},{"t":10,"s":[20,20]}]}
|
|
});
|
|
let animation = Animation::parse(&input.to_string()).expect("ellipse");
|
|
let frame = animation.frame_at(5.0);
|
|
let Some(Item::Stroke(stroke)) = frame.items.first() else { panic!("stroke") };
|
|
let [x, y] = stroke.polylines.first().and_then(|line| line.points.first()).expect("top vertex");
|
|
assert!((*x - 15.0).abs() < 0.001);
|
|
assert!((*y - 7.5).abs() < 0.001);
|
|
}
|
|
|
|
#[test]
|
|
fn vertex_budget_counts_all_paths_not_only_each_path() {
|
|
let mut input = fixture();
|
|
let mut path = input["layers"][0]["shapes"][0].clone();
|
|
path["ks"]["k"] = json!({"v":vec![[0,0];2050],"i":vec![[0,0];2050],"o":vec![[0,0];2050],"c":false});
|
|
input["layers"][0]["shapes"] = json!([path, path]);
|
|
assert!(matches!(Animation::parse(&input.to_string()), Err(Error::Unsupported {what,..}) if what.contains("4096")));
|
|
}
|
|
|
|
#[test]
|
|
fn exactly_eight_group_levels_are_accepted() {
|
|
let mut input = fixture();
|
|
let mut shapes = input["layers"][0]["shapes"].take();
|
|
for _ in 0..8 {
|
|
shapes.as_array_mut().expect("shapes").push(json!({"ty":"tr"}));
|
|
shapes = json!([{"ty":"gr","it":shapes}]);
|
|
}
|
|
input["layers"][0]["shapes"] = shapes;
|
|
assert!(Animation::parse(&input.to_string()).is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn masks_and_unimplemented_trim_modes_are_explicitly_unsupported() {
|
|
let mut input = fixture();
|
|
input["layers"][0]["hasMask"] = json!(true);
|
|
assert!(matches!(Animation::parse(&input.to_string()),Err(Error::Unsupported{what,..}) if what.contains("Mask")));
|
|
input["layers"][0]["hasMask"] = json!(false);
|
|
input["layers"][0]["shapes"].as_array_mut().expect("shapes").push(json!({"ty":"tm","m":2}));
|
|
assert!(matches!(Animation::parse(&input.to_string()),Err(Error::Unsupported{what,..}) if what.contains("trim")));
|
|
}
|
|
|
|
#[test]
|
|
fn point_budget_includes_every_stroke_and_fill_copy() {
|
|
let mut input = fixture();
|
|
let path = json!({"ty":"sh","ks":{"a":0,"k":{
|
|
"v":[[0,0],[100,0]],"i":[[0,0],[0,100]],"o":[[0,100],[0,0]],"c":false
|
|
}}});
|
|
let stroke = input["layers"][0]["shapes"][1].clone();
|
|
let mut shapes = vec![path];
|
|
shapes.extend(std::iter::repeat_n(stroke, 1000));
|
|
input["layers"][0]["shapes"] = json!(shapes);
|
|
assert!(matches!(Animation::parse(&input.to_string()),Err(Error::Unsupported{what,..}) if what.contains("20000")));
|
|
}
|