Testing & fixtures
How the workspace pins behaviour against regressions: a fixture corpus (the assets under
test) plus the golden harness in avatar-testkit (the machinery that
snapshots a report and diffs it). Most read paths produce a JSON report agents consume; a golden test
pins the whole serialized report, so any change surfaces as a reviewable diff instead of passing
silently. Full text: docs/reference/testing.md.
The corpus: three layers
- Committed synthetic Unity projects —
fixtures/projects/{Sample,Avatar,Dynamics}Project. Hand-authored to exercise specific lint rules and component-stats paths; hermetic, run on any machine. Resolved in tests viaavatar_testkit::corpus("projects/SampleProject"). - In-code synthetic FBX —
avatar_testkit::fbx::humanoid_skeleton()builds a deterministic binary FBX in memory via thefbxcelwriter (featurefbx). No committed.fbxblob; covers the armature + geometry-stats paths. - Env-gated real assets —
AVATAR_SAMPLE_FBX,AVATAR_SAMPLE_UNITYPACKAGE,AVATAR_SAMPLE_UNITYPACKAGE_WORLD. Tests self-skip when the variable is unset, so CI without fixtures stays green; on the self-hosted runner they point at real files, so the real-data paths run every push.
Layers 1–2 are hermetic and run everywhere (including forks); layer 3 is the ground-truth pass.
.gitignore) — the committed
corpus is synthetic, and real assets only ever enter tests through the env-var gate.
The harness — avatar-testkit
A publish = false workspace member, added as a dev-dependency by the crates that golden-test:
golden::assert_json(path, &value)— serialize to canonical pretty JSON (2-space indent, trailing newline) and compare against the file atpath(relative to the consuming crate). On mismatch it panics with a line-located diff; a missing file tells you to regenerate.golden::redact_roots(&mut value)/golden::redact— scrub machine-specific absolute paths (a report'sproject_root,source) before snapshotting, replacing the workspace-root prefix with<ROOT>so snapshots are identical on every machine.corpus(rel)/workspace_root()— resolve a corpus path from any crate's tests, at runtime.fbx::humanoid_skeleton()— the in-code synthetic FBX.
Snapshots live beside the consuming test, under crates/<crate>/tests/golden/*.json,
and are committed. Lists with no guaranteed order (lint diagnostics, the per-avatar
PerfReport vec) are sorted in the test before snapshotting so the golden is stable.
Writing a golden test
use avatar_testkit::{corpus, golden};
#[test]
fn golden_my_project() {
let report = avatar_lint::run(&corpus("projects/SampleProject")).unwrap();
let mut value = serde_json::to_value(&report).unwrap();
golden::redact_roots(&mut value);
golden::assert_json("tests/golden/SampleProject.lint.json", &value);
}
Updating snapshots
After an intentional change to a report shape or a fixture, regenerate and review the diff before committing — the diff is the change-review:
UPDATE_GOLDEN=1 cargo test --workspace # rewrite every snapshot
git diff -- '**/tests/golden/**' # review, then commit
UPDATE_GOLDEN is honored for any non-empty, non-0 value. With it unset, a
mismatch fails the test — which is the point.
Current golden coverage
| Crate | Snapshot | Covers |
|---|---|---|
avatar-lint | {Sample,Avatar,Dynamics}Project.lint.json | the full LintReport per corpus project |
avatar-stats | {Sample,Avatar,Dynamics}Project.project-stats.json | per-avatar PerfReports (component side) |
avatar-stats | humanoid_skeleton.fbx-stats.json | FBX geometry PerfReport |
avatar-armature | humanoid_skeleton.armature.json | the full ArmatureReport (humanoid mapping) |
avatar-migrate | Sdk2Project.migrate.json, Sdk2Project.migrated.prefab.txt, Sdk2Project.FX.controller.txt, Sdk2Project.physbones.json, Sdk2Project.physbones.tuned.json | the full MigrationReport, the rewritten prefab text, the generated FX controller for the synthetic SDK2 fixture, and the avatar physbone list of the migrated prefab before / after a split + set (curves) + stretch pass |
avatar-testkit::fbx builder)
and add a golden test that runs the analysis over it. See also fixtures/README.md and
CONTRIBUTING.md.