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