mirror of
https://github.com/HDFGroup/hdf5.git
synced 2026-09-25 04:09:44 +03:00
* Fix NULL pointer access when H5A_operator2_t is NULL Passing NULL for the callback function pointer to H5Aiterate2 and H5Aiterate_by_name was not detected, leading to a subsequent access of an uninitialized pointer. Add a check for this "no operator specified" case in both functions so they fail gracefully instead. Fixes GHSA-r7g4-hv2f-5c66 - CVE-2025-9274 * Fix format * Fix Java test to handle NULL callback to H5Aiterate2
1045 lines
42 KiB
Java
1045 lines
42 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 COPYING 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 java.lang.foreign.ValueLayout;
|
|
|
|
import org.hdfgroup.javahdf5.H5A_info_t;
|
|
import org.hdfgroup.javahdf5.H5A_operator2_t;
|
|
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;
|
|
|
|
/**
|
|
* TestH5Affm - FFM-based tests for HDF5 Attribute operations.
|
|
* Tests the H5A* API using Foreign Function & Memory (FFM) bindings.
|
|
*/
|
|
public class TestH5Affm {
|
|
private static final String H5_FILE = "testA.h5";
|
|
private static final int DIM_X = 4;
|
|
private static final int DIM_Y = 6;
|
|
private static final int RANK = 2;
|
|
|
|
@Rule
|
|
public TestName testname = new TestName();
|
|
|
|
long H5fid = hdf5_h.H5I_INVALID_HID();
|
|
long H5did = hdf5_h.H5I_INVALID_HID();
|
|
long H5sid = hdf5_h.H5I_INVALID_HID();
|
|
long H5aid = hdf5_h.H5I_INVALID_HID();
|
|
|
|
@Before
|
|
public void createH5file() throws Exception
|
|
{
|
|
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, RANK);
|
|
copyToSegment(dimsSegment, dims);
|
|
H5sid = hdf5_h.H5Screate_simple(RANK, dimsSegment, MemorySegment.NULL);
|
|
assertTrue("H5Screate_simple failed", isValidId(H5sid));
|
|
|
|
// Create dataset for attaching attributes
|
|
MemorySegment dsetName = stringToSegment(arena, "dset");
|
|
H5did = hdf5_h.H5Dcreate2(H5fid, dsetName, hdf5_h.H5T_NATIVE_INT_g(), H5sid, hdf5_h.H5P_DEFAULT(),
|
|
hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Dcreate2 failed", isValidId(H5did));
|
|
}
|
|
}
|
|
|
|
@After
|
|
public void deleteH5file() throws Exception
|
|
{
|
|
closeQuietly(H5aid, hdf5_h::H5Aclose);
|
|
closeQuietly(H5did, hdf5_h::H5Dclose);
|
|
closeQuietly(H5sid, hdf5_h::H5Sclose);
|
|
closeQuietly(H5fid, hdf5_h::H5Fclose);
|
|
|
|
H5aid = hdf5_h.H5I_INVALID_HID();
|
|
H5did = hdf5_h.H5I_INVALID_HID();
|
|
H5sid = hdf5_h.H5I_INVALID_HID();
|
|
H5fid = hdf5_h.H5I_INVALID_HID();
|
|
}
|
|
|
|
static
|
|
{
|
|
try {
|
|
System.loadLibrary("hdf5");
|
|
hdf5_h.H5open();
|
|
}
|
|
catch (UnsatisfiedLinkError e) {
|
|
System.err.println("Failed to load HDF5 library: " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Acreate()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create scalar attribute space
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
assertTrue("H5Screate scalar failed", isValidId(attr_sid));
|
|
|
|
// Create attribute
|
|
MemorySegment attrName = stringToSegment(arena, "attr1");
|
|
H5aid = 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(H5aid));
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Awrite_read()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attribute with array dataspace
|
|
long[] attr_dims = {3};
|
|
MemorySegment attrDimsSegment = allocateLongArray(arena, 1);
|
|
attrDimsSegment.setAtIndex(ValueLayout.JAVA_LONG, 0, attr_dims[0]);
|
|
|
|
long attr_sid = hdf5_h.H5Screate_simple(1, attrDimsSegment, MemorySegment.NULL);
|
|
assertTrue("H5Screate_simple failed", isValidId(attr_sid));
|
|
|
|
MemorySegment attrName = stringToSegment(arena, "int_array_attr");
|
|
H5aid = 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(H5aid));
|
|
|
|
// Write data
|
|
int[] write_data = {10, 20, 30};
|
|
MemorySegment writeSegment = allocateIntArray(arena, 3);
|
|
copyToSegment(writeSegment, write_data);
|
|
|
|
int result = hdf5_h.H5Awrite(H5aid, hdf5_h.H5T_NATIVE_INT_g(), writeSegment);
|
|
assertTrue("H5Awrite failed", isSuccess(result));
|
|
|
|
// Read back
|
|
MemorySegment readSegment = allocateIntArray(arena, 3);
|
|
result = hdf5_h.H5Aread(H5aid, hdf5_h.H5T_NATIVE_INT_g(), readSegment);
|
|
assertTrue("H5Aread failed", isSuccess(result));
|
|
|
|
// Verify
|
|
int[] read_data = new int[3];
|
|
copyFromSegment(readSegment, read_data);
|
|
assertArrayEquals("Data mismatch", write_data, read_data);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aopen()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attribute first
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment attrName = stringToSegment(arena, "test_attr");
|
|
|
|
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);
|
|
|
|
// Open attribute
|
|
H5aid = hdf5_h.H5Aopen(H5did, attrName, hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Aopen failed", isValidId(H5aid));
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aclose()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment attrName = stringToSegment(arena, "temp_attr");
|
|
|
|
H5aid = 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(H5aid));
|
|
|
|
int result = hdf5_h.H5Aclose(H5aid);
|
|
assertTrue("H5Aclose failed", isSuccess(result));
|
|
|
|
H5aid = hdf5_h.H5I_INVALID_HID();
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aget_name()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
String expectedName = "my_attribute";
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment attrName = stringToSegment(arena, expectedName);
|
|
|
|
H5aid = 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(H5aid));
|
|
|
|
// Get name size
|
|
long nameSize = hdf5_h.H5Aget_name(H5aid, 0, MemorySegment.NULL);
|
|
assertTrue("H5Aget_name size query failed", nameSize > 0);
|
|
|
|
// Get name
|
|
MemorySegment nameBuffer = arena.allocate(nameSize + 1);
|
|
hdf5_h.H5Aget_name(H5aid, nameSize + 1, nameBuffer);
|
|
|
|
String retrievedName = nameBuffer.getString(0);
|
|
assertEquals("Attribute name mismatch", expectedName, retrievedName);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aget_space()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attribute with specific dimensions
|
|
long[] dims = {5, 3};
|
|
MemorySegment dimsSegment = allocateLongArray(arena, 2);
|
|
copyToSegment(dimsSegment, dims);
|
|
|
|
long attr_sid = hdf5_h.H5Screate_simple(2, dimsSegment, MemorySegment.NULL);
|
|
MemorySegment attrName = stringToSegment(arena, "array_attr");
|
|
|
|
H5aid = 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(H5aid));
|
|
|
|
// Get dataspace
|
|
long retrieved_sid = hdf5_h.H5Aget_space(H5aid);
|
|
assertTrue("H5Aget_space failed", isValidId(retrieved_sid));
|
|
|
|
// Verify dimensions
|
|
MemorySegment retrievedDims = allocateLongArray(arena, 2);
|
|
hdf5_h.H5Sget_simple_extent_dims(retrieved_sid, retrievedDims, MemorySegment.NULL);
|
|
|
|
long[] readDims = new long[2];
|
|
copyFromSegment(retrievedDims, readDims);
|
|
assertArrayEquals("Dimensions mismatch", dims, readDims);
|
|
|
|
hdf5_h.H5Sclose(retrieved_sid);
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aget_type()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment attrName = stringToSegment(arena, "type_attr");
|
|
|
|
H5aid = hdf5_h.H5Acreate2(H5did, attrName, hdf5_h.H5T_NATIVE_DOUBLE_g(), attr_sid,
|
|
hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Acreate2 failed", isValidId(H5aid));
|
|
|
|
// Get type
|
|
long retrieved_tid = hdf5_h.H5Aget_type(H5aid);
|
|
assertTrue("H5Aget_type failed", isValidId(retrieved_tid));
|
|
|
|
// Verify it's a double type
|
|
int equal = hdf5_h.H5Tequal(retrieved_tid, hdf5_h.H5T_NATIVE_DOUBLE_g());
|
|
assertTrue("Type should be H5T_NATIVE_DOUBLE", equal > 0);
|
|
|
|
hdf5_h.H5Tclose(retrieved_tid);
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aexists()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
MemorySegment existingName = stringToSegment(arena, "existing_attr");
|
|
MemorySegment missingName = stringToSegment(arena, "missing_attr");
|
|
|
|
// Create one attribute
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
long aid = hdf5_h.H5Acreate2(H5did, existingName, 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);
|
|
|
|
// Check existing
|
|
int exists = hdf5_h.H5Aexists(H5did, existingName);
|
|
assertTrue("Attribute should exist", exists > 0);
|
|
|
|
// Check non-existing
|
|
exists = hdf5_h.H5Aexists(H5did, missingName);
|
|
assertEquals("Attribute should not exist", 0, exists);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Adelete()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
MemorySegment attrName = stringToSegment(arena, "deletable_attr");
|
|
|
|
// Create 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);
|
|
|
|
// Verify it exists
|
|
int exists = hdf5_h.H5Aexists(H5did, attrName);
|
|
assertTrue("Attribute should exist before delete", exists > 0);
|
|
|
|
// Delete
|
|
int result = hdf5_h.H5Adelete(H5did, attrName);
|
|
assertTrue("H5Adelete failed", isSuccess(result));
|
|
|
|
// Verify it's gone
|
|
exists = hdf5_h.H5Aexists(H5did, attrName);
|
|
assertEquals("Attribute should not exist after delete", 0, exists);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aget_storage_size()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attribute with 10 integers
|
|
long[] attr_dims = {10};
|
|
MemorySegment attrDimsSegment = allocateLongArray(arena, 1);
|
|
attrDimsSegment.setAtIndex(ValueLayout.JAVA_LONG, 0, attr_dims[0]);
|
|
|
|
long attr_sid = hdf5_h.H5Screate_simple(1, attrDimsSegment, MemorySegment.NULL);
|
|
MemorySegment attrName = stringToSegment(arena, "storage_attr");
|
|
|
|
H5aid = 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(H5aid));
|
|
|
|
// Write data
|
|
int[] data = new int[10];
|
|
MemorySegment dataSegment = allocateIntArray(arena, 10);
|
|
copyToSegment(dataSegment, data);
|
|
hdf5_h.H5Awrite(H5aid, hdf5_h.H5T_NATIVE_INT_g(), dataSegment);
|
|
|
|
// Get storage size
|
|
long storage_size = hdf5_h.H5Aget_storage_size(H5aid);
|
|
assertEquals("Storage size should be 10 * sizeof(int)", 40L, storage_size);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Awrite_readStr()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
String testString = "Hello HDF5 Attributes!";
|
|
|
|
// Create string type
|
|
long str_tid = hdf5_h.H5Tcopy(hdf5_h.H5T_C_S1_g());
|
|
assertTrue("H5Tcopy failed", isValidId(str_tid));
|
|
|
|
hdf5_h.H5Tset_size(str_tid, testString.length() + 1);
|
|
hdf5_h.H5Tset_strpad(str_tid, hdf5_h.H5T_STR_NULLTERM());
|
|
|
|
// Create attribute
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment attrName = stringToSegment(arena, "str_attr");
|
|
|
|
H5aid = hdf5_h.H5Acreate2(H5did, attrName, str_tid, attr_sid, hdf5_h.H5P_DEFAULT(),
|
|
hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Acreate2 failed", isValidId(H5aid));
|
|
|
|
// Write string
|
|
MemorySegment writeData = stringToSegment(arena, testString);
|
|
int writeResult = hdf5_h.H5Awrite(H5aid, str_tid, writeData);
|
|
assertTrue("H5Awrite failed", isSuccess(writeResult));
|
|
|
|
// Read string back
|
|
MemorySegment readData = arena.allocate(testString.length() + 1);
|
|
int readResult = hdf5_h.H5Aread(H5aid, str_tid, readData);
|
|
assertTrue("H5Aread failed", isSuccess(readResult));
|
|
|
|
String retrievedString = readData.getString(0);
|
|
assertEquals("String mismatch", testString, retrievedString);
|
|
|
|
hdf5_h.H5Tclose(str_tid);
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Arename()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
MemorySegment oldName = stringToSegment(arena, "old_name");
|
|
MemorySegment newName = stringToSegment(arena, "new_name");
|
|
|
|
// Create attribute
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
long aid = hdf5_h.H5Acreate2(H5did, oldName, 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);
|
|
|
|
// Verify old name exists
|
|
int exists = hdf5_h.H5Aexists(H5did, oldName);
|
|
assertTrue("Old name should exist", exists > 0);
|
|
|
|
// Rename
|
|
int result = hdf5_h.H5Arename(H5did, oldName, newName);
|
|
assertTrue("H5Arename failed", isSuccess(result));
|
|
|
|
// Verify new name exists and old doesn't
|
|
exists = hdf5_h.H5Aexists(H5did, newName);
|
|
assertTrue("New name should exist", exists > 0);
|
|
|
|
exists = hdf5_h.H5Aexists(H5did, oldName);
|
|
assertEquals("Old name should not exist", 0, exists);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aget_num_attrs()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create 3 attributes
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
MemorySegment attrName = stringToSegment(arena, "attr_" + i);
|
|
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 for attr_" + i, isValidId(aid));
|
|
hdf5_h.H5Aclose(aid);
|
|
}
|
|
|
|
// Get number of attributes
|
|
int num_attrs = hdf5_h.H5Aget_num_attrs(H5did);
|
|
assertTrue("Should have at least 3 attributes", num_attrs >= 3);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
// =========================
|
|
// Phase 1: Essential Query Operations
|
|
// =========================
|
|
|
|
@Test
|
|
public void testH5Aget_info()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attribute with scalar dataspace
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment attrName = stringToSegment(arena, "info_test_attr");
|
|
|
|
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 some data
|
|
MemorySegment data = allocateInt(arena);
|
|
setInt(data, 42);
|
|
int writeResult = hdf5_h.H5Awrite(aid, hdf5_h.H5T_NATIVE_INT_g(), data);
|
|
assertTrue("H5Awrite failed", isSuccess(writeResult));
|
|
|
|
// Get attribute info
|
|
MemorySegment info = H5A_info_t.allocate(arena);
|
|
int result = hdf5_h.H5Aget_info(aid, info);
|
|
assertTrue("H5Aget_info failed", isSuccess(result));
|
|
|
|
// Verify info fields
|
|
long data_size = H5A_info_t.data_size(info);
|
|
assertEquals("Data size should be 4 bytes (sizeof int)", 4L, data_size);
|
|
|
|
// corder_valid may be false if creation order tracking is not enabled
|
|
boolean corder_valid = H5A_info_t.corder_valid(info);
|
|
// Just verify we can read it (no assertion on value)
|
|
assertNotNull("corder_valid should be readable", Boolean.valueOf(corder_valid));
|
|
|
|
// cset should be ASCII by default
|
|
int cset = H5A_info_t.cset(info);
|
|
assertEquals("Character set should be ASCII", hdf5_h.H5T_CSET_ASCII(), cset);
|
|
|
|
hdf5_h.H5Aclose(aid);
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aget_info_by_idx()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create multiple attributes to test indexing
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
|
|
String[] attrNames = {"first_attr", "second_attr", "third_attr"};
|
|
for (String name : attrNames) {
|
|
MemorySegment attrName = stringToSegment(arena, name);
|
|
long aid = hdf5_h.H5Acreate2(H5did, attrName, hdf5_h.H5T_NATIVE_DOUBLE_g(), attr_sid,
|
|
hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Acreate2 failed for " + name, isValidId(aid));
|
|
hdf5_h.H5Aclose(aid);
|
|
}
|
|
|
|
// Get info for the second attribute (index 1) by name order
|
|
MemorySegment objName = stringToSegment(arena, ".");
|
|
MemorySegment info = H5A_info_t.allocate(arena);
|
|
|
|
int result = hdf5_h.H5Aget_info_by_idx(H5did, objName, hdf5_h.H5_INDEX_NAME(),
|
|
hdf5_h.H5_ITER_INC(), 1, info, hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Aget_info_by_idx failed", isSuccess(result));
|
|
|
|
// Verify we got valid info
|
|
long data_size = H5A_info_t.data_size(info);
|
|
assertEquals("Data size should be 8 bytes (sizeof double)", 8L, data_size);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aget_info_by_name()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attribute on dataset
|
|
String attrNameStr = "named_info_attr";
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment attrName = stringToSegment(arena, attrNameStr);
|
|
|
|
long aid = hdf5_h.H5Acreate2(H5did, attrName, hdf5_h.H5T_NATIVE_FLOAT_g(), attr_sid,
|
|
hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Acreate2 failed", isValidId(aid));
|
|
hdf5_h.H5Aclose(aid);
|
|
|
|
// Get info by name from the file (using dataset path)
|
|
MemorySegment objName = stringToSegment(arena, "dset");
|
|
MemorySegment info = H5A_info_t.allocate(arena);
|
|
|
|
int result = hdf5_h.H5Aget_info_by_name(H5fid, objName, attrName, info, hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Aget_info_by_name failed", isSuccess(result));
|
|
|
|
// Verify info
|
|
long data_size = H5A_info_t.data_size(info);
|
|
assertEquals("Data size should be 4 bytes (sizeof float)", 4L, data_size);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aget_name_by_idx()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create multiple attributes with known names
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
String[] attrNames = {"alpha", "beta", "gamma"};
|
|
String[] sortedNames = {"alpha", "beta", "gamma"}; // Already sorted alphabetically
|
|
|
|
for (String name : attrNames) {
|
|
MemorySegment attrName = stringToSegment(arena, name);
|
|
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 for " + name, isValidId(aid));
|
|
hdf5_h.H5Aclose(aid);
|
|
}
|
|
|
|
// Get name of each attribute by index (alphabetical order)
|
|
MemorySegment objName = stringToSegment(arena, ".");
|
|
|
|
for (int i = 0; i < sortedNames.length; i++) {
|
|
// Get name size first
|
|
long nameSize =
|
|
hdf5_h.H5Aget_name_by_idx(H5did, objName, hdf5_h.H5_INDEX_NAME(), hdf5_h.H5_ITER_INC(), i,
|
|
MemorySegment.NULL, 0, hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Aget_name_by_idx size query failed for index " + i, nameSize > 0);
|
|
|
|
// Get actual name
|
|
MemorySegment nameBuffer = arena.allocate(nameSize + 1);
|
|
long result =
|
|
hdf5_h.H5Aget_name_by_idx(H5did, objName, hdf5_h.H5_INDEX_NAME(), hdf5_h.H5_ITER_INC(), i,
|
|
nameBuffer, nameSize + 1, hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Aget_name_by_idx failed for index " + i, result > 0);
|
|
|
|
String retrievedName = nameBuffer.getString(0);
|
|
assertEquals("Name at index " + i + " should match", sortedNames[i], retrievedName);
|
|
}
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aget_create_plist()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attribute creation property list with specific settings
|
|
long acpl = hdf5_h.H5Pcreate(hdf5_h.H5P_CLS_ATTRIBUTE_CREATE_ID_g());
|
|
assertTrue("H5Pcreate acpl failed", isValidId(acpl));
|
|
|
|
// Set character encoding to UTF-8
|
|
int setResult = hdf5_h.H5Pset_char_encoding(acpl, hdf5_h.H5T_CSET_UTF8());
|
|
assertTrue("H5Pset_char_encoding failed", isSuccess(setResult));
|
|
|
|
// Create attribute with this property list
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment attrName = stringToSegment(arena, "plist_attr");
|
|
|
|
long aid = hdf5_h.H5Acreate2(H5did, attrName, hdf5_h.H5T_NATIVE_INT_g(), attr_sid, acpl,
|
|
hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Acreate2 failed", isValidId(aid));
|
|
|
|
// Get the creation property list back
|
|
long retrieved_acpl = hdf5_h.H5Aget_create_plist(aid);
|
|
assertTrue("H5Aget_create_plist failed", isValidId(retrieved_acpl));
|
|
|
|
// Verify the encoding is UTF-8
|
|
MemorySegment encoding = allocateInt(arena);
|
|
int getResult = hdf5_h.H5Pget_char_encoding(retrieved_acpl, encoding);
|
|
assertTrue("H5Pget_char_encoding failed", isSuccess(getResult));
|
|
|
|
int retrievedEncoding = getInt(encoding);
|
|
assertEquals("Character encoding should be UTF-8", hdf5_h.H5T_CSET_UTF8(), retrievedEncoding);
|
|
|
|
hdf5_h.H5Pclose(retrieved_acpl);
|
|
hdf5_h.H5Pclose(acpl);
|
|
hdf5_h.H5Aclose(aid);
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aexists_by_name()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attribute on dataset
|
|
String existingAttrName = "existing_by_name";
|
|
String nonExistingAttrName = "nonexistent_by_name";
|
|
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment attrName = stringToSegment(arena, existingAttrName);
|
|
|
|
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);
|
|
|
|
// Check existence from file using dataset path
|
|
MemorySegment objName = stringToSegment(arena, "dset");
|
|
MemorySegment existingAttrNameSeg = stringToSegment(arena, existingAttrName);
|
|
MemorySegment missingAttrNameSeg = stringToSegment(arena, nonExistingAttrName);
|
|
|
|
// Should exist
|
|
int exists = hdf5_h.H5Aexists_by_name(H5fid, objName, existingAttrNameSeg, hdf5_h.H5P_DEFAULT());
|
|
assertTrue("Attribute should exist", exists > 0);
|
|
|
|
// Should not exist
|
|
exists = hdf5_h.H5Aexists_by_name(H5fid, objName, missingAttrNameSeg, hdf5_h.H5P_DEFAULT());
|
|
assertEquals("Attribute should not exist", 0, exists);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
// =========================
|
|
// Phase 2: Advanced Operations
|
|
// =========================
|
|
|
|
@Test
|
|
public void testH5Aopen_by_idx()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create multiple attributes with known names
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
String[] attrNames = {"apple", "banana", "cherry"};
|
|
String[] sortedNames = {"apple", "banana", "cherry"}; // Already sorted
|
|
|
|
for (String name : attrNames) {
|
|
MemorySegment attrName = stringToSegment(arena, name);
|
|
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 for " + name, isValidId(aid));
|
|
hdf5_h.H5Aclose(aid);
|
|
}
|
|
|
|
// Open second attribute by index (index 1)
|
|
MemorySegment objName = stringToSegment(arena, ".");
|
|
long aid = hdf5_h.H5Aopen_by_idx(H5did, objName, hdf5_h.H5_INDEX_NAME(), hdf5_h.H5_ITER_INC(), 1,
|
|
hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Aopen_by_idx failed", isValidId(aid));
|
|
|
|
// Verify we opened the correct attribute by checking its name
|
|
long nameSize = hdf5_h.H5Aget_name(aid, 0, MemorySegment.NULL);
|
|
MemorySegment nameBuf = arena.allocate(nameSize + 1);
|
|
hdf5_h.H5Aget_name(aid, nameSize + 1, nameBuf);
|
|
String retrievedName = nameBuf.getString(0);
|
|
assertEquals("Should have opened 'banana' (index 1)", sortedNames[1], retrievedName);
|
|
|
|
hdf5_h.H5Aclose(aid);
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Adelete_by_idx()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create 3 attributes
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
String[] attrNames = {"first", "second", "third"};
|
|
|
|
for (String name : attrNames) {
|
|
MemorySegment attrName = stringToSegment(arena, name);
|
|
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 for " + name, isValidId(aid));
|
|
hdf5_h.H5Aclose(aid);
|
|
}
|
|
|
|
// Delete middle attribute (index 1 = "second")
|
|
MemorySegment objName = stringToSegment(arena, ".");
|
|
int result = hdf5_h.H5Adelete_by_idx(H5did, objName, hdf5_h.H5_INDEX_NAME(), hdf5_h.H5_ITER_INC(),
|
|
1, hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Adelete_by_idx failed", isSuccess(result));
|
|
|
|
// Verify "second" is gone
|
|
MemorySegment secondName = stringToSegment(arena, "second");
|
|
int exists = hdf5_h.H5Aexists(H5did, secondName);
|
|
assertEquals("'second' should not exist after deletion", 0, exists);
|
|
|
|
// Verify others still exist
|
|
MemorySegment firstName = stringToSegment(arena, "first");
|
|
MemorySegment thirdName = stringToSegment(arena, "third");
|
|
exists = hdf5_h.H5Aexists(H5did, firstName);
|
|
assertTrue("'first' should still exist", exists > 0);
|
|
exists = hdf5_h.H5Aexists(H5did, thirdName);
|
|
assertTrue("'third' should still exist", exists > 0);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Adelete_by_name()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attribute on dataset
|
|
String attrNameStr = "deletable_by_name";
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment attrName = stringToSegment(arena, attrNameStr);
|
|
|
|
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);
|
|
|
|
// Verify it exists
|
|
int exists = hdf5_h.H5Aexists(H5did, attrName);
|
|
assertTrue("Attribute should exist before delete", exists > 0);
|
|
|
|
// Delete by name from file using dataset path
|
|
MemorySegment objName = stringToSegment(arena, "dset");
|
|
int result = hdf5_h.H5Adelete_by_name(H5fid, objName, attrName, hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Adelete_by_name failed", isSuccess(result));
|
|
|
|
// Verify it's gone
|
|
exists = hdf5_h.H5Aexists(H5did, attrName);
|
|
assertEquals("Attribute should not exist after delete", 0, exists);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Arename_by_name()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attribute on dataset
|
|
String oldNameStr = "old_name_by_path";
|
|
String newNameStr = "new_name_by_path";
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment oldName = stringToSegment(arena, oldNameStr);
|
|
MemorySegment newName = stringToSegment(arena, newNameStr);
|
|
|
|
long aid = hdf5_h.H5Acreate2(H5did, oldName, 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);
|
|
|
|
// Verify old name exists
|
|
int exists = hdf5_h.H5Aexists(H5did, oldName);
|
|
assertTrue("Old name should exist", exists > 0);
|
|
|
|
// Rename by name from file using dataset path
|
|
MemorySegment objName = stringToSegment(arena, "dset");
|
|
int result = hdf5_h.H5Arename_by_name(H5fid, objName, oldName, newName, hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Arename_by_name failed", isSuccess(result));
|
|
|
|
// Verify new name exists and old doesn't
|
|
exists = hdf5_h.H5Aexists(H5did, newName);
|
|
assertTrue("New name should exist", exists > 0);
|
|
|
|
exists = hdf5_h.H5Aexists(H5did, oldName);
|
|
assertEquals("Old name should not exist", 0, exists);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aiterate2()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create multiple attributes
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
String[] attrNames = {"attr_A", "attr_B", "attr_C", "attr_D"};
|
|
|
|
for (String name : attrNames) {
|
|
MemorySegment attrName = stringToSegment(arena, name);
|
|
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 for " + name, isValidId(aid));
|
|
hdf5_h.H5Aclose(aid);
|
|
}
|
|
|
|
// Create iteration callback
|
|
final int[] count = {0};
|
|
final String[] names = new String[10];
|
|
H5A_operator2_t.Function cb = (loc_id, attr_name, ainfo, op_data) ->
|
|
{
|
|
try {
|
|
String name = attr_name.getString(0);
|
|
names[count[0]] = name;
|
|
count[0]++;
|
|
return 0; // Continue iteration
|
|
}
|
|
catch (Exception e) {
|
|
return -1; // Stop on error
|
|
}
|
|
};
|
|
|
|
MemorySegment callback = H5A_operator2_t.allocate(cb, arena);
|
|
MemorySegment idx = allocateLong(arena);
|
|
setLong(idx, 0);
|
|
|
|
// Iterate
|
|
int result = hdf5_h.H5Aiterate2(H5did, hdf5_h.H5_INDEX_NAME(), hdf5_h.H5_ITER_INC(), idx,
|
|
callback, MemorySegment.NULL);
|
|
assertTrue("H5Aiterate2 failed", isSuccess(result));
|
|
|
|
// Verify we iterated all attributes (at least the 4 we created)
|
|
assertTrue("Should have iterated at least 4 attributes", count[0] >= 4);
|
|
|
|
// Verify all our attributes were seen
|
|
boolean foundA = false, foundB = false, foundC = false, foundD = false;
|
|
for (int i = 0; i < count[0]; i++) {
|
|
if ("attr_A".equals(names[i]))
|
|
foundA = true;
|
|
if ("attr_B".equals(names[i]))
|
|
foundB = true;
|
|
if ("attr_C".equals(names[i]))
|
|
foundC = true;
|
|
if ("attr_D".equals(names[i]))
|
|
foundD = true;
|
|
}
|
|
assertTrue("Should have found attr_A", foundA);
|
|
assertTrue("Should have found attr_B", foundB);
|
|
assertTrue("Should have found attr_C", foundC);
|
|
assertTrue("Should have found attr_D", foundD);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aiterate_by_name()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attributes on dataset
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
String[] attrNames = {"iter_1", "iter_2", "iter_3"};
|
|
|
|
for (String name : attrNames) {
|
|
MemorySegment attrName = stringToSegment(arena, name);
|
|
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 for " + name, isValidId(aid));
|
|
hdf5_h.H5Aclose(aid);
|
|
}
|
|
|
|
// Create iteration callback
|
|
final int[] count = {0};
|
|
H5A_operator2_t.Function cb = (loc_id, attr_name, ainfo, op_data) ->
|
|
{
|
|
count[0]++;
|
|
return 0; // Continue
|
|
};
|
|
|
|
MemorySegment callback = H5A_operator2_t.allocate(cb, arena);
|
|
MemorySegment idx = allocateLong(arena);
|
|
setLong(idx, 0);
|
|
|
|
// Iterate from file using dataset path
|
|
MemorySegment objName = stringToSegment(arena, "dset");
|
|
int result =
|
|
hdf5_h.H5Aiterate_by_name(H5fid, objName, hdf5_h.H5_INDEX_NAME(), hdf5_h.H5_ITER_INC(), idx,
|
|
callback, MemorySegment.NULL, hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Aiterate_by_name failed", isSuccess(result));
|
|
|
|
// Verify we iterated at least our 3 attributes
|
|
assertTrue("Should have iterated at least 3 attributes", count[0] >= 3);
|
|
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Acreate_by_name_comprehensive()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
// Create attribute on dataset using path from file
|
|
String attrNameStr = "created_by_path_comprehensive";
|
|
long attr_sid = hdf5_h.H5Screate(hdf5_h.H5S_SCALAR());
|
|
MemorySegment objName = stringToSegment(arena, "dset");
|
|
MemorySegment attrName = stringToSegment(arena, attrNameStr);
|
|
|
|
long aid =
|
|
hdf5_h.H5Acreate_by_name(H5fid, objName, attrName, hdf5_h.H5T_NATIVE_DOUBLE_g(), attr_sid,
|
|
hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT(), hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Acreate_by_name failed", isValidId(aid));
|
|
|
|
// Write data
|
|
MemorySegment data = allocateDoubleArray(arena, 1);
|
|
data.setAtIndex(ValueLayout.JAVA_DOUBLE, 0, 3.14159);
|
|
int writeResult = hdf5_h.H5Awrite(aid, hdf5_h.H5T_NATIVE_DOUBLE_g(), data);
|
|
assertTrue("H5Awrite failed", isSuccess(writeResult));
|
|
|
|
hdf5_h.H5Aclose(aid);
|
|
|
|
// Verify attribute is accessible from dataset
|
|
MemorySegment attrNameCheck = stringToSegment(arena, attrNameStr);
|
|
int exists = hdf5_h.H5Aexists(H5did, attrNameCheck);
|
|
assertTrue("Attribute should exist on dataset", exists > 0);
|
|
|
|
// Open and read back to verify data
|
|
long aid2 = hdf5_h.H5Aopen(H5did, attrNameCheck, hdf5_h.H5P_DEFAULT());
|
|
assertTrue("H5Aopen failed", isValidId(aid2));
|
|
|
|
MemorySegment readData = allocateDoubleArray(arena, 1);
|
|
int readResult = hdf5_h.H5Aread(aid2, hdf5_h.H5T_NATIVE_DOUBLE_g(), readData);
|
|
assertTrue("H5Aread failed", isSuccess(readResult));
|
|
|
|
double value = readData.getAtIndex(ValueLayout.JAVA_DOUBLE, 0);
|
|
assertEquals("Data should match", 3.14159, value, 0.00001);
|
|
|
|
hdf5_h.H5Aclose(aid2);
|
|
hdf5_h.H5Sclose(attr_sid);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testH5Aiterate_nullCallback()
|
|
{
|
|
System.out.print(testname.getMethodName());
|
|
|
|
try (Arena arena = Arena.ofConfined()) {
|
|
MemorySegment idx = allocateLongArray(arena, 1);
|
|
copyToSegment(idx, new long[] {0});
|
|
|
|
// NULL callback must be rejected gracefully (H5E_BADVALUE), not crash
|
|
long result = hdf5_h.H5Aiterate2(H5did, hdf5_h.H5_INDEX_NAME(), hdf5_h.H5_ITER_INC(), idx,
|
|
MemorySegment.NULL, MemorySegment.NULL);
|
|
assertTrue("H5Aiterate2 should fail when callback is NULL", result < 0);
|
|
}
|
|
}
|
|
}
|