nigig-org/crates/apps/nigig-traffic/tests/asset_validation.rs

67 lines
2.2 KiB
Rust

//! Asset-manifest gates (TRAFFIC-12).
//!
//! Required signs/hazards/models are bundled, licensed, bounded, and
//! validated. Missing visual assets disable dependent lessons rather than
//! silently substituting cubes. Rule geometry stays independent of visuals.
use nigig_traffic::traffic::assets::{AssetEntry, AssetManifest};
fn entry(id: &str) -> AssetEntry {
AssetEntry {
logical_id: id.into(),
content_hash: "sha256:abc".into(),
license: "CC0".into(),
source: "kenney.nl".into(),
bytes: 1024,
triangles: 100,
}
}
#[test]
fn traversal_absolute_and_unsupported_types_rejected() {
assert!(AssetManifest::validate_id("../evil.glb").is_err());
assert!(AssetManifest::validate_id("/abs/path.glb").is_err());
assert!(AssetManifest::validate_id("a\\b.glb").is_err());
assert!(AssetManifest::validate_id("model.exe").is_err());
assert!(AssetManifest::validate_id("").is_err());
assert!(AssetManifest::validate_id("sign_stop.glb").is_ok());
assert!(AssetManifest::validate_id("car.png").is_ok());
}
#[test]
fn oversized_unlicensed_or_unhashed_rejected() {
let mut m = AssetManifest::default();
let mut bad = entry("a.glb");
bad.license = String::new();
assert!(m.insert(bad).is_err());
let mut bad = entry("b.glb");
bad.content_hash = String::new();
assert!(m.insert(bad).is_err());
let mut bad = entry("c.glb");
bad.triangles = 500_001;
assert!(m.insert(bad).is_err());
let mut bad = entry("d.glb");
bad.bytes = 150 * 1024 * 1024 + 1;
assert!(m.insert(bad).is_err());
assert!(m.insert(entry("ok.glb")).is_ok());
}
#[test]
fn current_catalog_has_no_hard_visual_dependencies() {
// Practice preview runs on reviewed primitives: no scenario category
// names a required visual asset, so nothing can silently cube-substitute
// for an assessment. When curriculum review adds required models, this
// test must grow with it (missing asset ⇒ lesson disabled).
for cat in [
"lanes",
"roundabout",
"parking",
"uturn",
"signs",
"priority",
"hazards",
"speed",
] {
assert_eq!(AssetManifest::required_for_category(cat), None, "{cat}");
}
}