1/* 2 * Copyright 2013, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32package org.jf.dexlib2.analysis; 33 34import com.google.common.collect.ImmutableSet; 35import junit.framework.Assert; 36import org.jf.dexlib2.immutable.ImmutableDexFile; 37import org.junit.Test; 38 39import java.io.IOException; 40 41public class CommonSuperclassTest { 42 // object tree: 43 // object 44 // one 45 // onetwo 46 // onetwothree 47 // onethree 48 // five (undefined class) 49 // fivetwo 50 // fivetwothree 51 // fivethree 52 53 private final ClassPath classPath; 54 55 public CommonSuperclassTest() throws IOException { 56 classPath = new ClassPath(new ImmutableDexFile(ImmutableSet.of( 57 TestUtils.makeClassDef("Ljava/lang/Object;", null), 58 TestUtils.makeClassDef("Ltest/one;", "Ljava/lang/Object;"), 59 TestUtils.makeClassDef("Ltest/two;", "Ljava/lang/Object;"), 60 TestUtils.makeClassDef("Ltest/onetwo;", "Ltest/one;"), 61 TestUtils.makeClassDef("Ltest/onetwothree;", "Ltest/onetwo;"), 62 TestUtils.makeClassDef("Ltest/onethree;", "Ltest/one;"), 63 TestUtils.makeClassDef("Ltest/fivetwo;", "Ltest/five;"), 64 TestUtils.makeClassDef("Ltest/fivetwothree;", "Ltest/fivetwo;"), 65 TestUtils.makeClassDef("Ltest/fivethree;", "Ltest/five;"), 66 TestUtils.makeInterfaceDef("Ljava/lang/Cloneable;"), 67 TestUtils.makeInterfaceDef("Ljava/io/Serializable;"), 68 69 // basic class and interface 70 TestUtils.makeClassDef("Liface/classiface1;", "Ljava/lang/Object;", "Liface/iface1;"), 71 TestUtils.makeInterfaceDef("Liface/iface1;"), 72 73 // a more complex interface tree 74 TestUtils.makeInterfaceDef("Liface/base1;"), 75 // implements undefined interface 76 TestUtils.makeInterfaceDef("Liface/sub1;", "Liface/base1;", "Liface/base2;"), 77 // this implements sub1, so that its interfaces can't be fully resolved either 78 TestUtils.makeInterfaceDef("Liface/sub2;", "Liface/base1;", "Liface/sub1;"), 79 TestUtils.makeInterfaceDef("Liface/sub3;", "Liface/base1;"), 80 TestUtils.makeInterfaceDef("Liface/sub4;", "Liface/base1;", "Liface/sub3;"), 81 TestUtils.makeClassDef("Liface/classsub1;", "Ljava/lang/Object;", "Liface/sub1;"), 82 TestUtils.makeClassDef("Liface/classsub2;", "Ljava/lang/Object;", "Liface/sub2;"), 83 TestUtils.makeClassDef("Liface/classsub3;", "Ljava/lang/Object;", "Liface/sub3;", "Liface/base;"), 84 TestUtils.makeClassDef("Liface/classsub4;", "Ljava/lang/Object;", "Liface/sub3;", "Liface/sub4;"), 85 TestUtils.makeClassDef("Liface/classsubsub4;", "Liface/classsub4;"), 86 TestUtils.makeClassDef("Liface/classsub1234;", "Ljava/lang/Object;", "Liface/sub1;", "Liface/sub2;", 87 "Liface/sub3;", "Liface/sub4;") 88 ))); 89 } 90 91 public void superclassTest(String commonSuperclass, 92 String type1, String type2) { 93 TypeProto commonSuperclassProto = classPath.getClass(commonSuperclass); 94 TypeProto type1Proto = classPath.getClass(type1); 95 TypeProto type2Proto = classPath.getClass(type2); 96 97 Assert.assertSame(commonSuperclassProto, type1Proto.getCommonSuperclass(type2Proto)); 98 Assert.assertSame(commonSuperclassProto, type2Proto.getCommonSuperclass(type1Proto)); 99 } 100 101 @Test 102 public void testGetCommonSuperclass() throws IOException { 103 String object = "Ljava/lang/Object;"; 104 String unknown = "Ujava/lang/Object;"; 105 String one = "Ltest/one;"; 106 String two = "Ltest/two;"; 107 String onetwo = "Ltest/onetwo;"; 108 String onetwothree = "Ltest/onetwothree;"; 109 String onethree = "Ltest/onethree;"; 110 String five = "Ltest/five;"; 111 String fivetwo = "Ltest/fivetwo;"; 112 String fivetwothree = "Ltest/fivetwothree;"; 113 String fivethree = "Ltest/fivethree;"; 114 115 // same object 116 superclassTest(object, object, object); 117 superclassTest(unknown, unknown, unknown); 118 superclassTest(one, one, one); 119 superclassTest(onetwo, onetwo, onetwo); 120 superclassTest(onetwothree, onetwothree, onetwothree); 121 superclassTest(onethree, onethree, onethree); 122 superclassTest(five, five, five); 123 superclassTest(fivetwo, fivetwo, fivetwo); 124 superclassTest(fivetwothree, fivetwothree, fivetwothree); 125 superclassTest(fivethree, fivethree, fivethree); 126 127 // same value, but different object 128 Assert.assertEquals( 129 onetwo, 130 classPath.getClass(onetwo).getCommonSuperclass(new ClassProto(classPath, onetwo)).getType()); 131 132 // other object is superclass 133 superclassTest(object, object, one); 134 135 // other object is superclass two levels up 136 superclassTest(object, object, onetwo); 137 138 // unknown and non-object class 139 superclassTest(unknown, one, unknown); 140 141 // unknown and object class 142 superclassTest(object, object, unknown); 143 144 // siblings 145 superclassTest(one, onetwo, onethree); 146 147 // nephew 148 superclassTest(one, onethree, onetwothree); 149 150 // unrelated 151 superclassTest(object, one, two); 152 153 // undefined superclass and object 154 superclassTest(object, fivetwo, object); 155 156 // undefined class and unrelated type 157 superclassTest(unknown, one, five); 158 159 // undefined superclass and unrelated type 160 superclassTest(unknown, one, fivetwo); 161 162 // undefined ancestor and unrelated type 163 superclassTest(unknown, one, fivetwothree); 164 165 // undefined class and direct subclass 166 superclassTest(five, five, fivetwo); 167 168 // undefined class and descendent 169 superclassTest(five, five, fivetwothree); 170 171 // undefined superclass and direct subclass 172 superclassTest(fivetwo, fivetwo, fivetwothree); 173 174 // siblings with undefined superclass 175 superclassTest(five, fivetwo, fivethree); 176 177 // undefined superclass and nephew 178 superclassTest(five, fivethree, fivetwothree); 179 } 180 181 @Test 182 public void testGetCommonSuperclass_interfaces() { 183 String classiface1 = "Liface/classiface1;"; 184 String iface1 = "Liface/iface1;"; 185 String base1 = "Liface/base1;"; 186 String base2 = "Liface/base2;"; 187 String sub1 = "Liface/sub1;"; 188 String sub2 = "Liface/sub2;"; 189 String sub3 = "Liface/sub3;"; 190 String sub4 = "Liface/sub4;"; 191 String classsub1 = "Liface/classsub1;"; 192 String classsub2 = "Liface/classsub2;"; 193 String classsub3 = "Liface/classsub3;"; 194 String classsub4 = "Liface/classsub4;"; 195 String classsubsub4 = "Liface/classsubsub4;"; 196 String classsub1234 = "Liface/classsub1234;"; 197 String object = "Ljava/lang/Object;"; 198 String unknown = "Ujava/lang/Object;"; 199 200 superclassTest(iface1, classiface1, iface1); 201 202 superclassTest(base1, base1, base1); 203 superclassTest(base1, base1, sub1); 204 superclassTest(base1, base1, classsub1); 205 superclassTest(base1, base1, sub2); 206 superclassTest(base1, base1, classsub2); 207 superclassTest(base1, base1, sub3); 208 superclassTest(base1, base1, classsub3); 209 superclassTest(base1, base1, sub4); 210 superclassTest(base1, base1, classsub4); 211 superclassTest(base1, base1, classsubsub4); 212 superclassTest(base1, base1, classsub1234); 213 214 superclassTest(object, sub3, iface1); 215 superclassTest(unknown, sub2, iface1); 216 superclassTest(unknown, sub1, iface1); 217 218 superclassTest(base2, base2, sub1); 219 superclassTest(base2, base2, classsub1); 220 superclassTest(base2, base2, sub2); 221 superclassTest(base2, base2, classsub2); 222 superclassTest(base2, base2, classsub1234); 223 224 superclassTest(unknown, iface1, classsub1234); 225 226 superclassTest(sub1, sub1, classsub1); 227 228 superclassTest(sub2, sub2, classsub2); 229 superclassTest(sub1, sub1, classsub2); 230 231 superclassTest(sub3, sub3, classsub3); 232 233 superclassTest(sub4, sub4, classsub4); 234 superclassTest(sub3, sub3, classsub4); 235 superclassTest(object, sub2, classsub4); 236 superclassTest(object, sub1, classsub4); 237 238 superclassTest(sub1, sub2, sub1); 239 240 superclassTest(sub1, sub1, classsub1234); 241 superclassTest(sub2, sub2, classsub1234); 242 superclassTest(sub3, sub3, classsub1234); 243 superclassTest(sub4, sub4, classsub1234); 244 245 superclassTest(unknown, sub3, classsub1); 246 superclassTest(unknown, sub4, classsub1); 247 superclassTest(unknown, sub3, classsub2); 248 superclassTest(unknown, sub4, classsub2); 249 250 superclassTest(unknown, sub4, base2); 251 superclassTest(unknown, classsub4, base2); 252 } 253 254 @Test 255 public void testGetCommonSuperclass_arrays() throws IOException { 256 String object = "Ljava/lang/Object;"; 257 String one = "Ltest/one;"; 258 String unknown = "Ujava/lang/Object;"; 259 260 String cloneable = "Ljava/lang/Cloneable;"; 261 String serializable = "Ljava/io/Serializable;"; 262 263 String object1 = "[Ljava/lang/Object;"; 264 String one1 = "[Ltest/one;"; 265 String one2 = "[[Ltest/one;"; 266 String two1 = "[Ltest/two;"; 267 String onetwo1 = "[Ltest/onetwo;"; 268 String onetwo2 = "[[Ltest/onetwo;"; 269 String onethree1 = "[Ltest/onethree;"; 270 String onethree2 = "[[Ltest/onethree;"; 271 String five = "Ltest/five;"; 272 String five1 = "[Ltest/five;"; 273 String unknown1 = "[Ujava/lang/Object;"; 274 275 String int1 = "[I"; 276 String int2 = "[[I"; 277 String float1 = "[F"; 278 279 superclassTest(one1, one1, one1); 280 superclassTest(object1, object1, one1); 281 superclassTest(one1, onetwo1, onethree1); 282 superclassTest(one1, one1, onethree1); 283 superclassTest(object1, one1, two1); 284 285 superclassTest(one2, one2, one2); 286 superclassTest(one2, one2, onetwo2); 287 superclassTest(one2, onetwo2, onethree2); 288 superclassTest(object1, one1, one2); 289 superclassTest(object1, two1, one2); 290 291 superclassTest(unknown1, five1, one1); 292 superclassTest(object1, five1, one2); 293 294 superclassTest(unknown1, one1, unknown1); 295 296 superclassTest(object, one1, one); 297 superclassTest(object, object1, one); 298 superclassTest(object, onetwo1, one); 299 superclassTest(object, five1, one); 300 superclassTest(object, one2, one); 301 302 superclassTest(object, one1, unknown); 303 superclassTest(object, unknown1, unknown); 304 305 superclassTest(cloneable, one1, cloneable); 306 superclassTest(serializable, one1, serializable); 307 308 superclassTest(object, one1, five); 309 310 superclassTest(int1, int1, int1); 311 superclassTest(object, int1, float1); 312 superclassTest(object, int1, int2); 313 } 314} 315