/*
* Copyright (C) 2012 RoboVM AB
*
* Licensed under the Apache License, Version 2.0 (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
*
* 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.robovm.rt.bro;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.robovm.rt.VM;
import org.robovm.rt.bro.annotation.Bridge;
import org.robovm.rt.bro.annotation.ByVal;
import org.robovm.rt.bro.annotation.Callback;
import org.robovm.rt.bro.annotation.MachineSizedFloat;
import org.robovm.rt.bro.annotation.MachineSizedSInt;
import org.robovm.rt.bro.annotation.MachineSizedUInt;
import org.robovm.rt.bro.annotation.Marshaler;
import org.robovm.rt.bro.annotation.Marshalers;
import org.robovm.rt.bro.annotation.MarshalsPointer;
import org.robovm.rt.bro.annotation.Pointer;
import org.robovm.rt.bro.annotation.StructMember;
import org.robovm.rt.bro.annotation.StructRet;
import org.robovm.rt.bro.ptr.BytePtr;
import org.robovm.rt.bro.ptr.CharPtr;
import org.robovm.rt.bro.ptr.DoublePtr;
import org.robovm.rt.bro.ptr.FloatPtr;
import org.robovm.rt.bro.ptr.IntPtr;
import org.robovm.rt.bro.ptr.LongPtr;
import org.robovm.rt.bro.ptr.Ptr;
import org.robovm.rt.bro.ptr.ShortPtr;
/**
* Tests {@link Bridge} and {@link Callback} methods.
*/
public class BridgeCallbackTest {
public static final class Point extends Struct<Point> {
@StructMember(0)
public native int x();
@StructMember(1)
public native int y();
@StructMember(0)
public native Point x(int x);
@StructMember(1)
public native Point y(int y);
}
public static final class PointPtr extends Ptr<Point, PointPtr> {}
public static final class PointPtrPtr extends Ptr<PointPtr, PointPtrPtr> {}
public static final class Points extends Struct<Points> {
@StructMember(0)
public native @ByVal Point p1();
@StructMember(0)
public native Points p1(@ByVal Point p1);
@StructMember(1)
public native @ByVal Point p2();
@StructMember(1)
public native Points p2(@ByVal Point p2);
@StructMember(2)
public native @ByVal Point p3();
@StructMember(2)
public native Points p3(@ByVal Point p3);
@StructMember(3)
public native @ByVal Point p4();
@StructMember(3)
public native Points p4(@ByVal Point p4);
}
public enum SimpleEnum {
V1, V2, V3
}
public enum TestValuedEnum implements ValuedEnum {
VM1(-1), V100(100), V1000(1000), V10000(10000);
private final int n;
private TestValuedEnum(int n) {
this.n = n;
}
public long value() {
return n;
}
}
public static final class TestBits extends Bits<TestBits> {
public static final TestBits V1 = new TestBits(1);
public static final TestBits V2 = new TestBits(2);
public static final TestBits V4 = new TestBits(4);
public static final TestBits V8 = new TestBits(8);
private static final TestBits[] VALUES = _values(TestBits.class);
private TestBits(long value) { super(value); }
private TestBits(long value, long mask) { super(value, mask); }
@Override
protected TestBits wrap(long value, long mask) {
return new TestBits(value, mask);
}
@Override
protected TestBits[] _values() {
return VALUES;
}
}
public static final class MoreTestBits extends Bits<MoreTestBits> {
public static final MoreTestBits V1 = new MoreTestBits(-1);
public static final MoreTestBits V2 = new MoreTestBits(0x80000000L);
public static final MoreTestBits V3 = new MoreTestBits(0x1234567880000000L);
private static final MoreTestBits[] VALUES = _values(MoreTestBits.class);
private MoreTestBits(long value) { super(value); }
private MoreTestBits(long value, long mask) { super(value, mask); }
@Override
protected MoreTestBits wrap(long value, long mask) {
return new MoreTestBits(value, mask);
}
@Override
protected MoreTestBits[] _values() {
return VALUES;
} }
public static class StringMarshaler {
static List<String> calls = new ArrayList<String>();
@MarshalsPointer
public static String toObject(Class<?> cls, long handle, long flags) {
BytePtr ptr = Struct.toStruct(BytePtr.class, handle);
String s = ptr.toStringAsciiZ();
calls.add("toObject(" + s + ", ?, " + Long.toHexString(flags) + ")");
return s;
}
@MarshalsPointer
public static long toNative(String s, long flags) {
calls.add("toNative(" + s + ", ?, " + Long.toHexString(flags) + ")");
BytePtr ptr = BytePtr.toBytePtrAsciiZ((String) s);
return ptr.getHandle();
}
// @AfterBridgeCall
// public static void afterToNative(String s, long handle, long flags) {
// calls.add("afterToNative(" + s + ", ?, " + Long.toHexString(flags) + ")");
// }
// @AfterCallbackCall
// public static void afterToObject(long handle, String s, long flags) {
// calls.add("afterToObject(?, " + s + ", " + Long.toHexString(flags) + ")");
// }
}
@Bridge
public static native int addInts(int x, int y);
@Callback
public static int addInts_cb(int x, int y) {
return x + y;
}
@Bridge
public static native Point addPoints(Point p1, Point p2);
@Callback
public static Point addPoints_cb(Point p1, Point p2) {
return new Point().x(p1.x() + p2.x()).y(p1.y() + p2.y());
}
@Bridge
public static native void scalePoint1(Point p, int scale);
@Callback
public static void scalePoint1_cb(Point p, int scale) {
p.x(p.x() * scale);
p.y(p.y() * scale);
}
@Bridge
public static native void scalePoint2(@ByVal Point p, int scale);
@Callback
public static void scalePoint2_cb(@ByVal Point p, int scale) {
p.x(p.x() * scale);
p.y(p.y() * scale);
}
@Bridge
public static native @ByVal Point copyPoint(Point p);
@Callback
public static @ByVal Point copyPoint_cb(Point p) {
return p;
}
@Bridge
public static native void createPoints(@StructRet Points ps, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
@Callback
public static void createPoints_cb(@StructRet Points ps, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
ps.p1(new Point().x(x1).y(y1));
ps.p2(new Point().x(x2).y(y2));
ps.p3(new Point().x(x3).y(y3));
ps.p4(new Point().x(x4).y(y4));
}
@Bridge
public static native void createPoint(int x, int y, PointPtr ptr);
@Callback
public static void createPoint_cb(int x, int y, PointPtr ptr) {
ptr.set(new Point().x(x).y(y));
}
@Bridge
public static native Point passLargeStructByVal(@ByVal Points ps);
@Callback
public static Point passLargeStructByVal_cb(@ByVal Points ps) {
int sumx = 0;
int sumy = 0;
sumx += ps.p1().x();
sumy += ps.p1().y();
sumx += ps.p2().x();
sumy += ps.p2().y();
sumx += ps.p3().x();
sumy += ps.p3().y();
sumx += ps.p4().x();
sumy += ps.p4().y();
ps.clear();
return new Point().x(sumx).y(sumy);
}
@Bridge
public static native @ByVal Points returnLargeStructByVal(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, LongPtr address);
@Callback
public static @ByVal Points returnLargeStructByVal_cb(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, LongPtr address) {
Points ps = new Points();
ps.p1(new Point().x(x1).y(y1));
ps.p2(new Point().x(x2).y(y2));
ps.p3(new Point().x(x3).y(y3));
ps.p4(new Point().x(x4).y(y4));
address.set(ps.getHandle());
return ps;
}
@Bridge
public static native @Marshaler(StringMarshaler.class) String append(
@Marshaler(StringMarshaler.class) String a,
@Marshaler(StringMarshaler.class) String b);
@Callback
public static @Marshaler(StringMarshaler.class) String append_cb(
@Marshaler(StringMarshaler.class) String a,
@Marshaler(StringMarshaler.class) String b) {
return a + b;
}
@Marshaler(StringMarshaler.class)
public static class Inner1 {
@Bridge
public static native String append(String a, String b);
@Callback
public static String append_cb(String a, String b) {
return a + b;
}
}
@Marshalers(@Marshaler(StringMarshaler.class))
public static class Inner2 {
@Bridge
public static native String append(String a, String b);
@Callback
public static String append_cb(String a, String b) {
return a + b;
}
}
@Marshaler(StringMarshaler.class)
public static class Inner3 {
public static class Inner4 {
@Bridge
public static native String append(String a, String b);
@Callback
public static String append_cb(String a, String b) {
return a + b;
}
}
}
// This must be small enough to always be returned in registers on all supported platforms
public static class SmallStruct extends Struct<SmallStruct> {
@StructMember(0) public native byte v1();
@StructMember(0) public native SmallStruct v1(byte v1);
@StructMember(1) public native byte v2();
@StructMember(1) public native SmallStruct v2(byte v2);
}
// This must be large enough to never be returned in registers on all supported platforms
public static class LargeStruct extends Struct<LargeStruct> {
@StructMember(0) public native long v1();
@StructMember(0) public native LargeStruct v1(long v1);
@StructMember(1) public native long v2();
@StructMember(1) public native LargeStruct v2(long v2);
@StructMember(2) public native long v3();
@StructMember(2) public native LargeStruct v3(long v3);
@StructMember(3) public native long v4();
@StructMember(3) public native LargeStruct v4(long v4);
}
public static class NativeObj extends NativeObject {
@Bridge public native int simpleInstanceMethod(int x, LongPtr l);
@Callback public int simpleInstanceMethod_cb(int x, LongPtr l) {
l.set(getHandle());
return x * x;
}
@Bridge public native @ByVal SmallStruct returnSmallStructInstanceMethod(@ByVal SmallStruct s, LongPtr l);
@Callback public @ByVal SmallStruct returnSmallStructInstanceMethod_cb(@ByVal SmallStruct s, LongPtr l) {
l.set(getHandle());
return s;
}
@Bridge public native @ByVal LargeStruct returnLargeStructInstanceMethod(@ByVal LargeStruct s, LongPtr l);
@Callback public @ByVal LargeStruct returnLargeStructInstanceMethod_cb(@ByVal LargeStruct s, LongPtr l) {
l.set(getHandle());
return s;
}
}
@Bridge
public static native SimpleEnum marshalSimpleEnum(SimpleEnum v);
@Callback
public static SimpleEnum marshalSimpleEnum_cb(SimpleEnum v) {
SimpleEnum[] values = SimpleEnum.values();
return values[(v.ordinal() + 1) % values.length];
}
@Bridge
public static native TestValuedEnum marshalValuedEnum(TestValuedEnum v);
@Callback
public static TestValuedEnum marshalValuedEnum_cb(TestValuedEnum v) {
TestValuedEnum[] values = TestValuedEnum.values();
return values[(v.ordinal() + 1) % values.length];
}
@Bridge
public static native @Marshaler(ValuedEnum.AsUnsignedIntMarshaler.class) TestValuedEnum marshalValuedEnumAsUnsignedInt(
@Marshaler(ValuedEnum.AsUnsignedIntMarshaler.class) TestValuedEnum v);
@Callback
public static @Marshaler(ValuedEnum.AsUnsignedIntMarshaler.class) TestValuedEnum marshalValuedEnumAsUnsignedInt_cb(
@Marshaler(ValuedEnum.AsUnsignedIntMarshaler.class) TestValuedEnum v) {
TestValuedEnum[] values = TestValuedEnum.values();
return values[(v.ordinal() + 1) % values.length];
}
@Bridge
public static native TestBits marshalBits1(TestBits v1, TestBits v2);
@Callback
public static int marshalBits1_cb(int v1, int v2) {
return v1 | v2;
}
@Bridge
public static native int marshalBits2(int v1, int v2);
@Callback
public static TestBits marshalBits2_cb(TestBits v1, TestBits v2) {
return v1.set(v2);
}
@Bridge
public static native String marshalStringsWithDefaultMarshaler(String a, String b);
@Callback
public static BytePtr marshalStringsWithDefaultMarshaler_cb(String a, String b) {
return a == null && b == null ? null : BytePtr.toBytePtrAsciiZ(String.format("a = %s, b = %s", a, b));
}
@Bridge
public static native BytePtr marshalBuffersWithDefaultMarshaler(ByteBuffer a, ByteBuffer b);
@Callback
public static BytePtr marshalBuffersWithDefaultMarshaler_cb(BytePtr a, BytePtr b) {
return a == null && b == null ? null
: BytePtr.toBytePtrAsciiZ(
String.format("a = %s, b = %s",
a == null ? null : a.toStringAsciiZ(),
b == null ? null : b.toStringAsciiZ()));
}
@Bridge
public static native BytePtr marshal1DByteArrayWithDefaultMarshaler(byte[] a, byte[] b);
@Callback
public static BytePtr marshal1DByteArrayWithDefaultMarshaler_cb(BytePtr a, BytePtr b) {
return a == null && b == null ? null
: BytePtr.toBytePtrAsciiZ(
String.format("a = %s, b = %s",
a == null ? null : a.toStringAsciiZ(),
b == null ? null : b.toStringAsciiZ()));
}
@Bridge
public static native short marshal1DShortArrayWithDefaultMarshaler(short[] a);
@Callback
public static short marshal1DShortArrayWithDefaultMarshaler_cb(ShortPtr ptr) {
if (ptr == null) {
return -1;
}
short sum = 0;
while (ptr.get() != 0) {
sum += ptr.get();
ptr = ptr.next();
}
return sum;
}
@Bridge
public static native char marshal1DCharArrayWithDefaultMarshaler(char[] a);
@Callback
public static char marshal1DCharArrayWithDefaultMarshaler_cb(CharPtr ptr) {
if (ptr == null) {
return 0xffff;
}
char sum = 0;
while (ptr.get() != 0) {
sum += ptr.get();
ptr = ptr.next();
}
return sum;
}
@Bridge
public static native int marshal1DIntArrayWithDefaultMarshaler(int[] a);
@Callback
public static int marshal1DIntArrayWithDefaultMarshaler_cb(IntPtr ptr) {
if (ptr == null) {
return -1;
}
int sum = 0;
while (ptr.get() != 0) {
sum += ptr.get();
ptr = ptr.next();
}
return sum;
}
@Bridge
public static native long marshal1DLongArrayWithDefaultMarshaler(long[] a);
@Callback
public static long marshal1DLongArrayWithDefaultMarshaler_cb(LongPtr ptr) {
if (ptr == null) {
return -1;
}
long sum = 0;
while (ptr.get() != 0) {
sum += ptr.get();
ptr = ptr.next();
}
return sum;
}
@Bridge
public static native float marshal1DFloatArrayWithDefaultMarshaler(float[] a);
@Callback
public static float marshal1DFloatArrayWithDefaultMarshaler_cb(FloatPtr ptr) {
if (ptr == null) {
return -1.0f;
}
float sum = 0.0f;
while (ptr.get() != 0.0f) {
sum += ptr.get();
ptr = ptr.next();
}
return sum;
}
@Bridge
public static native double marshal1DDoubleArrayWithDefaultMarshaler(double[] a);
@Callback
public static double marshal1DDoubleArrayWithDefaultMarshaler_cb(DoublePtr ptr) {
if (ptr == null) {
return -1.0;
}
double sum = 0.0;
while (ptr.get() != 0.0) {
sum += ptr.get();
ptr = ptr.next();
}
return sum;
}
@Bridge
public static native @MachineSizedFloat double marshalMachinedSizeFloatAsDouble(@MachineSizedFloat double d);
@Callback
public static @MachineSizedFloat double marshalMachinedSizeFloatAsDouble_cb(@MachineSizedFloat double d) {
return d;
}
@Bridge
public static native @MachineSizedFloat float marshalMachinedSizeFloatAsFloat(@MachineSizedFloat float f);
@Callback
public static @MachineSizedFloat float marshalMachinedSizeFloatAsFloat_cb(@MachineSizedFloat float f) {
return f;
}
@Bridge
public static native @MachineSizedSInt long marshalMachinedSizeSInt(@MachineSizedSInt long l);
@Callback
public static @MachineSizedSInt long marshalMachinedSizeSInt_cb(@MachineSizedSInt long l) {
return l;
}
@Bridge
public static native @MachineSizedUInt long marshalMachinedSizeUInt(@MachineSizedUInt long l);
@Callback
public static @MachineSizedUInt long marshalMachinedSizeUInt_cb(@MachineSizedUInt long l) {
return l;
}
@Bridge
public static native long marshalBitsAsMachineSizedInt1(@Marshaler(Bits.AsMachineSizedIntMarshaler.class) MoreTestBits v);
@Callback
public static long marshalBitsAsMachineSizedInt1_cb(@MachineSizedUInt long l) {
return l;
}
@Bridge
public static native @Marshaler(Bits.AsMachineSizedIntMarshaler.class) MoreTestBits marshalBitsAsMachineSizedInt2(long v);
@Callback
public static @MachineSizedUInt long marshalBitsAsMachineSizedInt2_cb(long v) {
return v;
}
@Bridge(dynamic = true)
public static native int dynamicBridge(@Pointer long targetFunction, int a, int b);
@Callback
public static int dynamicBridge_target(int a, int b) {
return a + b;
}
private static Method find(Class<?> cls, String name) {
for (Method m : cls.getDeclaredMethods()) {
if (m.getName().equals(name)) {
return m;
}
}
return null;
}
private static void bind(Class<?> cls) {
for (Method m : cls.getDeclaredMethods()) {
if (m.getAnnotation(Bridge.class) != null) {
Method callbackMethod = find(cls, m.getName() + "_cb");
if (callbackMethod != null) {
VM.bindBridgeMethod(m, VM.getCallbackMethodImpl(callbackMethod));
}
}
}
}
static {
bind(BridgeCallbackTest.class);
bind(BridgeCallbackTest.Inner1.class);
bind(BridgeCallbackTest.Inner2.class);
bind(BridgeCallbackTest.Inner3.Inner4.class);
bind(BridgeCallbackTest.NativeObj.class);
}
@Test
public void testPrimitiveParameters() {
assertEquals(8, addInts(5, 3));
}
@Test
public void testMarshalStructParametersAndReturnValue() {
Point p1 = new Point().x(1).y(2);
Point p2 = new Point().x(3).y(4);
Point sum = addPoints(p1, p2);
assertEquals(4, sum.x());
assertEquals(6, sum.y());
}
@Test
public void testMarshalStructParametersByRef() {
Point p = new Point().x(1).y(2);
scalePoint1(p, 5);
assertEquals(5, p.x());
assertEquals(10, p.y());
}
@Test
public void testMarshalStructParametersByVal() {
Point p = new Point().x(1).y(2);
scalePoint2(p, 5);
assertEquals(1, p.x());
assertEquals(2, p.y());
}
@Test
public void testMarshalStructStructRet() {
Points ps = new Points();
createPoints(ps, 1, 2, 3, 4, 5, 6, 7, 8);
assertEquals(1, ps.p1().x());
assertEquals(2, ps.p1().y());
assertEquals(3, ps.p2().x());
assertEquals(4, ps.p2().y());
assertEquals(5, ps.p3().x());
assertEquals(6, ps.p3().y());
assertEquals(7, ps.p4().x());
assertEquals(8, ps.p4().y());
}
@Test
public void testNullByValParameter() {
try {
scalePoint2(null, 5);
fail("NullPointerException expected");
} catch (NullPointerException e) {
}
}
@Test
public void testNullStructRet() {
try {
createPoints(null, 1, 2, 3, 4, 5, 6, 7, 8);
fail("NullPointerException expected");
} catch (NullPointerException e) {
}
}
@Test
public void testMarshalStructReturnValueByVal() {
Point p1 = new Point().x(1).y(2);
Point p2 = copyPoint(p1);
assertEquals(1, p2.x());
assertEquals(2, p2.y());
assertFalse(p1.equals(p2));
}
@Test
public void testMarshalStructPtr() {
PointPtr ptr = new PointPtr();
assertNull(ptr.get());
createPoint(10, 20, ptr);
Point p = ptr.get();
assertNotNull(p);
assertEquals(10, p.x());
assertEquals(20, p.y());
}
@Test
public void testMarshalLargeStructParameterByVal() {
Points ps = new Points();
ps.p1(new Point().x(1).y(2));
ps.p2(new Point().x(2).y(4));
ps.p3(new Point().x(3).y(6));
ps.p4(new Point().x(4).y(8));
Point sum = passLargeStructByVal(ps);
assertEquals(1, ps.p1().x());
assertEquals(2, ps.p1().y());
assertEquals(2, ps.p2().x());
assertEquals(4, ps.p2().y());
assertEquals(3, ps.p3().x());
assertEquals(6, ps.p3().y());
assertEquals(4, ps.p4().x());
assertEquals(8, ps.p4().y());
assertEquals(10, sum.x());
assertEquals(20, sum.y());
}
@Test
public void testMarshalLargeStructReturnValueByVal() {
LongPtr address = new LongPtr();
Points ps = returnLargeStructByVal(1, 2, 3, 4, 5, 6, 7, 8, address);
assertEquals(1, ps.p1().x());
assertEquals(2, ps.p1().y());
assertEquals(3, ps.p2().x());
assertEquals(4, ps.p2().y());
assertEquals(5, ps.p3().x());
assertEquals(6, ps.p3().y());
assertEquals(7, ps.p4().x());
assertEquals(8, ps.p4().y());
assertFalse(address.get() == ps.getHandle());
}
@Test
public void testMarshalNonNativeTypeInlineMarshaler() {
String s = append("foo", "bar");
assertEquals("foobar", s);
}
@Test
public void testMarshalNonNativeTypeMarshalerOnClass() {
String s = Inner1.append("foo", "bar");
assertEquals("foobar", s);
}
@Test
public void testMarshalNonNativeTypeMarshalersOnClass() {
String s = Inner2.append("foo", "bar");
assertEquals("foobar", s);
}
@Test
public void testMarshalerOnOuterClass() {
String s = Inner3.Inner4.append("foo", "bar");
assertEquals("foobar", s);
}
// @Test
// public void testMarshalerCallSequence() {
// StringMarshaler.calls = new ArrayList<String>();
// append("foo", "bar");
// assertEquals(10, StringMarshaler.calls.size());
// assertEquals("toNative(foo, ?, 0)", StringMarshaler.calls.get(0));
// assertEquals("toNative(bar, ?, 0)", StringMarshaler.calls.get(1));
// assertEquals("toObject(foo, ?, 1)", StringMarshaler.calls.get(2));
// assertEquals("toObject(bar, ?, 1)", StringMarshaler.calls.get(3));
// assertEquals("afterToObject(?, foo, 1)", StringMarshaler.calls.get(4));
// assertEquals("afterToObject(?, bar, 1)", StringMarshaler.calls.get(5));
// assertEquals("toNative(foobar, ?, 1)", StringMarshaler.calls.get(6));
// assertEquals("afterToNative(foo, ?, 0)", StringMarshaler.calls.get(7));
// assertEquals("afterToNative(bar, ?, 0)", StringMarshaler.calls.get(8));
// assertEquals("toObject(foobar, ?, 0)", StringMarshaler.calls.get(9));
// }
@Test
public void testMarshalSimpleEnum() {
assertEquals(SimpleEnum.V2, marshalSimpleEnum(SimpleEnum.V1));
assertEquals(SimpleEnum.V3, marshalSimpleEnum(SimpleEnum.V2));
assertEquals(SimpleEnum.V1, marshalSimpleEnum(SimpleEnum.V3));
}
@Test
public void testMarshalValuedEnum() {
assertEquals(TestValuedEnum.V100, marshalValuedEnum(TestValuedEnum.VM1));
assertEquals(TestValuedEnum.V1000, marshalValuedEnum(TestValuedEnum.V100));
assertEquals(TestValuedEnum.V10000, marshalValuedEnum(TestValuedEnum.V1000));
assertEquals(TestValuedEnum.VM1, marshalValuedEnum(TestValuedEnum.V10000));
}
@Test
public void testMarshalValuedEnumAsUnsignedInt() {
try {
marshalValuedEnumAsUnsignedInt(TestValuedEnum.VM1);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("" + 0xffffffffL));
assertTrue(e.getMessage().contains("0xffffffff"));
}
try {
marshalValuedEnumAsUnsignedInt(TestValuedEnum.V10000);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("" + 0xffffffffL));
assertTrue(e.getMessage().contains("0xffffffff"));
}
assertEquals(TestValuedEnum.V1000, marshalValuedEnumAsUnsignedInt(TestValuedEnum.V100));
assertEquals(TestValuedEnum.V10000, marshalValuedEnumAsUnsignedInt(TestValuedEnum.V1000));
}
@Test
public void testMarshalBits1() {
assertEquals(1 | 8, marshalBits1(TestBits.V1, TestBits.V8).value());
}
@Test
public void testMarshalBits2() {
assertEquals(1 | 8, marshalBits2(1, 8));
}
@Test
public void testMarshalStringsWithDefaultMarshaler() {
assertEquals("a = foo, b = bar", marshalStringsWithDefaultMarshaler("foo", "bar"));
assertEquals("a = null, b = bar", marshalStringsWithDefaultMarshaler(null, "bar"));
assertEquals("a = foo, b = null", marshalStringsWithDefaultMarshaler("foo", null));
assertNull(marshalStringsWithDefaultMarshaler(null, null));
}
@Test
public void testMarshalBuffersWithDefaultMarshaler() {
assertEquals("a = foo, b = bar", marshalBuffersWithDefaultMarshaler(
ByteBuffer.wrap("foo".getBytes()),
ByteBuffer.wrap("bar".getBytes())
).toStringAsciiZ());
assertEquals("a = null, b = bar", marshalBuffersWithDefaultMarshaler(
null, ByteBuffer.allocateDirect(3).put("bar".getBytes())).toStringAsciiZ());
assertEquals("a = foo, b = null", marshalBuffersWithDefaultMarshaler(
ByteBuffer.allocateDirect(3).put("foo".getBytes()), null).toStringAsciiZ());
assertNull(marshalBuffersWithDefaultMarshaler(null, null));
}
@Test
public void testMarshal1DByteArrayWithDefaultMarshaler() {
assertEquals("a = foo, b = bar", marshal1DByteArrayWithDefaultMarshaler(
new byte[] {'f', 'o', 'o', 0},
new byte[] {'b', 'a', 'r', 0}
).toStringAsciiZ());
assertEquals("a = null, b = bar", marshal1DByteArrayWithDefaultMarshaler(
null, new byte[] {'b', 'a', 'r', 0}).toStringAsciiZ());
assertEquals("a = foo, b = null", marshal1DByteArrayWithDefaultMarshaler(
new byte[] {'f', 'o', 'o', 0}, null).toStringAsciiZ());
assertNull(marshal1DByteArrayWithDefaultMarshaler(null, null));
}
@Test
public void testMarshal1DShortArrayWithDefaultMarshaler() {
assertEquals(0, marshal1DShortArrayWithDefaultMarshaler(
new short[] {0}));
assertEquals(12345, marshal1DShortArrayWithDefaultMarshaler(
new short[] {10000, 2000, 300, 40, 5, 0}));
assertEquals(-1, marshal1DShortArrayWithDefaultMarshaler(null));
}
@Test
public void testMarshal1DCharArrayWithDefaultMarshaler() {
assertEquals(0, marshal1DCharArrayWithDefaultMarshaler(
new char[] {0}));
assertEquals(12345, marshal1DCharArrayWithDefaultMarshaler(
new char[] {10000, 2000, 300, 40, 5, 0}));
assertEquals(0xffff, marshal1DCharArrayWithDefaultMarshaler(null));
}
@Test
public void testMarshal1DIntArrayWithDefaultMarshaler() {
assertEquals(0, marshal1DIntArrayWithDefaultMarshaler(
new int[] {0}));
assertEquals(1000002345, marshal1DIntArrayWithDefaultMarshaler(
new int[] {1000000000, 2000, 300, 40, 5, 0}));
assertEquals(-1, marshal1DIntArrayWithDefaultMarshaler(null));
}
@Test
public void testMarshal1DLongArrayWithDefaultMarshaler() {
assertEquals(0, marshal1DLongArrayWithDefaultMarshaler(
new long[] {0}));
assertEquals(1000000000000002345L, marshal1DLongArrayWithDefaultMarshaler(
new long[] {1000000000000000000L, 2000, 300, 40, 5, 0}));
assertEquals(-1, marshal1DLongArrayWithDefaultMarshaler(null));
}
@Test
public void testMarshal1DFloatArrayWithDefaultMarshaler() {
assertEquals(0.0f, marshal1DFloatArrayWithDefaultMarshaler(
new float[] {0}), 0);
assertEquals(1.2345f, marshal1DFloatArrayWithDefaultMarshaler(
new float[] {1, 0.2f, 0.03f, 0.004f, 0.0005f, 0}), 0.001f);
assertEquals(-1.0f, marshal1DFloatArrayWithDefaultMarshaler(null), 0);
}
@Test
public void testMarshal1DDoubleArrayWithDefaultMarshaler() {
assertEquals(0.0, marshal1DDoubleArrayWithDefaultMarshaler(
new double[] {0}), 0);
assertEquals(1.2345, marshal1DDoubleArrayWithDefaultMarshaler(
new double[] {1, 0.2, 0.03, 0.004, 0.0005, 0}), 0.001);
assertEquals(-1.0, marshal1DDoubleArrayWithDefaultMarshaler(null), 0);
}
float fpi = (float) Math.PI;
@Test
public void testMarshalMachinedSizeFloatAsDouble() {
long ldpi = Double.doubleToLongBits(Math.PI);
long lfpi = Double.doubleToLongBits(fpi);
assertNotEquals(ldpi, lfpi);
if (Bro.IS_32BIT) {
assertEquals(lfpi, Double.doubleToLongBits(marshalMachinedSizeFloatAsDouble(Math.PI)));
} else {
assertEquals(Math.PI, marshalMachinedSizeFloatAsDouble(Math.PI), 0);
}
}
@Test
public void testMarshalMachinedSizeSInt() {
if (Bro.IS_32BIT) {
assertEquals(-1L, marshalMachinedSizeSInt(-1L));
assertEquals(0xffffffff80000000L, marshalMachinedSizeSInt(0x80000000L));
assertEquals(0xffffffff80000000L, marshalMachinedSizeSInt(0x1234567880000000L));
} else { // 64-bit
assertEquals(-1L, marshalMachinedSizeSInt(-1L));
assertEquals(0x80000000L, marshalMachinedSizeSInt(0x80000000L));
assertEquals(0x1234567880000000L, marshalMachinedSizeSInt(0x1234567880000000L));
}
}
@Test
public void testMarshalMachinedSizeUInt() {
if (Bro.IS_32BIT) {
assertEquals(0xffffffffL, marshalMachinedSizeUInt(-1L));
assertEquals(0x80000000L, marshalMachinedSizeUInt(0x80000000L));
assertEquals(0x80000000L, marshalMachinedSizeUInt(0x1234567880000000L));
} else { // 64-bit
assertEquals(-1L, marshalMachinedSizeUInt(-1L));
assertEquals(0x80000000L, marshalMachinedSizeUInt(0x80000000L));
assertEquals(0x1234567880000000L, marshalMachinedSizeUInt(0x1234567880000000L));
}
}
@Test
public void testMarshalBitsAsMachineSizedIntToNative() {
if (Bro.IS_32BIT) {
assertEquals(0xffffffffL, marshalBitsAsMachineSizedInt1(MoreTestBits.V1));
assertEquals(0x80000000L, marshalBitsAsMachineSizedInt1(MoreTestBits.V2));
assertEquals(0x80000000L, marshalBitsAsMachineSizedInt1(MoreTestBits.V3));
} else { // 64-bit
assertEquals(-1, marshalBitsAsMachineSizedInt1(MoreTestBits.V1));
assertEquals(0x80000000L, marshalBitsAsMachineSizedInt1(MoreTestBits.V2));
assertEquals(0x1234567880000000L, marshalBitsAsMachineSizedInt1(MoreTestBits.V3));
}
}
@Test
public void testMarshalBitsAsMachineSizedIntFromNative() {
if (Bro.IS_32BIT) {
assertEquals(new MoreTestBits(0xffffffffL), marshalBitsAsMachineSizedInt2(-1));
assertEquals(MoreTestBits.V2, marshalBitsAsMachineSizedInt2(0xffffffff80000000L));
assertEquals(MoreTestBits.V2, marshalBitsAsMachineSizedInt2(0x1234567880000000L));
} else { // 64-bit
assertEquals(MoreTestBits.V1, marshalBitsAsMachineSizedInt2(-1));
assertEquals(new MoreTestBits(0xffffffff80000000L), marshalBitsAsMachineSizedInt2(0xffffffff80000000L));
assertEquals(MoreTestBits.V3, marshalBitsAsMachineSizedInt2(0x1234567880000000L));
}
}
@Test
public void testInstanceMethods() throws Exception {
NativeObj obj = new NativeObj();
Method setHandle = NativeObject.class.getDeclaredMethod("setHandle", long.class);
setHandle.setAccessible(true);
setHandle.invoke(obj, 0x12345678);
LongPtr l = new LongPtr();
assertEquals(100 * 100, obj.simpleInstanceMethod(100, l));
assertEquals(obj.getHandle(), l.get());
SmallStruct ss1 = new SmallStruct().v1((byte) 64).v2((byte) 128);
SmallStruct ss2 = obj.returnSmallStructInstanceMethod(ss1, l);
assertNotEquals(ss1.getHandle(), ss2.getHandle());
assertEquals(64, ss2.v1() & 0xff);
assertEquals(128, ss2.v2() & 0xff);
assertEquals(obj.getHandle(), l.get());
LargeStruct ls1 = new LargeStruct().v1(0x12).v2(0x1234).v3(0x12345678).v4(0x123456789abcdef0L);
LargeStruct ls2 = obj.returnLargeStructInstanceMethod(ls1, l);
assertNotEquals(ls1.getHandle(), ls2.getHandle());
assertEquals(0x12, ls2.v1());
assertEquals(0x1234, ls2.v2());
assertEquals(0x12345678, ls2.v3());
assertEquals(0x123456789abcdef0L, ls2.v4());
assertEquals(obj.getHandle(), l.get());
}
@Test
public void testDynamicBridge() throws Exception {
long targetFnPtr = VM.getCallbackMethodImpl(this.getClass().getDeclaredMethod("dynamicBridge_target", int.class, int.class));
assertEquals(10, dynamicBridge(targetFnPtr, 2, 8));
}
}