#![cfg(all(feature = "ndarray", not(target_pointer_width = "32")))]
use hdf5_pure::{Error, File, FileBuilder};
use ndarray::{Array1, Array2, Array3, ArrayD, ShapeBuilder, array};
use tempfile::tempdir;
fn write_then_open(name: &str, build: impl FnOnce(&mut FileBuilder)) -> File {
let mut fb = FileBuilder::new();
build(&mut fb);
let bytes = fb.finish().unwrap();
let file = File::from_bytes(bytes).unwrap();
file.dataset(name).unwrap();
file
}
#[test]
fn roundtrip_1d_f32() {
let a: Array1<f32> = array![1.5, 2.5, 3.5, 4.5];
let file = write_then_open("v", |fb| {
fb.create_dataset("v").with_ndarray(&a);
});
let ds = file.dataset("v").unwrap();
assert_eq!(ds.shape().unwrap(), vec![4]);
let back: Array1<f32> = ds.read_array().unwrap();
assert_eq!(back, a);
}
#[test]
fn roundtrip_2d_f64() {
let a: Array2<f64> = array![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
let file = write_then_open("m", |fb| {
fb.create_dataset("m").with_ndarray(&a);
});
let ds = file.dataset("m").unwrap();
assert_eq!(ds.shape().unwrap(), vec![2, 3]);
let back: Array2<f64> = ds.read_array().unwrap();
assert_eq!(back, a);
}
#[test]
fn roundtrip_3d_i32() {
let a: Array3<i32> = Array3::from_shape_vec((2, 2, 3), (0..12).collect()).unwrap();
let file = write_then_open("cube", |fb| {
fb.create_dataset("cube").with_ndarray(&a);
});
let ds = file.dataset("cube").unwrap();
assert_eq!(ds.shape().unwrap(), vec![2, 2, 3]);
let back: Array3<i32> = ds.read_array().unwrap();
assert_eq!(back, a);
}
#[test]
fn roundtrip_2d_i64_and_u32() {
let a: Array2<i64> = array![[-1, -2], [-3, -4], [-5, -6]];
let b: Array2<u32> = array![[10, 20, 30], [40, 50, 60]];
let mut fb = FileBuilder::new();
fb.create_dataset("a").with_ndarray(&a);
fb.create_dataset("b").with_ndarray(&b);
let file = File::from_bytes(fb.finish().unwrap()).unwrap();
assert_eq!(
file.dataset("a").unwrap().read_array::<i64, _>().unwrap(),
a
);
assert_eq!(
file.dataset("b").unwrap().read_array::<u32, _>().unwrap(),
b
);
}
#[test]
fn read_array_dyn_reports_runtime_rank() {
let a: Array3<f64> = Array3::from_shape_vec((3, 1, 2), vec![1., 2., 3., 4., 5., 6.]).unwrap();
let file = write_then_open("d", |fb| {
fb.create_dataset("d").with_ndarray(&a);
});
let dynamic: ArrayD<f64> = file.dataset("d").unwrap().read_array_dyn().unwrap();
assert_eq!(dynamic.ndim(), 3);
assert_eq!(dynamic.shape(), &[3, 1, 2]);
assert_eq!(dynamic, a.into_dyn());
}
#[test]
fn transposed_view_is_written_row_major() {
let a: Array2<f64> = array![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
let transposed = a.t(); assert!(!transposed.is_standard_layout());
let file = write_then_open("t", |fb| {
fb.create_dataset("t").with_ndarray(&transposed);
});
let ds = file.dataset("t").unwrap();
assert_eq!(ds.shape().unwrap(), vec![3, 2]);
let back: Array2<f64> = ds.read_array().unwrap();
assert_eq!(back, transposed);
assert_eq!(back, array![[1.0, 4.0], [2.0, 5.0], [3.0, 6.0]]);
}
#[test]
fn fortran_order_array_is_written_row_major() {
let f: Array2<f64> =
Array2::from_shape_vec((2, 3).f(), vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]).unwrap();
assert!(!f.is_standard_layout());
let expected: Array2<f64> = array![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
assert_eq!(f, expected);
let file = write_then_open("f", |fb| {
fb.create_dataset("f").with_ndarray(&f);
});
let back: Array2<f64> = file.dataset("f").unwrap().read_array().unwrap();
assert_eq!(back, expected);
}
#[test]
fn read_array_wrong_rank_errors() {
let a: Array3<f64> =
Array3::from_shape_vec((2, 2, 2), (0..8).map(|x| x as f64).collect()).unwrap();
let file = write_then_open("cube", |fb| {
fb.create_dataset("cube").with_ndarray(&a);
});
let ds = file.dataset("cube").unwrap();
let err = ds.read_array::<f64, ndarray::Ix2>().unwrap_err();
assert!(matches!(err, Error::Shape(_)), "got {err:?}");
assert_eq!(ds.read_array_dyn::<f64>().unwrap(), a.into_dyn());
}
#[test]
fn crosscheck_2d_with_reference_library() {
let dir = tempdir().unwrap();
let path = dir.path().join("nd2.h5");
let a: Array2<f64> = array![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
let mut fb = FileBuilder::new();
fb.create_dataset("m").with_ndarray(&a);
fb.write(&path).unwrap();
let file = hdf5::File::open(&path).unwrap();
let ds = file.dataset("m").unwrap();
assert_eq!(ds.shape(), vec![2, 3]);
let read: Array2<f64> = ds.read_2d::<f64>().unwrap();
assert_eq!(read, a);
}
#[test]
fn crosscheck_3d_with_reference_library() {
let dir = tempdir().unwrap();
let path = dir.path().join("nd3.h5");
let a: Array3<i32> = Array3::from_shape_vec((2, 3, 4), (0..24).collect()).unwrap();
let mut fb = FileBuilder::new();
fb.create_dataset("cube").with_ndarray(&a);
fb.write(&path).unwrap();
let file = hdf5::File::open(&path).unwrap();
let ds = file.dataset("cube").unwrap();
assert_eq!(ds.shape(), vec![2, 3, 4]);
let read: ArrayD<i32> = ds.read_dyn::<i32>().unwrap();
assert_eq!(read, a.into_dyn());
}
#[test]
fn crosscheck_chunked_compressed_ndarray() {
let dir = tempdir().unwrap();
let path = dir.path().join("nd_chunked.h5");
let a: Array2<f64> = Array2::from_shape_fn((8, 8), |(i, j)| (i * 8 + j) as f64 * 0.25);
let mut fb = FileBuilder::new();
fb.create_dataset("m")
.with_ndarray(&a)
.with_chunks(&[4, 4])
.with_deflate(6);
fb.write(&path).unwrap();
let file = hdf5::File::open(&path).unwrap();
let read: Array2<f64> = file.dataset("m").unwrap().read_2d::<f64>().unwrap();
assert_eq!(read, a);
let ours = File::open(&path).unwrap();
let back: Array2<f64> = ours.dataset("m").unwrap().read_array().unwrap();
assert_eq!(back, a);
}