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