# HG changeset patch # User Michael Starzinger # Date 1304886634 -7200 # Node ID 5350588b2890ac205c459ed8a9987876ff52bfa4 # Parent ee4aa08ddaa404cbcc83fd613c0368fe63331288 Added new test runner for Smali tests. * pom.xml: Added dependency to Smali with test scope. * SmalifyingRunner.java: New test runner to be used by JUnit. * rewriter/ScrambledBlocksTest.java: Sample test case. * rewriter/ScrambledBlocksTest$DEXCode.smali: Sample test case. diff -r ee4aa08ddaa4 -r 5350588b2890 pom.xml --- a/pom.xml Mon May 02 19:42:59 2011 +0200 +++ b/pom.xml Sun May 08 22:30:34 2011 +0200 @@ -128,5 +128,11 @@ 1.5 test + + org.jf + smali + 1.2.7-dev + test + diff -r ee4aa08ddaa4 -r 5350588b2890 src/test/java/org/icedrobot/daneel/SmalifyingRunner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/org/icedrobot/daneel/SmalifyingRunner.java Sun May 08 22:30:34 2011 +0200 @@ -0,0 +1,131 @@ +/* + * 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 . + * + * 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.File; +import java.io.PrintWriter; +import java.lang.reflect.Field; +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; + +/** + * 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 Smali assembler source for an inner class {@code DEXCode} of the test case. + * An instance of the test code will be injected into the static {@code dexCode} + * field of the test case. + */ +public class SmalifyingRunner 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 SmalifyingRunner(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 { + assembleTestCode(); + } 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 assembleTestCode() throws Exception { + File tmp = File.createTempFile("daneel-smalifier", ".dex"); + tmp.deleteOnExit(); + + // Find the original assembler source for the test code. + String testClass = getTestClass().getJavaClass().getName() + "$DEXCode"; + String srcName = testClass.replace('.', '/') + ".smali"; + URL srcURL = ClassLoader.getSystemResource(srcName); + if (srcURL == null) + throw new DaneelException("Unable to find test source."); + String src = srcURL.getFile(); + if (src == null) + throw new DaneelException("Unable to convert URL to path."); + + // Compile the test assembler source into DEX using 'smali'. + String[] args = new String[] { "-o", tmp.toString(), src.toString() }; + org.jf.smali.main.main(args); + + // Rewrite test code from DEX back to Java using our rewriter. + DexFile dex = DexFile.parse(tmp); + byte[] testCode = DexRewriter.rewrite(testClass, dex); + + // Verify the rewritten test code. + PrintWriter err = new PrintWriter(System.err); + Verifier.verify(null, dex, testClass, testCode, err); + + // 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); + Class loadedTestClass = (Class) m.invoke(cl, testClass, testCode, + 0, testCode.length); + + // Inject an instance of the test code into the test case. + Field f = getTestClass().getJavaClass().getField("dexCode"); + f.set(null, loadedTestClass.newInstance()); + } +} diff -r ee4aa08ddaa4 -r 5350588b2890 src/test/java/org/icedrobot/daneel/rewriter/ScrambledBlocksTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/org/icedrobot/daneel/rewriter/ScrambledBlocksTest.java Sun May 08 22:30:34 2011 +0200 @@ -0,0 +1,60 @@ +/* + * 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 . + * + * 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.rewriter; + +import static org.junit.Assert.assertEquals; + +import org.icedrobot.daneel.SmalifyingRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(SmalifyingRunner.class) +@org.junit.Ignore("Rewriter cannot patch uninitialized variables.") +public class ScrambledBlocksTest { + + @Test + public void test() { + assertEquals(0.5f, dexCode.check(), 0); + } + + // Keep this field named "dexCode" to allow dependency injection. + public static DEXInterface dexCode; + public static interface DEXInterface { + float check(); + } +} diff -r ee4aa08ddaa4 -r 5350588b2890 src/test/resources/org/icedrobot/daneel/rewriter/ScrambledBlocksTest$DEXCode.smali --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/resources/org/icedrobot/daneel/rewriter/ScrambledBlocksTest$DEXCode.smali Sun May 08 22:30:34 2011 +0200 @@ -0,0 +1,57 @@ +## +# 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 . +# +# 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. +## + +.class public Lorg/icedrobot/daneel/rewriter/ScrambledBlocksTest$DEXCode; +.implements Lorg/icedrobot/daneel/rewriter/ScrambledBlocksTest$DEXInterface; +.super Ljava/lang/Object; + +.method public constructor ()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;->()V + return-void +.end method + +.method public check()F + .registers 2 + goto :L2 + :L1 + move v1, v0 + return v1 + :L2 + const v0, 0.5f + goto :L1 +.end method