/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the LICENSE file, which can be found at the root of the source code * * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package jtest; import static org.junit.Assert.*; import static jtest.FfmTestSupport.*; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import org.hdfgroup.javahdf5.hdf5_h; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; /** * FFM-only tests for HDF5 Reference (H5R) operations. * * This test class uses direct FFM bindings without the hdf.hdf5lib wrapper layer. */ public class TestH5Rffm { @Rule public TestName testname = new TestName(); private static final String H5_FILE = "test_H5Rffm.h5"; private static final int DIM_X = 4; private static final int DIM_Y = 6; long H5fid = hdf5_h.H5I_INVALID_HID(); long H5dsid = hdf5_h.H5I_INVALID_HID(); long H5did = hdf5_h.H5I_INVALID_HID(); long H5gid = hdf5_h.H5I_INVALID_HID(); @Before public void createH5file() { System.out.print(testname.getMethodName()); try (Arena arena = Arena.ofConfined()) { // Create file MemorySegment filename = stringToSegment(arena, H5_FILE); H5fid = hdf5_h.H5Fcreate(filename, hdf5_h.H5F_ACC_TRUNC(), hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT()); assertTrue("H5Fcreate failed", isValidId(H5fid)); // Create dataspace long[] dims = {DIM_X, DIM_Y}; MemorySegment dimsSegment = allocateLongArray(arena, 2); copyToSegment(dimsSegment, dims); H5dsid = hdf5_h.H5Screate_simple(2, dimsSegment, MemorySegment.NULL); assertTrue("H5Screate_simple failed", isValidId(H5dsid)); // Create group MemorySegment groupname = stringToSegment(arena, "Group1"); H5gid = hdf5_h.H5Gcreate2(H5fid, groupname, hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT()); assertTrue("H5Gcreate2 failed", isValidId(H5gid)); // Create dataset MemorySegment dsetname = stringToSegment(arena, "dset"); H5did = hdf5_h.H5Dcreate2(H5fid, dsetname, hdf5_h.H5T_STD_I32BE_g(), H5dsid, hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT()); assertTrue("H5Dcreate2 failed", isValidId(H5did)); // Write some data int[][] data = new int[DIM_X][DIM_Y]; for (int i = 0; i < DIM_X; i++) for (int j = 0; j < DIM_Y; j++) data[i][j] = i * DIM_Y + j; MemorySegment dataBuffer = allocateIntArray(arena, DIM_X * DIM_Y); for (int i = 0; i < DIM_X; i++) for (int j = 0; j < DIM_Y; j++) dataBuffer.setAtIndex(java.lang.foreign.ValueLayout.JAVA_INT, i * DIM_Y + j, data[i][j]); int result = hdf5_h.H5Dwrite(H5did, hdf5_h.H5T_NATIVE_INT_g(), hdf5_h.H5S_ALL(), hdf5_h.H5S_ALL(), hdf5_h.H5P_DEFAULT(), dataBuffer); assertTrue("H5Dwrite failed", isSuccess(result)); // Flush file result = hdf5_h.H5Fflush(H5fid, hdf5_h.H5F_SCOPE_LOCAL()); assertTrue("H5Fflush failed", isSuccess(result)); } } @After public void deleteH5file() { if (isValidId(H5did)) { closeQuietly(H5did, hdf5_h::H5Dclose); H5did = hdf5_h.H5I_INVALID_HID(); } if (isValidId(H5gid)) { closeQuietly(H5gid, hdf5_h::H5Gclose); H5gid = hdf5_h.H5I_INVALID_HID(); } if (isValidId(H5dsid)) { closeQuietly(H5dsid, hdf5_h::H5Sclose); H5dsid = hdf5_h.H5I_INVALID_HID(); } if (isValidId(H5fid)) { closeQuietly(H5fid, hdf5_h::H5Fclose); H5fid = hdf5_h.H5I_INVALID_HID(); } System.out.println(); } // ============================================================================ // Phase 1: Object Reference Operations // ============================================================================ @Test public void testH5Rcreate_destroy_object() { try (Arena arena = Arena.ofConfined()) { // Allocate reference buffer MemorySegment ref_ptr = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); // Create object reference to dataset MemorySegment dsetname = stringToSegment(arena, "dset"); int result = hdf5_h.H5Rcreate_object(H5fid, dsetname, hdf5_h.H5P_DEFAULT(), ref_ptr); assertTrue("H5Rcreate_object failed", isSuccess(result)); // Get reference type int ref_type = hdf5_h.H5Rget_type(ref_ptr); assertEquals("Reference type should be OBJECT", hdf5_h.H5R_OBJECT2(), ref_type); // Destroy reference result = hdf5_h.H5Rdestroy(ref_ptr); assertTrue("H5Rdestroy failed", isSuccess(result)); } } @Test public void testH5Ropen_object() { try (Arena arena = Arena.ofConfined()) { // Create object reference MemorySegment ref_ptr = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); MemorySegment dsetname = stringToSegment(arena, "dset"); int result = hdf5_h.H5Rcreate_object(H5fid, dsetname, hdf5_h.H5P_DEFAULT(), ref_ptr); assertTrue("H5Rcreate_object failed", isSuccess(result)); // Open object via reference long opened_did = hdf5_h.H5Ropen_object(ref_ptr, hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT()); assertTrue("H5Ropen_object failed", isValidId(opened_did)); // Verify it's a dataset int obj_type = hdf5_h.H5Iget_type(opened_did); assertEquals("Should be dataset type", hdf5_h.H5I_DATASET(), obj_type); // Close opened object hdf5_h.H5Dclose(opened_did); // Destroy reference hdf5_h.H5Rdestroy(ref_ptr); } } // ============================================================================ // Phase 2: Region Reference Operations // ============================================================================ @Test public void testH5Rcreate_region() { try (Arena arena = Arena.ofConfined()) { // Create a region selection (hyperslab) long region_sid = hdf5_h.H5Scopy(H5dsid); assertTrue("H5Scopy failed", isValidId(region_sid)); long[] start = {1, 1}; long[] count = {2, 3}; MemorySegment starts = allocateLongArray(arena, 2); MemorySegment counts = allocateLongArray(arena, 2); copyToSegment(starts, start); copyToSegment(counts, count); int result = hdf5_h.H5Sselect_hyperslab(region_sid, hdf5_h.H5S_SELECT_SET(), starts, MemorySegment.NULL, counts, MemorySegment.NULL); assertTrue("H5Sselect_hyperslab failed", isSuccess(result)); // Create region reference MemorySegment ref_ptr = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); MemorySegment dsetname = stringToSegment(arena, "dset"); result = hdf5_h.H5Rcreate_region(H5fid, dsetname, region_sid, hdf5_h.H5P_DEFAULT(), ref_ptr); assertTrue("H5Rcreate_region failed", isSuccess(result)); // Verify reference type int ref_type = hdf5_h.H5Rget_type(ref_ptr); assertEquals("Reference type should be DATASET_REGION", hdf5_h.H5R_DATASET_REGION2(), ref_type); // Clean up hdf5_h.H5Rdestroy(ref_ptr); hdf5_h.H5Sclose(region_sid); } } @Test public void testH5Ropen_region() { try (Arena arena = Arena.ofConfined()) { // Create region selection long region_sid = hdf5_h.H5Scopy(H5dsid); assertTrue("H5Scopy failed", isValidId(region_sid)); long[] start = {0, 0}; long[] count = {2, 2}; MemorySegment starts = allocateLongArray(arena, 2); MemorySegment counts = allocateLongArray(arena, 2); copyToSegment(starts, start); copyToSegment(counts, count); int result = hdf5_h.H5Sselect_hyperslab(region_sid, hdf5_h.H5S_SELECT_SET(), starts, MemorySegment.NULL, counts, MemorySegment.NULL); assertTrue("H5Sselect_hyperslab failed", isSuccess(result)); // Create region reference MemorySegment ref_ptr = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); MemorySegment dsetname = stringToSegment(arena, "dset"); result = hdf5_h.H5Rcreate_region(H5fid, dsetname, region_sid, hdf5_h.H5P_DEFAULT(), ref_ptr); assertTrue("H5Rcreate_region failed", isSuccess(result)); // Open region long opened_region_sid = hdf5_h.H5Ropen_region(ref_ptr, hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT()); assertTrue("H5Ropen_region failed", isValidId(opened_region_sid)); // Verify region selection has correct number of points long npoints = hdf5_h.H5Sget_select_npoints(opened_region_sid); assertEquals("Region should have 4 points (2x2)", 4L, npoints); // Clean up hdf5_h.H5Sclose(opened_region_sid); hdf5_h.H5Rdestroy(ref_ptr); hdf5_h.H5Sclose(region_sid); } } // ============================================================================ // Phase 3: Attribute Reference Operations // ============================================================================ @Test public void testH5Rcreate_open_attr() { try (Arena arena = Arena.ofConfined()) { // Create attribute on dataset MemorySegment attrname = stringToSegment(arena, "test_attr"); long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR()); long aid = hdf5_h.H5Acreate2(H5did, attrname, hdf5_h.H5T_NATIVE_INT_g(), attr_sid, hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT()); assertTrue("H5Acreate2 failed", isValidId(aid)); // Write attribute value MemorySegment attrData = allocateInt(arena); setInt(attrData, 42); int result = hdf5_h.H5Awrite(aid, hdf5_h.H5T_NATIVE_INT_g(), attrData); assertTrue("H5Awrite failed", isSuccess(result)); hdf5_h.H5Aclose(aid); hdf5_h.H5Sclose(attr_sid); // Flush to ensure attribute is written hdf5_h.H5Fflush(H5fid, hdf5_h.H5F_SCOPE_LOCAL()); // Create attribute reference MemorySegment ref_ptr = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); MemorySegment dsetname = stringToSegment(arena, "dset"); result = hdf5_h.H5Rcreate_attr(H5fid, dsetname, attrname, hdf5_h.H5P_DEFAULT(), ref_ptr); assertTrue("H5Rcreate_attr failed", isSuccess(result)); // Verify reference type int ref_type = hdf5_h.H5Rget_type(ref_ptr); assertEquals("Reference type should be ATTR", hdf5_h.H5R_ATTR(), ref_type); // Open attribute via reference long opened_aid = hdf5_h.H5Ropen_attr(ref_ptr, hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT()); assertTrue("H5Ropen_attr failed", isValidId(opened_aid)); // Read attribute value back MemorySegment readData = allocateInt(arena); result = hdf5_h.H5Aread(opened_aid, hdf5_h.H5T_NATIVE_INT_g(), readData); assertTrue("H5Aread failed", isSuccess(result)); int value = getInt(readData); assertEquals("Attribute value should be 42", 42, value); // Clean up hdf5_h.H5Aclose(opened_aid); hdf5_h.H5Rdestroy(ref_ptr); } } @Test public void testH5Rget_attr_name() { try (Arena arena = Arena.ofConfined()) { // Create attribute MemorySegment attrname = stringToSegment(arena, "my_attribute"); long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR()); long aid = hdf5_h.H5Acreate2(H5did, attrname, hdf5_h.H5T_NATIVE_INT_g(), attr_sid, hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT()); assertTrue("H5Acreate2 failed", isValidId(aid)); hdf5_h.H5Aclose(aid); hdf5_h.H5Sclose(attr_sid); hdf5_h.H5Fflush(H5fid, hdf5_h.H5F_SCOPE_LOCAL()); // Create attribute reference MemorySegment ref_ptr = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); MemorySegment dsetname = stringToSegment(arena, "dset"); int result = hdf5_h.H5Rcreate_attr(H5fid, dsetname, attrname, hdf5_h.H5P_DEFAULT(), ref_ptr); assertTrue("H5Rcreate_attr failed", isSuccess(result)); // Get attribute name size long name_size = hdf5_h.H5Rget_attr_name(ref_ptr, MemorySegment.NULL, 0); assertTrue("H5Rget_attr_name size query failed", name_size > 0); // Get attribute name MemorySegment nameBuffer = arena.allocate(name_size + 1); long actual_size = hdf5_h.H5Rget_attr_name(ref_ptr, nameBuffer, name_size + 1); assertTrue("H5Rget_attr_name failed", actual_size > 0); String retrieved_name = nameBuffer.getString(0); assertEquals("Attribute name should match", "my_attribute", retrieved_name); // Clean up hdf5_h.H5Rdestroy(ref_ptr); } } // ============================================================================ // Phase 4: Reference Utility Operations // ============================================================================ @Test public void testH5Rcopy_equal() { try (Arena arena = Arena.ofConfined()) { // Create original reference MemorySegment ref1 = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); MemorySegment dsetname = stringToSegment(arena, "dset"); int result = hdf5_h.H5Rcreate_object(H5fid, dsetname, hdf5_h.H5P_DEFAULT(), ref1); assertTrue("H5Rcreate_object failed", isSuccess(result)); // Copy reference MemorySegment ref2 = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); result = hdf5_h.H5Rcopy(ref1, ref2); assertTrue("H5Rcopy failed", isSuccess(result)); // Test equality result = hdf5_h.H5Requal(ref1, ref2); assertTrue("References should be equal", result > 0); // Create different reference MemorySegment ref3 = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); MemorySegment groupname = stringToSegment(arena, "Group1"); result = hdf5_h.H5Rcreate_object(H5fid, groupname, hdf5_h.H5P_DEFAULT(), ref3); assertTrue("H5Rcreate_object Group1 failed", isSuccess(result)); // Test inequality result = hdf5_h.H5Requal(ref1, ref3); assertEquals("References should not be equal", 0, result); // Clean up hdf5_h.H5Rdestroy(ref1); hdf5_h.H5Rdestroy(ref2); hdf5_h.H5Rdestroy(ref3); } } @Test public void testH5Rget_file_name() { try (Arena arena = Arena.ofConfined()) { // Create reference MemorySegment ref_ptr = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); MemorySegment dsetname = stringToSegment(arena, "dset"); int result = hdf5_h.H5Rcreate_object(H5fid, dsetname, hdf5_h.H5P_DEFAULT(), ref_ptr); assertTrue("H5Rcreate_object failed", isSuccess(result)); // Get file name size long name_size = hdf5_h.H5Rget_file_name(ref_ptr, MemorySegment.NULL, 0); assertTrue("H5Rget_file_name size query failed", name_size > 0); // Get file name MemorySegment nameBuffer = arena.allocate(name_size + 1); long actual_size = hdf5_h.H5Rget_file_name(ref_ptr, nameBuffer, name_size + 1); assertTrue("H5Rget_file_name failed", actual_size > 0); String retrieved_name = nameBuffer.getString(0); assertEquals("File name should match", H5_FILE, retrieved_name); // Clean up hdf5_h.H5Rdestroy(ref_ptr); } } @Test public void testH5R_complete_workflow() { try (Arena arena = Arena.ofConfined()) { // 1. Create object reference MemorySegment obj_ref = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); MemorySegment dsetname = stringToSegment(arena, "dset"); int result = hdf5_h.H5Rcreate_object(H5fid, dsetname, hdf5_h.H5P_DEFAULT(), obj_ref); assertTrue("Create object reference failed", isSuccess(result)); // 2. Verify type int ref_type = hdf5_h.H5Rget_type(obj_ref); assertEquals("Type should be OBJECT2", hdf5_h.H5R_OBJECT2(), ref_type); // 3. Copy reference MemorySegment obj_ref_copy = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); result = hdf5_h.H5Rcopy(obj_ref, obj_ref_copy); assertTrue("Copy reference failed", isSuccess(result)); // 4. Verify equality result = hdf5_h.H5Requal(obj_ref, obj_ref_copy); assertTrue("References should be equal", result > 0); // 5. Open via reference long opened_did = hdf5_h.H5Ropen_object(obj_ref, hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT()); assertTrue("Open object failed", isValidId(opened_did)); // 6. Get name long name_size = hdf5_h.H5Rget_obj_name(obj_ref, hdf5_h.H5P_DEFAULT(), MemorySegment.NULL, 0); assertTrue("Get name size failed", name_size > 0); MemorySegment nameBuffer = arena.allocate(name_size + 1); hdf5_h.H5Rget_obj_name(obj_ref, hdf5_h.H5P_DEFAULT(), nameBuffer, name_size + 1); String obj_name = nameBuffer.getString(0); assertEquals("Object name should be /dset", "/dset", obj_name); // 7. Clean up hdf5_h.H5Dclose(opened_did); hdf5_h.H5Rdestroy(obj_ref); hdf5_h.H5Rdestroy(obj_ref_copy); } } @Test public void testH5Rget_type() { System.out.print(testname.getMethodName()); try (Arena arena = Arena.ofConfined()) { MemorySegment dsetname = stringToSegment(arena, "/dset"); MemorySegment ref_ptr = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); int result = hdf5_h.H5Rcreate_object(H5fid, dsetname, hdf5_h.H5P_DEFAULT(), ref_ptr); assertTrue("H5Rcreate_object failed", isSuccess(result)); // Get reference type int ref_type = hdf5_h.H5Rget_type(ref_ptr); assertEquals("Should be object reference", hdf5_h.H5R_OBJECT2(), ref_type); hdf5_h.H5Rdestroy(ref_ptr); } } @Test public void testH5Rget_obj_type() { System.out.print(testname.getMethodName()); try (Arena arena = Arena.ofConfined()) { MemorySegment dsetname = stringToSegment(arena, "/dset"); MemorySegment ref_ptr = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); int result = hdf5_h.H5Rcreate_object(H5fid, dsetname, hdf5_h.H5P_DEFAULT(), ref_ptr); assertTrue("H5Rcreate_object failed", isSuccess(result)); // Get object type MemorySegment obj_type = allocateIntArray(arena, 1); result = hdf5_h.H5Rget_obj_type3(ref_ptr, hdf5_h.H5P_DEFAULT(), obj_type); assertTrue("H5Rget_obj_type3 failed", isSuccess(result)); int type_value = getInt(obj_type); assertTrue("Object type should be valid", type_value >= 0); hdf5_h.H5Rdestroy(ref_ptr); } } @Test public void testH5Rget_obj_name() { System.out.print(testname.getMethodName()); try (Arena arena = Arena.ofConfined()) { MemorySegment dsetname = stringToSegment(arena, "/dset"); MemorySegment ref_ptr = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); int result = hdf5_h.H5Rcreate_object(H5fid, dsetname, hdf5_h.H5P_DEFAULT(), ref_ptr); assertTrue("H5Rcreate_object failed", isSuccess(result)); // Get object name size long name_size = hdf5_h.H5Rget_obj_name(ref_ptr, hdf5_h.H5P_DEFAULT(), MemorySegment.NULL, 0); assertTrue("H5Rget_obj_name size query failed", name_size > 0); // Get object name MemorySegment nameBuffer = arena.allocate(name_size + 1); long actual_size = hdf5_h.H5Rget_obj_name(ref_ptr, hdf5_h.H5P_DEFAULT(), nameBuffer, name_size + 1); assertTrue("H5Rget_obj_name failed", actual_size > 0); String obj_name = segmentToString(nameBuffer); assertEquals("Object name should match", "/dset", obj_name); hdf5_h.H5Rdestroy(ref_ptr); } } @Test public void testH5Requal() { System.out.print(testname.getMethodName()); try (Arena arena = Arena.ofConfined()) { MemorySegment dsetname = stringToSegment(arena, "/dset"); MemorySegment ref_ptr1 = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); MemorySegment ref_ptr2 = arena.allocate(hdf5_h.H5R_REF_BUF_SIZE()); // Create two identical references int result = hdf5_h.H5Rcreate_object(H5fid, dsetname, hdf5_h.H5P_DEFAULT(), ref_ptr1); assertTrue("H5Rcreate_object 1 failed", isSuccess(result)); result = hdf5_h.H5Rcreate_object(H5fid, dsetname, hdf5_h.H5P_DEFAULT(), ref_ptr2); assertTrue("H5Rcreate_object 2 failed", isSuccess(result)); // Compare references int equal = hdf5_h.H5Requal(ref_ptr1, ref_ptr2); assertTrue("References should be equal", equal > 0); hdf5_h.H5Rdestroy(ref_ptr1); hdf5_h.H5Rdestroy(ref_ptr2); } } }