Files
hdf5/java/jtest/TestH5PLffm.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

423 lines
16 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 java.lang.foreign.ValueLayout;
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 Plugin (H5PL) operations.
*
* NOTE: These tests focus on plugin path management and loading state control.
* Actual plugin loading requires external plugin libraries and specialized setup.
*/
public class TestH5PLffm {
@Rule
public TestName testname = new TestName();
// Store initial state to restore after tests
private int initialPluginState;
private int initialPathCount;
@Before
public void setUp()
{
System.out.print(testname.getMethodName());
// Save initial plugin loading state
try (Arena arena = Arena.ofConfined()) {
MemorySegment stateSeg = arena.allocate(ValueLayout.JAVA_INT);
int result = hdf5_h.H5PLget_loading_state(stateSeg);
if (result >= 0) {
initialPluginState = stateSeg.get(ValueLayout.JAVA_INT, 0);
}
}
// Save initial path count
try (Arena arena = Arena.ofConfined()) {
MemorySegment countSeg = arena.allocate(ValueLayout.JAVA_INT);
int result = hdf5_h.H5PLsize(countSeg);
if (result >= 0) {
initialPathCount = countSeg.get(ValueLayout.JAVA_INT, 0);
}
}
}
@After
public void tearDown()
{
// Restore initial plugin loading state
hdf5_h.H5PLset_loading_state(initialPluginState);
// Remove any paths added during testing (in reverse order)
try (Arena arena = Arena.ofConfined()) {
MemorySegment countSeg = arena.allocate(ValueLayout.JAVA_INT);
hdf5_h.H5PLsize(countSeg);
int currentCount = countSeg.get(ValueLayout.JAVA_INT, 0);
// Remove paths added by tests
while (currentCount > initialPathCount) {
hdf5_h.H5PLremove(currentCount - 1);
currentCount--;
}
}
System.out.println();
}
/**
* Test H5PLset_loading_state and H5PLget_loading_state
*/
@Test
public void testH5PLset_and_get_loading_state()
{
try (Arena arena = Arena.ofConfined()) {
MemorySegment stateSeg = arena.allocate(ValueLayout.JAVA_INT);
// Get initial state
int result = hdf5_h.H5PLget_loading_state(stateSeg);
assertEquals("H5PLget_loading_state should succeed", 0, result);
int originalState = stateSeg.get(ValueLayout.JAVA_INT, 0);
// Enable all plugins
result = hdf5_h.H5PLset_loading_state(hdf5_h.H5PL_ALL_PLUGIN());
assertEquals("H5PLset_loading_state should succeed", 0, result);
result = hdf5_h.H5PLget_loading_state(stateSeg);
assertEquals("H5PLget_loading_state should succeed", 0, result);
int allState = stateSeg.get(ValueLayout.JAVA_INT, 0);
assertEquals("All plugins should be enabled", hdf5_h.H5PL_ALL_PLUGIN(), allState);
// Enable only filter plugins
result = hdf5_h.H5PLset_loading_state(hdf5_h.H5PL_FILTER_PLUGIN());
assertEquals("H5PLset_loading_state should succeed", 0, result);
result = hdf5_h.H5PLget_loading_state(stateSeg);
assertEquals("H5PLget_loading_state should succeed", 0, result);
int filterState = stateSeg.get(ValueLayout.JAVA_INT, 0);
assertEquals("Only filter plugins should be enabled", hdf5_h.H5PL_FILTER_PLUGIN(), filterState);
// Disable all plugins
result = hdf5_h.H5PLset_loading_state(0);
assertEquals("H5PLset_loading_state should succeed", 0, result);
result = hdf5_h.H5PLget_loading_state(stateSeg);
assertEquals("H5PLget_loading_state should succeed", 0, result);
int disabledState = stateSeg.get(ValueLayout.JAVA_INT, 0);
assertEquals("All plugins should be disabled", 0, disabledState);
// Restore original state
hdf5_h.H5PLset_loading_state(originalState);
}
}
/**
* Test H5PLsize - get number of plugin search paths
*/
@Test
public void testH5PLsize()
{
try (Arena arena = Arena.ofConfined()) {
MemorySegment countSeg = arena.allocate(ValueLayout.JAVA_INT);
int result = hdf5_h.H5PLsize(countSeg);
assertEquals("H5PLsize should succeed", 0, result);
int pathCount = countSeg.get(ValueLayout.JAVA_INT, 0);
assertTrue("Path count should be non-negative", pathCount >= 0);
}
}
/**
* Test H5PLappend - add path to end of search list
*/
@Test
public void testH5PLappend()
{
try (Arena arena = Arena.ofConfined()) {
MemorySegment countSeg = arena.allocate(ValueLayout.JAVA_INT);
// Get initial count
hdf5_h.H5PLsize(countSeg);
int initialCount = countSeg.get(ValueLayout.JAVA_INT, 0);
// Append a test path
MemorySegment testPath = stringToSegment(arena, "/tmp/test_plugin_path");
int result = hdf5_h.H5PLappend(testPath);
assertEquals("H5PLappend should succeed", 0, result);
// Verify count increased
hdf5_h.H5PLsize(countSeg);
int newCount = countSeg.get(ValueLayout.JAVA_INT, 0);
assertEquals("Path count should increase by 1", initialCount + 1, newCount);
// Verify the path was added at the end
long size = hdf5_h.H5PLget(newCount - 1, MemorySegment.NULL, 0);
assertTrue("Should get path size", size > 0);
MemorySegment pathBuf = arena.allocate(ValueLayout.JAVA_BYTE, (int)size + 1);
size = hdf5_h.H5PLget(newCount - 1, pathBuf, size + 1);
String retrievedPath = segmentToString(pathBuf);
assertEquals("Retrieved path should match", "/tmp/test_plugin_path", retrievedPath);
}
}
/**
* Test H5PLprepend - add path to beginning of search list
*/
@Test
public void testH5PLprepend()
{
try (Arena arena = Arena.ofConfined()) {
MemorySegment countSeg = arena.allocate(ValueLayout.JAVA_INT);
// Get initial count
hdf5_h.H5PLsize(countSeg);
int initialCount = countSeg.get(ValueLayout.JAVA_INT, 0);
// Prepend a test path
MemorySegment testPath = stringToSegment(arena, "/tmp/test_prepend_path");
int result = hdf5_h.H5PLprepend(testPath);
assertEquals("H5PLprepend should succeed", 0, result);
// Verify count increased
hdf5_h.H5PLsize(countSeg);
int newCount = countSeg.get(ValueLayout.JAVA_INT, 0);
assertEquals("Path count should increase by 1", initialCount + 1, newCount);
// Verify the path was added at the beginning (index 0)
long size = hdf5_h.H5PLget(0, MemorySegment.NULL, 0);
assertTrue("Should get path size", size > 0);
MemorySegment pathBuf = arena.allocate(ValueLayout.JAVA_BYTE, (int)size + 1);
size = hdf5_h.H5PLget(0, pathBuf, size + 1);
String retrievedPath = segmentToString(pathBuf);
assertEquals("Retrieved path should match", "/tmp/test_prepend_path", retrievedPath);
}
}
/**
* Test H5PLinsert - insert path at specific index
*/
@Test
public void testH5PLinsert()
{
try (Arena arena = Arena.ofConfined()) {
MemorySegment countSeg = arena.allocate(ValueLayout.JAVA_INT);
// Add two paths first
MemorySegment path1 = stringToSegment(arena, "/tmp/path1");
MemorySegment path2 = stringToSegment(arena, "/tmp/path2");
hdf5_h.H5PLappend(path1);
hdf5_h.H5PLappend(path2);
// Get count before insert
hdf5_h.H5PLsize(countSeg);
int beforeCount = countSeg.get(ValueLayout.JAVA_INT, 0);
// Insert path at index 1 (between path1 and path2)
MemorySegment insertPath = stringToSegment(arena, "/tmp/path_inserted");
int result = hdf5_h.H5PLinsert(insertPath, beforeCount - 1);
assertEquals("H5PLinsert should succeed", 0, result);
// Verify count increased
hdf5_h.H5PLsize(countSeg);
int afterCount = countSeg.get(ValueLayout.JAVA_INT, 0);
assertEquals("Path count should increase by 1", beforeCount + 1, afterCount);
// Verify the path was inserted at correct position
long size = hdf5_h.H5PLget(beforeCount - 1, MemorySegment.NULL, 0);
MemorySegment pathBuf = arena.allocate(ValueLayout.JAVA_BYTE, (int)size + 1);
hdf5_h.H5PLget(beforeCount - 1, pathBuf, size + 1);
String retrievedPath = segmentToString(pathBuf);
assertEquals("Retrieved path should match", "/tmp/path_inserted", retrievedPath);
}
}
/**
* Test H5PLreplace - replace path at specific index
*/
@Test
public void testH5PLreplace()
{
try (Arena arena = Arena.ofConfined()) {
MemorySegment countSeg = arena.allocate(ValueLayout.JAVA_INT);
// Add a test path
MemorySegment originalPath = stringToSegment(arena, "/tmp/original_path");
hdf5_h.H5PLappend(originalPath);
// Get count and index of last path
hdf5_h.H5PLsize(countSeg);
int count = countSeg.get(ValueLayout.JAVA_INT, 0);
int lastIdx = count - 1;
// Replace the last path
MemorySegment replacePath = stringToSegment(arena, "/tmp/replacement_path");
int result = hdf5_h.H5PLreplace(replacePath, lastIdx);
assertEquals("H5PLreplace should succeed", 0, result);
// Verify count unchanged
hdf5_h.H5PLsize(countSeg);
int newCount = countSeg.get(ValueLayout.JAVA_INT, 0);
assertEquals("Path count should remain the same", count, newCount);
// Verify the path was replaced
long size = hdf5_h.H5PLget(lastIdx, MemorySegment.NULL, 0);
MemorySegment pathBuf = arena.allocate(ValueLayout.JAVA_BYTE, (int)size + 1);
hdf5_h.H5PLget(lastIdx, pathBuf, size + 1);
String retrievedPath = segmentToString(pathBuf);
assertEquals("Retrieved path should be replacement", "/tmp/replacement_path", retrievedPath);
}
}
/**
* Test H5PLremove - remove path at specific index
*/
@Test
public void testH5PLremove()
{
try (Arena arena = Arena.ofConfined()) {
MemorySegment countSeg = arena.allocate(ValueLayout.JAVA_INT);
// Add a test path
MemorySegment testPath = stringToSegment(arena, "/tmp/path_to_remove");
hdf5_h.H5PLappend(testPath);
// Get count before removal
hdf5_h.H5PLsize(countSeg);
int beforeCount = countSeg.get(ValueLayout.JAVA_INT, 0);
// Remove the last path
int result = hdf5_h.H5PLremove(beforeCount - 1);
assertEquals("H5PLremove should succeed", 0, result);
// Verify count decreased
hdf5_h.H5PLsize(countSeg);
int afterCount = countSeg.get(ValueLayout.JAVA_INT, 0);
assertEquals("Path count should decrease by 1", beforeCount - 1, afterCount);
}
}
/**
* Test H5PLget - retrieve path at specific index
*/
@Test
public void testH5PLget()
{
try (Arena arena = Arena.ofConfined()) {
MemorySegment countSeg = arena.allocate(ValueLayout.JAVA_INT);
// Add a known test path
String knownPath = "/tmp/test_get_path";
MemorySegment testPath = stringToSegment(arena, knownPath);
hdf5_h.H5PLappend(testPath);
// Get the index of the path we just added
hdf5_h.H5PLsize(countSeg);
int count = countSeg.get(ValueLayout.JAVA_INT, 0);
int lastIdx = count - 1;
// First call to get size (with NULL buffer)
long size = hdf5_h.H5PLget(lastIdx, MemorySegment.NULL, 0);
assertTrue("Should return path length", size > 0);
// Second call to get actual path
MemorySegment pathBuf = arena.allocate(ValueLayout.JAVA_BYTE, (int)size + 1);
long actualSize = hdf5_h.H5PLget(lastIdx, pathBuf, size + 1);
assertEquals("Sizes should match", size, actualSize);
String retrievedPath = segmentToString(pathBuf);
assertEquals("Retrieved path should match", knownPath, retrievedPath);
}
}
/**
* Test H5PLget with invalid index
*/
@Test
public void testH5PLget_invalid_index()
{
try (Arena arena = Arena.ofConfined()) {
// Try to get path at very large invalid index
long size = hdf5_h.H5PLget(99999, MemorySegment.NULL, 0);
// Should return negative value or zero for invalid index
assertTrue("Should return error for invalid index", size <= 0);
}
}
/**
* Test plugin type constants
*/
@Test
public void testH5PL_plugin_type_constants()
{
// Verify plugin type flag constants exist and have expected values
int filterPlugin = hdf5_h.H5PL_FILTER_PLUGIN();
int volPlugin = hdf5_h.H5PL_VOL_PLUGIN();
int vfdPlugin = hdf5_h.H5PL_VFD_PLUGIN();
int allPlugin = hdf5_h.H5PL_ALL_PLUGIN();
// Filter plugin should be bit 0
assertEquals("H5PL_FILTER_PLUGIN should be 0x0001", 0x0001, filterPlugin);
// VOL plugin should be bit 1
assertEquals("H5PL_VOL_PLUGIN should be 0x0002", 0x0002, volPlugin);
// VFD plugin should be bit 2
assertEquals("H5PL_VFD_PLUGIN should be 0x0004", 0x0004, vfdPlugin);
// All plugins should be 0xFFFF
assertEquals("H5PL_ALL_PLUGIN should be 0xFFFF", 0xFFFF, allPlugin);
}
/**
* Test multiple plugin types enabled simultaneously
*/
@Test
public void testH5PL_multiple_plugin_types()
{
try (Arena arena = Arena.ofConfined()) {
MemorySegment stateSeg = arena.allocate(ValueLayout.JAVA_INT);
// Enable filter and VOL plugins
int combinedMask = hdf5_h.H5PL_FILTER_PLUGIN() | hdf5_h.H5PL_VOL_PLUGIN();
int result = hdf5_h.H5PLset_loading_state(combinedMask);
assertEquals("H5PLset_loading_state should succeed", 0, result);
// Verify state
hdf5_h.H5PLget_loading_state(stateSeg);
int state = stateSeg.get(ValueLayout.JAVA_INT, 0);
assertEquals("State should match combined mask", combinedMask, state);
// Verify individual bits are set
assertTrue("Filter plugin should be enabled", (state & hdf5_h.H5PL_FILTER_PLUGIN()) != 0);
assertTrue("VOL plugin should be enabled", (state & hdf5_h.H5PL_VOL_PLUGIN()) != 0);
assertFalse("VFD plugin should not be enabled", (state & hdf5_h.H5PL_VFD_PLUGIN()) != 0);
}
}
}