fangorn/huorn-minecraft
public
ref:main
package io.fangorn.huorn.nativelib;
import java.nio.ByteBuffer;
/**
* Standalone JNI integration test for the Rust native terminal library.
* This class MUST be named NativeTerminal in the io.fangorn.huorn.nativelib
* package to match the JNI function name mangling.
*
* Run:
* javac -d . NativeTerminal.java
* java -Djava.library.path=../../target/release io.fangorn.huorn.nativelib.NativeTerminal
*/
public class NativeTerminal {
private static native long nativeCreate(int cols, int rows, float fontSize, String shell, String workingDir, String backend);
private static native void nativeDestroy(long handle);
private static native void nativeSendText(long handle, String text);
private static native void nativeSendKey(long handle, int keycode, int modifiers);
private static native boolean nativeGetPixelData(long handle, ByteBuffer buffer);
private static native int[] nativeGetDimensions(long handle);
private static native void nativeResize(long handle, int cols, int rows);
private static native boolean nativePollPty(long handle);
private static native boolean nativeIsAlive(long handle);
private static native void nativeScroll(long handle, int delta);
public static native void nativeInitAudit(String logPath);
public static native void nativeAuditEvent(long handle, String eventType, String jsonPayload);
public static native void nativeAuditEventGlobal(String eventType, String jsonPayload);
static { System.loadLibrary("huorn_minecraft"); }
static int passed = 0, failed = 0;
static void check(String name, boolean ok, String detail) {
System.out.println((ok ? " PASS: " : " FAIL: ") + name + (detail != null ? " (" + detail + ")" : ""));
if (ok) passed++; else failed++;
}
public static void main(String[] args) throws Exception {
System.out.println("=== Huorn-Minecraft JNI Integration Test ===\n");
long h = nativeCreate(80, 24, 14.0f, "", "", "plain");
check("Create terminal", h != 0, "handle=" + h);
check("Is alive", nativeIsAlive(h), null);
int[] dims = nativeGetDimensions(h);
check("Dimensions valid", dims != null && dims[0] > 0 && dims[1] > 0,
dims[0] + "x" + dims[1] + " cell=" + dims[2] + "x" + dims[3]);
ByteBuffer buf = ByteBuffer.allocateDirect(dims[0] * dims[1] * 4);
boolean dirty = nativeGetPixelData(h, buf);
check("First render", dirty, null);
buf.rewind();
int bright = 0;
for (int i = 0; i < dims[0] * dims[1]; i++) {
int r = buf.get() & 0xFF, g = buf.get() & 0xFF, b = buf.get() & 0xFF;
buf.get();
if (r > 100 || g > 100 || b > 100) bright++;
}
check("Has rendered content", bright > 5, "brightPx=" + bright);
nativeSendText(h, "echo JNI_TEST_OK\n");
Thread.sleep(300);
nativePollPty(h);
buf = ByteBuffer.allocateDirect(dims[0] * dims[1] * 4);
nativeGetPixelData(h, buf);
buf.rewind();
int fg = 0;
for (int i = 0; i < dims[0] * dims[1]; i++) {
int r = buf.get() & 0xFF, g = buf.get() & 0xFF, b = buf.get() & 0xFF;
buf.get();
if (r > 100 || g > 100 || b > 100) fg++;
}
check("Text rendered after echo", fg > 100, "fgPx=" + fg);
nativeResize(h, 120, 40);
int[] nd = nativeGetDimensions(h);
check("Resize", nd[0] > dims[0] && nd[1] > dims[1], nd[0] + "x" + nd[1]);
nativeSendKey(h, 67, 2);
check("Ctrl+C", true, null);
nativeScroll(h, 5);
nativeScroll(h, -5);
check("Scroll", true, null);
Thread.sleep(100);
nativePollPty(h);
check("Alive after Ctrl+C", nativeIsAlive(h), null);
nativeDestroy(h);
check("Destroy", true, null);
System.out.println("\n=== " + passed + " passed, " + failed + " failed ===");
System.exit(failed > 0 ? 1 : 0);
}
}