use super::*;
#[test]
fn options_default_equals_new() {
assert_eq!(AudioEncoderOptions::default(), AudioEncoderOptions::new());
assert_eq!(AudioEncoderOptions::new().compute(), DEFAULT_AUDIO_COMPUTE);
assert_eq!(DEFAULT_AUDIO_COMPUTE, ComputeUnits::All);
}
#[test]
fn options_with_and_set_compute() {
let opts = AudioEncoderOptions::new().with_compute(ComputeUnits::CpuOnly);
assert_eq!(opts.compute(), ComputeUnits::CpuOnly);
let mut opts = AudioEncoderOptions::new();
opts.set_compute(ComputeUnits::CpuAndGpu);
assert_eq!(opts.compute(), ComputeUnits::CpuAndGpu);
}
#[test]
fn first_non_finite_finds_offenders() {
assert_eq!(first_non_finite(&[0.0, 1.0, 2.0]), None);
assert_eq!(first_non_finite(&[0.0, f32::NAN, 2.0]), Some(1));
assert_eq!(first_non_finite(&[f32::INFINITY]), Some(0));
assert_eq!(first_non_finite(&[1.0, 2.0, f32::NEG_INFINITY]), Some(2));
assert_eq!(
first_non_finite(&[0.0, -0.0, f32::MIN_POSITIVE / 2.0]),
None
);
}
#[test]
fn check_window_len_rejects_over_length_only() {
assert!(check_window_len(TARGET_SAMPLES).is_ok());
assert!(check_window_len(TARGET_SAMPLES - 1).is_ok());
assert!(check_window_len(1).is_ok());
let err = check_window_len(TARGET_SAMPLES + 1).unwrap_err();
let msg = err.to_string();
assert!(
matches!(err, Error::AudioTooLong(ref e) if e.len() == TARGET_SAMPLES + 1 && e.max() == TARGET_SAMPLES),
"expected AudioTooLong with len {} and max {TARGET_SAMPLES}, got {err:?}",
TARGET_SAMPLES + 1
);
assert!(
msg.contains("embed_windows"),
"AudioTooLong should name the long-audio path: {msg}"
);
}
#[test]
fn at_cap_plan_is_admitted_and_reserved_fallibly() {
let plan = WindowPlan::new().with_hop_samples(5);
assert_eq!(plan.max_windows(), 100_000);
let spans = plan
.spans(500_000)
.expect("at-cap plan must be admitted, not refused");
assert_eq!(
spans.len(),
100_000,
"hop=5 over 500_000 samples plans exactly 100_000 spans"
);
assert_eq!(spans.len() as u32, plan.max_windows());
}
#[cfg(feature = "serde")]
#[test]
fn options_serde_roundtrip() {
let opts = AudioEncoderOptions::new().with_compute(ComputeUnits::CpuAndGpu);
let json = serde_json::to_string(&opts).unwrap();
assert!(json.contains("cpu_and_gpu"), "serialized as as_str: {json}");
let back: AudioEncoderOptions = serde_json::from_str(&json).unwrap();
assert_eq!(back, opts);
}
#[cfg(feature = "serde")]
#[test]
fn options_serde_missing_compute_defaults() {
let opts: AudioEncoderOptions = serde_json::from_str("{}").unwrap();
assert_eq!(opts.compute(), DEFAULT_AUDIO_COMPUTE);
}
use crate::{AxisRange, FeatureInfo, ModelDescription, model::RawShapeConstraint};
fn fixed(name: &str, shape: &[usize], dtype: DataType) -> FeatureInfo {
multi_array(name, shape, dtype, false, 2, vec![shape.to_vec()], shape)
}
fn multi_array(
name: &str,
shape: &[usize],
dtype: DataType,
optional: bool,
raw_type: isize,
enumerated: Vec<Vec<usize>>,
pinned: &[usize],
) -> FeatureInfo {
FeatureInfo::from_parts(
name.to_string(),
shape.to_vec(),
Some(dtype),
optional,
Some(RawShapeConstraint::new(
raw_type,
enumerated,
pinned.iter().map(|d| AxisRange::new(*d, 1)).collect(),
)),
)
}
fn htsat_description() -> ModelDescription {
ModelDescription::from_parts(
vec![fixed(
names::INPUT_FEATURES,
&[1, 1, T_FRAMES, N_MELS],
DataType::F32,
)],
vec![fixed(
names::AUDIO_EMBEDS,
&[1, EMBEDDING_DIM],
DataType::F32,
)],
Vec::new(),
)
}
fn check(description: &ModelDescription) -> Result<()> {
crate::model::contract::check_load_contract(description, &audio_contract())
.map_err(contract_violation)
}
#[test]
fn the_contract_accepts_the_converted_geometry() {
assert!(check(&htsat_description()).is_ok());
}
#[test]
fn the_contract_refuses_a_flexible_input_declaring_its_exact_numbers() {
let description = ModelDescription::from_parts(
vec![multi_array(
names::INPUT_FEATURES,
&[1, 1, T_FRAMES, N_MELS],
DataType::F32,
false,
3,
Vec::new(),
&[1, 1, T_FRAMES, N_MELS],
)],
vec![fixed(
names::AUDIO_EMBEDS,
&[1, EMBEDDING_DIM],
DataType::F32,
)],
Vec::new(),
);
let err = check(&description).unwrap_err();
assert!(
matches!(&err, Error::ContractMismatch(m) if m.feature() == names::INPUT_FEATURES),
"{err}"
);
}
#[test]
fn the_contract_refuses_a_right_shaped_fp16_graph() {
let description = ModelDescription::from_parts(
vec![fixed(
names::INPUT_FEATURES,
&[1, 1, T_FRAMES, N_MELS],
DataType::F16,
)],
vec![fixed(
names::AUDIO_EMBEDS,
&[1, EMBEDDING_DIM],
DataType::F32,
)],
Vec::new(),
);
let err = check(&description).unwrap_err();
assert!(
matches!(&err, Error::ContractMismatch(m) if m.feature() == names::INPUT_FEATURES),
"{err}"
);
}
#[test]
fn the_contract_refuses_a_transposed_spectrogram() {
let description = ModelDescription::from_parts(
vec![fixed(
names::INPUT_FEATURES,
&[1, 1, N_MELS, T_FRAMES],
DataType::F32,
)],
vec![fixed(
names::AUDIO_EMBEDS,
&[1, EMBEDDING_DIM],
DataType::F32,
)],
Vec::new(),
);
assert!(matches!(
check(&description),
Err(Error::ContractMismatch(_))
));
}
#[test]
fn the_contract_refuses_a_different_projection_width() {
let description = ModelDescription::from_parts(
vec![fixed(
names::INPUT_FEATURES,
&[1, 1, T_FRAMES, N_MELS],
DataType::F32,
)],
vec![fixed(names::AUDIO_EMBEDS, &[1, 768], DataType::F32)],
Vec::new(),
);
let err = check(&description).unwrap_err();
assert!(
matches!(&err, Error::ContractMismatch(m) if m.feature() == names::AUDIO_EMBEDS),
"{err}"
);
}
#[test]
fn the_contract_refuses_an_extra_required_input() {
let description = ModelDescription::from_parts(
vec![
fixed(
names::INPUT_FEATURES,
&[1, 1, T_FRAMES, N_MELS],
DataType::F32,
),
fixed("is_longer", &[1, 1], DataType::I32),
],
vec![fixed(
names::AUDIO_EMBEDS,
&[1, EMBEDDING_DIM],
DataType::F32,
)],
Vec::new(),
);
assert!(
matches!(check(&description), Err(Error::UnsatisfiableInput(name)) if name == "is_longer"),
"{:?}",
check(&description)
);
}
#[test]
fn the_contract_accepts_an_extra_optional_input() {
let description = ModelDescription::from_parts(
vec![
fixed(
names::INPUT_FEATURES,
&[1, 1, T_FRAMES, N_MELS],
DataType::F32,
),
multi_array(
"is_longer",
&[1, 1],
DataType::I32,
true,
2,
vec![vec![1, 1]],
&[1, 1],
),
],
vec![fixed(
names::AUDIO_EMBEDS,
&[1, EMBEDDING_DIM],
DataType::F32,
)],
Vec::new(),
);
assert!(check(&description).is_ok());
}
#[test]
fn the_contract_refuses_an_optional_embeds_output() {
let description = ModelDescription::from_parts(
vec![fixed(
names::INPUT_FEATURES,
&[1, 1, T_FRAMES, N_MELS],
DataType::F32,
)],
vec![multi_array(
names::AUDIO_EMBEDS,
&[1, EMBEDDING_DIM],
DataType::F32,
true,
2,
vec![vec![1, EMBEDDING_DIM]],
&[1, EMBEDDING_DIM],
)],
Vec::new(),
);
let err = check(&description).unwrap_err();
assert!(
matches!(&err, Error::ContractMismatch(m) if m.feature() == names::AUDIO_EMBEDS),
"{err}"
);
}
#[test]
fn the_contract_refuses_a_graph_that_declares_state() {
let description = ModelDescription::from_parts(
vec![fixed(
names::INPUT_FEATURES,
&[1, 1, T_FRAMES, N_MELS],
DataType::F32,
)],
vec![fixed(
names::AUDIO_EMBEDS,
&[1, EMBEDDING_DIM],
DataType::F32,
)],
vec![fixed("kv_cache", &[1, 8], DataType::F32)],
);
assert!(
matches!(check(&description), Err(Error::UnsatisfiableState(name)) if name == "kv_cache")
);
}
#[test]
fn the_audio_contract_refuses_the_vendored_silero_bundle() {
let bundle = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../Models/vadkit/silero-vad-unified-256ms-v6.2.1.mlmodelc");
assert!(
bundle.is_dir(),
"the vendored silero bundle is committed, so this gate is NOT model-gated; \
looked for {}",
bundle.display()
);
let model = Model::load(&bundle, ComputeUnits::CpuOnly).expect("the committed bundle loads");
assert!(
model.description().input(names::INPUT_FEATURES).is_none(),
"silero declares no `input_features`, which is what makes it this gate's model"
);
let violation = Checked::new(model, &audio_contract())
.expect_err("silero does not satisfy the CLAP audio contract");
assert!(
matches!(&violation, crate::model::contract::ContractViolation::Missing(m)
if m.feature() == names::INPUT_FEATURES),
"expected `input_features` missing, got {violation}"
);
}