use hdf5_pure::{DType, Datatype, EnumTypeBuilder, File, FileBuilder, FormatError};
fn write_then_open(build: impl FnOnce(&mut FileBuilder)) -> File {
let mut builder = FileBuilder::new();
build(&mut builder);
let bytes = builder.finish().expect("finish");
File::from_bytes(bytes).expect("from_bytes")
}
#[test]
fn i32_enum_dataset_preserves_members_and_values() {
let dt = EnumTypeBuilder::i32_based()
.value("RED", 0)
.value("GREEN", 1)
.value("BLUE", 2)
.build();
let file = write_then_open(|b| {
b.create_dataset("color")
.with_enum_i32_data(dt, &[0, 1, 2, 1]);
});
let ds = file.dataset("color").unwrap();
assert_eq!(ds.shape().unwrap(), vec![4]);
match ds.datatype().unwrap() {
Datatype::Enumeration {
base_type, members, ..
} => {
assert!(
matches!(
*base_type,
Datatype::FixedPoint {
size: 4,
signed: true,
..
}
),
"expected i32 base, got {base_type:?}"
);
let pairs: Vec<(&str, &[u8])> = members
.iter()
.map(|m| (m.name.as_str(), m.value.as_slice()))
.collect();
assert_eq!(
pairs,
vec![
("RED", &0i32.to_le_bytes()[..]),
("GREEN", &1i32.to_le_bytes()[..]),
("BLUE", &2i32.to_le_bytes()[..]),
]
);
}
other => panic!("expected Enumeration, got {other:?}"),
}
}
#[test]
fn i32_enum_dataset_reads_back_through_base_type() {
let dt = EnumTypeBuilder::i32_based()
.value("RED", 0)
.value("GREEN", 1)
.value("BLUE", 2)
.build();
let file = write_then_open(|b| {
b.create_dataset("color")
.with_enum_i32_data(dt, &[0, 1, 2, 1]);
});
let ds = file.dataset("color").unwrap();
assert_eq!(ds.read_i32().unwrap(), vec![0, 1, 2, 1]);
assert_eq!(ds.read_i64().unwrap(), vec![0, 1, 2, 1]);
assert_eq!(ds.read_u32().unwrap(), vec![0, 1, 2, 1]);
assert_eq!(ds.read_f64().unwrap(), vec![0.0, 1.0, 2.0, 1.0]);
}
#[test]
fn enum_dataset_classifies_as_dtype_enum_of_member_names() {
let dt = EnumTypeBuilder::i32_based()
.value("RED", 0)
.value("GREEN", 1)
.value("BLUE", 2)
.build();
let file = write_then_open(|b| {
b.create_dataset("color").with_enum_i32_data(dt, &[0, 1, 2]);
});
let ds = file.dataset("color").unwrap();
assert_eq!(
ds.dtype().unwrap(),
DType::Enum(vec!["RED".into(), "GREEN".into(), "BLUE".into()])
);
assert_eq!(format!("{}", ds.dtype().unwrap()), "enum[RED, GREEN, BLUE]");
}
#[test]
fn u8_enum_dataset_roundtrips() {
let dt = EnumTypeBuilder::u8_based()
.u8_value("OFF", 0)
.u8_value("ON", 1)
.build();
let file = write_then_open(|b| {
b.create_dataset("switch")
.with_enum_u8_data(dt, &[0, 1, 1, 0]);
});
let ds = file.dataset("switch").unwrap();
assert_eq!(
ds.dtype().unwrap(),
DType::Enum(vec!["OFF".into(), "ON".into()])
);
assert_eq!(ds.read_raw().unwrap().len(), 4);
assert_eq!(ds.read_u8().unwrap(), vec![0, 1, 1, 0]);
assert_eq!(ds.read_i32().unwrap(), vec![0, 1, 1, 0]);
}
#[test]
fn u8_enum_reads_identically_to_a_plain_u8_dataset() {
let dt = EnumTypeBuilder::u8_based()
.u8_value("LO", 0)
.u8_value("HI", 255)
.build();
let file = write_then_open(|b| {
b.create_dataset("level").with_enum_u8_data(dt, &[0, 255]);
b.create_dataset("plain").with_u8_data(&[0, 255]);
});
let level = file.dataset("level").unwrap();
let plain = file.dataset("plain").unwrap();
assert_eq!(level.read_u8().unwrap(), vec![0, 255]);
assert_eq!(level.read_u32().unwrap(), vec![0, 255]);
assert_eq!(level.read_i32().unwrap(), plain.read_i32().unwrap());
assert_eq!(level.read_u32().unwrap(), plain.read_u32().unwrap());
}
#[test]
fn enum_i32_data_into_u8_enum_type_is_rejected() {
let u8_enum = EnumTypeBuilder::u8_based()
.u8_value("OFF", 0)
.u8_value("ON", 1)
.build();
let mut builder = FileBuilder::new();
builder
.create_dataset("bad")
.with_enum_i32_data(u8_enum, &[0, 1]);
match builder.finish() {
Err(hdf5_pure::Error::Format(FormatError::ShapeDataMismatch {
expected,
actual,
element_size,
})) => {
assert_eq!(element_size, 1);
assert_eq!(expected, 2); assert_eq!(actual, 8); }
other => panic!("expected ShapeDataMismatch, got {other:?}"),
}
}
#[test]
fn non_enum_reads_are_unaffected_by_the_enum_unwrap() {
let file = write_then_open(|b| {
b.create_dataset("ints").with_i32_data(&[10, 20, 30]);
b.create_dataset("text").with_vlen_strings(&["a", "bc"]);
});
assert_eq!(
file.dataset("ints").unwrap().read_i32().unwrap(),
vec![10, 20, 30]
);
let err = file.dataset("text").unwrap().read_i32().unwrap_err();
assert!(
matches!(
err,
hdf5_pure::Error::Format(FormatError::TypeMismatch { .. })
),
"reading a vlen-string dataset as i32 should still be a TypeMismatch, got {err:?}"
);
}