blob: 3f1ee56dd57efb15e6a116c9551046cdbb7d1b7e [file] [log] [blame]
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.analysis;
import com.google.common.collect.ImmutableSet;
import junit.framework.Assert;
import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.immutable.ImmutableDexFile;
import org.junit.Test;
import java.io.IOException;
public class CommonSuperclassTest {
// object tree:
// object
// one
// onetwo
// onetwothree
// onethree
// five (undefined class)
// fivetwo
// fivetwothree
// fivethree
private final ClassPath classPath;
public CommonSuperclassTest() throws IOException {
classPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.forApi(19),
ImmutableSet.of(
TestUtils.makeClassDef("Ljava/lang/Object;", null),
TestUtils.makeClassDef("Ltest/one;", "Ljava/lang/Object;"),
TestUtils.makeClassDef("Ltest/two;", "Ljava/lang/Object;"),
TestUtils.makeClassDef("Ltest/onetwo;", "Ltest/one;"),
TestUtils.makeClassDef("Ltest/onetwothree;", "Ltest/onetwo;"),
TestUtils.makeClassDef("Ltest/onethree;", "Ltest/one;"),
TestUtils.makeClassDef("Ltest/fivetwo;", "Ltest/five;"),
TestUtils.makeClassDef("Ltest/fivetwothree;", "Ltest/fivetwo;"),
TestUtils.makeClassDef("Ltest/fivethree;", "Ltest/five;"),
TestUtils.makeInterfaceDef("Ljava/lang/Cloneable;"),
TestUtils.makeInterfaceDef("Ljava/io/Serializable;"),
// basic class and interface
TestUtils.makeClassDef("Liface/classiface1;", "Ljava/lang/Object;", "Liface/iface1;"),
TestUtils.makeInterfaceDef("Liface/iface1;"),
// a more complex interface tree
TestUtils.makeInterfaceDef("Liface/base1;"),
// implements undefined interface
TestUtils.makeInterfaceDef("Liface/sub1;", "Liface/base1;", "Liface/base2;"),
// this implements sub1, so that its interfaces can't be fully resolved either
TestUtils.makeInterfaceDef("Liface/sub2;", "Liface/base1;", "Liface/sub1;"),
TestUtils.makeInterfaceDef("Liface/sub3;", "Liface/base1;"),
TestUtils.makeInterfaceDef("Liface/sub4;", "Liface/base1;", "Liface/sub3;"),
TestUtils.makeClassDef("Liface/classsub1;", "Ljava/lang/Object;", "Liface/sub1;"),
TestUtils.makeClassDef("Liface/classsub2;", "Ljava/lang/Object;", "Liface/sub2;"),
TestUtils.makeClassDef("Liface/classsub3;", "Ljava/lang/Object;", "Liface/sub3;",
"Liface/base;"),
TestUtils.makeClassDef("Liface/classsub4;", "Ljava/lang/Object;", "Liface/sub3;",
"Liface/sub4;"),
TestUtils.makeClassDef("Liface/classsubsub4;", "Liface/classsub4;"),
TestUtils.makeClassDef("Liface/classsub1234;", "Ljava/lang/Object;", "Liface/sub1;",
"Liface/sub2;", "Liface/sub3;", "Liface/sub4;")
))));
}
public void superclassTest(String commonSuperclass,
String type1, String type2) {
TypeProto commonSuperclassProto = classPath.getClass(commonSuperclass);
TypeProto type1Proto = classPath.getClass(type1);
TypeProto type2Proto = classPath.getClass(type2);
Assert.assertSame(commonSuperclassProto, type1Proto.getCommonSuperclass(type2Proto));
Assert.assertSame(commonSuperclassProto, type2Proto.getCommonSuperclass(type1Proto));
}
@Test
public void testGetCommonSuperclass() throws IOException {
String object = "Ljava/lang/Object;";
String unknown = "Ujava/lang/Object;";
String one = "Ltest/one;";
String two = "Ltest/two;";
String onetwo = "Ltest/onetwo;";
String onetwothree = "Ltest/onetwothree;";
String onethree = "Ltest/onethree;";
String five = "Ltest/five;";
String fivetwo = "Ltest/fivetwo;";
String fivetwothree = "Ltest/fivetwothree;";
String fivethree = "Ltest/fivethree;";
// same object
superclassTest(object, object, object);
superclassTest(unknown, unknown, unknown);
superclassTest(one, one, one);
superclassTest(onetwo, onetwo, onetwo);
superclassTest(onetwothree, onetwothree, onetwothree);
superclassTest(onethree, onethree, onethree);
superclassTest(five, five, five);
superclassTest(fivetwo, fivetwo, fivetwo);
superclassTest(fivetwothree, fivetwothree, fivetwothree);
superclassTest(fivethree, fivethree, fivethree);
// same value, but different object
Assert.assertEquals(
onetwo,
classPath.getClass(onetwo).getCommonSuperclass(new ClassProto(classPath, onetwo)).getType());
// other object is superclass
superclassTest(object, object, one);
// other object is superclass two levels up
superclassTest(object, object, onetwo);
// unknown and non-object class
superclassTest(unknown, one, unknown);
// unknown and object class
superclassTest(object, object, unknown);
// siblings
superclassTest(one, onetwo, onethree);
// nephew
superclassTest(one, onethree, onetwothree);
// unrelated
superclassTest(object, one, two);
// undefined superclass and object
superclassTest(object, fivetwo, object);
// undefined class and unrelated type
superclassTest(unknown, one, five);
// undefined superclass and unrelated type
superclassTest(unknown, one, fivetwo);
// undefined ancestor and unrelated type
superclassTest(unknown, one, fivetwothree);
// undefined class and direct subclass
superclassTest(five, five, fivetwo);
// undefined class and descendent
superclassTest(five, five, fivetwothree);
// undefined superclass and direct subclass
superclassTest(fivetwo, fivetwo, fivetwothree);
// siblings with undefined superclass
superclassTest(five, fivetwo, fivethree);
// undefined superclass and nephew
superclassTest(five, fivethree, fivetwothree);
}
@Test
public void testGetCommonSuperclass_interfaces() {
String classiface1 = "Liface/classiface1;";
String iface1 = "Liface/iface1;";
String base1 = "Liface/base1;";
String base2 = "Liface/base2;";
String sub1 = "Liface/sub1;";
String sub2 = "Liface/sub2;";
String sub3 = "Liface/sub3;";
String sub4 = "Liface/sub4;";
String classsub1 = "Liface/classsub1;";
String classsub2 = "Liface/classsub2;";
String classsub3 = "Liface/classsub3;";
String classsub4 = "Liface/classsub4;";
String classsubsub4 = "Liface/classsubsub4;";
String classsub1234 = "Liface/classsub1234;";
String object = "Ljava/lang/Object;";
String unknown = "Ujava/lang/Object;";
superclassTest(iface1, classiface1, iface1);
superclassTest(base1, base1, base1);
superclassTest(base1, base1, sub1);
superclassTest(base1, base1, classsub1);
superclassTest(base1, base1, sub2);
superclassTest(base1, base1, classsub2);
superclassTest(base1, base1, sub3);
superclassTest(base1, base1, classsub3);
superclassTest(base1, base1, sub4);
superclassTest(base1, base1, classsub4);
superclassTest(base1, base1, classsubsub4);
superclassTest(base1, base1, classsub1234);
superclassTest(object, sub3, iface1);
superclassTest(unknown, sub2, iface1);
superclassTest(unknown, sub1, iface1);
superclassTest(base2, base2, sub1);
superclassTest(base2, base2, classsub1);
superclassTest(base2, base2, sub2);
superclassTest(base2, base2, classsub2);
superclassTest(base2, base2, classsub1234);
superclassTest(unknown, iface1, classsub1234);
superclassTest(sub1, sub1, classsub1);
superclassTest(sub2, sub2, classsub2);
superclassTest(sub1, sub1, classsub2);
superclassTest(sub3, sub3, classsub3);
superclassTest(sub4, sub4, classsub4);
superclassTest(sub3, sub3, classsub4);
superclassTest(object, sub2, classsub4);
superclassTest(object, sub1, classsub4);
superclassTest(sub1, sub2, sub1);
superclassTest(sub1, sub1, classsub1234);
superclassTest(sub2, sub2, classsub1234);
superclassTest(sub3, sub3, classsub1234);
superclassTest(sub4, sub4, classsub1234);
superclassTest(unknown, sub3, classsub1);
superclassTest(unknown, sub4, classsub1);
superclassTest(unknown, sub3, classsub2);
superclassTest(unknown, sub4, classsub2);
superclassTest(unknown, sub4, base2);
superclassTest(unknown, classsub4, base2);
}
@Test
public void testGetCommonSuperclass_arrays() throws IOException {
String object = "Ljava/lang/Object;";
String one = "Ltest/one;";
String unknown = "Ujava/lang/Object;";
String cloneable = "Ljava/lang/Cloneable;";
String serializable = "Ljava/io/Serializable;";
String object1 = "[Ljava/lang/Object;";
String one1 = "[Ltest/one;";
String one2 = "[[Ltest/one;";
String two1 = "[Ltest/two;";
String onetwo1 = "[Ltest/onetwo;";
String onetwo2 = "[[Ltest/onetwo;";
String onethree1 = "[Ltest/onethree;";
String onethree2 = "[[Ltest/onethree;";
String five = "Ltest/five;";
String five1 = "[Ltest/five;";
String unknown1 = "[Ujava/lang/Object;";
String int1 = "[I";
String int2 = "[[I";
String float1 = "[F";
superclassTest(one1, one1, one1);
superclassTest(object1, object1, one1);
superclassTest(one1, onetwo1, onethree1);
superclassTest(one1, one1, onethree1);
superclassTest(object1, one1, two1);
superclassTest(one2, one2, one2);
superclassTest(one2, one2, onetwo2);
superclassTest(one2, onetwo2, onethree2);
superclassTest(object1, one1, one2);
superclassTest(object1, two1, one2);
superclassTest(unknown1, five1, one1);
superclassTest(object1, five1, one2);
superclassTest(unknown1, one1, unknown1);
superclassTest(object, one1, one);
superclassTest(object, object1, one);
superclassTest(object, onetwo1, one);
superclassTest(object, five1, one);
superclassTest(object, one2, one);
superclassTest(object, one1, unknown);
superclassTest(object, unknown1, unknown);
superclassTest(cloneable, one1, cloneable);
superclassTest(serializable, one1, serializable);
superclassTest(object, one1, five);
superclassTest(int1, int1, int1);
superclassTest(object, int1, float1);
superclassTest(object, int1, int2);
}
}