use anyhow::Result;
use openusd::sdf::{path, Value};
use openusd::usd;
const ASSETS: &str = "vendor/core-spec-supplemental-release_dec2025/value_resolution/tests/assets";
fn open(name: &str) -> Result<usd::Stage> {
usd::Stage::open(&format!("{ASSETS}/{name}/entry.usd"))
}
fn scalar(v: Option<Value>) -> Option<f64> {
match v {
Some(Value::Float(x)) => Some(x as f64),
Some(Value::Double(x)) => Some(x),
_ => None,
}
}
fn value_at(stage: &usd::Stage, attr: &str, time: f64) -> Option<f64> {
scalar(stage.value_at(path(attr).unwrap(), time).expect("value_at"))
}
#[test]
fn default_opinion() -> Result<()> {
let stage = open("default")?;
let default = stage.prim_at(path("/Root")?).attribute("root").get::<Value>()?;
assert_eq!(scalar(default), Some(2.0));
Ok(())
}
#[test]
fn timesamples_linear() -> Result<()> {
let stage = open("timesamples")?;
assert_eq!(value_at(&stage, "/Root.root", 1.0), Some(5.0));
assert_eq!(value_at(&stage, "/Root.root", 40.0), Some(15.0));
let mid = value_at(&stage, "/Root.root", 15.0).expect("interpolated");
assert!(mid > 5.0 && mid < 10.0, "expected (5, 10), got {mid}");
assert_eq!(value_at(&stage, "/Root.root", 60.0), Some(15.0));
assert_eq!(value_at(&stage, "/Root.root", 0.5), Some(5.0));
Ok(())
}
#[test]
fn timesamples_held() -> Result<()> {
let stage = open("timesamples")?;
stage.set_interpolation_type(usd::InterpolationType::Held);
assert_eq!(value_at(&stage, "/Root.root", 15.0), Some(5.0));
assert_eq!(value_at(&stage, "/Root.root", 30.0), Some(10.0));
Ok(())
}
#[test]
fn clip_basic() -> Result<()> {
let stage = open("clip_basic")?;
assert_eq!(value_at(&stage, "/Model.size", 0.0), Some(0.0));
assert_eq!(value_at(&stage, "/Model.size", 5.0), Some(5.0));
Ok(())
}
#[test]
fn clip_advanced() -> Result<()> {
let stage = open("clip_advanced")?;
assert_eq!(value_at(&stage, "/Model.local", 0.0), Some(0.0));
assert_eq!(value_at(&stage, "/Model.local", 5.0), Some(5.0));
assert_eq!(value_at(&stage, "/Model.local", 10.0), Some(10.0));
assert_eq!(value_at(&stage, "/Model.local", 15.0), Some(15.0));
assert_eq!(value_at(&stage, "/Model.local", 20.0), Some(20.0));
assert_eq!(value_at(&stage, "/Model.local", 25.0), Some(20.0));
assert_eq!(value_at(&stage, "/Model.ref", 0.0), Some(0.0));
assert_eq!(value_at(&stage, "/Model.ref", 5.0), Some(-5.0));
assert_eq!(value_at(&stage, "/Model.ref", 10.0), Some(-10.0));
assert_eq!(value_at(&stage, "/Model.ref", 20.0), Some(-20.0));
assert_eq!(value_at(&stage, "/Model.ref", 25.0), Some(-25.0));
assert_eq!(value_at(&stage, "/Model.ref", 30.0), Some(-25.0)); Ok(())
}
#[test]
fn clip_sets() -> Result<()> {
let stage = open("clip_sets")?;
assert_eq!(value_at(&stage, "/DefaultOrderTest.attr", 0.0), Some(10.0));
assert_eq!(value_at(&stage, "/DefaultOrderTest.attr", 1.0), Some(20.0));
assert_eq!(value_at(&stage, "/DefaultOrderTest.attr", 2.0), Some(30.0));
Ok(())
}
#[test]
fn clip_multi() -> Result<()> {
let stage = open("clip_multi")?;
let round1 = |t: f64| (value_at(&stage, "/Model_1.size", t).unwrap() * 10.0).round() / 10.0;
assert_eq!(round1(5.0), -5.0);
assert_eq!(round1(10.0), -10.0);
assert_eq!(round1(16.0 - 1e-9), -15.0);
assert_eq!(round1(16.0), -23.0);
assert_eq!(round1(19.0), -23.0);
assert_eq!(round1(22.0), -26.0);
assert_eq!(round1(25.0), -29.0);
Ok(())
}
#[test]
fn clip_timings() -> Result<()> {
let stage = open("clip_timings")?;
let round1 = |t: f64| (value_at(&stage, "/Model.size", t).unwrap() * 10.0).round() / 10.0;
assert_eq!(round1(0.0), 10.0);
assert_eq!(round1(15.0), 17.5);
assert_eq!(round1(30.0), 15.0);
assert_eq!(round1(40.0), 20.0);
assert_eq!(round1(50.0), 20.0); assert_eq!(round1(-1.0), 10.0); Ok(())
}