/*
* Copyright (C) 2014 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;
import static org.robovm.compiler.Annotations.*;
import static org.junit.Assert.*;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.robovm.compiler.Annotations.Visibility;
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import soot.SootResolver;
import soot.options.Options;
import soot.tagkit.AnnotationTag;
/**
* Tests {@link Annotations}
*/
public class AnnotationsTest {
@BeforeClass
public static void initializeSoot() throws IOException {
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);
}
private String join(List<AnnotationTag> annotations) {
StringBuilder sb = new StringBuilder();
List<String> l = new ArrayList<>();
for (AnnotationTag tag : annotations) {
String type = tag.getType();
type = type.substring(type.lastIndexOf('$') + 1, type.length() - 1);
l.add(type);
}
Collections.sort(l);
for (String type : l) {
if (sb.length() > 0) {
sb.append(" ");
}
sb.append("@" + type);
}
return sb.toString();
}
private String toString(SootMethod method) {
StringBuilder sb = new StringBuilder();
String s = join(getAnnotations(method, Visibility.Any));
sb.append(s);
sb.append(s.length() > 0 ? " " : "");
sb.append(method.getReturnType());
sb.append(' ');
sb.append(method.getName());
sb.append('(');
for (int i = 0; i < method.getParameterCount(); i++) {
if (i > 0) {
sb.append(", ");
}
s = join(Annotations.getParameterAnnotations(method, i, Visibility.Any));
sb.append(s);
sb.append(s.length() > 0 ? " " : "");
sb.append(method.getParameterType(i));
}
sb.append(')');
return sb.toString();
}
@interface A {}
@interface B {}
@interface C {}
@interface D {}
@Retention(RetentionPolicy.RUNTIME) @interface E {}
public static native void src1();
public static native void dest1();
public static native void src2(int a, int b);
public static native void dest2(int a, int b);
public static native void src3(@A int a, @B int b);
public static native void dest3(int a, int b);
public static native void src4(@A int a, @B int b);
public static native void dest4(int a, int b);
public static native void src5(@A int a, @B int b);
public static native void dest5(int a, int b);
public static native void src6(@A @B @C int a, @B @C @D int b);
public static native void dest6(int a, int b);
public static native void src7(@A @B @C int a, @B @C @D int b, @C @D @E int c);
public static native void dest7(int foo, int a, int b, int c);
public static native void src8(@A @B @C int a, @B @C @D int b, @C @D @E int c);
public static native void dest8(int a, int b, int foo, int c);
public static native void src9(@A int a, @B @E int b);
public static native void dest9(int a, int b);
@Test
public void testCopyParameterAnnotationsNoParams() {
SootClass sc = toSootClass(getClass());
SootMethod src = sc.getMethodByName("src1");
SootMethod dest = sc.getMethodByName("dest1");
copyParameterAnnotations(src, dest, 0, 0, 0, Visibility.Any);
assertEquals("void dest1()", toString(dest));
}
@Test
public void testCopyParameterAnnotationsNoAnnotations() {
SootClass sc = toSootClass(getClass());
SootMethod src = sc.getMethodByName("src2");
SootMethod dest = sc.getMethodByName("dest2");
copyParameterAnnotations(src, dest, 0, 2, 0, Visibility.Any);
assertEquals("void dest2(int, int)", toString(dest));
}
@Test
public void testCopyParameterAnnotationsSingleAllNoShift() {
SootClass sc = toSootClass(getClass());
SootMethod src = sc.getMethodByName("src3");
SootMethod dest = sc.getMethodByName("dest3");
copyParameterAnnotations(src, dest, 0, 2, 0, Visibility.Any);
assertEquals("void dest3(@A int, @B int)", toString(dest));
}
@Test
public void testCopyParameterAnnotationsSingleFirstNoShift() {
SootClass sc = toSootClass(getClass());
SootMethod src = sc.getMethodByName("src4");
SootMethod dest = sc.getMethodByName("dest4");
copyParameterAnnotations(src, dest, 0, 1, 0, Visibility.Any);
assertEquals("void dest4(@A int, int)", toString(dest));
}
@Test
public void testCopyParameterAnnotationsSingleLastNoShift() {
SootClass sc = toSootClass(getClass());
SootMethod src = sc.getMethodByName("src5");
SootMethod dest = sc.getMethodByName("dest5");
copyParameterAnnotations(src, dest, 1, 2, 0, Visibility.Any);
assertEquals("void dest5(int, @B int)", toString(dest));
}
@Test
public void testCopyParameterAnnotationsMultipleAllNoShift() {
SootClass sc = toSootClass(getClass());
SootMethod src = sc.getMethodByName("src6");
SootMethod dest = sc.getMethodByName("dest6");
copyParameterAnnotations(src, dest, 0, 2, 0, Visibility.Any);
assertEquals("void dest6(@A @B @C int, @B @C @D int)", toString(dest));
}
@Test
public void testCopyParameterAnnotationsMultipleSubsetWithShift() {
SootClass sc = toSootClass(getClass());
SootMethod src = sc.getMethodByName("src7");
SootMethod dest = sc.getMethodByName("dest7");
copyParameterAnnotations(src, dest, 0, 3, 1, Visibility.Any);
assertEquals("void dest7(int, @A @B @C int, @B @C @D int, @C @D @E int)", toString(dest));
}
@Test
public void testCopyParameterAnnotationsTwiceMultipleSubsetWithShift() {
SootClass sc = toSootClass(getClass());
SootMethod src = sc.getMethodByName("src8");
SootMethod dest = sc.getMethodByName("dest8");
copyParameterAnnotations(src, dest, 0, 2, 0, Visibility.Any);
copyParameterAnnotations(src, dest, 2, 3, 1, Visibility.Any);
assertEquals("void dest8(@A @B @C int, @B @C @D int, int, @C @D @E int)", toString(dest));
}
@Test
public void testCopyParameterAnnotationsOnlyInvisibleNoShift() {
SootClass sc = toSootClass(getClass());
SootMethod src = sc.getMethodByName("src9");
SootMethod dest = sc.getMethodByName("dest9");
copyParameterAnnotations(src, dest, 0, 2, 0, Visibility.RuntimeVisible);
assertEquals("void dest9(int, @E int)", toString(dest));
}
}