changeset 136:5350588b2890 default tip

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.
author Michael Starzinger <michi@complang.tuwien.ac.at>
date Sun, 08 May 2011 22:30:34 +0200
parents ee4aa08ddaa4
children
files pom.xml src/test/java/org/icedrobot/daneel/SmalifyingRunner.java src/test/java/org/icedrobot/daneel/rewriter/ScrambledBlocksTest.java src/test/resources/org/icedrobot/daneel/rewriter/ScrambledBlocksTest$DEXCode.smali
diffstat 4 files changed, 254 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- 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 @@
       <version>1.5</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.jf</groupId>
+      <artifactId>smali</artifactId>
+      <version>1.2.7-dev</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>
--- /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 <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.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());
+    }
+}
--- /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 <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.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();
+    }
+}
--- /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 <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.
+##
+
+.class public Lorg/icedrobot/daneel/rewriter/ScrambledBlocksTest$DEXCode;
+.implements Lorg/icedrobot/daneel/rewriter/ScrambledBlocksTest$DEXInterface;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()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