Files
hdf5/java/jtest/TestH5Rffm.java
Allen Byrne b754dcb8f2 Move Java wrappers to FFM using jextract and java 25 (#5957)
FFM build requires Java 25, Jextract 25.
Generates FFM bindings during configure.
JNI is default when the requirements are not met or can be forced.
Presets added for maven and FFM - JNI is default selection.
Enhanced Maven options will work with either JNI or FFM
New Workflows for testing and maven uploads.
Extensive documentation changes for java.
2025-11-04 14:03:06 -06:00

563 lines
23 KiB
Java

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 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);
}
}
}