• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
testA()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
testT0()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  
toSet(JavaSource...javaSources)112      private static Set<JavaSource> toSet(JavaSource...javaSources){
113          return new HashSet<JavaSource>(Arrays.asList(javaSources));
114      }
115  
toStringSet(JavaSource... javaSources)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  
toStringSet(String... javaSourceName)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
testT1()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
testT0_T1()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
testA0()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
testA0_T3()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
testG0()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
testG1()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
testI0()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
testOuter0()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
testParameterAnnotation()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
testEnum()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
testAllReader()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
testAllReader0()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