DexMergeTest.java revision 081c7142b29ccd6e1744b26e097b6a4d7c12f2bd
1081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson/*
2081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * Copyright (C) 2011 The Android Open Source Project
3081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson *
4081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * you may not use this file except in compliance with the License.
6081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * You may obtain a copy of the License at
7081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson *
8081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson *
10081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * Unless required by applicable law or agreed to in writing, software
11081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * See the License for the specific language governing permissions and
14081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * limitations under the License.
15081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson */
16081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
17081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonpackage com.android.dx.merge;
18081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
19081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport dalvik.system.PathClassLoader;
20081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport java.io.File;
21081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport java.io.FileInputStream;
22081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport java.io.FileOutputStream;
23081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport java.io.IOException;
24081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport java.io.InputStream;
25081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport java.io.OutputStream;
26081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport java.util.Arrays;
27081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport java.util.jar.JarEntry;
28081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport java.util.jar.JarOutputStream;
29081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport junit.framework.TestCase;
30081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
31081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson/**
32081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * Test that DexMerge works by merging dex files, and then loading them into
33081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * the current VM.
34081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson */
35081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonpublic final class DexMergeTest extends TestCase {
36081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
37081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    public void testFillArrayData() throws Exception {
38081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        ClassLoader loader = mergeAndLoad(
39081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                "/testdata/Basic.dex",
40081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                "/testdata/FillArrayData.dex");
41081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
42081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        Class<?> basic = loader.loadClass("testdata.Basic");
43081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals(1, basic.getDeclaredMethods().length);
44081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
45081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        Class<?> fillArrayData = loader.loadClass("testdata.FillArrayData");
46081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertTrue(Arrays.equals(
47081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                new byte[] { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, -112, -23, 121 },
48081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                (byte[]) fillArrayData.getMethod("newByteArray").invoke(null)));
49081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertTrue(Arrays.equals(
50081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                new char[] { 0xFFFF, 0x4321, 0xABCD, 0, 'a', 'b', 'c' },
51081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                (char[]) fillArrayData.getMethod("newCharArray").invoke(null)));
52081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertTrue(Arrays.equals(
53081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                new long[] { 4660046610375530309L, 7540113804746346429L, -6246583658587674878L },
54081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                (long[]) fillArrayData.getMethod("newLongArray").invoke(null)));
55081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    }
56081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
57081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    public void testTryCatchFinally() throws Exception {
58081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        ClassLoader loader = mergeAndLoad(
59081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                "/testdata/Basic.dex",
60081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                "/testdata/TryCatchFinally.dex");
61081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
62081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        Class<?> basic = loader.loadClass("testdata.Basic");
63081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals(1, basic.getDeclaredMethods().length);
64081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
65081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        Class<?> tryCatchFinally = loader.loadClass("testdata.TryCatchFinally");
66081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        tryCatchFinally.getDeclaredMethod("method").invoke(null);
67081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    }
68081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
69081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    public void testStaticValues() throws Exception {
70081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        ClassLoader loader = mergeAndLoad(
71081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                "/testdata/Basic.dex",
72081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson                "/testdata/StaticValues.dex");
73081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
74081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        Class<?> basic = loader.loadClass("testdata.Basic");
75081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals(1, basic.getDeclaredMethods().length);
76081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
77081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        Class<?> staticValues = loader.loadClass("testdata.StaticValues");
78081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals((byte) 1, staticValues.getField("a").get(null));
79081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals((short) 2, staticValues.getField("b").get(null));
80081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals('C', staticValues.getField("c").get(null));
81081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals(0xabcd1234, staticValues.getField("d").get(null));
82081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals(4660046610375530309L,staticValues.getField("e").get(null));
83081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals(0.5f, staticValues.getField("f").get(null));
84081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals(-0.25, staticValues.getField("g").get(null));
85081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals("this is a String", staticValues.getField("h").get(null));
86081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals(String.class, staticValues.getField("i").get(null));
87081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals("[0, 1]", Arrays.toString((int[]) staticValues.getField("j").get(null)));
88081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals(null, staticValues.getField("k").get(null));
89081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals(true, staticValues.getField("l").get(null));
90081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        assertEquals(false, staticValues.getField("m").get(null));
91081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    }
92081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
93081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    public ClassLoader mergeAndLoad(String dexAResource, String dexBResource) throws IOException {
94081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        File dexA = resourceToFile(dexAResource);
95081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        File dexB = resourceToFile(dexBResource);
96081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        File mergedDex = File.createTempFile("DexMergeTest", ".classes.dex");
97081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        new DexMerger(mergedDex, dexA, dexB).merge();
98081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        File mergedJar = dexToJar(mergedDex);
99081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        return new PathClassLoader(mergedJar.getPath(), getClass().getClassLoader());
100081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    }
101081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
102081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    private File resourceToFile(String resource) throws IOException {
103081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        File result = File.createTempFile("DexMergeTest", ".resource");
104081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        result.deleteOnExit();
105081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        FileOutputStream out = new FileOutputStream(result);
106081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        InputStream in = getClass().getResourceAsStream(resource);
107081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        if (in == null) {
108081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson            throw new IllegalArgumentException("No such resource: " + resource);
109081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        }
110081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        copy(in, out);
111081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        out.close();
112081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        return result;
113081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    }
114081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
115081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    private File dexToJar(File dex) throws IOException {
116081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        File result = File.createTempFile("DexMergeTest", ".jar");
117081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        result.deleteOnExit();
118081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result));
119081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        jarOut.putNextEntry(new JarEntry("classes.dex"));
120081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        copy(new FileInputStream(dex), jarOut);
121081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        jarOut.closeEntry();
122081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        jarOut.close();
123081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        return result;
124081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    }
125081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
126081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    private void copy(InputStream in, OutputStream out) throws IOException {
127081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        byte[] buffer = new byte[1024];
128081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        int count;
129081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        while ((count = in.read(buffer)) != -1) {
130081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson            out.write(buffer, 0, count);
131081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        }
132081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        in.close();
133081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    }
134081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson}
135