/* * Copyright (C) 2015 RoboVM AB * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>. */ package org.robovm.compiler.plugin.objc; import static org.junit.Assert.*; import java.nio.ByteBuffer; import org.junit.Before; import org.junit.Test; import org.robovm.rt.bro.Struct; import org.robovm.rt.bro.annotation.Array; import org.robovm.rt.bro.annotation.ByVal; 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.Pointer; import org.robovm.rt.bro.annotation.StructMember; import soot.Scene; import soot.SootClass; import soot.SootResolver; import soot.options.Options; /** * Tests {@link TypeEncoder}. */ public class TypeEncoderTest { @Before public void initializeSoot() { soot.G.reset(); Options.v().set_output_format(Options.output_format_jimple); Options.v().set_include_all(true); Options.v().set_print_tags_in_output(true); Options.v().set_allow_phantom_refs(true); Options.v().set_soot_classpath(System.getProperty("sun.boot.class.path") + ":" + System.getProperty("java.class.path")); Scene.v().loadNecessaryClasses(); } private SootClass toSootClass(Class<?> cls) { return SootResolver.v().resolveClass(cls.getName(), SootClass.SIGNATURES); } public static class IPoint extends Struct<IPoint> { @StructMember(0) public native int getX(); @StructMember(0) public native void setX(int x); @StructMember(1) public native int getY(); @StructMember(1) public native void setY(int y); } public static class FPoint extends Struct<FPoint> { @StructMember(0) public native @MachineSizedFloat double getX(); @StructMember(0) public native void setX(@MachineSizedFloat double x); @StructMember(1) public native @MachineSizedFloat double getY(); @StructMember(1) public native void setY(@MachineSizedFloat double y); } public static class FRect extends Struct<FRect> { @StructMember(0) public native @ByVal FPoint getP1(); @StructMember(0) public native void setP1(@ByVal FPoint x); @StructMember(1) public native @ByVal FPoint getP2(); @StructMember(1) public native void setP2(@ByVal FPoint x); } public static class Union extends Struct<Union> { @StructMember(0) public native @ByVal FPoint getV1(); @StructMember(0) public native void setV1(@ByVal FPoint x); @StructMember(0) public native int getV2(); @StructMember(0) public native void setV2(int x); } public static class Unsupported1 extends Struct<Unsupported1> { @StructMember(0) public native @Array(10) ByteBuffer getV(); @StructMember(0) public native void setV(@Array(10) ByteBuffer x); } public static class Unsupported2 extends Struct<Unsupported2> { @StructMember(0) public native @Array(10) byte[] getV(); @StructMember(0) public native void setV(@Array(10) byte[] x); } public abstract static class Methods { abstract void m1(); abstract boolean m2(byte b, short s, char c, int i, long l, float f, double d); abstract @Pointer long m3(@Pointer long a, @MachineSizedSInt long b, @MachineSizedUInt long c, @MachineSizedFloat float d, @MachineSizedFloat double e); abstract IPoint m4(@ByVal IPoint p1, @ByVal FPoint p2); abstract void m5(@ByVal FRect r); abstract void m6(@ByVal Union u); abstract String m7(String s); abstract void m8(@ByVal Unsupported1 u); abstract void m9(@ByVal Unsupported2 u); } @Test public void testVoidReturnTypeNoParameters() { assertEquals("v", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m1"), false)); } @Test public void testSimplePrimitiveTypes() { assertEquals("ccsSiqfd", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m2"), false)); assertEquals("ccsSiqfd", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m2"), true)); } @Test public void testArchDependentPrimitiveTypes() { assertEquals("^v^viIff", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m3"), false)); assertEquals("^v^vqQdd", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m3"), true)); } @Test public void testSimpleStructTypes() { assertEquals("^v{?=ii}{?=ff}", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m4"), false)); assertEquals("^v{?=ii}{?=dd}", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m4"), true)); } @Test public void testNestedStructTypes() { assertEquals("v{?={?=ff}{?=ff}}", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m5"), false)); assertEquals("v{?={?=dd}{?=dd}}", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m5"), true)); } @Test public void testUnionTypes() { assertEquals("v(?=i{?=ff})", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m6"), false)); assertEquals("v(?=i{?=dd})", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m6"), true)); } @Test public void testObjectType() { assertEquals("@@", new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m7"), false)); } @Test public void testArrayInStructTypeFails1() { // We don't support arrays in structs yet try { new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m8"), false); fail("IllegalArgumentException expected"); } catch (IllegalArgumentException e) { // Expected } } @Test public void testArrayInStructTypeFails2() { // We don't support arrays in structs yet try { new TypeEncoder().encode(toSootClass(Methods.class).getMethodByName("m9"), false); fail("IllegalArgumentException expected"); } catch (IllegalArgumentException e) { // Expected } } }