//! Helpers shared by the container tests. #![allow(dead_code)] /// The generated fixtures (own test data, see ATTRIBUTION.md). pub const FIXTURES: &[&str] = &[ "000-base.aep", "001-empty.aep", "010-layer-name.aep", "012-layer-shy.aep", "013-layer-locked.aep", "014-layer-solo.aep", "015-layer-3d.aep", "016-layer-blend-multiply.aep", "017-layer-motionblur.aep", "018-layer-stretch200.aep", "019-layer-inpoint1.aep", "021-layer-starttime0.5.aep", "022-layer-parent-null.aep", "023-layer-quality-draft.aep", "024-layer-collapse.aep", "025-layer-adjustment.aep", "026-layer-guide.aep", "030-comp-size-1280x720.aep", "031-comp-fps30.aep", "032-comp-duration10.aep", "033-comp-bg-green.aep", "034-comp-shutter90.aep", "035-comp-workarea-1-2.aep", "037-comp-pixelaspect2.aep", "038-comp-motionblur.aep", "039-comp-renderer-advanced3d.aep", "040-static-position-100-200.aep", "041-static-scale-50.aep", "042-static-rotation-45.aep", "043-static-opacity-25.aep", "044-static-anchor-10-20.aep", "052-key-position-2key-ease.aep", "053-key-position-2key-hold-key1.aep", "054-key-position-2key-spatial-bezier.aep", "055-key-position-3key-inserted-t2.5.aep", "056-key-position-3key-roving-key2.aep", "057-key-position-3key-label9-key2.aep", "058-key-opacity-2key.aep", "060-expr-opacity-wiggle.aep", "071-fx-slider-value77.aep", "073-fx-color-0.2-0.6-1.aep", "077-fx-dropdown-default.aep", "080-fx-dropshadow-default.aep", "090-mask-rect.aep", "091-mask-rect-props.aep", "093-mask-path-2keys.aep", "110-text-A.aep", "113-text-Hello-size60-fillorange.aep", "122-marker-comp-1s.aep", "123-marker-layer-1s.aep", "124-precomp-Pre.aep", "126-footage-png-layer.aep", "202-key-out-hold-in-linear.aep", "203-key-in-hold-out-linear.aep", "204-key-ease-asymmetric.aep", "205-key-opacity-ease-asymmetric.aep", "206-key-scale-2key-linear.aep", "208-key-mask-feather-2key-linear.aep", "210-key-fill-color-2key-linear.aep", "211-anchor-100x100-solid-10-20.aep", "212-anchor-400x300-solid-100-50.aep", "213-expr-opacity-wiggle-disabled.aep", "214-fx-gaussianblur-default.aep", "215-fx-fill-default.aep", "216-fx-gaussianblur-40.aep", "217-fx-checkbox-on.aep", "218-fx-point-111-222.aep", "219-fx-angle-90.aep", "220-fx-layercontrol-to-layer1.aep", "221-fx-slider-2key.aep", "222-layer-video-off.aep", "223-layer-audio-off.aep", "224-layer-effects-off.aep", "225-layer-blend-screen.aep", "226-layer-blend-add.aep", "227-layer-blend-overlay.aep", "228-layer-blend-difference.aep", "229-comp-fps-29.97.aep", "230-comp-fps-23.976.aep", "231-comp-bg-grey-0.5.aep", "232-mask-ellipse.aep", "233-mask-open-path.aep", "234-mask-mode-intersect.aep", "235-mask-mode-lighten.aep", "236-mask-mode-darken.aep", "237-mask-mode-difference.aep", "238-shape-rect-rounded-corners.aep", "239-shape-stroke-green-w8-round.aep", "240-shape-custom-path-tangents.aep", "241-shape-gradient-fill-linear.aep", "242-shape-group-position-50-50.aep", "243-text-multiline-A-CR-B.aep", "245-text-box-400x200-Hello.aep", "246-text-box-center-align.aep", "247-text-tracking-100.aep", "248-text-range-fill-red-1-3.aep", "249-marker-layer-full.aep", "251-camera-one-node.aep", "252-light-point.aep", "253-camera-position-100-200-m1000.aep", "254-light-spot-intensity-50.aep", "256-camera-two-node-default.aep", "259-solid-blue-0-0-1.aep", "299-save-noise.aep", "300-fx-gaussianblur-0-explicit.aep", "301-fx-gaussianblur-40-then-25.aep", "302-fx-fill-opacity-100-explicit.aep", "303-fx-fill-opacity-50-then-100.aep", "304-fx-slider-0-explicit.aep", "305-key-scale-bezier-ease.aep", "306-key-maskfeather-bezier-ease.aep", "307-key-fillcolor-bezier.aep", "309-solid-100x100-mask-rect.aep", "310-solid-100x100-pointcontrol.aep", "311-position-default-explicit.aep", "316-layer-stretch50.aep", "317-layer-stretch150.aep", "318-layer-inpoint-0.3333.aep", "319-precomp-timeremap.aep", "320-fx-layercontrol-self-explicit.aep", "321-fx-layercontrol-none.aep", "323-fx-dropdown-5items.aep", "324-fx-dropdown-5items-select3.aep", "325-comp-pixelaspect-0.9091.aep", "326-comp-shutterphase-m90.aep", "327-comp-displaystartframe-100.aep", "328-mask-two-ellipse-rect.aep", "329-mask-ellipse-mode-none.aep", "330-shape-polystar-star-5-50-100.aep", "331-shape-polystar-polygon-5-100.aep", "332-shape-gradient-fill-radial.aep", "333-shape-group-two-rects.aep", "334-text-box-right-align.aep", "335-text-point-fauxbold.aep", "336-text-point-fauxitalic.aep", "337-text-point-allcaps.aep", "338-text-point-smallcaps.aep", "339-text-point-leading60.aep", "340-text-range-two-styles.aep", "341-camera-zoom-2000.aep", "342-camera-dof-800-30.aep", "343-light-spot-color-red.aep", "344-light-spot-coneangle-60.aep", "345-light-spot-conefeather-30.aep", "347-marker-layer-label3.aep", "348-marker-layer-navigation-cue.aep", "349-marker-layer-event-cue-params.aep", "350-footage-wav-imported.aep", "351-footage-wav-as-layer.aep", "352-footage-pngseq-imported.aep", "354-footage-pngseq-timeremap.aep", "356-fx-tint-default.aep", "357-fx-tint-black-0.2-0.4-0.6.aep", "361-fx-tint-amount-0.aep", "363-fx-tint-amount-2key.aep", "364-fx-tint-white-2key.aep", "366-fx-blur-then-tint.aep", "368-fx-ramp-default.aep", "369-fx-ramp-start-100-200.aep", "371-fx-ramp-startcolor-red.aep", "374-fx-ramp-end-2000-m100.aep", "377-fx-ramp-shape-radial.aep", "378-fx-ramp-scatter-12.aep", "380-fx-ramp-blend-25pct.aep", "382-fx-ramp-start-2key.aep", "383-fx-ramp-on-100x100-start-10-20.aep", "389-fx-exposure-default.aep", "390-fx-exposure-channels-individual.aep", "391-fx-exposure-master-1.5.aep", "393-fx-exposure-offset-0.1.aep", "394-fx-exposure-gamma-2.2.aep", "395-fx-exposure-individual-red-1.aep", "396-fx-exposure-bypass-on.aep", "397-fx-exposure-master-2key.aep", "403-matte-L-alpha-M.aep", "404-matte-L-alphainv-M.aep", "405-matte-L-luma-M.aep", "406-matte-L-lumainv-M.aep", "407-matte-M-alpha-L-below.aep", "408-matte-L-alpha-M-visible.aep", "509-marker-comp-two.aep", "510-marker-layer-0.52-dur0.3.aep", "451-shape-ellipse-400x300-fill.aep", "457-shape-group-scale-50-80.aep", "462-shape-layer-anchor-10-20.aep", "464-shape-stroke-opacity-50.aep", "467-shape-trim-end-70.aep", "469-shape-trim-type-2.aep", "471-shape-rect-roundness-30.aep", "473-shape-star-points-6.aep", "482-shape-two-groups.aep", "483-shape-nested-group-rect.aep", "519-shape-all-items-default.aep", "410-fx-invert-channel-2.aep", "411-fx-invert-blend-50.aep", "413-fx-fastbox-radius-20.aep", "414-fx-fastbox-iterations-1.aep", "416-fx-fastbox-repeatedge-off.aep", "418-fx-gaussian-dimensions-3.aep", "419-fx-gaussian-repeatedge-off.aep", "422-fx-dropshadow-opacity-204.aep", "426-fx-dropshadow-shadowonly-on.aep", "427-fx-glow-default.aep", "429-fx-glow-threshold-76.5.aep", "438-fx-glow-midpoint-0.25.aep", "444-fx-huesat-hue-90.aep", "446-fx-huesat-light-m30.aep", "448-fx-huesat-colorizehue-120.aep", "512-fx-levels-inblack-0.1.aep", "514-fx-levels-gamma-2.aep", "516-fx-levels-outwhite-0.9.aep", "517-text-box-600x400-wrap.aep", "526-text-point-HHHH-default.aep", "527-text-point-HHHH-baseline-normal.aep", "528-text-point-HHHH-baseline-subscript.aep", "485-layer-3d-on.aep", "486-layer-3d-rotx-30.aep", "487-layer-3d-roty-45.aep", "488-layer-3d-orientation-10-20-30.aep", "529-fx-timewarp-default.aep", "530-fx-timewarp-speed-25.aep", "531-fx-timewarp-speed-keyed-50-200.aep", "532-fx-timewarp-method-1.aep", "533-fx-timewarp-sourceframe-12.aep", "534-fx-slider-expression-time10.aep", "535-camera-position-on-3d-rotx.aep", "536-camera-one-node-position-on-3d-rotx.aep", "537-camera-default-on-3d-rotx.aep", "538-text-point-HHHH-normal-ref.aep", "539-text-hscale-0.9.aep", "540-text-vscale-1.5.aep", "541-text-baselineshift-41.aep", "542-text-autokern-none.aep", "543-text-autokern-optical.aep", "544-text-applystroke-on.aep", "545-text-strokewidth-5.aep", "546-text-applyfill-off.aep", "548-text-linejoin-round.aep", "550-text-strokeoverfill-off.aep", "552-text-nobreak-on.aep", "553-text-tsume-0.5.aep", "554-text-kerning-50.aep", "555-text-ligature-on.aep", "556-text-autohyphenate-off.aep", "558-text-hangingroman-on.aep", "559-text-everyline-on.aep", "560-text-firstlineindent-20.aep", "561-text-startindent-30.aep", "562-text-endindent-40.aep", "563-text-spacebefore-10.aep", "564-text-spaceafter-12.aep", "565-text-justify-fullleft.aep", "566-text-justify-fullcenter.aep", "567-text-justify-fullright.aep", "568-text-justify-fullall.aep", "569-text-direction-rtl.aep", "571-text-digitset-arabic.aep", "572-text-leadingtype-japanese.aep", "573-text-baselinedir-rotated.aep", "575-text-vertical-rtl.aep", "576-text-baselinedir-crossstream.aep", "578-text-digitset-hindi.aep", "595-text-stroke-scale-shift-combined.aep", "596-text-combined-fill-over-stroke.aep", "579-textanim-position-0-m50.aep", "580-textanim-start-25.aep", "581-textanim-end-75.aep", "582-textanim-offset-10.aep", "583-textanim-units-index.aep", "584-textanim-basedon-3-words.aep", "585-textanim-mode-2-subtract.aep", "586-textanim-amount-50.aep", "587-textanim-shape-2-rampup.aep", "588-textanim-smoothness-50.aep", "589-textanim-easehigh-30.aep", "590-textanim-easelow-40.aep", "591-textanim-randomize-seed-7.aep", "592-textanim-many-props.aep", "593-textanim-start-keyed-ease-0-100.aep", "594-textanim-position-start-keyed-ease.aep", "725-text-point-HHHH-normal-ref-S18.aep", "727-text-reset-paragraph.aep", "728-textanim-character-offset-3.aep", "711-fx-directional-blur-30-40-on-M.aep", "712-fx-eleven-effects-defaults-on-M.aep", "713-fx-radial-blur-zoom-20-on-M.aep", "714-fx-ccradial-type2-30-60-on-M.aep", "715-fx-venetian-40-30-50-5-on-M.aep", "716-fx-channel-blur-5-10-15-20-edge-horiz-on-M.aep", "717-fx-blackwhite-set-tint-on-L.aep", "718-fx-tritone-set-blend25-on-L.aep", "719-fx-lumakey-darker-140-20-1-2.5-on-M.aep", "720-fx-simplechoker-3.5-on-M.aep", "721-fx-simplechoker-3.5-view-matte-on-M.aep", "722-fx-mattechoker-set-on-M.aep", "723-fx-transform-set-on-M.aep", "597-key-anchor-ease-out50-40-in30-60.aep", "598-key-ramp-point-ease-color-bezier.aep", "599-key-mask-path-ease-infl75.aep", "700-key-mask-path-ease-out20-in50.aep", "701-light-parallel-int80-color.aep", "702-light-ambient-int50-color.aep", "703-key-orientation-0-to-10-20-30-linear.aep", "704-light-environment-default.aep", "705-mask-on-text-rect-40-m70-160-10.aep", "706-mask-on-shape-rect-0-m150-100-150.aep", "707-shape-merge-subtract-rect-ellipse.aep", "708-shape-merge-intersect-rect-ellipse.aep", "709-shape-repeater-3-pos150-60-rot10-scale90-80-op40.aep", "710-shape-offset-paths-20-round.aep", "730-key-anchor-ease-on-400x800-solid.aep", "731-shape-merge-offset-repeater-defaults.aep", "732-text-box-byteedit-para24-0.aep", "733-text-box-byteedit-para35-0.aep", "734-text-box-byteedit-style68-1.aep", "828-shape-offset-paths-20-copies3-copyoffset1.5-stroke.aep", "851-shape-key-trim-end-0-100-linear.aep", "852-shape-key-trim-end-bezier-out0-60-in20-30.aep", "853-shape-key-group-position-0-200-100-linear.aep", "854-shape-key-fill-color-red-blue-linear.aep", "855-shape-key-trim-offset-0-90-hold.aep", "856-shape-trim-end-expression-time50.aep", "857-shape-key-group-scale-100-50-150-linear.aep", "900-mask-added-no-path.aep", "901-mask-no-path-expansion-m100.aep", "902-settings-rec709-16bpc-steps-png-grey-solid.aep", "905-fx-24-effects-set-one-comp.aep", "906-blendmodes-13-solids-on-steps.aep", "963-curves-red-mid-down-on-S.aep", "964-curves-rgb-s-curve-on-S.aep", "951-styles-all-nine-defaults-on-B.aep", "966-style-drop-shadow-opacity50-distance20.aep", "970-style-stroke-size10-color-green.aep", "974-style-gradient-overlay-angle45-scale150.aep", "975-style-fill-opacity0-with-drop-shadow.aep", "976-style-drop-shadow-opacity-keyed-100-20-linear.aep", "977-styles-all-params-changed.aep", "979-style-inner-glow-source-2.aep", "981-layer-stretch-minus100-start5.aep", "982-layer-stretch-minus100-opacity-keys.aep", "983-layer-stretch-minus50-opacity-keys.aep", "985-meshwarp-3x3-vertex-moved-on-S.aep", "986-shape-fill-switched-off-green.aep", "988-style-drop-shadow-switched-off.aep", ]; use craft_aep::{AepFile, Comp, Layer, LayerType, Project, parse}; /// Parses a fixture; the bytes must outlive the file, so the caller keeps them. pub fn open(bytes: &[u8]) -> AepFile<'_> { parse(bytes).expect("fixture parses") } /// The first composition of a project (comp `C` in the corpus; in 124 the precomp `Pre` comes later). pub fn first_comp<'f, 'a>(project: &Project<'f, 'a>) -> Comp<'f, 'a> { project.all_items().into_iter().find_map(|i| i.comp()).expect("a composition") } /// The solid `L` of the base composition: the bottom layer (the first one made; id 0x1b in the /// single-case files, another id in each case of a combined file). pub fn base_layer<'f, 'a>(comp: &Comp<'f, 'a>) -> Layer<'f, 'a> { comp.layers().last().expect("a layer") } /// The layer with this id in a composition. pub fn layer_with_id<'f, 'a>(comp: &Comp<'f, 'a>, id: u32) -> Layer<'f, 'a> { comp.layers().find(|l| l.id() == Some(id)).unwrap_or_else(|| panic!("no layer with id {id:#x}")) } /// The layer with this user-set name in a composition. pub fn layer_named<'f, 'a>(comp: &Comp<'f, 'a>, name: &str) -> Layer<'f, 'a> { comp.layers().find(|l| l.name().as_deref() == Some(name)).unwrap_or_else(|| panic!("no layer named {name}")) } /// The layer that shows this name: its own name, or its source's while it has none. pub fn layer_shown_as<'f, 'a>(project: &Project<'f, 'a>, comp: &Comp<'f, 'a>, name: &str) -> Layer<'f, 'a> { let shown = |l: &Layer<'f, 'a>| l.name().or_else(|| project.layer_source(l)?.display_name()); comp.layers().find(|l| shown(l).as_deref() == Some(name)).unwrap_or_else(|| panic!("no layer shown as {name}")) } /// The first layer of this type in a composition. pub fn layer_of_type<'f, 'a>(comp: &Comp<'f, 'a>, layer_type: LayerType) -> Layer<'f, 'a> { comp.layers().find(|l| l.header().is_some_and(|h| h.layer_type == layer_type)).unwrap_or_else(|| panic!("no {layer_type:?} layer")) } /// A copy of a layer's `LIST Layr` with its id (`ldta` bytes 0-3) set to 0, for comparing the /// same layer in two cases of a combined file. pub fn without_layer_id(layer: &craft_aep::Chunk<'_>) -> craft_aep::Chunk<'static> { let mut c = layer.clone().into_owned(); if let craft_aep::Body::List { children, .. } = &mut c.body && let Some(ldta) = children.iter_mut().find(|x| x.is(b"ldta")) && let craft_aep::Body::Data(d) = &mut ldta.body { d.to_mut()[..4].fill(0); } c } /// Compares floats with a tolerance. pub fn near(a: f64, b: f64, tol: f64) -> bool { (a - b).abs() <= tol } pub fn assert_near(got: &[f64], want: &[f64], tol: f64) { assert_eq!(got.len(), want.len(), "{got:?} vs {want:?}"); for (g, w) in got.iter().zip(want) { assert!(near(*g, *w, tol), "{got:?} != {want:?}"); } }