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