Mercurial > hg > icedrobot > daneel
view src/test/java/org/icedrobot/daneel/DexifyingRunner.java @ 133:2b2a1c413c0f
Implemented rewriting of fill-array-data.
* rewriter/DexRewriter.java (visitInstrFillArrayData): Implemented.
* DexifyingRunner.java: Now also verifies generated code to ease debugging.
* rewriter/FillArrayDataTest.java: Enabled and expanded test case.
author | Michael Starzinger <michi@complang.tuwien.ac.at> |
---|---|
date | Thu, 28 Apr 2011 00:26:59 +0200 |
parents | 73f2f6cbd446 |
children |
line wrap: on
line source
/* * Daneel - Dalvik to Java bytecode compiler * Copyright (C) 2011 IcedRobot team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * This file is subject to the "Classpath" exception: * * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. * * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under terms * of your choice, provided that you also meet, for each linked independent * module, the terms and conditions of the license of that module. An * independent module is a module which is not derived from or based on * this library. If you modify this library, you may extend this exception * to your version of the library, but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. */ package org.icedrobot.daneel; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.PrintWriter; import java.lang.reflect.Method; import java.net.URL; import org.icedrobot.daneel.dex.DexFile; import org.icedrobot.daneel.loader.Verifier; import org.icedrobot.daneel.rewriter.DexRewriter; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; import com.android.dx.command.dexer.Main; import com.android.dx.command.dexer.Main.Arguments; /** * A JUnit runner implementation which makes sure that test code is pushed * through the Daneel stack before running a test case. The test code should be * a static inner class of the test case and be named {@code DEXCode} for this * runner to recognize it. */ public class DexifyingRunner extends BlockJUnit4ClassRunner { /** * Constructs a new JUnit test runner for the given test class. Keep a * constructor with that signature around, so that the JUnit framework can * instantiate us for {@link org.junit.runner.RunWith} annotations. * * @param testClass The given test class. */ public DexifyingRunner(Class<?> testClass) throws InitializationError { super(testClass); } /** * Overridden to add pre-processing of test code within our test classes. * This is what triggers the test code to be pushed through Daneel. */ @Override protected Statement classBlock(RunNotifier notifier) { try { rewriteTestCode(); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } return super.classBlock(notifier); } /** * Performs the steps necessary to push the test code through Daneel. */ private void rewriteTestCode() throws Exception { File tmp = File.createTempFile("daneel-dexifier", ".dex"); tmp.deleteOnExit(); // Find the original test class file. String testClass = getTestClass().getJavaClass().getName() + "$DEXCode"; String srcName = testClass.replace('.', '/') + ".class"; URL srcURL = ClassLoader.getSystemResource(srcName); if (srcURL == null) throw new DaneelException("Unable to find test code."); String src = srcURL.getFile(); if (src == null) throw new DaneelException("Unable to convert URL to path."); // Convert test code into DEX by running it through the 'dx' tool. String[] args = new String[] { "--no-strict", "--output=" + tmp, src }; Arguments arguments = new Arguments(); arguments.parse(args); int dexerResult = Main.run(arguments); if (dexerResult != 0) throw new DaneelException("Unable to execute 'dx' tool."); // Rewrite test code from DEX back to Java using our rewriter. DexFile dex; if( !System.getProperty("os.name").contains("Windows") ) { dex = DexFile.parse(tmp); } else { //hack for Windows Java bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154 byte[] data = new byte[(int)tmp.length()]; DataInputStream dai = new DataInputStream(new FileInputStream(tmp)); dai.readFully(data); dai.close(); dex = DexFile.parse(data); } byte[] testCode = DexRewriter.rewrite(testClass, dex); // Verify the rewritten test code. PrintWriter err = new PrintWriter(System.err); Verifier.verify(null, dex, testClass, testCode, err); // From this point on we no longer need the DEX file if (!tmp.delete()) throw new DaneelException("Unable to delete DEX file."); // Load the rewritten test code using the system class loader. ClassLoader cl = ClassLoader.getSystemClassLoader(); Method m = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); m.setAccessible(true); m.invoke(cl, testClass, testCode, 0, testCode.length); } }