/* * 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.Field; import java.lang.reflect.Method; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.nio.LongBuffer; import java.util.Arrays; import org.junit.Before; import org.junit.Test; import org.robovm.rt.VM; import org.robovm.rt.bro.annotation.Array; import org.robovm.rt.bro.annotation.ByRef; import org.robovm.rt.bro.annotation.ByVal; import org.robovm.rt.bro.annotation.GlobalValue; 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.StructMember; import org.robovm.rt.bro.ptr.Ptr; /** * Tests {@link GlobalValue} methods. */ public class GlobalValueTest { 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 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; } } private static void bind(Class<?> cls) { long ptr = VM.getLong(VM.getObjectAddress(memory) + EFFECTIVE_DIRECT_ADDRESS_OFFSET); for (Method m : cls.getDeclaredMethods()) { if (m.getAnnotation(GlobalValue.class) != null) { VM.bindBridgeMethod(m, ptr); } } } static final ByteBuffer memory = ByteBuffer.allocateDirect(1024); private static final int EFFECTIVE_DIRECT_ADDRESS_OFFSET; static { try { Field f1 = Buffer.class.getDeclaredField("effectiveDirectAddress"); if (f1.getType() != long.class) { throw new Error("java.nio.Buffer.effectiveDirectAddress should be a long"); } EFFECTIVE_DIRECT_ADDRESS_OFFSET = VM.getInstanceFieldOffset(VM.getFieldAddress(f1)); } catch (NoSuchFieldException e) { throw new Error(e); } bind(GlobalValueTest.class); } @Before public void setup() { memory.clear(); while (memory.hasRemaining()) { memory.put((byte) 0); } memory.clear(); } @GlobalValue public static native byte byteGetter(); @GlobalValue public static native void byteSetter(byte b); @GlobalValue public static native short shortGetter(); @GlobalValue public static native void shortSetter(short b); @GlobalValue public static native char charGetter(); @GlobalValue public static native void charSetter(char b); @GlobalValue public static native int intGetter(); @GlobalValue public static native void intSetter(int b); @GlobalValue public static native long longGetter(); @GlobalValue public static native void longSetter(long b); @GlobalValue public static native float floatGetter(); @GlobalValue public static native void floatSetter(float b); @GlobalValue public static native double doubleGetter(); @GlobalValue public static native void doubleSetter(double b); @GlobalValue public static native @ByVal Point structByValGetter(); @GlobalValue public static native void structByValSetter(@ByVal Point b); @GlobalValue public static native @ByRef Point structByRefGetter(); @GlobalValue public static native void structByRefSetter(@ByRef Point b); @GlobalValue public static native SimpleEnum enumGetter(); @GlobalValue public static native void enumSetter(SimpleEnum b); @GlobalValue public static native TestValuedEnum valuedEnumGetter(); @GlobalValue public static native void valuedEnumSetter(TestValuedEnum b); @GlobalValue public static native TestBits bitsGetter(); @GlobalValue public static native void bitsSetter(TestBits b); @GlobalValue public static native PointPtr ptrGetter(); @GlobalValue public static native void ptrSetter(PointPtr b); @GlobalValue public static native @Array(10) String arrayAsStringGetter(); @GlobalValue public static native void arrayAsStringSetter(@Array(10) String b); @GlobalValue public static native @Array(10) ByteBuffer arrayAsByteBufferGetter(); @GlobalValue public static native void arrayAsByteBufferSetter(@Array(10) ByteBuffer b); @GlobalValue public static native @Array(10) byte[] arrayAsByteArrayGetter(); @GlobalValue public static native void arrayAsByteArraySetter(@Array(10) byte[] b); @GlobalValue public static native @MachineSizedFloat double machineSizedFloatGetterD(); @GlobalValue public static native void machineSizedFloatSetterD(@MachineSizedFloat double b); @GlobalValue public static native @MachineSizedFloat float machineSizedFloatGetterF(); @GlobalValue public static native void machineSizedFloatSetterF(@MachineSizedFloat float b); @GlobalValue public static native @MachineSizedSInt long machineSizedSIntGetter(); @GlobalValue public static native void machineSizedSIntSetter(@MachineSizedSInt long b); @GlobalValue public static native @MachineSizedUInt long machineSizedUIntGetter(); @GlobalValue public static native void machineSizedUIntSetter(@MachineSizedUInt long b); @Test public void testByte() throws Exception { assertEquals(0, memory.get(0)); assertEquals(0, byteGetter()); byteSetter((byte) 0xff); assertEquals(0xff, memory.get(0) & 0xff); assertEquals(0xff, byteGetter() & 0xff); } @Test public void testShort() throws Exception { assertEquals(0, memory.order(ByteOrder.nativeOrder()).asShortBuffer().get(0)); assertEquals(0, shortGetter()); shortSetter((short) 0xffff); assertEquals(0xffff, memory.order(ByteOrder.nativeOrder()).asShortBuffer().get(0) & 0xffff); assertEquals(0xffff, shortGetter() & 0xffff); } @Test public void testChar() throws Exception { assertEquals(0, memory.order(ByteOrder.nativeOrder()).asCharBuffer().get(0)); assertEquals(0, charGetter()); charSetter((char) 0xffff); assertEquals(0xffff, memory.order(ByteOrder.nativeOrder()).asCharBuffer().get(0)); assertEquals(0xffff, charGetter()); } @Test public void testInt() throws Exception { assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(0, intGetter()); intSetter(0xffffffff); assertEquals(0xffffffff, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0) & 0xffffffff); assertEquals(0xffffffff, intGetter() & 0xffffffff); } @Test public void testLong() throws Exception { assertEquals(0, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(0)); assertEquals(0, longGetter()); longSetter(0xffffffffffffffffL); assertEquals(0xffffffffffffffffL, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(0)); assertEquals(0xffffffffffffffffL, longGetter()); } @Test public void testFloat() throws Exception { assertEquals(0, memory.order(ByteOrder.nativeOrder()).asFloatBuffer().get(0), 0); assertEquals(0, floatGetter(), 0); floatSetter((float) Math.PI); assertEquals((float) Math.PI, memory.order(ByteOrder.nativeOrder()).asFloatBuffer().get(0), 0.00001f); assertEquals((float) Math.PI, floatGetter(), 0.00001f); } @Test public void testDouble() throws Exception { assertEquals(0, memory.order(ByteOrder.nativeOrder()).asDoubleBuffer().get(0), 0); assertEquals(0, doubleGetter(), 0); doubleSetter(Math.PI); assertEquals(Math.PI, memory.order(ByteOrder.nativeOrder()).asDoubleBuffer().get(0), 0.00001); assertEquals(Math.PI, doubleGetter(), 0.00001); } @Test public void testStructByVal() throws Exception { IntBuffer memoryAsIntBuffer = memory.order(ByteOrder.nativeOrder()).asIntBuffer(); assertEquals(0, memoryAsIntBuffer.get(0)); assertEquals(0, memoryAsIntBuffer.get(1)); assertEquals(0, structByValGetter().x()); assertEquals(0, structByValGetter().y()); structByValGetter().x(9876); structByValGetter().y(5432); assertEquals(9876, memoryAsIntBuffer.get(0)); assertEquals(5432, memoryAsIntBuffer.get(1)); assertEquals(9876, structByValGetter().x()); assertEquals(5432, structByValGetter().y()); structByValSetter(new Point().x(1234).y(5678)); assertEquals(1234, memoryAsIntBuffer.get(0)); assertEquals(5678, memoryAsIntBuffer.get(1)); assertEquals(1234, structByValGetter().x()); assertEquals(5678, structByValGetter().y()); } @Test public void testStructByRef() throws Exception { LongBuffer memoryAsLongBuffer = memory.order(ByteOrder.nativeOrder()).asLongBuffer(); assertEquals(0, memoryAsLongBuffer.get(0)); assertNull(structByRefGetter()); Point p = new Point(); structByRefSetter(p); assertEquals(p.getHandle(), memoryAsLongBuffer.get(0)); } @Test public void testEnum() throws Exception { assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(SimpleEnum.V1, enumGetter()); enumSetter(SimpleEnum.V3); assertEquals(2, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(SimpleEnum.V3, enumGetter()); } @Test public void testValuedEnum() throws Exception { assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); try { valuedEnumGetter(); fail("IllegalArgumentException expected"); } catch (IllegalArgumentException e) {} valuedEnumSetter(TestValuedEnum.V100); assertEquals(100, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(TestValuedEnum.V100, valuedEnumGetter()); } @Test public void testBits() throws Exception { assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(0, bitsGetter().value()); bitsSetter(TestBits.V8); assertEquals(8, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(TestBits.V8, bitsGetter()); } @Test public void testPtr() { LongBuffer memoryAsLongBuffer = memory.order(ByteOrder.nativeOrder()).asLongBuffer(); assertEquals(0, memoryAsLongBuffer.get(0)); assertNull(ptrGetter()); PointPtr ptr = new PointPtr(); assertNull(ptr.get()); Point p = new Point(); ptr.set(p); ptrSetter(ptr); assertEquals(ptr.getHandle(), memoryAsLongBuffer.get(0)); assertEquals(ptr, ptrGetter()); assertEquals(ptr.get(), ptrGetter().get()); } @Test public void testArrayAsString() throws Exception { assertEquals(0, memory.get(0)); assertEquals("", arrayAsStringGetter()); arrayAsStringSetter("foobar"); byte[] bytes = new byte[7]; memory.get(bytes); assertEquals("foobar", new String(bytes, 0, 6)); assertEquals("foobar", arrayAsStringGetter()); assertEquals(0, bytes[6]); } @Test public void testArrayAsByteBuffer() throws Exception { byte[] bytes1 = new byte[10]; byte[] bytes2 = new byte[10]; memory.get(bytes1); memory.clear(); assertTrue(Arrays.equals(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, bytes1)); arrayAsByteBufferGetter().get(bytes2); assertTrue(Arrays.equals(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, bytes2)); arrayAsByteBufferSetter(ByteBuffer.wrap(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})); memory.get(bytes1); memory.clear(); assertTrue(Arrays.equals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, bytes1)); arrayAsByteBufferGetter().get(bytes2); assertTrue(Arrays.equals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, bytes2)); } @Test public void testArrayAsByteArray() throws Exception { byte[] bytes1 = new byte[10]; memory.get(bytes1); memory.clear(); assertTrue(Arrays.equals(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, bytes1)); assertTrue(Arrays.equals(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, arrayAsByteArrayGetter())); arrayAsByteArraySetter(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); memory.get(bytes1); memory.clear(); assertTrue(Arrays.equals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, bytes1)); assertTrue(Arrays.equals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, arrayAsByteArrayGetter())); } float fpi = (float) Math.PI; @Test public void testMachineSizedFloat() throws Exception { long ldpi = Double.doubleToLongBits(Math.PI); long lfpi = Double.doubleToLongBits(fpi); assertNotEquals(ldpi, lfpi); if (Bro.IS_32BIT) { assertEquals(0f, memory.order(ByteOrder.nativeOrder()).asFloatBuffer().get(0), 0f); assertEquals(0.0, machineSizedFloatGetterD(), 0); assertEquals(0.0, machineSizedFloatGetterF(), 0); machineSizedFloatSetterD(Math.PI); assertEquals(fpi, memory.order(ByteOrder.nativeOrder()).asFloatBuffer().get(0), 0f); assertEquals(fpi, machineSizedFloatGetterF(), 0); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(1)); assertEquals(lfpi, Double.doubleToLongBits(machineSizedFloatGetterD())); machineSizedFloatSetterF(fpi); assertEquals(fpi, memory.order(ByteOrder.nativeOrder()).asFloatBuffer().get(0), 0f); assertEquals(fpi, machineSizedFloatGetterF(), 0); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(1)); assertEquals(lfpi, Double.doubleToLongBits(machineSizedFloatGetterD())); } else { // 64-bit assertEquals(0, memory.order(ByteOrder.nativeOrder()).asDoubleBuffer().get(0), 0); assertEquals(0.0, machineSizedFloatGetterD(), 0); assertEquals(0.0, machineSizedFloatGetterF(), 0); machineSizedFloatSetterD(Math.PI); assertEquals(Math.PI, memory.order(ByteOrder.nativeOrder()).asDoubleBuffer().get(0), 0f); assertEquals(fpi, machineSizedFloatGetterF(), 0); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(1)); assertEquals(ldpi, Double.doubleToLongBits(machineSizedFloatGetterD())); machineSizedFloatSetterF(fpi); assertEquals((double) fpi, memory.order(ByteOrder.nativeOrder()).asDoubleBuffer().get(0), 0f); assertEquals(fpi, machineSizedFloatGetterF(), 0); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(1)); assertEquals(lfpi, Double.doubleToLongBits(machineSizedFloatGetterD())); } } @Test public void testMachineSizedSInt() throws Exception { if (Bro.IS_32BIT) { assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(0, machineSizedSIntGetter()); machineSizedSIntSetter(-1); assertEquals(-1, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(-1, machineSizedSIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(1)); machineSizedSIntSetter(0x80000000L); assertEquals(0xffffffff80000000L, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(0xffffffff80000000L, machineSizedSIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(1)); machineSizedSIntSetter(0x1234567880000000L); assertEquals(0xffffffff80000000L, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(0xffffffff80000000L, machineSizedSIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(1)); } else { // 64-bit assertEquals(0, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(0)); assertEquals(0, machineSizedSIntGetter()); machineSizedSIntSetter(-1); assertEquals(-1, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(0)); assertEquals(-1, machineSizedSIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(1)); machineSizedSIntSetter(0x80000000L); assertEquals(0x80000000L, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(0)); assertEquals(0x80000000L, machineSizedSIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(1)); machineSizedSIntSetter(0x1234567880000000L); assertEquals(0x1234567880000000L, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(0)); assertEquals(0x1234567880000000L, machineSizedSIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(1)); } } @Test public void testMachineSizedUInt() throws Exception { if (Bro.IS_32BIT) { assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(0, machineSizedUIntGetter()); machineSizedUIntSetter(-1); assertEquals(-1, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(0xffffffffL, machineSizedUIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(1)); machineSizedUIntSetter(0x80000000L); assertEquals(0xffffffff80000000L, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(0x80000000L, machineSizedUIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(1)); machineSizedUIntSetter(0x1234567880000000L); assertEquals(0xffffffff80000000L, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(0)); assertEquals(0x80000000L, machineSizedUIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asIntBuffer().get(1)); } else { // 64-bit assertEquals(0, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(0)); assertEquals(0, machineSizedUIntGetter()); machineSizedUIntSetter(-1); assertEquals(-1, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(0)); assertEquals(-1, machineSizedUIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(1)); machineSizedUIntSetter(0x80000000L); assertEquals(0x80000000L, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(0)); assertEquals(0x80000000L, machineSizedUIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(1)); machineSizedUIntSetter(0x1234567880000000L); assertEquals(0x1234567880000000L, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(0)); assertEquals(0x1234567880000000L, machineSizedUIntGetter()); assertEquals(0, memory.order(ByteOrder.nativeOrder()).asLongBuffer().get(1)); } } }