use std::collections::BTreeMap;
use tensogram::*;
fn make_global_meta() -> GlobalMetadata {
GlobalMetadata {
..Default::default()
}
}
fn make_descriptor(shape: Vec<u64>, dtype: Dtype, byte_order: ByteOrder) -> DataObjectDescriptor {
let strides = if shape.is_empty() {
vec![]
} else {
let mut s = vec![1u64; shape.len()];
for i in (0..shape.len() - 1).rev() {
s[i] = s[i + 1] * shape[i + 1];
}
s
};
DataObjectDescriptor {
obj_type: "ntensor".to_string(),
ndim: shape.len() as u64,
shape,
strides,
dtype,
byte_order,
encoding: "none".to_string(),
filter: "none".to_string(),
compression: "none".to_string(),
params: BTreeMap::new(),
masks: None,
}
}
fn f32_bytes(values: &[f32]) -> Vec<u8> {
values.iter().flat_map(|v| v.to_ne_bytes()).collect()
}
fn f64_bytes(values: &[f64]) -> Vec<u8> {
values.iter().flat_map(|v| v.to_ne_bytes()).collect()
}
#[test]
fn default_encode_rejects_nan_float32() {
let data = f32_bytes(&[1.0, f32::NAN, 3.0]);
let desc = make_descriptor(vec![3], Dtype::Float32, ByteOrder::native());
let err = encode(
&make_global_meta(),
&[(&desc, &data)],
&EncodeOptions::default(),
)
.unwrap_err();
let msg = err.to_string();
assert!(matches!(err, TensogramError::Encoding(_)));
assert!(msg.contains("NaN"), "message must name the kind: {msg}");
assert!(
msg.contains("element 1"),
"message must name the index: {msg}"
);
assert!(
msg.contains("float32"),
"message must name the dtype: {msg}"
);
}
#[test]
fn default_encode_rejects_positive_inf_float64() {
let data = f64_bytes(&[1.0, f64::INFINITY]);
let desc = make_descriptor(vec![2], Dtype::Float64, ByteOrder::native());
let err = encode(
&make_global_meta(),
&[(&desc, &data)],
&EncodeOptions::default(),
)
.unwrap_err();
assert!(err.to_string().contains("+Inf"));
}
#[test]
fn default_encode_rejects_negative_inf_float64() {
let data = f64_bytes(&[1.0, f64::NEG_INFINITY]);
let desc = make_descriptor(vec![2], Dtype::Float64, ByteOrder::native());
let err = encode(
&make_global_meta(),
&[(&desc, &data)],
&EncodeOptions::default(),
)
.unwrap_err();
assert!(err.to_string().contains("-Inf"));
}
#[test]
fn default_encode_rejects_complex64_nan_in_real() {
let data: Vec<u8> = [1.0_f32, 2.0, f32::NAN, 3.0]
.iter()
.flat_map(|v| v.to_ne_bytes())
.collect();
let desc = make_descriptor(vec![2], Dtype::Complex64, ByteOrder::native());
let err = encode(
&make_global_meta(),
&[(&desc, &data)],
&EncodeOptions::default(),
)
.unwrap_err();
let msg = err.to_string();
assert!(msg.contains("NaN") && msg.contains("real"));
}
#[test]
fn default_encode_rejects_float16_nan_bit_level() {
let data: Vec<u8> = [0x3C00u16, 0x7E00]
.iter()
.flat_map(|v| v.to_ne_bytes())
.collect();
let desc = make_descriptor(vec![2], Dtype::Float16, ByteOrder::native());
let err = encode(
&make_global_meta(),
&[(&desc, &data)],
&EncodeOptions::default(),
)
.unwrap_err();
assert!(err.to_string().contains("NaN"));
}
#[test]
fn default_encode_accepts_all_finite_float64() {
let data = f64_bytes(&[1.0, 2.0, 3.0, 4.0]);
let desc = make_descriptor(vec![4], Dtype::Float64, ByteOrder::native());
encode(
&make_global_meta(),
&[(&desc, &data)],
&EncodeOptions::default(),
)
.expect("finite data must encode");
}
#[test]
fn default_encode_accepts_negative_zero_and_subnormals() {
let subnormal = f64::from_bits(0x0000_0000_0000_0001);
let data = f64_bytes(&[0.0, -0.0, subnormal, -subnormal]);
let desc = make_descriptor(vec![4], Dtype::Float64, ByteOrder::native());
encode(
&make_global_meta(),
&[(&desc, &data)],
&EncodeOptions::default(),
)
.expect("-0.0 and subnormals are finite, must pass");
}
#[test]
fn default_encode_never_scans_integer_dtypes() {
let data = vec![0xFFu8; 16]; let desc = make_descriptor(vec![4], Dtype::Uint32, ByteOrder::native());
encode(
&make_global_meta(),
&[(&desc, &data)],
&EncodeOptions::default(),
)
.expect("uint32 payload must encode regardless of bit pattern");
}
#[test]
fn encode_pre_encoded_accepts_opaque_nan_bytes() {
let data = f32_bytes(&[1.0, f32::NAN]);
let desc = make_descriptor(vec![2], Dtype::Float32, ByteOrder::native());
encode_pre_encoded(
&make_global_meta(),
&[(&desc, &data)],
&EncodeOptions::default(),
)
.expect("encode_pre_encoded must not run the finite check");
}