use crate::{
features::{DesignParameter, DistinctMembers, ParameterId, ParameterValue},
scalar::FiniteReal,
};
#[test]
fn parameter_real_admission_preserves_finite_signed_wire_values() {
for value in [-f64::MAX, -1.0, -0.0, 0.0, 1.0, f64::MAX] {
let parameter = ParameterValue::Real(FiniteReal::new(value).unwrap());
let wire = serde_json::json!({"kind": "real", "value": value});
assert_eq!(serde_json::to_value(¶meter).unwrap(), wire);
assert_eq!(
serde_json::from_value::<ParameterValue>(wire).unwrap(),
parameter
);
}
for value in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
assert!(FiniteReal::new(value).is_none());
let deserializer = serde::de::value::F64Deserializer::<serde::de::value::Error>::new(value);
let error = super::super::deserialize_parameter_real(deserializer).unwrap_err();
assert!(error.to_string().contains("value"));
}
}
#[test]
fn parameter_dependencies_reject_duplicates_and_preserve_source_order() {
let first = ParameterId::mint("test:test:parameter#first").unwrap();
let second = ParameterId::mint("test:test:parameter#second").unwrap();
assert!(DistinctMembers::try_from(
vec![first.clone(), first.clone()],
&cadmpeg_test_support::service_decode_context()
)
.is_err());
let mut dependencies = DistinctMembers::try_from(
vec![second.clone(), first.clone()],
&cadmpeg_test_support::service_decode_context(),
)
.unwrap();
assert!(!dependencies
.insert(
&cadmpeg_test_support::service_decode_context(),
first.clone(),
"insert fixture member"
)
.expect("member insertion admission"));
assert_eq!(dependencies.as_slice(), &[second.clone(), first.clone()]);
dependencies.retain(|id| id == &first);
assert_eq!(dependencies.as_slice(), std::slice::from_ref(&first));
dependencies.clear();
assert!(dependencies.is_empty());
let mut wire = serde_json::json!({
"id":"test:test:parameter#owner", "ordinal":0, "name":"value", "expression":"first+second",
"dependencies":[second, first]
});
let parameter: DesignParameter = serde_json::from_value(wire.clone()).unwrap();
assert_eq!(serde_json::to_value(parameter).unwrap(), wire);
wire["dependencies"] = serde_json::json!([first, first]);
let error = serde_json::from_value::<DesignParameter>(wire.clone()).unwrap_err();
assert!(error.to_string().contains("dependencies"));
wire.as_object_mut().unwrap().remove("dependencies");
let parameter: DesignParameter = serde_json::from_value(wire.clone()).unwrap();
assert!(parameter.dependencies.is_empty());
assert_eq!(serde_json::to_value(parameter).unwrap(), wire);
}
#[test]
fn reserved_parameter_dependencies_preserve_order_and_reject_repeats() {
let first = ParameterId::mint("test:test:parameter#first").unwrap();
let second = ParameterId::mint("test:test:parameter#second").unwrap();
let ordered = crate::test_support::with_service_decode_context(|ctx| {
DistinctMembers::try_from(vec![second.clone(), first.clone()], ctx)
.map_err(cadmpeg_core::CodecError::from)
})
.expect("source-ordered members are distinct");
assert_eq!(ordered.as_slice(), &[second.clone(), first.clone()]);
assert!(crate::test_support::with_service_decode_context(|ctx| {
DistinctMembers::try_from(vec![first.clone(), second, first], ctx)
.map_err(cadmpeg_core::CodecError::from)
})
.is_err());
}
#[test]
fn distinct_constructor_preserves_collection_refusal_in_the_caller_session() {
use cadmpeg_core::decode::{DecodeArena, DecodeContext, DecodePolicy, ResourceDimension};
let arena = DecodeArena::new();
let mut policy = DecodePolicy::service();
policy.limits.max_collection_items = 0;
let (ctx, _) = DecodeContext::from_root_bytes(&[], &arena, &policy).unwrap();
let member = ParameterId::mint("test:model:parameter#member").unwrap();
let Err(crate::features::FeatureCollectionError::Resource(limit)) =
DistinctMembers::try_from(vec![member], &ctx)
else {
panic!("member slot must be refused");
};
assert_eq!(limit.dimension, ResourceDimension::CollectionItems);
assert!(
matches!(ctx.finish_session(), Err(cadmpeg_core::CodecError::ResourceLimit(sticky)) if sticky == limit)
);
}