com.github.trugath.jdalvikvm.VirtualMachineTest.java Source code

Java tutorial

Introduction

Here is the source code for com.github.trugath.jdalvikvm.VirtualMachineTest.java

Source

/*
 * Developed by Koji Hisano <koji.hisano@eflow.jp>
 *
 * Copyright (C) 2009 eflow Inc. <http://www.eflow.jp/en/>
 *
 * This file is a part of Android Dalvik VM on Java.
 * http://code.google.com/p/android-dalvik-vm-on-java/
 *
 * This project 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 2 of the License, or
 * (at your option) any later version.
 *
 * This project 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package com.github.trugath.jdalvikvm;

import java.io.*;
import java.util.*;

import com.github.trugath.jdalvikvm.dvmtests.*;
import com.github.trugath.jdalvikvm.jvmtests.*;

import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import org.apache.commons.io.*;
import org.apache.commons.io.output.NullOutputStream;
import org.apache.commons.lang.SystemUtils;

@RunWith(JUnit4.class)
public class VirtualMachineTest {

    private static final String DX_JAR_FILE_PATH = "lib/dx.jar";

    private static final String TEST_CLASSES_OUTPUT_PATH = "target/scala-2.11/test-classes";
    private static final String SCOVERAGE_TEST_CLASSES_OUTPUT_PATH = "target/scala-2.11/scoverage-test-classes";

    @Test
    public void testScalaBasic() {
        runByClass(TestScalaBasic.class);

        assertEquals("test", getLine());
    }

    @Test
    public void test0x2C() {
        runByClass(Test0x2C.class);

        assertEquals("0x1", getLine());
        assertEquals("0x10", getLine());
        assertEquals("0x100", getLine());
        assertEquals("0x1000", getLine());
        assertEquals("default", getLine());
    }

    @Test
    public void test0x52to0x5F() {
        runByClass(Test0x52to0x5F.class);

        assertNull(getLine());
    }

    @Test
    public void testTest0x14() {
        runByClass(Test0x14.class);

        assertEquals("" + 0x12345678, getLine());
        assertEquals("" + -0x12345678, getLine());
    }

    @Test
    public void testDouble() {
        runByClass(DoubleTest.class);

        assertEquals("1d + 2d = '3.0'", getLine());

        assertEquals("Values are NaN.", getLine());
        assertEquals("Values are NaN.", getLine());
        assertEquals("0d <= 0d", getLine());
        assertEquals("0d >= 0d", getLine());
        assertEquals("0d < 1d", getLine());
        assertEquals("1d > 0d", getLine());

        assertEquals("(int)1.5d = 1", getLine());
        assertEquals("(long)1.5d = 1", getLine());
        assertEquals("(float)1.5d = 1.5", getLine());
        assertEquals("(double)1 = 1.0", getLine());
        assertEquals("(double)1L = 1.0", getLine());
        assertEquals("(double)1f = 1.0", getLine());

        assertEquals("4.0 + 2.0 = 6.0", getLine());
        assertEquals("4.0 - 2.0 = 2.0", getLine());
        assertEquals("4.0 * 2.0 = 8.0", getLine());
        assertEquals("4.0 / 2.0 = 2.0", getLine());
        assertEquals("4.0 % 2.0 = 0.0", getLine());
        assertEquals("-(4.0) = -4.0", getLine());

        assertEquals("da[0] is '2.0'.", getLine());

        assertEquals("d0 = 0.0", getLine());
        assertEquals("d1 = 1.0", getLine());
        assertEquals("d2 = 2.0", getLine());
        assertEquals("d3 = 3.0", getLine());
        assertEquals("d4 = 4.0", getLine());

        assertEquals("0.0", getLine());
        assertEquals("1.0", getLine());
        assertEquals("2.0", getLine());
    }

    @Test
    public void testFloat() {
        runByClass(FloatTest.class);

        assertEquals("1f + 2f = '3.0'", getLine());

        assertEquals("Values are NaN.", getLine());
        assertEquals("Values are NaN.", getLine());
        assertEquals("0f <= 0f", getLine());
        assertEquals("0f >= 0f", getLine());
        assertEquals("0f < 1f", getLine());
        assertEquals("1f > 0f", getLine());

        assertEquals("(int)1.5f = 1", getLine());
        assertEquals("(long)1.5f = 1", getLine());
        assertEquals("(float)1 = 1.0", getLine());
        assertEquals("(float)1L = 1.0", getLine());

        assertEquals("4.0 + 2.0 = 6.0", getLine());
        assertEquals("4.0 - 2.0 = 2.0", getLine());
        assertEquals("4.0 * 2.0 = 8.0", getLine());
        assertEquals("4.0 / 2.0 = 2.0", getLine());
        assertEquals("4.0 % 2.0 = 0.0", getLine());
        assertEquals("-(4.0) = -4.0", getLine());

        assertEquals("fa[0] is '2.0'.", getLine());

        assertEquals("f0 = 0.0", getLine());
        assertEquals("f1 = 1.0", getLine());
        assertEquals("f2 = 2.0", getLine());
        assertEquals("f3 = 3.0", getLine());
        assertEquals("f4 = 4.0", getLine());

        assertEquals("0.0", getLine());
        assertEquals("1.0", getLine());
        assertEquals("2.0", getLine());
        assertEquals("3.0", getLine());
    }

    @Test
    public void testInheritanceFromObject() {
        runByClass(InheritanceFromObjectTest.class, new Class[] { InheritanceFromObjectTest.Wait.class },
                new String[] { InheritanceFromObjectTest.class.getName() + "$1" });

        assertEquals("toString", getLine());

        assertEquals("notified", getLine());
        assertEquals("interrupted", getLine());
    }

    @Test
    public void testThreadWaitWithTime() {
        runByClass(ThreadWaitWithTimeTest.class, new Class[0],
                new String[] { ThreadWaitWithTimeTest.class.getName() + "$1" });

        assertEquals("notified", getLine());
        assertEquals("timeout", getLine());
    }

    @Test
    public void testThreadNotifyAll() {
        runByClass(ThreadNotifyAllTest.class, new Class[0],
                new String[] { ThreadNotifyAllTest.class.getName() + "$1" });

        for (int i = 0; i < 10; i++) {
            assertEquals("" + i, getLine());
        }
    }

    @Test
    public void testThreadWait() {
        runByClass(ThreadWaitTest.class, new Class[0], new String[] { ThreadWaitTest.class.getName() + "$1" });

        assertEquals("notified", getLine());
        assertEquals("interrupted", getLine());
    }

    @Test
    public void testThreadReentrantSynchronizedMethod() {
        runByClass(ThreadReentrantSynchronizedMethodTest.class, new Class[0],
                new String[] { ThreadReentrantSynchronizedMethodTest.class.getName() + "$1" });

        assertEquals("1", getLine());
        assertEquals("2", getLine());
    }

    @Test
    public void testThreadSynchronizedMethod() {
        runByClass(ThreadSynchronizedMethodTest.class, new Class[0],
                new String[] { ThreadSynchronizedMethodTest.class.getName() + "$1" });

        assertEquals("1", getLine());
        assertEquals("2", getLine());
    }

    @Test
    public void testThreadReentrantSynchronizedBlock() {
        runByClass(ThreadReentrantSynchronizedBlockTest.class, new Class[0],
                new String[] { ThreadReentrantSynchronizedBlockTest.class.getName() + "$1" });

        assertEquals("1", getLine());
        assertEquals("2", getLine());
    }

    @Test
    public void testThreadSynchronized() {
        runByClass(ThreadSynchronizedBlockTest.class, new Class[0],
                new String[] { ThreadSynchronizedBlockTest.class.getName() + "$1" });

        assertEquals("1", getLine());
        assertEquals("2", getLine());
    }

    @Test
    public void testThreadInterrupt() {
        runByClass(ThreadInterruptTest.class, new Class[0],
                new String[] { ThreadInterruptTest.class.getName() + "$1" });

        assertEquals("sleep->interrupted", getLine());
        assertEquals("join->interrupted", getLine());
    }

    @Test
    public void testThreadSleep() {
        runByClass(ThreadSleepTest.class);

        assertEquals("slept", getLine());
    }

    @Test
    public void testThreadYield() {
        runByClass(ThreadYieldTest.class, new Class[0], new String[] { ThreadYieldTest.class.getName() + "$1" });

        assertEquals("new", getLine());
        assertEquals("main", getLine());
    }

    @Test
    public void testThreadMethods() {
        runByClass(ThreadMethodsTest.class, new Class[0],
                new String[] { ThreadMethodsTest.class.getName() + "$1" });

        assertEquals("activeCount = 2", getLine());
        assertEquals("newThreadName = new", getLine());
        assertEquals("mainThreadName = main", getLine());
    }

    @Test
    public void testSimpleThread() {
        runByClass(ThreadSimpleTest.class, new Class[0], new String[] { ThreadSimpleTest.class.getName() + "$1" });

        assertEquals("newThread", getLine());
        assertEquals("mainThread", getLine());
    }

    @Test
    public void testNativeInterface() {
        runByClass(NativeInterface.class, new Class[0], new String[] { NativeInterface.class.getName() + "$1" });

        assertEquals("message", getLine());
    }

    @Test
    public void testInnerClass() {
        runByClass(
                InnerClassTest.class, new Class[] { InnerClassTest.InnerStatic.class,
                        InnerClassTest.InnerInstance.class, Interface.class },
                new String[] { InnerClassTest.class.getName() + "$1" });

        assertEquals("message", getLine());
        assertEquals("result", getLine());

        assertEquals("1 + 2 = 3", getLine());

        assertEquals("in", getLine());
        assertEquals("out", getLine());
    }

    @Test
    public void testUserDefinedInterface() {
        runByClass(UserDefinedInterfaceTest.class, new Class[] { Interface.class, Implementation.class });

        assertEquals("message", getLine());
        assertEquals("result", getLine());
    }

    @Test
    public void testInheritance() {
        runByClass(InheritanceTest.class, new Class[] { ParentClass.class, ChildClass.class });

        assertEquals("parent", getLine());
        assertEquals("child_hidden", getLine());
        assertEquals("parent_hidden", getLine());

        assertEquals("parent", getLine());
        assertEquals("child_hidden", getLine());
    }

    @Test
    public void testInstance() {
        runByClass(InstanceTest.class);
        assertEquals("public_method", getLine());
        assertEquals("protected_method", getLine());
        assertEquals("package_method", getLine());
        assertEquals("private_method", getLine());
        assertEquals("get_field", getLine());
        assertEquals("set_field", getLine());
    }

    @Test
    public void testOtherClass() {
        runByClass(OtherClassTest.class, new Class[] { OtherClass.class });
        assertEquals("method", getLine());
        assertEquals("get_field", getLine());
        assertEquals("set_field", getLine());
    }

    @Test
    public void testBug23() throws Exception {
        long start = System.currentTimeMillis();
        runByClass(Bug23Test.class);
        long end = System.currentTimeMillis();
        long result = Long.parseLong(getLine());
        assertTrue(start <= result && result <= end);
    }

    @Test
    public void testBug22() throws Exception {
        runByClass(Bug22Test.class);
        assertEquals("test", getLine());
    }

    @Test
    public void testBug17And20() {
        runByClass(Bug17And20Test.class);
        assertEquals("ClassCastException occured.", getLine());
        assertEquals("The null can be casted.", getLine());
    }

    @Test
    public void testBug16() {
        runByClass(Bug16Test.class);
        assertEquals("l = 1, j = 1", getLine());
    }

    @Test
    public void testBug13() {
        runByClass(Bug13Test.class);
    }

    @Test
    public void testBug12() {
        runByClass(Bug12Test.class);
        assertEquals("test", getLine());
        assertEquals("hello, world", getLine());
    }

    @Test
    public void testBug10And11() {
        runByClass(Bug10And11Test.class);
        assertEquals("java.lang.RuntimeException", getLine());
    }

    @Test
    public void testBug9() {
        runByClass(Bug9Test.class);
        assertEquals("SOFTKEY_SK2", getLine());
    }

    @Test
    public void testInterface() {
        runByClass(InterfaceTest.class);
        assertEquals("1", getLine());
        assertEquals("2", getLine());
    }

    @Test
    public void testArrayLength() {
        runByClass(ArrayLengthTest.class);
        String[] array = new String[] { "boolean", "byte", "short", "int", "long", "Object", "String", "Vector" };
        for (int i = 0; i < array.length; i++) {
            assertEquals("new " + array[i] + "[" + i + "].length = " + i, getLine());
            assertEquals("new " + array[i] + "[" + i + "][].length = " + i, getLine());
            assertEquals("new " + array[i] + "[" + i + "][" + i + "].length = " + i, getLine());
            assertEquals("new " + array[i] + "[" + i + "][][].length = " + i, getLine());
            assertEquals("new " + array[i] + "[" + i + "][" + i + "][].length = " + i, getLine());
            assertEquals("new " + array[i] + "[" + i + "][" + i + "][" + i + "].length = " + i, getLine());
        }
    }

    @Test
    public void testCallMethods() {
        runByClass(CallMethodsTest.class);
        assertEquals("", getLine());

        assertEquals("false", getLine());
        assertEquals("true", getLine());

        assertEquals("true", getLine());
        assertEquals("false", getLine());

        assertEquals("a", getLine());
        assertEquals("b", getLine());

        assertEquals("1", getLine());
        assertEquals("2", getLine());

        assertEquals("2", getLine());
        assertEquals("3", getLine());

        assertEquals("3", getLine());
        assertEquals("4", getLine());

        assertEquals("4", getLine());
        assertEquals("5", getLine());

        assertEquals("eXg", getLine());
        assertEquals("eXgeXg", getLine());

        assertEquals("false,a,1,2,3,4,eXg", getLine());
        assertEquals("eXg,4,3,2,1,a,false", getLine());

        assertEquals("1,2,3", getLine());
    }

    @Test
    public void testCallSuperClassMethod() {
        runByClass(CallSuperClassMethodTest.class);
        assertEquals("java.lang.String", getLine());
    }

    @Test
    public void testCreateException() {
        runByClass(CreateExceptionTest.class);
        assertEquals("O", getLine());
    }

    @Test
    public void testInstanceOf() {
        runByClass(InstanceOfTest.class);
        assertEquals("The str is a String.", getLine());
        assertEquals("The str is a Object.", getLine());
        assertEquals("The null is not a Object.", getLine());
    }

    @Test
    public void testParentException() {
        runByClass(ParentExceptionTest.class);
        assertEquals("catchubN", getLine());
        assertEquals("finallyubN", getLine());
    }

    @Test
    public void testClassMethodExceptionInCalledMethod() {
        runByClass(ClassMethodExceptionInCalledMethodTest.class);
        assertEquals("catchubN", getLine());
        assertEquals("finallyubN", getLine());
    }

    @Test
    public void testConstructorExceptionInCalledMethod() {
        runByClass(ConstructorExceptionInCalledMethodTest.class);
        assertEquals("catchubN", getLine());
        assertEquals("finallyubN", getLine());
    }

    @Test
    public void testInstanceMethodExceptionInCalledMethod() {
        runByClass(InstanceMethodExceptionInCalledMethodTest.class);
        assertEquals("catchubN", getLine());
        assertEquals("finallyubN", getLine());
    }

    @Test
    public void testClassMethodException() {
        runByClass(ClassMethodExceptionTest.class);
        assertEquals("catchubN", getLine());
        assertEquals("finallyubN", getLine());
    }

    @Test
    public void testConstructorException() {
        runByClass(ConstructorExceptionTest.class);
        assertEquals("catchubN", getLine());
        assertEquals("finallyubN", getLine());
    }

    @Test
    public void testInstanceMethodException() {
        runByClass(InstanceMethodExceptionTest.class);
        assertEquals("catchubN", getLine());
        assertEquals("finallyubN", getLine());
    }

    @Test
    public void testStaticFields() {
        runByClass(StaticFieldsTest.class);
        assertNull(getLine());
    }

    @Test
    public void testArray() {
        runByClass(ArrayTest.class);
        assertEquals("", getLine());
        assertEquals("<NUM VAL=1>", getLine());
        assertEquals("<NUM VAL=2>", getLine());
        assertEquals("<NUM VAL=3>", getLine());
        assertEquals("<NUM VAL=4>", getLine());
        assertEquals("<NUM VAL=5>", getLine());
        assertEquals("", getLine());

        assertEquals("", getLine());
        assertEquals("<NUM VAL=1>", getLine());
        assertEquals("<NUM VAL=2>", getLine());
        assertEquals("<NUM VAL=3>", getLine());
        assertEquals("<NUM VAL=4>", getLine());
        assertEquals("<NUM VAL=5>", getLine());
        assertEquals("", getLine());

        assertEquals("", getLine());
        assertEquals("<NUM VAL=1>", getLine());
        assertEquals("<NUM VAL=2>", getLine());
        assertEquals("<NUM VAL=3>", getLine());
        assertEquals("<NUM VAL=4>", getLine());
        assertEquals("<NUM VAL=5>", getLine());
        assertEquals("", getLine());
    }

    @Test
    public void testOperatorsForLongType() {
        runByClass(OperatorsForLongType.class);
        long value = 8;
        assertEquals("<NUM VAL=" + (value + 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value - 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value * 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value / 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value % 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (-value) + ">", getLine());
        assertEquals("<NUM VAL=" + (value << 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value >> 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value >>> 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value & 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value | 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value ^ 2) + ">", getLine());
        value++;
        assertEquals("<NUM VAL=" + value + ">", getLine());
    }

    @Test
    public void testLongConstants() {
        runByClass(LongConstantsTest.class);
        for (int i = 1; i <= 3; i++) {
            assertEquals("<NUM VAL=" + i + ">", getLine());
        }
    }

    @Test
    public void testWideByteCode() {
        runByClass(WideByteCodeTest.class);
        assertEquals("<NUM VAL=1000>", getLine());
    }

    @Test
    public void testCast() {
        runByClass(CastTest.class);
        assertEquals("<NUM VAL=-1>", getLine());
        assertEquals("<NUM VAL=-1>", getLine());
        assertEquals("<NUM VAL=65535>", getLine());
        assertEquals("<NUM VAL=-1>", getLine());
        assertEquals("<NUM VAL=-1>", getLine());
    }

    @Test
    public void testConditions() {
        runByClass(ConditionsTest.class);

        assertEquals("", getLine());
        assertEquals("", getLine());
        assertEquals("", getLine());
        assertEquals("", getLine());
        assertEquals("", getLine());
        assertEquals("", getLine());

        assertEquals("", getLine());
        assertEquals("", getLine());
        assertEquals("", getLine());
        assertEquals("", getLine());
        assertEquals("", getLine());
        assertEquals("", getLine());

        assertEquals("", getLine());
        assertEquals("", getLine());

        assertEquals("", getLine());
        assertEquals("", getLine());
    }

    @Test
    public void testOperatorsForIntType() {
        runByClass(OperatorsForIntTypeTest.class);
        int value = 8;
        assertEquals("<NUM VAL=" + (value + 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value - 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value * 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value / 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value % 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (-value) + ">", getLine());
        assertEquals("<NUM VAL=" + (value << 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value >> 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value >>> 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value & 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value | 2) + ">", getLine());
        assertEquals("<NUM VAL=" + (value ^ 2) + ">", getLine());
        value++;
        assertEquals("<NUM VAL=" + value + ">", getLine());
    }

    @Test
    public void testPopByteCode() {
        runByClass(PopByteCodeTest.class);
        assertEquals("", getLine());
    }

    @Test
    public void testAloadAstoreByteCode() {
        runByClass(AloadAstoreByteCodeTest.class);
        assertEquals("<NUM VAL=4321>", getLine());
    }

    @Test
    public void testIloadIstoreByteCode() {
        runByClass(IloadIstoreByteCodeTest.class);
        assertEquals("<NUM VAL=4321>", getLine());
    }

    @Test
    public void testIntConstants() {
        runByClass(IntConstantsTest.class);
        for (int i = -1; i <= 6; i++) {
            assertEquals("<NUM VAL=" + i + ">", getLine());
        }
        assertEquals("<NUM VAL=" + 0x100 + ">", getLine());
        assertEquals("<NUM VAL=" + 0x10000 + ">", getLine());
    }

    @Test
    public void testNull() {
        runByClass(NullTest.class);
        assertEquals("", getLine());
        assertEquals(null, getLine());
    }

    @Test
    public void testHello() {
        runByClass(HelloTest.class);
        assertEquals("", getLine());
    }

    private List lines = new ArrayList();

    private void runByClass(Class mainClass) {
        runByClass(mainClass, new Class[0]);
    }

    private void runByClass(Class mainClass, Class[] relatedClasses) {
        runByClass(mainClass, relatedClasses, new String[0]);
    }

    private void runByClass(Class mainClass, Class[] relatedClasses, String[] relatedClassNames) {
        String[] files = new String[1 + relatedClasses.length + relatedClassNames.length];
        files[0] = toClassFilePath(mainClass);
        for (int i = 0; i < relatedClasses.length; i++) {
            files[1 + i] = toClassFilePath(relatedClasses[i]);
        }
        for (int i = 0; i < relatedClassNames.length; i++) {
            files[1 + relatedClasses.length + i] = toClassFilePath(relatedClassNames[i]);
        }
        byte[] dexFileContent = compile(getClassFilesRootDirectory(), files);
        run(dexFileContent, mainClass.getName(), false);
    }

    private File getClassFilesRootDirectory() {
        if (new File(TEST_CLASSES_OUTPUT_PATH).exists())
            return new File(TEST_CLASSES_OUTPUT_PATH).getAbsoluteFile();
        else
            return new File(SCOVERAGE_TEST_CLASSES_OUTPUT_PATH).getAbsoluteFile();
    }

    private String toClassFilePath(Class clazz) {
        return toClassFilePath(clazz.getName());
    }

    private String toClassFilePath(String className) {
        return className.replace(".", File.separator) + ".class";
    }

    private byte[] compile(File classesDirectory, String[] files) {
        String[] cmdarray = new String[files.length + 5];
        cmdarray[0] = "java";
        cmdarray[1] = "-jar";
        cmdarray[2] = new File(DX_JAR_FILE_PATH).getAbsolutePath();
        cmdarray[3] = "--dex";
        String dexFilePath = new File(SystemUtils.JAVA_IO_TMPDIR, FilenameUtils.getBaseName(files[0]) + ".dex")
                .getAbsolutePath();
        cmdarray[4] = "--output=" + dexFilePath;
        System.arraycopy(files, 0, cmdarray, 5, files.length);

        try {
            Process process = Runtime.getRuntime().exec(cmdarray, null, classesDirectory);
            process.waitFor();
        } catch (Exception e) {
            throw new IllegalStateException("Compiling failed.", e);
        }

        FileInputStream in = null;
        try {
            in = new FileInputStream(dexFilePath);
            return IOUtils.toByteArray(in);
        } catch (IOException e) {
            throw new IllegalStateException("Loading " + dexFilePath + " failed.", e);
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    private VirtualMachine run(final byte[] dexFileContent, final String mainClassName,
            final boolean runInNewThread) {
        lines.clear();

        final PrintStream oldErr = System.err;
        final PrintStream newOutAndErr = new PrintStream(new NullOutputStream()) {
            public synchronized void println(Object o) {
                println("" + o);
            }

            public void println(int x) {
                println("" + x);
            }

            public void println(long l) {
                println("" + l);
            }

            public void println(float f) {
                println("" + f);
            }

            public void println(double d) {
                println("" + d);
            }

            public synchronized void println(String x) {
                lines.add(x);
            }
        };
        System.setOut(newOutAndErr);
        System.setErr(newOutAndErr);

        final VirtualMachine vm = new VirtualMachine() {
            protected void error(Throwable e) {
                System.setErr(oldErr);
                e.printStackTrace();
                System.setErr(newOutAndErr);
            }
        };
        vm.load(dexFileContent);
        if (runInNewThread) {
            new java.lang.Thread() {
                public void run() {
                    vm.run(mainClassName, new String[0]);
                }
            }.start();
        } else {
            vm.run(mainClassName, new String[0]);
        }

        return vm;
    }

    private String getLine() {
        if (lines.isEmpty()) {
            return null;
        }
        return (String) lines.remove(0);
    }
}