Home | History | Annotate | Download | only in reader
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package dex.reader;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertNotNull;
     21 import static org.junit.Assert.assertTrue;
     22 
     23 import java.io.FileWriter;
     24 import java.io.IOException;
     25 import java.lang.reflect.Modifier;
     26 import java.util.Arrays;
     27 import java.util.HashSet;
     28 import java.util.List;
     29 import java.util.Set;
     30 
     31 import org.junit.Test;
     32 
     33 import dex.reader.util.JavaSource;
     34 import dex.structure.DexAnnotation;
     35 import dex.structure.DexAnnotationAttribute;
     36 import dex.structure.DexClass;
     37 import dex.structure.DexEncodedValue;
     38 import dex.structure.DexField;
     39 import dex.structure.DexFile;
     40 import dex.structure.DexMethod;
     41 import dex.structure.DexParameter;
     42 
     43 
     44 public class DexFileReaderTests extends DexTestsCommon {
     45 
     46     private static final String LDALVIK_ANNOTATION_SIGNATURE = "Ldalvik/annotation/Signature;";
     47 
     48 
     49     JavaSource A = new JavaSource("a.b.c.A",
     50             "package a.b.c; public class A{ public void get() {}}"
     51     );
     52 
     53     @Test
     54     public void testA() throws IOException {
     55         DexFile dexFile = javaToDexUtil.getFrom(A);
     56         assertEquals(1, dexFile.getDefinedClasses().size());
     57         @SuppressWarnings("unused")
     58         DexClass class1 = getClass(dexFile, "La/b/c/A;");
     59         System.out.println(dexFile);
     60     }
     61 
     62 
     63     JavaSource T0 = new JavaSource("T0",
     64             "public class T0 {" +
     65             "    public int publicIntField;" +
     66             "    protected long protectedLongField;" +
     67             "    short defaultShortField;" +
     68             "    private double privateDoubleField;" +
     69             "    " +
     70             "    public String publicStringMethodInt(int a){ return \"bla\"; }" +
     71             "    protected String protectedStringMethodInt(int a){ return \"bla\"; }" +
     72             "    String defaultStringMethodInt(int a){ return \"bla\"; }" +
     73             "    private String privateStringMethodInt(int a){ return \"bla\"; }" +
     74             "}"
     75     );
     76 
     77     /**
     78      * Tests parsing a simple class.
     79      */
     80     @Test
     81     public void testT0() throws IOException {
     82 
     83         DexFile dexFile = javaToDexUtil.getFrom(T0);
     84         assertEquals(1, dexFile.getDefinedClasses().size());
     85         DexClass clazz = dexFile.getDefinedClasses().get(0);
     86         assertEquals("LT0;", clazz.getName());
     87         assertPublic(clazz);
     88         //fields
     89         assertEquals(4, clazz.getFields().size());
     90         DexField field = getField(clazz, "publicIntField");
     91         assertPublic(field);
     92         field = getField(clazz, "protectedLongField");
     93         assertProtected(field);
     94         field = getField(clazz, "defaultShortField");
     95         assertDefault(field);
     96         field = getField(clazz, "privateDoubleField");
     97         assertPrivate(field);
     98         //methods
     99         DexMethod method = getMethod(clazz, "publicStringMethodInt", "I");
    100         assertPublic(method);
    101         method = getMethod(clazz, "protectedStringMethodInt", "I");/** a.b.C */
    102         assertProtected(method);
    103         method = getMethod(clazz, "defaultStringMethodInt", "I");
    104         assertDefault(method);
    105         method = getMethod(clazz, "privateStringMethodInt", "I");
    106         assertPrivate(method);
    107     }
    108 
    109     JavaSource T1 = new JavaSource( "T1","public class T1 extends T0 {}" );
    110 
    111 
    112     private static Set<JavaSource> toSet(JavaSource...javaSources){
    113         return new HashSet<JavaSource>(Arrays.asList(javaSources));
    114     }
    115 
    116     private static Set<String> toStringSet(JavaSource... javaSources) {
    117         Set<String> names = new HashSet<String>();
    118         for (JavaSource javaSource : javaSources) {
    119             names.add(javaSource.getName());
    120         }
    121 
    122         return names;
    123     }
    124 
    125     private static Set<String> toStringSet(String... javaSourceName) {
    126         return new HashSet<String>(Arrays.asList(javaSourceName));
    127     }
    128 
    129     /**
    130      * Tests parsing a simple sub class.
    131      * @throws IOException
    132      */
    133     @Test
    134     public void testT1() throws IOException {
    135         DexFile dexFile = javaToDexUtil.getFrom(toSet(T1, T0), toStringSet(T1));
    136         assertEquals(1, dexFile.getDefinedClasses().size());
    137         DexClass clazz = dexFile.getDefinedClasses().get(0);
    138         assertEquals("LT1;", clazz.getName());
    139         assertPublic(clazz);
    140         assertEquals("LT0;", clazz.getSuperClass());
    141     }
    142 
    143     /**
    144      * Tests parsing T0 and T1 from same dex file.
    145      *
    146      * @throws IOException
    147      */
    148     @Test
    149     public void testT0_T1() throws IOException {
    150         DexFile dexFile = javaToDexUtil.getFrom(T1, T0);
    151         assertEquals(2, dexFile.getDefinedClasses().size());
    152 
    153         DexClass T0 = getClass(dexFile, "LT0;");
    154         assertPublic(T0);
    155 
    156         DexClass T1 = getClass(dexFile, "LT1;");
    157         assertPublic(T1);
    158 
    159         assertEquals(T1.getSuperClass(), T0.getName());
    160     }
    161 
    162     static final JavaSource A0 = new JavaSource("A0",
    163     "import java.lang.annotation.*;" +
    164     "@Retention(RetentionPolicy.RUNTIME)" +
    165     "@Target(ElementType.TYPE)" +
    166     "public @interface A0 {}"
    167      );
    168 
    169     /**
    170      * Tests parsing Annotation Declaration.
    171      */
    172     @Test
    173     public void testA0() throws IOException {
    174         DexFile dexFile = javaToDexUtil.getFrom(A0);
    175         assertEquals(1, dexFile.getDefinedClasses().size());
    176 
    177         DexClass A0 = getClass(dexFile, "LA0;");
    178         assertPublic(A0);
    179         assertEquals(2, A0.getAnnotations().size());
    180     }
    181 
    182 
    183     static final JavaSource T3 = new JavaSource("T3",
    184     "import java.io.*;" +
    185     "@A0 " +
    186     "public final class T3 {}"
    187     );
    188 
    189 
    190     /**
    191      * Tests parsing Annotated Class.
    192      */
    193     @Test
    194     public void testA0_T3() throws IOException {
    195         DexFile dexFile = javaToDexUtil.getFrom(T3, A0);
    196         assertEquals(2, dexFile.getDefinedClasses().size());
    197 
    198         DexClass T3 = getClass(dexFile, "LT3;");
    199         assertPublic(T3);
    200         assertEquals(1, T3.getAnnotations().size());
    201 
    202         DexAnnotation annotation = getAnnotation(T3, "LA0;");
    203 
    204         DexClass A0 = getClass(dexFile, "LA0;");
    205 
    206         assertEquals(A0.getName(), annotation.getTypeName());
    207     }
    208 
    209 
    210     static final JavaSource G0 = new JavaSource("G0","public class G0<T>{}");
    211 
    212     /**
    213      * Tests parsing Generic Type.
    214      */
    215     @Test
    216     public void testG0() throws IOException {
    217         DexFile dexFile = javaToDexUtil.getFrom(G0);
    218         assertEquals(1, dexFile.getDefinedClasses().size());
    219         DexClass G0 = getClass(dexFile, "LG0;");
    220         assertPublic(G0);
    221         DexAnnotation sig = getAnnotation(G0, LDALVIK_ANNOTATION_SIGNATURE);
    222         assertEquals(1, sig.getAttributes().size());
    223         DexAnnotationAttribute dexAnnotationValue = sig.getAttributes().get(0);
    224         assertNotNull(dexAnnotationValue.getEncodedValue());
    225         Object value = dexAnnotationValue.getEncodedValue().getValue();
    226         assertTrue(value instanceof List);
    227         StringBuilder builder = new StringBuilder();
    228         for (Object o : (List<?>)value) {
    229             builder.append(((DexEncodedValue)o).getValue());
    230         }
    231         //FIXME verify
    232         assertEquals("<T:Ljava/lang/Object;>Ljava/lang/Object;", builder.toString());
    233     }
    234 
    235     static final JavaSource G1 = new JavaSource("G1","public class G1<T extends G1>{}");
    236 
    237     /**
    238      * Tests parsing Generic Type.
    239      */
    240     @Test
    241     public void testG1() throws IOException {
    242         DexFile dexFile = javaToDexUtil.getFrom(G1);
    243         assertEquals(1, dexFile.getDefinedClasses().size());
    244         DexClass G1 = getClass(dexFile, "LG1;");
    245         assertPublic(G1);
    246         DexAnnotation sig = getAnnotation(G1, LDALVIK_ANNOTATION_SIGNATURE);
    247         assertEquals(1, sig.getAttributes().size());
    248         DexAnnotationAttribute dexAnnotationValue = sig.getAttributes().get(0);
    249         assertNotNull(dexAnnotationValue.getEncodedValue());
    250         Object value = dexAnnotationValue.getEncodedValue().getValue();
    251         assertTrue(value instanceof List);
    252         StringBuilder builder = new StringBuilder();
    253         for (Object o : (List<?>)value) {
    254             builder.append(((DexEncodedValue)o).getValue());
    255         }
    256         //FIXME verify
    257         assertEquals("<T:LG1;>Ljava/lang/Object;", builder.toString());
    258     }
    259 
    260 
    261 
    262     static final JavaSource I0 = new JavaSource("I0",
    263     "import java.io.Serializable;" +
    264     "public interface I0 extends Serializable {}"
    265     );
    266 
    267     /**
    268      * Tests parsing Interface Type.
    269      */
    270     @Test
    271     public void testI0() throws IOException {
    272         DexFile dexFile = javaToDexUtil.getFrom(I0);
    273         assertEquals(1, dexFile.getDefinedClasses().size());
    274         DexClass I0 = getClass(dexFile, "LI0;");
    275         assertPublic(I0);
    276         assertTrue(Modifier.isInterface(I0.getModifiers()));
    277         assertEquals(1,  I0.getInterfaces().size());
    278         assertEquals("Ljava/io/Serializable;",  I0.getInterfaces().get(0));
    279     }
    280 
    281 
    282     static final JavaSource Outer0 = new JavaSource("Outer0",
    283     "public class Outer0 {" +
    284     "    static class StaticInner {}" +
    285     "    class Inner{}" +
    286     "}"
    287     );
    288 
    289     /**
    290      * Tests parsing Interface Type.
    291      * @throws IOException
    292      */
    293     @SuppressWarnings("unchecked")
    294     @Test
    295     public void testOuter0() throws IOException {
    296         DexFile dexFile = javaToDexUtil.getFrom(toSet(Outer0), toStringSet("Outer0", "Outer0$Inner", "Outer0$StaticInner"));
    297         assertEquals(3, dexFile.getDefinedClasses().size());
    298         DexClass Outer0 = getClass(dexFile, "LOuter0;");
    299         DexAnnotation sig = getAnnotation(Outer0, "Ldalvik/annotation/MemberClasses;");
    300         assertEquals(1, sig.getAttributes().size());
    301         DexAnnotationAttribute dexAnnotationValue = sig.getAttributes().get(0);
    302         assertNotNull(dexAnnotationValue.getEncodedValue());
    303         List<DexEncodedValue> values = (List<DexEncodedValue>) dexAnnotationValue.getEncodedValue().getValue();
    304         Set<String> innerTypeNames = new HashSet<String>();
    305         for (DexEncodedValue value : values) {
    306             innerTypeNames.add((String) value.getValue());
    307         }
    308         DexClass inner = getClass(dexFile, "LOuter0$Inner;");
    309         DexClass staticInner = getClass(dexFile, "LOuter0$StaticInner;");
    310         assertTrue(innerTypeNames.contains(inner.getName()));
    311         assertTrue(innerTypeNames.contains(staticInner.getName()));
    312     }
    313 
    314     static final JavaSource parameterAnnotation = new JavaSource("A",
    315             "public class A {" +
    316             "  void m(@Deprecated int a) {}" +
    317             "}");
    318 
    319     /**
    320      * Tests parameter annotation.
    321      *
    322      * @throws IOException
    323      */
    324     @Test
    325     public void testParameterAnnotation() throws IOException {
    326         DexFile dexFile = javaToDexUtil.getFrom(parameterAnnotation);
    327         assertEquals(1, dexFile.getDefinedClasses().size());
    328         DexClass A = getClass(dexFile, "LA;");
    329 
    330         DexMethod method = getMethod(A, "m", "I");
    331         assertEquals(1, method.getParameters().size());
    332         DexParameter dexParameter = method.getParameters().get(0);
    333         assertEquals("I", dexParameter.getTypeName());
    334 
    335         assertEquals(1, dexParameter.getAnnotations().size());
    336         DexAnnotation annotation = dexParameter.getAnnotations().iterator().next();
    337         assertEquals("Ljava/lang/Deprecated;", annotation.getTypeName());
    338     }
    339 
    340     @Test
    341     public void testEnum() throws IOException {
    342         JavaSource source = new JavaSource("E", "public enum E { A,B; public static final E C = null; }");
    343         DexFile dexFile = javaToDexUtil.getFrom(source);
    344         assertEquals(1, dexFile.getDefinedClasses().size());
    345         DexClass E = getClass(dexFile, "LE;");
    346         System.out.println(E);
    347         System.out.println(E.getFields());
    348     }
    349 
    350     /**
    351      * Tests parsing of huge dex file.
    352      * @throws IOException
    353      */
    354     @Test
    355     public void testAllReader() throws IOException {
    356         FileWriter w = new FileWriter("dex/classes.out.dex");
    357         DexFileReader dexReader = new DexFileReader();
    358         DexFile dexFile = dexReader.read(new DexBuffer("dex/classes.dex"));
    359         TypeFormatter formatter = new TypeFormatter();
    360         w.append(formatter.formatDexFile(dexFile));
    361         w.flush();
    362         w.close();
    363         assertTrue(true);
    364     }
    365 
    366     /**
    367      * Tests parsing of huge dex file.
    368      * @throws IOException
    369      */
    370     @Test
    371     public void testAllReader0() throws IOException {
    372         FileWriter w = new FileWriter("dex/classes0.out.dex");
    373         DexFileReader dexReader = new DexFileReader();
    374         DexFile dexFile = dexReader.read(new DexBuffer("dex/classes0.dex"));
    375         TypeFormatter formatter = new TypeFormatter();
    376         w.append(formatter.formatDexFile(dexFile));
    377         w.flush();
    378         w.close();
    379         assertTrue(true);
    380     }
    381 
    382 }
    383