use ironlab_ir::*;
use proptest::prelude::*;
use serde_json::json;
#[test]
fn nan_is_written_as_null() {
let array = NdArray::vector(vec![1.5, f64::NAN, -2.0]);
let value = serde_json::to_value(&array).unwrap();
assert_eq!(value, json!({ "shape": [3], "values": [1.5, null, -2.0] }));
}
#[test]
fn null_is_read_as_nan() {
let array: NdArray =
serde_json::from_value(json!({ "shape": [2], "values": [null, 4.0] })).unwrap();
assert_eq!(array.shape, vec![2]);
assert!(array.values[0].is_nan());
assert_eq!(array.values[1], 4.0);
}
#[test]
fn infinities_are_written_as_null_and_read_as_nan() {
let array = NdArray::vector(vec![f64::INFINITY, f64::NEG_INFINITY]);
let value = serde_json::to_value(&array).unwrap();
assert_eq!(value["values"], json!([null, null]));
let restored: NdArray = serde_json::from_value(value).unwrap();
assert!(restored.values.iter().all(|v| v.is_nan()));
}
#[test]
fn non_numeric_values_are_rejected() {
let result: Result<NdArray, _> =
serde_json::from_value(json!({ "shape": [1], "values": ["1.0"] }));
assert!(result.is_err());
}
#[test]
fn arrays_with_nan_in_the_same_places_are_equal() {
let a = NdArray::vector(vec![1.0, f64::NAN]);
assert_eq!(a, a.clone());
assert_ne!(a, NdArray::vector(vec![1.0, 2.0]));
let reshaped = NdArray {
shape: vec![1, 2],
values: a.values.clone(),
};
assert_ne!(a, reshaped);
}
#[test]
fn from_shape_rejects_a_mismatched_value_count() {
assert!(NdArray::from_shape(vec![2, 3], vec![0.0; 6]).is_ok());
assert!(matches!(
NdArray::from_shape(vec![2, 3], vec![0.0; 5]),
Err(IrError::InvalidShape { len: 5, .. })
));
}
fn value_with_non_finite() -> impl Strategy<Value = f64> {
prop_oneof![
4 => any::<f64>(),
1 => Just(f64::NAN),
1 => Just(f64::INFINITY),
1 => Just(f64::NEG_INFINITY),
1 => Just(-0.0),
1 => Just(f64::MIN_POSITIVE / 3.0),
]
}
proptest! {
#[test]
fn array_values_round_trip_through_json(values in prop::collection::vec(value_with_non_finite(), 0..64)) {
let array = NdArray::vector(values.clone());
let text = serde_json::to_string(&array).unwrap();
let restored: NdArray = serde_json::from_str(&text).unwrap();
prop_assert_eq!(&restored.shape, &array.shape);
prop_assert_eq!(restored.values.len(), values.len());
for (original, restored) in values.iter().zip(&restored.values) {
if original.is_finite() {
prop_assert_eq!(original.to_bits(), restored.to_bits());
} else {
prop_assert!(restored.is_nan());
}
}
}
}