AdapterTest.java
/*
* Copyright (C) 2015-2022 Samuel Audet
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
* the Free Software Foundation (subject to the "Classpath" exception),
* either version 2, or any later version (collectively, the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.gnu.org/licenses/
* http://www.gnu.org/software/classpath/license.html
*
* or as provided in the LICENSE.txt file that accompanied this code.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bytedeco.javacpp;
import java.io.File;
import java.nio.IntBuffer;
import org.bytedeco.javacpp.annotation.ByRef;
import org.bytedeco.javacpp.annotation.Cast;
import org.bytedeco.javacpp.annotation.Const;
import org.bytedeco.javacpp.annotation.Function;
import org.bytedeco.javacpp.annotation.Name;
import org.bytedeco.javacpp.annotation.Optional;
import org.bytedeco.javacpp.annotation.Platform;
import org.bytedeco.javacpp.annotation.SharedPtr;
import org.bytedeco.javacpp.annotation.StdBasicString;
import org.bytedeco.javacpp.annotation.StdMove;
import org.bytedeco.javacpp.annotation.StdString;
import org.bytedeco.javacpp.annotation.StdU16String;
import org.bytedeco.javacpp.annotation.StdU32String;
import org.bytedeco.javacpp.annotation.StdVector;
import org.bytedeco.javacpp.annotation.StdWString;
import org.bytedeco.javacpp.annotation.UniquePtr;
import org.bytedeco.javacpp.annotation.AsUtf16;
import org.bytedeco.javacpp.tools.Builder;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Test cases for text and data strings. Uses various classes from JavaCPP.
*
* @author Samuel Audet
*/
@Platform(compiler = "cpp17", include = "AdapterTest.h")
public class AdapterTest {
static native @StdString String testStdString(@StdString String str);
static native @StdString BytePointer testStdString(@StdString BytePointer str);
static native @StdWString CharPointer testStdWString(@StdWString CharPointer str);
static native @StdWString @AsUtf16 String testStdWString(@StdWString @AsUtf16 String str);
static native @StdWString IntPointer testStdWString(@StdWString IntPointer str);
static native @StdBasicString("char") String testStdString2(@StdBasicString("char") String str);
static native @Cast("char*") @StdBasicString("char") BytePointer testStdString2(@Cast("char*") @StdBasicString("char") BytePointer str);
static native @Cast("wchar_t*") @StdBasicString("wchar_t") CharPointer testStdWString2(@Cast("wchar_t*") @StdBasicString("wchar_t") CharPointer str);
static native @Cast("wchar_t*") @StdBasicString("wchar_t") IntPointer testStdWString2(@Cast("wchar_t*") @StdBasicString("wchar_t") IntPointer str);
static native @StdU16String CharPointer testStdU16String(@StdU16String CharPointer str);
static native @StdU16String @AsUtf16 String testStdU16String(@StdU16String @AsUtf16 String str);
static native @StdU32String IntPointer testStdU32String(@StdU32String IntPointer str);
static native String testCharString(String str);
static native @Cast("char*") BytePointer testCharString(@Cast("char*") BytePointer str);
static native CharPointer testShortString(CharPointer str);
static native @AsUtf16 String testShortString(@AsUtf16 String str);
static native IntPointer testIntString(IntPointer str);
static native @Const @ByRef @StdString byte[] getConstStdString();
static native @Const @ByRef @Cast("char*") @StdBasicString("char") byte[] getConstStdString2();
static class SharedData extends Pointer {
SharedData(Pointer p) { super(p); }
SharedData(int data) { allocate(data); }
@SharedPtr @Name("std::make_shared<SharedData>") native void allocate(int data);
native int data(); native SharedData data(int data);
}
static native @SharedPtr SharedData createSharedData();
static native void storeSharedData(@SharedPtr SharedData s);
static native @SharedPtr SharedData fetchSharedData();
static native int useCount();
static native int useCount(@SharedPtr SharedData s);
static class UniqueData extends Pointer {
UniqueData(Pointer p) { super(p); }
UniqueData(int data) { allocate(data); }
native void allocate(int data);
native int data(); native UniqueData data(int data);
}
@Function static native @UniquePtr UniqueData createUniqueData();
static native void createUniqueData(@UniquePtr UniqueData u);
static native void storeUniqueData(@Const @UniquePtr UniqueData u);
static native @Const @UniquePtr UniqueData fetchUniqueData();
static native int constructorCount(); static native void constructorCount(int c);
static native int destructorCount(); static native void destructorCount(int c);
static native @StdVector IntPointer testStdVectorByVal(@StdVector IntPointer v);
static native @StdVector IntPointer testStdVectorByRef(@StdVector IntBuffer v);
static native @StdVector int[] testStdVectorByPtr(@StdVector int[] v);
static native @Cast("const char**") @StdVector PointerPointer testStdVectorConstPointer(@Cast("const char**") @StdVector PointerPointer v);
static class MovedData extends Pointer {
MovedData(Pointer p) { super(p); }
MovedData(int data) { allocate(data); }
native void allocate(int data);
native int data(); native MovedData data(int data);
}
static native @StdMove MovedData getMovedData();
static native void putMovedData(@StdMove MovedData m);
static native @Optional IntPointer testOptionalInt(@Optional IntPointer o);
static class SharedFunction extends FunctionPointer {
public SharedFunction(Pointer p) { super(p); }
public SharedFunction() { allocate(); }
private native void allocate();
public native int call(@Cast({"", "std::shared_ptr<SharedData>"}) @SharedPtr SharedData s);
}
static native int testCallback(@Const @ByRef SharedFunction f, @SharedPtr SharedData s);
static class UniqueFunction extends FunctionPointer {
public UniqueFunction(Pointer p) { super(p); }
public UniqueFunction() { allocate(); }
private native void allocate();
public native int call(@Cast({"", "std::unique_ptr<UniqueData>", "std::unique_ptr<UniqueData>&&"}) @UniquePtr UniqueData u);
}
static native int testCallback(@ByRef UniqueFunction f, @UniquePtr UniqueData s);
@BeforeClass public static void setUpClass() throws Exception {
System.out.println("Builder");
Class c = AdapterTest.class;
Builder builder = new Builder().classesOrPackages(c.getName());
File[] outputFiles = builder.build();
System.out.println("Loader");
Loader.load(c);
}
@Test public void testStdString() {
System.out.println("StdString");
byte[] data = new byte[42];
for (int i = 0; i < data.length; i++) {
data[i] = (byte)i;
}
BytePointer dataPtr1 = new BytePointer(data);
BytePointer dataPtr2 = testStdString(dataPtr1);
for (int i = 0; i < data.length; i++) {
assertEquals(data[i], dataPtr1.get(i));
assertEquals(data[i], dataPtr2.get(i));
}
String textStr1 = "This is a normal ASCII string.";
String textStr2 = testStdString(textStr1);
assertEquals(textStr1, textStr2);
String textStr3 = testStdString2(textStr1);
assertEquals(textStr1, textStr3);
BytePointer textPtr1 = new BytePointer(textStr1);
BytePointer textPtr2 = testStdString(textPtr1);
assertEquals(textStr1, textPtr1.getString());
assertEquals(textStr1, textPtr2.getString());
BytePointer textPtr3 = testStdString2(textPtr1);
assertEquals(textStr1, textPtr3.getString());
CharPointer textCharPtr1 = new CharPointer(textStr1);
assertEquals(textStr1, textCharPtr1.getString());
IntPointer textIntPtr1 = new IntPointer(textStr1);
assertEquals(textStr1, textIntPtr1.getString());
if (Loader.getPlatform().startsWith("windows")) {
// UTF-16
CharPointer textCharPtr2 = testStdWString(textCharPtr1);
assertEquals(textStr1, textCharPtr2.getString());
CharPointer textCharPtr3 = testStdWString2(textCharPtr1);
assertEquals(textStr1, textCharPtr3.getString());
String textStr4 = testStdWString(textStr1);
assertEquals(textStr1, textStr4);
} else {
// UTF-32
IntPointer textIntPtr2 = testStdWString(textIntPtr1);
assertEquals(textStr1, textIntPtr2.getString());
IntPointer textIntPtr3 = testStdWString2(textIntPtr1);
assertEquals(textStr1, textIntPtr3.getString());
}
CharPointer textCharPtr4 = testStdU16String(textCharPtr1);
assertEquals(textStr1, textCharPtr4.getString());
String textStr5 = testStdU16String(textStr1);
assertEquals(textStr1, textStr5);
IntPointer textIntPtr4 = testStdU32String(textIntPtr1);
assertEquals(textStr1, textIntPtr4.getString());
byte[] test = getConstStdString();
assertEquals("test", new String(test));
byte[] test2 = getConstStdString2();
assertEquals("test", new String(test2));
System.gc();
}
@Test public void testCharString() {
System.out.println("CharString");
String textStr1 = "This is a normal ASCII string.";
String textStr2 = testCharString(textStr1);
assertEquals(textStr1, textStr2);
BytePointer textPtr1 = new BytePointer(textStr1);
BytePointer textPtr2 = testCharString(textPtr1);
assertEquals(textStr1, textPtr1.getString());
assertEquals(textStr1, textPtr2.getString());
System.gc();
}
@Test public void testShortString() {
System.out.println("ShortString");
String textStr1 = "This is a normal ASCII string.";
CharPointer textPtr1 = new CharPointer(textStr1);
CharPointer textPtr2 = testShortString(textPtr1);
assertEquals(textStr1, textPtr1.getString());
assertEquals(textStr1, textPtr2.getString());
String textStr2 = testShortString(textStr1);
assertEquals(textStr1, textStr2);
System.gc();
}
@Test public void testIntString() {
System.out.println("IntString");
String textStr = "This is a normal ASCII string.";
IntPointer textPtr1 = new IntPointer(textStr);
IntPointer textPtr2 = testIntString(textPtr1);
assertEquals(textStr, textPtr1.getString());
assertEquals(textStr, textPtr2.getString());
System.gc();
}
@Test public void testSharedPtr() {
System.out.println("SharedPtr");
SharedData sharedData = createSharedData();
assertEquals(42, sharedData.data());
assertEquals(2, useCount(sharedData)); // 1 in Java shareData, 1 in JNI sharePtr2
storeSharedData(sharedData);
assertEquals(2, useCount()); // 1 in C++ static var, 1 in Java sharedData
sharedData.deallocate();
assertEquals(1, useCount());
sharedData = fetchSharedData();
assertEquals(13, sharedData.data());
assertEquals(0, useCount());
final SharedData[] sharedData2 = new SharedData[1];
int data = testCallback(new SharedFunction() {
@Override public int call(SharedData d) {
d.data(2 * d.data());
sharedData2[0] = d;
return 3 * d.data();
}
}, sharedData);
assertEquals(2 * 13, sharedData2[0].data());
assertEquals(2 * 3 * 13, data);
assertEquals(3, useCount(sharedData)); // 1 in JNI sharePtr2, 1 in sharedData, 1 in sharedData2[0]
sharedData.deallocate();
sharedData2[0].deallocate();
assertEquals(1, constructorCount());
assertEquals(1, destructorCount());
SharedData sd = new SharedData(45);
assertEquals(2, useCount(sd));
storeSharedData(sd);
assertEquals(3, useCount(sd));
sd.deallocate();
assertEquals(1, useCount());
sd = fetchSharedData();
assertEquals(2, useCount(sd));
assertEquals(13, sd.data());
sd.deallocate();
assertEquals(2, constructorCount());
assertEquals(2, destructorCount());
System.gc();
}
@Test public void testUniquePtr() {
System.out.println("UniquePtr");
UniqueData uniqueData = fetchUniqueData();
assertEquals(13, uniqueData.data());
uniqueData = createUniqueData();
assertEquals(5, uniqueData.data());
storeUniqueData(uniqueData);
uniqueData = fetchUniqueData();
assertEquals(5, uniqueData.data());
uniqueData = new UniqueData(null);
createUniqueData(uniqueData);
assertEquals(42, uniqueData.data());
storeUniqueData(uniqueData);
uniqueData = fetchUniqueData();
assertEquals(42, uniqueData.data());
final UniqueData[] uniqueData2 = new UniqueData[1];
int data = testCallback(new UniqueFunction() {
@Override public int call(UniqueData d) {
d.data(2 * d.data());
uniqueData2[0] = d;
return 3 * d.data();
}
}, uniqueData);
assertEquals(2 * 42, uniqueData2[0].data());
assertEquals(2 * 3 * 42, data);
uniqueData2[0].deallocate();
System.gc();
}
@Test public void testStdVector() {
System.out.println("StdVector");
int[] arr = {5, 7, 13, 37, 42};
IntPointer ptr = new IntPointer(arr);
IntBuffer buf = ptr.asBuffer();
PointerPointer ptrptr = new PointerPointer(ptr, ptr, ptr, ptr, ptr);
IntPointer ptr2 = testStdVectorByVal(ptr);
IntBuffer buf2 = testStdVectorByRef(buf).asBuffer();
int[] arr2 = testStdVectorByPtr(arr);
PointerPointer ptrptr2 = testStdVectorConstPointer(ptrptr);
for (int i = 0; i < arr.length; i++) {
assertEquals(ptr.get(i), ptr2.get(i));
assertEquals(buf.get(i), buf2.get(i));
assertEquals(arr[i], arr2[i]);
assertEquals(ptrptr.get(i), ptrptr2.get(i));
}
System.gc();
}
@Test public void testStdMove() {
System.out.println("StdMove");
MovedData m = getMovedData();
System.out.println(m);
System.out.println(m.data());
assertEquals(13, m.data());
assertNotNull(m.deallocator());
m.deallocate();
m = new MovedData(42);
putMovedData(m);
System.out.println(m);
System.out.println(m.data()); // probably 42, but undefined
MovedData m2 = getMovedData();
System.out.println(m2);
System.out.println(m2.data());
assertEquals(42, m2.data());
assertNotEquals(m.address(), m2.address());
assertNotNull(m.deallocator());
assertNotNull(m2.deallocator());
m.deallocate();
m2.deallocate();
}
@Test public void testOptional() {
System.out.println("Optional");
assertTrue(testOptionalInt(new IntPointer((Pointer)null)).isNull());
assertEquals(42, testOptionalInt(new IntPointer(1).put(42)).get(0));
}
}