summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Marie Henaff <jmhenaff@google.com>2014-05-19 17:34:13 +0200
committerJean-Marie Henaff <jmhenaff@google.com>2014-10-14 10:35:18 +0200
commitf265ce821c48ed54ad8d00060664b55a8f8e1bb7 (patch)
tree798f4464e8669ce31fbd5bbe0a2e3404d4e47ff1
parent706b60417fe72a4a70bc61da2f915fe3693dd0c2 (diff)
downloadtoolchain_jack-f265ce821c48ed54ad8d00060664b55a8f8e1bb7.zip
toolchain_jack-f265ce821c48ed54ad8d00060664b55a8f8e1bb7.tar.gz
toolchain_jack-f265ce821c48ed54ad8d00060664b55a8f8e1bb7.tar.bz2
WIP Use JUnit for jack-tests.
(cherry picked from commit 452cbd7d69db557ecdbbd20875a669752cf2d9d7) Change-Id: I96a34b90c9525fa4403f6f940d6fcdf4656722ab
-rw-r--r--build.xml74
-rw-r--r--ddmlib/README.android9
-rw-r--r--ddmlib/ddmlib.jarbin0 -> 251343 bytes
-rw-r--r--hamcrest-core/Android.mk10
-rw-r--r--jack-tests/.checkstyle13
-rw-r--r--jack-tests/.classpath10
-rw-r--r--jack-tests/.project6
-rw-r--r--jack-tests/jackstyle.xml314
-rw-r--r--jack-tests/prebuilts/core-hostdex.jarbin0 -> 8043981 bytes
-rw-r--r--jack-tests/prebuilts/jarjar.jarbin0 -> 112749 bytes
-rw-r--r--jack-tests/prebuilts/junit4-hostdex.jarbin0 -> 563629 bytes
-rw-r--r--jack-tests/prebuilts/proguard.jarbin0 -> 716008 bytes
-rw-r--r--jack-tests/src/com/android/jack/test/category/RuntimeRegressionTest.java25
-rw-r--r--jack-tests/src/com/android/jack/test/comparator/Comparator.java28
-rw-r--r--jack-tests/src/com/android/jack/test/comparator/ComparatorComposite.java46
-rw-r--r--jack-tests/src/com/android/jack/test/comparator/ComparatorDex.java81
-rw-r--r--jack-tests/src/com/android/jack/test/comparator/ComparatorDexAnnotations.java44
-rw-r--r--jack-tests/src/com/android/jack/test/comparator/ComparatorDiff.java60
-rw-r--r--jack-tests/src/com/android/jack/test/comparator/ComparatorException.java44
-rw-r--r--jack-tests/src/com/android/jack/test/comparator/ComparatorFile.java37
-rw-r--r--jack-tests/src/com/android/jack/test/comparator/ComparatorMapping.java44
-rw-r--r--jack-tests/src/com/android/jack/test/helper/CheckDexStructureTestHelper.java37
-rw-r--r--jack-tests/src/com/android/jack/test/helper/ErrorTestHelper.java75
-rw-r--r--jack-tests/src/com/android/jack/test/helper/GenericComparisonTestHelper.java45
-rw-r--r--jack-tests/src/com/android/jack/test/helper/IncrementalTestHelper.java169
-rw-r--r--jack-tests/src/com/android/jack/test/helper/JackDexMergerTestHelper.java97
-rw-r--r--jack-tests/src/com/android/jack/test/helper/RuntimeTestHelper.java373
-rw-r--r--jack-tests/src/com/android/jack/test/helper/SourceToDexComparisonTestHelper.java166
-rw-r--r--jack-tests/src/com/android/jack/test/runner/AbstractRuntimeRunner.java73
-rw-r--r--jack-tests/src/com/android/jack/test/runner/ArtRunnerDevice.java70
-rw-r--r--jack-tests/src/com/android/jack/test/runner/ArtRunnerHost.java66
-rw-r--r--jack-tests/src/com/android/jack/test/runner/DalvikRunner.java49
-rw-r--r--jack-tests/src/com/android/jack/test/runner/DalvikRunnerDevice.java81
-rw-r--r--jack-tests/src/com/android/jack/test/runner/DalvikRunnerHost.java78
-rw-r--r--jack-tests/src/com/android/jack/test/runner/DeviceRunner.java336
-rw-r--r--jack-tests/src/com/android/jack/test/runner/HostRunner.java52
-rw-r--r--jack-tests/src/com/android/jack/test/runner/RuntimeRunner.java46
-rw-r--r--jack-tests/src/com/android/jack/test/runner/RuntimeRunnerException.java40
-rw-r--r--jack-tests/src/com/android/jack/test/runner/RuntimeRunnerFactory.java87
-rw-r--r--jack-tests/src/com/android/jack/test/runtime/RuntimeTest.java43
-rw-r--r--jack-tests/src/com/android/jack/test/runtime/RuntimeTestInfo.java39
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/AbstractTestTools.java566
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/AndroidToolchain.java49
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/DummyToolchain.java76
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/IToolchain.java81
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/JackApiToolchain.java230
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/JackBasedToolchain.java88
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/JackCliToolchain.java281
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/JillBasedToolchain.java69
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/LegacyJillToolchain.java229
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/LegacyToolchain.java293
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/TestConfigurationException.java43
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/Toolchain.java154
-rw-r--r--jack-tests/src/com/android/jack/test/util/BytesStreamSucker.java74
-rw-r--r--jack-tests/src/com/android/jack/test/util/CharactersStreamSucker.java65
-rw-r--r--jack-tests/src/com/android/jack/test/util/ExecFileException.java65
-rw-r--r--jack-tests/src/com/android/jack/test/util/ExecuteFile.java292
-rw-r--r--jack-tests/src/com/android/jack/test/util/NullPrintStream.java181
-rwxr-xr-xjack-tests/test-exit-status.sh18
-rw-r--r--jack-tests/tests.properties12
-rw-r--r--jack-tests/tests/com/android/jack/AllTests.java54
-rw-r--r--jack-tests/tests/com/android/jack/AllWithRegressionTests.java35
-rw-r--r--jack-tests/tests/com/android/jack/RegressionTests.java56
-rw-r--r--jack-tests/tests/com/android/jack/annotation/AnnotationTests.java66
-rw-r--r--jack-tests/tests/com/android/jack/arithmetic/ArithmeticTests.java50
-rw-r--r--jack-tests/tests/com/android/jack/classpath/ClasspathTest.java77
-rw-r--r--jack-tests/tests/com/android/jack/enums/EnumTests.java43
-rw-r--r--jack-tests/tests/com/android/jack/enums/test003/test.properties4
-rw-r--r--jack-tests/tests/com/android/jack/error/AnnotationProcessorErrorTest.java241
-rw-r--r--jack-tests/tests/com/android/jack/error/CommandLineErrorTest.java95
-rw-r--r--jack-tests/tests/com/android/jack/error/FileAccessErrorTest.java180
-rw-r--r--jack-tests/tests/com/android/jack/experimenal/incremental/DependenciesTests005.java80
-rw-r--r--jack-tests/tests/com/android/jack/invoke/test001/jack/InvokeClone.java2
-rw-r--r--jack-tests/tests/com/android/jack/jarjar/JarjarTests.java48
-rw-r--r--jack-tests/tests/com/android/jack/java7/ExceptionsTest.java74
-rw-r--r--jack-tests/tests/com/android/jack/shrob/AbstractTest.java561
-rw-r--r--jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java166
-rw-r--r--jack-tests/tests/com/android/jack/tools/merger/MergerAllTests.java28
-rw-r--r--jack-tests/tests/com/android/jack/tools/merger/MergerTestTools.java59
-rw-r--r--jack-tests/tests/com/android/jack/tools/merger/test011/MergerTest011.java185
-rw-r--r--jack/src/com/android/jack/Options.java18
-rw-r--r--jack/tests/com/android/jack/AllTestsWithoutKnownBugs.java34
-rw-r--r--junit4/Android.mk17
83 files changed, 7901 insertions, 5 deletions
diff --git a/build.xml b/build.xml
index 697bc5a..b0b4d34 100644
--- a/build.xml
+++ b/build.xml
@@ -52,6 +52,7 @@
<property name="jack-tests.dir" value="${jack-project.dir}/jack-tests" />
<property name="antlr.dir" value="${jack-project.dir}/antlr"/>
<property name="args4j.dir" value="${jack-project.dir}/args4j"/>
+ <property name="ddm-lib.dir" value="${jack-project.dir}/ddmlib"/>
<property name="dx.dir" value="${jack-project.dir}/dx"/>
<property name="ecj.dir" value="${jack-project.dir}/ecj"/>
<property name="freemarker.dir" value="${jack-project.dir}/freemarker"/>
@@ -275,23 +276,72 @@
<!-- jack-tests -->
<!-- ******************* -->
<property name="jack-tests.libs.dir" value="${jack-tests.dir}/libs" />
+ <property name="jack-tests.build.dir" value="${jack-tests.dir}/build" />
+ <property name="jack-tests.dist.dir" value="${jack-tests.dir}/dist" />
+ <property name="jack-tests.libname" value="jack-tests-lib.jar" />
<target name="jack-tests-clean">
<delete dir="${jack-tests.libs.dir}" />
</target>
- <target name="jack-tests" depends="core-stubs-mini,junit4">
- <!-- project layout -->
- <mkdir dir="${jack-tests.libs.dir}" />
- <!-- fetch dependencies -->
+ <target name="jack-tests-copy-libs" depends="core-stubs-mini,junit4,dx-ref-lib,ddm-lib,ecj,
+ antlr-rt-lib,guava-lib,dex-lib,jsr305-lib,dexcomparator-lib">
<copy todir="${jack-tests.libs.dir}" flatten="true">
<filelist dir="/" >
<file name="${junit4.dist.dir}/${junit4.execname}"/>
<file name="${core-stubs-mini.dist.dir}/${core-stubs-mini.libname}"/>
+ <file name="${dx-ref.dist.dir}/${dx-ref.libname}"/>
+ <file name="${ddm-lib.dist.dir}/${ddm-lib.libname}"/>
+ <file name="${ecj.dist.dir}/${ecj.libname}"/>
+ <file name="${antlr-rt.dist.dir}/${antlr-rt.libname}"/>
+ <file name="${guava.dist.dir}/${guava.libname}"/>
+ <file name="${dexlib.dist.dir}/${dexlib.libname}"/>
+ <file name="${jsr305.dist.dir}/${jsr305.libname}"/>
+ <file name="${dexcomparator.dist.dir}/${dexcomparator.libname}"/>
</filelist>
</copy>
</target>
+ <target name="jack-tests" depends="jack-tests-copy-libs">
+ <!-- project layout -->
+ <mkdir dir="${jack-tests.build.outdir}"/>
+ <mkdir dir="${jack-tests.dist.dir}"/>
+ <!-- compile -->
+ <javac
+ destdir="${jack-tests.build.outdir}"
+ source="1.5" target="1.5"
+ debug="true" includeantruntime="false">
+ <src path="${jack-tests.dir}/src"/>
+ <src path="${jack-tests.dir}/tests"/>
+ <exclude name="com/android/jack/classpath/test002/lib1override/**"/>
+ <exclude name="com/android/jack/enums/test003/link/Other.java"/>
+ <exclude name="com/android/jack/enums/test003/link/Values.java"/>
+ <exclude name="com/android/jack/error/test001/jack/A.java"/>
+ <exclude name="com/android/jack/error/test002/jack/A.java"/>
+ <exclude name="com/android/jack/nopackage/jack/**"/>
+ <exclude name="com/android/jack/java7/boxing/**"/>
+ <exclude name="com/android/jack/java7/switches/**"/>
+ <exclude name="com/android/jack/java7/exceptions/**"/>
+ <exclude name="com/android/jack/java7/trywithresources/**"/>
+ <exclude name="com/android/jack/java7/parser/**"/>
+ <exclude name="com/android/jack/jarjar/test003/dontcompile/**"/>
+ <exclude name="com/android/jack/lookup/test001/liboverride/**"/>
+ <classpath>
+ <filelist dir=".">
+ <!-- <file name="${jsr305.dist.dir}/${jsr305.libname}" /> -->
+ <file name="${junit4.dist.dir}/${junit4.libname}" />
+ <file name="${jackunittests.dist.dir}/${jackunittests.libname}" />
+ <file name="${dexcomparator.dist.dir}/${dexcomparator.libname}" />
+ <file name="${ddm-lib.dist.dir}/${ddm-lib.libname}" />
+ </filelist>
+ </classpath>
+ </javac>
+ <!-- package -->
+ <jar destfile="${jack-tests.dist.dir}/${jack-tests.libname}"
+ basedir="${jack-tests.build.outdir}"
+ includes="**"/>
+ </target>
+
<!-- ******************* -->
<!-- antlr -->
@@ -344,6 +394,22 @@
<!-- ******************* -->
+ <!-- ddmlib -->
+ <!-- ******************* -->
+ <property name="ddm-lib.libname" value="ddmlib.jar"/>
+ <property name="ddm-lib.dist.dir" value="${ddm-lib.dir}/dist"/>
+
+ <target name="ddm-lib-clean">
+ <delete dir="${ddm-lib.dist.dir}"/>
+ </target>
+
+ <target name="ddm-lib">
+ <mkdir dir="${ddm-lib.dist.dir}"/>
+ <copy file="${ddm-lib.dir}/ddmlib.jar" tofile="${ddm-lib.dist.dir}/${ddm-lib.libname}"/>
+ </target>
+
+
+ <!-- ******************* -->
<!-- dx-lib -->
<!-- ******************* -->
<property name="dx.build.dir" value="${dx.dir}/build"/>
diff --git a/ddmlib/README.android b/ddmlib/README.android
new file mode 100644
index 0000000..9729ef7
--- /dev/null
+++ b/ddmlib/README.android
@@ -0,0 +1,9 @@
+URL: https://android.git.corp.google.com/platform/prebuilts/devtools/+/42f8ef3570f43414858a974ddd593ac13ab02163/tools/lib/ddmlib.jar
+Tag: AOSP master, prebuilts/devtools
+License: Apache 2
+Description: A library to control android/host operations.
+Local Modifications: None.
+
+Commit 42f8ef3570f43414858a974ddd593ac13ab02163
+from branch master
+
diff --git a/ddmlib/ddmlib.jar b/ddmlib/ddmlib.jar
new file mode 100644
index 0000000..5b9e8bb
--- /dev/null
+++ b/ddmlib/ddmlib.jar
Binary files differ
diff --git a/hamcrest-core/Android.mk b/hamcrest-core/Android.mk
index 547bdad..e41fbde 100644
--- a/hamcrest-core/Android.mk
+++ b/hamcrest-core/Android.mk
@@ -39,3 +39,13 @@ LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_JAVA_LIBRARY)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := hamcrest-core-target-jack
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_JAVA_LIBRARY)
+
diff --git a/jack-tests/.checkstyle b/jack-tests/.checkstyle
new file mode 100644
index 0000000..5cc9f9e
--- /dev/null
+++ b/jack-tests/.checkstyle
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
+ <local-check-config name="Jack Tests CheckStyle" location="jackstyle.xml" type="project" description="">
+ <additional-data name="protect-config-file" value="true"/>
+ </local-check-config>
+ <fileset name="all" enabled="false" check-config-name="Sun Checks" local="false">
+ <file-match-pattern match-pattern="." include-pattern="true"/>
+ </fileset>
+ <fileset name="Jack Tests Checkstyle" enabled="true" check-config-name="Jack Tests CheckStyle" local="true">
+ <file-match-pattern match-pattern="^src.*\.java$" include-pattern="true"/>
+ </fileset>
+</fileset-config>
diff --git a/jack-tests/.classpath b/jack-tests/.classpath
index ad8cdf8..b61e0f4 100644
--- a/jack-tests/.classpath
+++ b/jack-tests/.classpath
@@ -4,5 +4,15 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry excluding="com/android/jack/classpath/test002/lib1override/|com/android/jack/compiletime/|com/android/jack/enums/test003/link/Other.java|com/android/jack/enums/test003/link/Values.java|com/android/jack/error/test001/jack/A.java|com/android/jack/error/test002/jack/A.java|com/android/jack/java7/boxing/|com/android/jack/java7/exceptions/|com/android/jack/java7/parser/|com/android/jack/java7/switches/|com/android/jack/java7/trywithresources/|com/android/jack/nopackage/jack/|com/android/jack/lookup/test001/liboverride/|com/android/jack/jarjar/test003/dontcompile/" kind="src" path="tests"/>
<classpathentry kind="lib" path="libs/junit4.jar"/>
+ <classpathentry kind="lib" path="libs/antlr-runtime-lib.jar"/>
+ <classpathentry kind="lib" path="libs/dx-ref.jar"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/dexcomparator"/>
+ <classpathentry kind="lib" path="libs/ecj.jar"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/Scheduler"/>
+ <classpathentry kind="lib" path="libs/guava-lib.jar"/>
+ <classpathentry kind="lib" path="libs/dex-lib.jar"/>
+ <classpathentry kind="lib" path="libs/jsr305-lib.jar"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/Jack"/>
+ <classpathentry kind="lib" path="libs/ddmlib.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/jack-tests/.project b/jack-tests/.project
index f4f439a..0461f29 100644
--- a/jack-tests/.project
+++ b/jack-tests/.project
@@ -10,8 +10,14 @@
<arguments>
</arguments>
</buildCommand>
+ <buildCommand>
+ <name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
</natures>
</projectDescription>
diff --git a/jack-tests/jackstyle.xml b/jack-tests/jackstyle.xml
new file mode 100644
index 0000000..3940973
--- /dev/null
+++ b/jack-tests/jackstyle.xml
@@ -0,0 +1,314 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC
+ "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
+ "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+
+<!-- This is a checkstyle configuration file. For descriptions of
+what the following rules do, please see the checkstyle configuration
+page at http://checkstyle.sourceforge.net/config.html -->
+
+<!-- Checks with numbered comments refer to recommendations made
+by Joshua Bloch in his book Effective Java -->
+
+<module name="Checker">
+ <property name="charset" value="UTF-8"/>
+ <module name="FileTabCharacter">
+ <!-- Checks that there are no tab characters in the file.
+ -->
+ </module>
+
+ <module name="RegexpSingleline">
+ <!-- Checks that FIXME is not used in comments. TODO is preferred.
+ -->
+ <property name="format" value="((//.*)|(\*.*))FIXME" />
+ <property name="message" value='TODO is preferred to FIXME. e.g. "TODO(johndoe): Refactor when v2 is released."' />
+ </module>
+
+ <module name="RegexpSingleline">
+ <!-- Checks that TODOs are properly formatted.
+
+ The (?&lt;!TODO\(.{0,100}) makes the regex ignore any secondary TODO's on the line
+ so that things like //TODO(bob): remove this TODO on 1/1/2020 don't trigger a warning
+ because of the second TODO. (The {0,100} is because java doesn't recoginize arbitrary
+ length look backs, but we know each java line should be < 100 chars.)
+ -->
+ <property name="format" value="((//.*)|(\*.*))(?&lt;!TODO\(.{0,100})(TODO[^(])|(TODO\([^)]*$)" />
+ <property name="message" value='All TODOs should be named. e.g. "TODO(johndoe): Refactor when v2 is released."' />
+ </module>
+
+
+ <!-- All Java AST specific tests live under TreeWalker module. -->
+ <module name="TreeWalker">
+
+ <!--
+
+ IMPORT CHECKS
+
+ -->
+
+ <module name="RedundantImport">
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="AvoidStarImport">
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="UnusedImports">
+ <!-- DPL is a notable violator of this rule. -->
+ <property name="severity" value="error"/>
+ <!-- Imports used only in Javadoc are tolerated. -->
+ <property name="processJavadoc" value="true"/>
+ <message
+ key="import.unused"
+ value="Unused import: {0}." />
+ </module>
+
+ <module name="ImportOrder">
+ <!-- Checks for out of order import statements. -->
+ <property name="severity" value="warning"/>
+ <property name="groups" value="com.google,*,java,javax"/>
+ <!-- This ensures that static imports go first. -->
+ <property name="option" value="top"/>
+ <property name="tokens" value="STATIC_IMPORT, IMPORT"/>
+ </module>
+
+ <!--
+
+ JAVADOC CHECKS
+
+ -->
+
+ <module name="JavadocType">
+ <!-- Item 28 - Write doc comments for all exposed API elements. -->
+ <!-- Ensure all classes with visability greater than or equal to
+ protected have class level documentation. -->
+ <property name="scope" value="protected"/>
+ <property name="severity" value="error"/>
+ <!-- Style guide doesn't prohibit custom tags. Typos will be caught by other tools. -->
+ <property name="allowUnknownTags" value="true"/>
+ <property name="allowMissingParamTags" value="true"/>
+ <message key="javadoc.missing"
+ value="Missing a Javadoc comment."/>
+ </module>
+
+ <!--
+
+ NAMING CHECKS
+
+ -->
+
+ <!-- Item 38 - Adhere to generally accepted naming conventions -->
+
+ <module name="PackageName">
+ <!-- Validates identifiers for package names against the
+ supplied expression. -->
+ <!-- Here the default checkstyle rule restricts package name parts to
+ seven characters, this is not in line with common practice at Google.
+ -->
+ <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]{1,})*$"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="TypeNameCheck">
+ <metadata name="altname" value="TypeName"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="StaticVariableNameCheck">
+ <!-- Validates static, non-final fields against the supplied
+ expression "^[a-z][a-zA-Z0-9]*?$". -->
+ <metadata name="altname" value="StaticVariableName"/>
+ <property name="applyToPublic" value="true"/>
+ <property name="applyToProtected" value="true"/>
+ <property name="applyToPackage" value="true"/>
+ <property name="applyToPrivate" value="true"/>
+ <property name="format" value="^[a-z][a-zA-Z0-9]*?$"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="MemberNameCheck">
+ <!-- Validates non-static members against the supplied expression. -->
+ <metadata name="altname" value="MemberName"/>
+ <property name="applyToPublic" value="true"/>
+ <property name="applyToProtected" value="true"/>
+ <property name="applyToPackage" value="true"/>
+ <property name="applyToPrivate" value="true"/>
+ <property name="format" value="^[a-z][a-zA-Z0-9]*?$"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="MethodNameCheck">
+ <!-- Validates identifiers for method names. -->
+ <metadata name="altname" value="MethodName"/>
+ <property name="format" value="^[a-z][a-zA-Z0-9]*([a-zA-Z0-9]+)*$"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="ParameterName">
+ <!-- Validates identifiers for method parameters against the
+ expression "^[a-z][a-zA-Z0-9]*$". -->
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="LocalFinalVariableName">
+ <!-- Validates identifiers for local final variables against the
+ expression "^[a-z][a-zA-Z0-9]*$". -->
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="LocalVariableName">
+ <!-- Validates identifiers for local variables against the
+ expression "^[a-z][a-zA-Z0-9]*$". -->
+ <property name="severity" value="warning"/>
+ </module>
+
+
+ <!--
+
+ LENGTH and CODING CHECKS
+
+ -->
+
+ <module name="LineLength">
+ <!-- Checks if a line is too long. -->
+ <property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="100"/>
+ <property name="severity" value="error"/>
+
+ <!--
+ The default ignore pattern exempts the following elements:
+ - import statements
+ - long URLs inside comments
+ -->
+
+ <property name="ignorePattern"
+ value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
+ default="^(package .*;\s*)|(import .*;\s*)|( *\* *https?://.*)|(\s*@[\w\.\$]+::\w+(?:\([^\(]*\)|\(\)\(\))?[,;]?)|(\s+\* \{@(link|see) [^\s][^\}]*\}[\.,;]?)$"/>
+ </module>
+
+ <module name="LeftCurly">
+ <!-- Checks for placement of the left curly brace ('{'). -->
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="RightCurly">
+ <!-- Checks right curlies on CATCH, ELSE, and TRY blocks are on
+ the same line. e.g., the following example is fine:
+ <pre>
+ if {
+ ...
+ } else
+ </pre>
+ -->
+ <!-- This next example is not fine:
+ <pre>
+ if {
+ ...
+ }
+ else
+ </pre>
+ -->
+ <property name="option" value="same"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <!-- Checks for braces around if and else blocks -->
+ <module name="NeedBraces">
+ <property name="severity" value="warning"/>
+ <property name="tokens" value="LITERAL_IF, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO"/>
+ </module>
+
+ <module name="UpperEll">
+ <!-- Checks that long constants are defined with an upper ell.-->
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="FallThrough">
+ <!-- Warn about falling through to the next case statement. Similar to
+ javac -Xlint:fallthrough, but the check is suppressed if there is a single-line comment
+ on the last non-blank line preceding the fallen-into case.
+ -->
+ <property name="reliefPattern"
+ value=".*"/>
+ <property name="severity" value="error"/>
+ </module>
+
+
+ <!--
+
+ MODIFIERS CHECKS
+
+ -->
+
+ <module name="ModifierOrder">
+ <!-- Warn if modifier order is inconsistent with JLS3 8.1.1, 8.3.1, and
+ 8.4.3. The prescribed order is:
+ public, protected, private, abstract, static, final, transient, volatile,
+ synchronized, native, strictfp
+ -->
+ </module>
+
+
+ <!--
+
+ WHITESPACE CHECKS
+
+ -->
+
+ <module name="WhitespaceAround">
+ <!-- Checks that various tokens are surrounded by whitespace.
+ This includes most binary operators and keywords followed
+ by regular or curly braces.
+ -->
+ <property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,
+ BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,
+ EQUAL, GE, GT, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
+ LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
+ LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,
+ MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,
+ SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="WhitespaceAfter">
+ <!-- Checks that commas, semicolons and typecasts are followed by
+ whitespace.
+ -->
+ <property name="tokens" value="COMMA, SEMI, TYPECAST"/>
+ </module>
+
+ <module name="NoWhitespaceAfter">
+ <!-- Checks that there is no whitespace after various unary operators.
+ Linebreaks are allowed.
+ -->
+ <property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS,
+ UNARY_PLUS"/>
+ <property name="allowLineBreaks" value="true"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="NoWhitespaceBefore">
+ <!-- Checks that there is no whitespace before various unary operators.
+ Linebreaks are allowed.
+ -->
+ <property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/>
+ <property name="allowLineBreaks" value="true"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="ParenPad">
+ <!-- Checks that there is no whitespace before close parens or after
+ open parens.
+ -->
+ <property name="severity" value="warning"/>
+ </module>
+
+ <!--
+
+ MISC CHECKS
+
+ -->
+
+ </module>
+</module>
+
diff --git a/jack-tests/prebuilts/core-hostdex.jar b/jack-tests/prebuilts/core-hostdex.jar
new file mode 100644
index 0000000..05de7fb
--- /dev/null
+++ b/jack-tests/prebuilts/core-hostdex.jar
Binary files differ
diff --git a/jack-tests/prebuilts/jarjar.jar b/jack-tests/prebuilts/jarjar.jar
new file mode 100644
index 0000000..89390bf
--- /dev/null
+++ b/jack-tests/prebuilts/jarjar.jar
Binary files differ
diff --git a/jack-tests/prebuilts/junit4-hostdex.jar b/jack-tests/prebuilts/junit4-hostdex.jar
new file mode 100644
index 0000000..cb4a0b7
--- /dev/null
+++ b/jack-tests/prebuilts/junit4-hostdex.jar
Binary files differ
diff --git a/jack-tests/prebuilts/proguard.jar b/jack-tests/prebuilts/proguard.jar
new file mode 100644
index 0000000..56d68ba
--- /dev/null
+++ b/jack-tests/prebuilts/proguard.jar
Binary files differ
diff --git a/jack-tests/src/com/android/jack/test/category/RuntimeRegressionTest.java b/jack-tests/src/com/android/jack/test/category/RuntimeRegressionTest.java
new file mode 100644
index 0000000..b969a69
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/category/RuntimeRegressionTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.category;
+
+/**
+ * Tests that can be grouped in one compilation step for
+ * regression tests.
+ */
+public interface RuntimeRegressionTest {
+
+}
diff --git a/jack-tests/src/com/android/jack/test/comparator/Comparator.java b/jack-tests/src/com/android/jack/test/comparator/Comparator.java
new file mode 100644
index 0000000..794a465
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/comparator/Comparator.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.comparator;
+
+import com.android.jack.DifferenceFoundException;
+
+/**
+ * Common interface for comparator.
+ */
+public interface Comparator {
+
+ void compare() throws DifferenceFoundException, ComparatorException;
+
+}
diff --git a/jack-tests/src/com/android/jack/test/comparator/ComparatorComposite.java b/jack-tests/src/com/android/jack/test/comparator/ComparatorComposite.java
new file mode 100644
index 0000000..438e78e
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/comparator/ComparatorComposite.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.comparator;
+
+import com.android.jack.DifferenceFoundException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {link Comparator} is composed of one or several comparators.
+ */
+public class ComparatorComposite implements Comparator {
+
+ @Nonnull
+ private List<Comparator> comparators = new ArrayList<Comparator>();
+
+ public ComparatorComposite(@Nonnull Comparator... comparators) {
+ for (Comparator comparator : comparators) {
+ this.comparators.add(comparator);
+ }
+ }
+
+ @Override
+ public void compare() throws DifferenceFoundException, ComparatorException {
+ for (Comparator comparator : comparators) {
+ comparator.compare();
+ }
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/comparator/ComparatorDex.java b/jack-tests/src/com/android/jack/test/comparator/ComparatorDex.java
new file mode 100644
index 0000000..ddfa3fd
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/comparator/ComparatorDex.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.comparator;
+
+import com.android.jack.DexComparator;
+import com.android.jack.DifferenceFoundException;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link Comparator} is used ton compare dex files.
+ */
+public class ComparatorDex extends ComparatorFile {
+
+ private boolean withDebugInfo = false;
+ private boolean strict = false;
+ private boolean compareDebugInfoBinary = false;
+ private boolean compareInstructionNumber = false;
+ private float instructionNumberTolerance = 0f;
+
+ public ComparatorDex(@Nonnull File candidate, @Nonnull File reference) {
+ super(candidate, reference);
+ }
+
+ @Nonnull
+ public ComparatorDex setWithDebugInfo(boolean withDebugInfo) {
+ this.withDebugInfo = withDebugInfo;
+ return this;
+ }
+
+ @Nonnull
+ public ComparatorDex setStrict(boolean strict) {
+ this.strict = strict;
+ return this;
+ }
+
+ @Nonnull
+ public ComparatorDex setCompareDebugInfoBinary(boolean compareDebugInfoBinary) {
+ this.compareDebugInfoBinary = compareDebugInfoBinary;
+ return this;
+ }
+
+ @Nonnull
+ public ComparatorDex setCompareInstructionNumber(boolean compareInstructionNumber) {
+ this.compareInstructionNumber = compareInstructionNumber;
+ return this;
+ }
+
+ @Nonnull
+ public ComparatorDex setInstructionNumberTolerance(float instructionNumberTolerance) {
+ this.instructionNumberTolerance = instructionNumberTolerance;
+ return this;
+ }
+
+ @Override
+ public void compare() throws DifferenceFoundException, ComparatorException {
+ try {
+ new DexComparator(withDebugInfo, strict, compareDebugInfoBinary, compareInstructionNumber,
+ instructionNumberTolerance).compare(reference, candidate);
+ } catch (IOException e) {
+ throw new ComparatorException(e);
+ }
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/comparator/ComparatorDexAnnotations.java b/jack-tests/src/com/android/jack/test/comparator/ComparatorDexAnnotations.java
new file mode 100644
index 0000000..a72c319
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/comparator/ComparatorDexAnnotations.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.comparator;
+
+import com.android.jack.DexAnnotationsComparator;
+import com.android.jack.DifferenceFoundException;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link Comparator} is used to compare dex files annotations.
+ */
+public class ComparatorDexAnnotations extends ComparatorFile {
+
+ public ComparatorDexAnnotations(@Nonnull File candidate, @Nonnull File reference) {
+ super(candidate, reference);
+ }
+
+ @Override
+ public void compare() throws DifferenceFoundException, ComparatorException {
+ try {
+ new DexAnnotationsComparator().compare(reference, candidate);
+ } catch (IOException e) {
+ throw new ComparatorException(e);
+ }
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/comparator/ComparatorDiff.java b/jack-tests/src/com/android/jack/test/comparator/ComparatorDiff.java
new file mode 100644
index 0000000..9c44470
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/comparator/ComparatorDiff.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.comparator;
+
+import com.android.jack.DifferenceFoundException;
+import com.android.jack.test.util.ExecFileException;
+import com.android.jack.test.util.ExecuteFile;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link Comparator} uses the {@code diff} shell command to compare 2 files.
+ */
+public class ComparatorDiff extends ComparatorFile {
+
+ public ComparatorDiff(@Nonnull File candidate, @Nonnull File reference) {
+ super(candidate, reference);
+ }
+
+ @Override
+ public void compare() throws DifferenceFoundException, ComparatorException {
+ try {
+ ExecuteFile ef = new ExecuteFile(
+ "diff " + candidate.getAbsolutePath() + " " + reference.getAbsolutePath());
+ ef.setOut(System.out);
+ ef.setErr(System.err);
+
+ int exitStatus = ef.run();
+ switch (exitStatus) {
+ case 0:
+ break;
+ case 1:
+ throw new DifferenceFoundException();
+ default:
+ throw new ComparatorException("Exit status: " + exitStatus);
+ }
+ } catch (ExecFileException e) {
+ throw new ComparatorException(e);
+ } catch (IOException e) {
+ throw new ComparatorException(e);
+ }
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/comparator/ComparatorException.java b/jack-tests/src/com/android/jack/test/comparator/ComparatorException.java
new file mode 100644
index 0000000..037a501
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/comparator/ComparatorException.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.comparator;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This exception is thrown when something went wrong with the comparator execution.
+ */
+public class ComparatorException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public ComparatorException() {
+ super();
+ }
+
+ public ComparatorException(@Nonnull String message, @Nonnull Throwable cause) {
+ super(message, cause);
+ }
+
+ public ComparatorException(@Nonnull String message) {
+ super(message);
+ }
+
+ public ComparatorException(@Nonnull Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/jack-tests/src/com/android/jack/test/comparator/ComparatorFile.java b/jack-tests/src/com/android/jack/test/comparator/ComparatorFile.java
new file mode 100644
index 0000000..9bdcc2c
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/comparator/ComparatorFile.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.comparator;
+
+import java.io.File;
+
+import javax.annotation.Nonnull;
+
+/**
+ * {@link Comparator}s of this type are used to compare files.
+ */
+public abstract class ComparatorFile implements Comparator {
+
+ @Nonnull
+ protected File candidate;
+ @Nonnull
+ protected File reference;
+
+ protected ComparatorFile(@Nonnull File candidate, @Nonnull File reference) {
+ this.candidate = candidate;
+ this.reference = reference;
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/comparator/ComparatorMapping.java b/jack-tests/src/com/android/jack/test/comparator/ComparatorMapping.java
new file mode 100644
index 0000000..09e78af
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/comparator/ComparatorMapping.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.comparator;
+
+import com.android.jack.DifferenceFoundException;
+import com.android.jack.shrob.ListingComparator;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link Comparator} is used to compare shrob mappings.
+ */
+public class ComparatorMapping extends ComparatorFile {
+
+ public ComparatorMapping(@Nonnull File candidate, @Nonnull File reference) {
+ super(candidate, reference);
+ }
+
+ @Override
+ public void compare() throws DifferenceFoundException, ComparatorException {
+ try {
+ ListingComparator.compare(reference, candidate);
+ } catch (IOException e) {
+ throw new ComparatorException(e);
+ }
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/helper/CheckDexStructureTestHelper.java b/jack-tests/src/com/android/jack/test/helper/CheckDexStructureTestHelper.java
new file mode 100644
index 0000000..f3858bf
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/helper/CheckDexStructureTestHelper.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.helper;
+
+
+import java.io.File;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link SourceToDexComparisonTestHelper} is used to compare dex files structures.
+ */
+public class CheckDexStructureTestHelper extends SourceToDexComparisonTestHelper {
+
+ public CheckDexStructureTestHelper(@Nonnull File fileOrSourceList) throws Exception {
+ super(fileOrSourceList);
+ }
+
+ public void compare() throws Exception {
+ runTest(createDexFileComparator());
+ }
+
+}
diff --git a/jack-tests/src/com/android/jack/test/helper/ErrorTestHelper.java b/jack-tests/src/com/android/jack/test/helper/ErrorTestHelper.java
new file mode 100644
index 0000000..d7142f5
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/helper/ErrorTestHelper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.helper;
+
+import com.android.jack.test.toolchain.AbstractTestTools;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This class is used by error tests, it basically handles the directory structure.
+ */
+public class ErrorTestHelper {
+
+ @Nonnull
+ private final File testingFolder;
+ @Nonnull
+ private final File sourceFolder;
+ @Nonnull
+ private final File jackFolder;
+ @Nonnull
+ private final File outputDexFolder;
+
+ public ErrorTestHelper() throws IOException {
+ this.testingFolder = AbstractTestTools.createTempDir();
+ this.sourceFolder = new File(testingFolder, "src");
+ if (!this.sourceFolder.mkdirs()) {
+ throw new IOException("Failed to create folder " + this.sourceFolder.getPath());
+ }
+ this.jackFolder = new File(testingFolder, "jack");
+ if (!this.jackFolder.mkdirs()) {
+ throw new IOException("Failed to create folder " + this.jackFolder.getPath());
+ }
+ this.outputDexFolder = new File(this.testingFolder, "dex");
+ if (!this.outputDexFolder.mkdirs()) {
+ throw new IOException("Failed to create folder " + this.outputDexFolder.getPath());
+ }
+ }
+
+ @Nonnull
+ public File getSourceFolder() {
+ return sourceFolder;
+ }
+
+ @Nonnull
+ public File getJackFolder() {
+ return jackFolder;
+ }
+
+ @Nonnull
+ public File getTestingFolder() {
+ return testingFolder;
+ }
+
+ @Nonnull
+ public File getOutputDexFolder() {
+ return outputDexFolder;
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/helper/GenericComparisonTestHelper.java b/jack-tests/src/com/android/jack/test/helper/GenericComparisonTestHelper.java
new file mode 100644
index 0000000..0b947ee
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/helper/GenericComparisonTestHelper.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.helper;
+
+import com.android.jack.test.comparator.Comparator;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This class implements a pattern of tests where two compilers are used on the same
+ * sources and the result is then compared with a variety of {@link Comparator}s.
+ */
+public abstract class GenericComparisonTestHelper {
+
+ @Nonnull
+ protected abstract void executeCandidateToolchain() throws Exception;
+ @Nonnull
+ protected abstract void executeReferenceToolchain() throws Exception;
+
+ public final void runTest(@Nonnull Comparator... comparators) throws Exception {
+
+ assert comparators.length > 0 : "You must provide at least one comparator";
+
+ executeCandidateToolchain();
+ executeReferenceToolchain();
+
+ for (Comparator comparator : comparators) {
+ comparator.compare();
+ }
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/helper/IncrementalTestHelper.java b/jack-tests/src/com/android/jack/test/helper/IncrementalTestHelper.java
new file mode 100644
index 0000000..4f5e172
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/helper/IncrementalTestHelper.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.helper;
+
+import com.android.jack.backend.jayce.JayceFileImporter;
+import com.android.jack.test.runner.DalvikRunnerHost;
+import com.android.jack.test.runner.RuntimeRunnerFactory;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.JackBasedToolchain;
+import com.android.jack.test.toolchain.JillBasedToolchain;
+
+import junit.framework.Assert;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This class is used to write tests on incremental compilation.
+ */
+public class IncrementalTestHelper {
+
+ @Nonnull
+ private final File testingFolder;
+ @Nonnull
+ private final File sourceFolder;
+ @Nonnull
+ private final File dexOutDir;
+ @Nonnull
+ private final File dexFile;
+ @Nonnull
+ private final File compilerStateFolder;
+ @Nonnull
+ private final File jackFolder;
+ @Nonnull
+ private final Set<File> javaFiles = new HashSet<File>();
+ @Nonnull
+ private final Map<String, Long> fileModificationDate = new HashMap<String, Long>();
+
+ public IncrementalTestHelper(@Nonnull File testingFolder) throws IOException {
+ this.testingFolder = testingFolder;
+ this.sourceFolder = new File(testingFolder, "src");
+ if (!this.sourceFolder.mkdirs()) {
+ throw new IOException("Failed to create folder " + this.sourceFolder.getAbsolutePath());
+ }
+ compilerStateFolder = new File(testingFolder, "compileState");
+ if (!compilerStateFolder.exists() && !compilerStateFolder.mkdir()) {
+ throw new IOException("Failed to create folder " + compilerStateFolder.getAbsolutePath());
+ }
+ dexOutDir = new File(testingFolder, "outputBinary");
+ if (!dexOutDir.exists() && !dexOutDir.mkdir()) {
+ throw new IOException("Failed to create folder " + dexOutDir.getAbsolutePath());
+ }
+ dexFile = new File(dexOutDir, "classes.dex");
+ jackFolder = new File(compilerStateFolder, "jackFiles");
+ }
+
+ @Nonnull
+ public File addJavaFile(@Nonnull String packageName, @Nonnull String fileName,
+ @Nonnull String fileContent) throws IOException {
+ File file = AbstractTestTools.createJavaFile(sourceFolder, packageName, fileName, fileContent);
+ javaFiles.add(file);
+ return file;
+ }
+
+ public void deleteJavaFile(@Nonnull File javaFile)
+ throws IOException {
+ AbstractTestTools.deleteFile(javaFile);
+ javaFiles.remove(javaFile);
+ }
+
+ @Nonnull
+ public File getCompilerStateFolder() {
+ return compilerStateFolder;
+ }
+
+ public void cleanSnapshot() {
+ fileModificationDate.clear();
+ }
+
+ public void snapshotJackFilesModificationDate() {
+ List<File> jackFiles = new ArrayList<File>();
+ fillJackFiles(jackFolder, jackFiles);
+ for (File jackFile : jackFiles) {
+ fileModificationDate.put(jackFile.getAbsolutePath(), Long.valueOf(jackFile.lastModified()));
+ }
+ }
+
+ private void fillJackFiles(@Nonnull File file, @Nonnull List<File> jackFiles) {
+ if (file.isDirectory()) {
+ for (File subFile : file.listFiles()) {
+ fillJackFiles(subFile, jackFiles);
+ }
+ } else if (file.getName().endsWith(JayceFileImporter.JAYCE_FILE_EXTENSION)) {
+ jackFiles.add(file);
+ }
+ }
+
+ @Nonnull
+ public List<String> getFQNOfRebuiltTypes() {
+ assert !fileModificationDate.isEmpty();
+
+ List<String> fqnOfRebuiltTypes = new ArrayList<String>();
+ List<File> jackFiles = new ArrayList<File>();
+ fillJackFiles(jackFolder, jackFiles);
+
+ for (File jackFile : jackFiles) {
+ Long previousDate = fileModificationDate.get(jackFile.getAbsolutePath());
+ if (previousDate == null || jackFile.lastModified() > previousDate.longValue()) {
+ String jackFileName = jackFile.getAbsolutePath();
+ String binaryTypeName = jackFileName.substring(0, jackFileName.indexOf(".jack"));
+ binaryTypeName = binaryTypeName.substring(jackFolder.getAbsolutePath().length() + 1);
+ fqnOfRebuiltTypes.add(binaryTypeName.replace(File.separatorChar, '.'));
+ }
+ }
+
+ return (fqnOfRebuiltTypes);
+ }
+
+ public void incrementalBuildFromFolder() throws Exception {
+ JackBasedToolchain jackToolchain =
+ AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class, JillBasedToolchain.class);
+ jackToolchain.setIncrementalFolder(getCompilerStateFolder());
+
+ jackToolchain.srcToExe(
+ AbstractTestTools.getClasspathAsString(jackToolchain.getDefaultBootClasspath()), dexOutDir,
+ sourceFolder);
+
+ Thread.sleep(1000);
+ }
+
+ @Nonnull
+ public String run(@Nonnull String mainClass) throws Exception {
+ DalvikRunnerHost runner =
+ (DalvikRunnerHost) RuntimeRunnerFactory.create("dalvik-fast-host");
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ runner.setOutputStream(out);
+ Assert.assertEquals(0, runner.run(new String [0], new String[] {mainClass}, dexFile));
+ return out.toString();
+ }
+
+ @Nonnull
+ public List<File> getJackFiles() {
+ return AbstractTestTools.getFiles(jackFolder, ".jack");
+ }
+
+}
diff --git a/jack-tests/src/com/android/jack/test/helper/JackDexMergerTestHelper.java b/jack-tests/src/com/android/jack/test/helper/JackDexMergerTestHelper.java
new file mode 100644
index 0000000..b9d8669
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/helper/JackDexMergerTestHelper.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.helper;
+
+import com.android.jack.Options;
+import com.android.jack.TestTools;
+import com.android.jack.backend.dex.rop.CodeItemBuilder;
+import com.android.jack.test.comparator.Comparator;
+import com.android.jack.test.comparator.ComparatorComposite;
+import com.android.jack.test.comparator.ComparatorDex;
+import com.android.jack.test.comparator.ComparatorDexAnnotations;
+import com.android.jack.test.comparator.ComparatorDiff;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.JackBasedToolchain;
+import com.android.sched.scheduler.ScheduleInstance;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This class defines a helper for dex merger tests.
+ */
+public class JackDexMergerTestHelper extends SourceToDexComparisonTestHelper {
+
+ public JackDexMergerTestHelper(@Nonnull File fileOrSourceList) throws Exception {
+ super(fileOrSourceList);
+ }
+
+ @Override
+ @Nonnull
+ protected JackBasedToolchain getCandidateToolchain() {
+ // Mono dex
+ JackBasedToolchain toolchain =
+ AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ toolchain.addProperty(Options.EMIT_LINE_NUMBER_DEBUG_INFO.getName(),
+ Boolean.toString(withDebugInfos));
+ toolchain.addProperty(ScheduleInstance.DEFAULT_RUNNER.getName(), "single-threaded");
+ toolchain.addProperty(CodeItemBuilder.FORCE_JUMBO.getName(), "true");
+
+ return toolchain;
+ }
+
+ @Override
+ @Nonnull
+ protected JackBasedToolchain getReferenceToolchain() {
+ // One dex per type
+ JackBasedToolchain toolchain =
+ AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ File oneDexPerTypeFolder;
+ try {
+ oneDexPerTypeFolder = TestTools.createTempDir("oneDexPerType", "dex");
+ toolchain.addProperty(Options.EMIT_LINE_NUMBER_DEBUG_INFO.getName(),
+ Boolean.toString(withDebugInfos));
+ toolchain.addProperty(ScheduleInstance.DEFAULT_RUNNER.getName(), "single-threaded");
+ toolchain.addProperty(Options.TYPEDEX_DIR.getName(),
+ oneDexPerTypeFolder.getAbsolutePath());
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ return toolchain;
+ }
+
+ @Override
+ @Nonnull
+ public Comparator createDexFileComparator() {
+ ComparatorDex comparatorDex = new ComparatorDex(candidateDex, refDex);
+ comparatorDex.setWithDebugInfo(false);
+ comparatorDex.setStrict(true);
+ comparatorDex.setCompareDebugInfoBinary(false);
+ comparatorDex.setCompareInstructionNumber(true);
+ comparatorDex.setInstructionNumberTolerance(0);
+ ComparatorDexAnnotations comparatorAnnotations =
+ new ComparatorDexAnnotations(candidateDex, refDex);
+ ComparatorDiff comparatorDiff = new ComparatorDiff(candidateDex, refDex);
+ return new ComparatorComposite(comparatorDex, comparatorAnnotations, comparatorDiff);
+ }
+
+ public void compare() throws Exception {
+ runTest(createDexFileComparator());
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/helper/RuntimeTestHelper.java b/jack-tests/src/com/android/jack/test/helper/RuntimeTestHelper.java
new file mode 100644
index 0000000..2923699
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/helper/RuntimeTestHelper.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.helper;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+
+import com.android.jack.test.runner.RuntimeRunner;
+import com.android.jack.test.runtime.RuntimeTestInfo;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.AndroidToolchain;
+import com.android.jack.test.toolchain.Toolchain.SourceLevel;
+import com.android.sched.util.collect.Lists;
+
+import junit.framework.Assert;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * This class is used to write runtime tests.
+ */
+public class RuntimeTestHelper {
+
+ @Nonnull
+ private AndroidToolchain candidateTestTools;
+ @Nonnull
+ private AndroidToolchain referenceTestTools;
+
+ @Nonnull
+ private List<File> baseDirs = new ArrayList<File>(1);
+ @Nonnull
+ private List<String> jUnitClasses = new ArrayList<String>(1);
+
+ @Nonnull
+ private String srcDirName = "jack";
+ @Nonnull
+ private String libDirName = "lib";
+ @Nonnull
+ private String refDirName = "dx";
+ @Nonnull
+ private String linkDirName = "link";
+
+ private boolean withDebugInfos = false;
+
+ @CheckForNull
+ private String jarjarRulesFileName;
+ @CheckForNull
+ private String[] proguardFlagsFileNames;
+
+ @Nonnull
+ private String propertyFileName = "test.properties";
+
+ {
+ candidateTestTools = AbstractTestTools.getCandidateToolchain(AndroidToolchain.class);
+ referenceTestTools = AbstractTestTools.getReferenceToolchain(AndroidToolchain.class);
+ }
+
+ public RuntimeTestHelper(@Nonnull RuntimeTestInfo... rtTestInfos) {
+ for (RuntimeTestInfo info : rtTestInfos) {
+ baseDirs.add(info.directory);
+ jUnitClasses.add(info.jUnit);
+ }
+ }
+
+ @Nonnull
+ public RuntimeTestHelper setSrcDirName(@Nonnull String srcDirName) {
+ this.srcDirName = srcDirName;
+ return this;
+ }
+
+ @Nonnull
+ public RuntimeTestHelper setLibDirName(@Nonnull String libDirName) {
+ this.libDirName = libDirName;
+ return this;
+ }
+
+ @Nonnull
+ public RuntimeTestHelper setRefDirName(@Nonnull String refDirName) {
+ this.refDirName = refDirName;
+ return this;
+ }
+
+ @Nonnull
+ public RuntimeTestHelper setLinkDirName(@Nonnull String linkDirName) {
+ this.linkDirName = linkDirName;
+ return this;
+ }
+
+ @Nonnull
+ public RuntimeTestHelper setWithDebugInfos(boolean withDebugInfos) {
+ this.withDebugInfos = withDebugInfos;
+ return this;
+ }
+
+ @Nonnull
+ public RuntimeTestHelper setSourceLevel(@Nonnull SourceLevel level) {
+ candidateTestTools.setSourceLevel(level);
+ referenceTestTools.setSourceLevel(level);
+ return this;
+ }
+
+ @Nonnull
+ public RuntimeTestHelper setPropertyFileName(@Nonnull String propertyFileName) {
+ this.propertyFileName = propertyFileName;
+ return this;
+ }
+
+ @Nonnull
+ public RuntimeTestHelper setJarjarRulesFileName(@Nonnull String name) {
+ this.jarjarRulesFileName = name;
+ return this;
+ }
+
+ @Nonnull
+ public RuntimeTestHelper setProguardFlagsFileNames(@Nonnull String[] proguardFlagsFileNames) {
+ this.proguardFlagsFileNames = proguardFlagsFileNames;
+ return this;
+ }
+
+ public void compileAndRunTest() throws Exception {
+ Properties testProperties = new Properties();
+ try {
+ loadTestProperties(testProperties);
+ } catch (FileNotFoundException e) {
+ // No file, no pb
+ }
+
+ candidateTestTools.setWithDebugInfos(withDebugInfos);
+ referenceTestTools.setWithDebugInfos(withDebugInfos);
+
+ File[] candidateBootClasspath = candidateTestTools.getDefaultBootClasspath();
+ File[] referenceBootClasspath = referenceTestTools.getDefaultBootClasspath();
+
+ String candidateBootClasspathAsString =
+ AbstractTestTools.getClasspathAsString(candidateTestTools.getDefaultBootClasspath());
+ String referenceBootClasspathAsString =
+ AbstractTestTools.getClasspathAsString(referenceTestTools.getDefaultBootClasspath());
+
+ // Compile lib src
+ File libLibRef = null;
+ File libBinaryRef = null;
+ File libLibCandidate = null;
+ if (getLibSrc().length != 0) {
+ libLibRef =
+ AbstractTestTools.createTempFile("-lib-ref", referenceTestTools.getLibraryExtension());
+ File libBinaryRefDir = AbstractTestTools.createTempDir();
+ libBinaryRef = new File(libBinaryRefDir, referenceTestTools.getBinaryFileName());
+ referenceTestTools.srcToLib(referenceBootClasspathAsString, libLibRef, /* zipFiles = */true,
+ getLibSrc());
+ referenceTestTools.libToDex(libLibRef, libBinaryRefDir);
+
+ libLibCandidate = AbstractTestTools.createTempFile("-lib-candidate",
+ candidateTestTools.getLibraryExtension());
+ candidateTestTools.srcToLib(candidateBootClasspathAsString, libLibCandidate,
+ /* zipFiles = */true, getLibSrc());
+ }
+
+ // Compile test src
+ String candidateClasspathAsString;
+ String referenceClasspathAsString;
+ if (getLibSrc().length != 0) {
+ File[] candidateClassPath = new File[candidateBootClasspath.length + 1];
+ System.arraycopy(candidateBootClasspath, 0, candidateClassPath, 0,
+ candidateBootClasspath.length);
+ candidateClassPath[candidateClassPath.length - 1] = libLibRef;
+ candidateClasspathAsString = AbstractTestTools.getClasspathAsString(candidateClassPath);
+ File[] referenceClasspath = new File[referenceBootClasspath.length + 1];
+ System.arraycopy(referenceBootClasspath, 0, referenceClasspath, 0,
+ referenceBootClasspath.length);
+ referenceClasspath[referenceClasspath.length - 1] = libLibRef;
+ referenceClasspathAsString = AbstractTestTools.getClasspathAsString(referenceClasspath);
+ } else {
+ candidateClasspathAsString = candidateBootClasspathAsString;
+ referenceClasspathAsString = referenceBootClasspathAsString;
+ }
+
+ File jarjarRules = getJarjarRules();
+ List<File> proguargFlags = getProguardFlags();
+
+ File testBinaryDir = AbstractTestTools.createTempDir();
+ File testBinary = new File(testBinaryDir, candidateTestTools.getBinaryFileName());
+ if (jarjarRules != null) {
+ candidateTestTools.setJarjarRules(jarjarRules);
+ }
+ candidateTestTools.addProguardFlags(proguargFlags.toArray(new File [proguargFlags.size()]));
+ candidateTestTools.srcToExe(candidateClasspathAsString, testBinaryDir, getSrcDir());
+
+ File testLib =
+ AbstractTestTools.createTempFile("testRef", referenceTestTools.getLibraryExtension());
+ referenceTestTools.srcToLib(referenceClasspathAsString, testLib, /* zipFiles = */true,
+ getSrcDir());
+
+ // Compile link src
+ File linkBinary = null;
+ if (getLinkSrc().length != 0) {
+ File linkBinaryDir = AbstractTestTools.createTempDir();
+ linkBinary = new File(linkBinaryDir, candidateTestTools.getBinaryFileName());
+ candidateTestTools.setJarjarRules(jarjarRules);
+ candidateTestTools.addProguardFlags(proguargFlags.toArray(new File [proguargFlags.size()]));
+ candidateTestTools.srcToExe(candidateBootClasspathAsString, linkBinaryDir, getLinkSrc());
+ }
+
+ // Compile ref part src
+ List<File> referenceClasspath = new ArrayList<File>();
+ for (File f : referenceBootClasspath) {
+ referenceClasspath.add(f);
+ }
+ if (libLibRef != null) {
+ referenceClasspath.add(libLibRef);
+ }
+ if (testLib != null) {
+ referenceClasspath.add(testLib);
+ }
+ referenceClasspathAsString = AbstractTestTools.getClasspathAsString(
+ referenceClasspath.toArray(new File[referenceClasspath.size()]));
+
+ File refPartBinaryDir = AbstractTestTools.createTempDir();
+ File refPartBinary = new File(refPartBinaryDir, referenceTestTools.getBinaryFileName());
+ referenceTestTools.srcToExe(referenceClasspathAsString, refPartBinaryDir, getRefSrcDir());
+
+ List<File> rtClasspath = new ArrayList<File>();
+ rtClasspath.add(new File(AbstractTestTools.getJackRootDir(),
+ "toolchain/jack/jack-tests/prebuilts/core-hostdex.jar"));
+ rtClasspath.add(new File(AbstractTestTools.getJackRootDir(),
+ "toolchain/jack/jack-tests/prebuilts/junit4-hostdex.jar"));
+ if (refPartBinary != null) {
+ rtClasspath.add(refPartBinary);
+ }
+ if (linkBinary != null) {
+ rtClasspath.add(linkBinary);
+ }
+ if (testBinary != null) {
+ rtClasspath.add(testBinary);
+ }
+ if (libBinaryRef != null) {
+ rtClasspath.add(libBinaryRef);
+ }
+
+ // Run JUnit on runtime env(s)
+ runOnRuntimeEnvironments(jUnitClasses, testProperties,
+ rtClasspath.toArray(new File[rtClasspath.size()]));
+ }
+
+ private static void runOnRuntimeEnvironments(@Nonnull List<String> jUnitClasses,
+ @Nonnull Properties testProperties, @Nonnull File... classpathFiles) throws Exception {
+ List<RuntimeRunner> runnerList = AbstractTestTools.listRuntimeTestRunners(testProperties);
+ for (RuntimeRunner runner : runnerList) {
+ Assert.assertEquals(0, runner.run(
+ getRuntimeArgs(runner.getClass().getSimpleName(), testProperties), Lists.add(jUnitClasses,
+ 0, AbstractTestTools.JUNIT_RUNNER_NAME).toArray(new String[jUnitClasses.size() + 1]),
+ classpathFiles));
+ }
+ }
+
+ @Nonnull
+ private static final String[] getRuntimeArgs(@Nonnull String rtName,
+ @Nonnull Properties properties) {
+
+ String args = properties.getProperty("rt.args." + rtName);
+ List<String> result = new ArrayList<String>(0);
+ if (args != null) {
+ for (String arg : Splitter.on(CharMatcher.WHITESPACE).split(args)) {
+ result.add(arg);
+ }
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ private void loadTestProperties(@Nonnull Properties properties) throws FileNotFoundException,
+ IOException {
+ File[] propertyFile = getDirectoryOrFile(propertyFileName);
+ if (propertyFile.length != 0) {
+ if (baseDirs.size() > 1) {
+ throw new AssertionError("Non regression test found");
+ }
+ if (propertyFile[0].exists()) {
+ properties.load(new FileInputStream(propertyFile[0]));
+ }
+ }
+ }
+
+ @Nonnull
+ private File[] getSrcDir() {
+ return getDirectoryOrFile(srcDirName);
+ }
+
+ @Nonnull
+ private File[] getLibSrc() {
+ return getDirectoryOrFile(libDirName);
+ }
+
+ @Nonnull
+ private File[] getLinkSrc() {
+ File[] result = getDirectoryOrFile(linkDirName);
+ if (result.length != 0 && baseDirs.size() > 1) {
+ throw new AssertionError("Not a regression test");
+ }
+ return result;
+ }
+
+ @Nonnull
+ private File[] getRefSrcDir() {
+ return getDirectoryOrFile(refDirName);
+ }
+
+ @CheckForNull
+ private File getJarjarRules() {
+ File[] result = getDirectoryOrFile(jarjarRulesFileName);
+ if (result.length != 0) {
+ if (baseDirs.size() > 1) {
+ throw new AssertionError("Not a regression test");
+ }
+ return result[0];
+ }
+ return null;
+ }
+
+ @Nonnull
+ private List<File> getProguardFlags() {
+ List<File> result = new ArrayList<File>();
+ if (proguardFlagsFileNames != null) {
+ for (String s : proguardFlagsFileNames) {
+ File[] f = getDirectoryOrFile(s);
+ if (f.length != 0 && f[0].exists()) {
+ result.add(f[0]);
+ }
+ }
+ }
+
+ if (!result.isEmpty() && baseDirs.size() > 1) {
+ throw new AssertionError("Not a regression test");
+ }
+
+ return result;
+ }
+
+ @Nonnull
+ private File[] getDirectoryOrFile(@CheckForNull String name) {
+ List<File> result = new ArrayList<File>();
+ if (name != null) {
+ for (File f : baseDirs) {
+ File absFile = new File(f, name);
+ if (absFile.exists()) {
+ result.add(absFile);
+ }
+ }
+ }
+ return result.toArray(new File[result.size()]);
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/helper/SourceToDexComparisonTestHelper.java b/jack-tests/src/com/android/jack/test/helper/SourceToDexComparisonTestHelper.java
new file mode 100644
index 0000000..72d9108
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/helper/SourceToDexComparisonTestHelper.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.helper;
+
+import com.android.jack.test.comparator.Comparator;
+import com.android.jack.test.comparator.ComparatorDex;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.AndroidToolchain;
+
+import java.io.File;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * This class is a {@link GenericComparisonTestHelper} where the two compilers perform
+ * a source-to-dex compilation.
+ */
+public class SourceToDexComparisonTestHelper extends GenericComparisonTestHelper {
+
+ @Nonnull
+ private File candidateDexDir;
+ @Nonnull
+ protected File candidateDex;
+ @Nonnull
+ private File refDexDir;
+ @Nonnull
+ protected File refDex;
+
+ @Nonnull
+ private File[] candidateClasspath;
+ @Nonnull
+ private File[] referenceClasspath;
+
+ @Nonnull
+ private File fileOrSourceList;
+
+ @CheckForNull
+ private File jarjarRulesFile = null;
+ @Nonnull
+ private File[] proguardFlagFiles = new File[0];
+
+ @Nonnull
+ private AndroidToolchain candidateTestTools;
+ @Nonnull
+ private AndroidToolchain referenceTestTools;
+
+ protected boolean withDebugInfos = false;
+
+ public SourceToDexComparisonTestHelper(@Nonnull File fileOrSourceList) throws Exception {
+
+ this.fileOrSourceList = fileOrSourceList;
+
+ candidateTestTools = getCandidateToolchain();
+ referenceTestTools = getReferenceToolchain();
+
+ candidateClasspath = candidateTestTools.getDefaultBootClasspath();
+ referenceClasspath = referenceTestTools.getDefaultBootClasspath();
+
+ candidateDexDir = AbstractTestTools.createTempDir();
+ refDexDir = AbstractTestTools.createTempDir();
+
+ candidateDex = new File(candidateDexDir, candidateTestTools.getBinaryFileName());
+ refDex = new File(refDexDir, referenceTestTools.getBinaryFileName());
+ }
+
+ @Nonnull
+ protected AndroidToolchain getCandidateToolchain() {
+ return AbstractTestTools.getCandidateToolchain(AndroidToolchain.class);
+ }
+
+ @Nonnull
+ protected AndroidToolchain getReferenceToolchain() {
+ return AbstractTestTools.getReferenceToolchain(AndroidToolchain.class);
+ }
+
+ @Nonnull
+ public SourceToDexComparisonTestHelper setCandidateTestTools(
+ @Nonnull AndroidToolchain candidateTestTools) {
+ this.candidateTestTools = candidateTestTools;
+ return this;
+ }
+
+ @Nonnull
+ public SourceToDexComparisonTestHelper setReferenceTestTools(
+ @Nonnull AndroidToolchain referenceTestTools) {
+ this.referenceTestTools = referenceTestTools;
+ return this;
+ }
+
+ @Nonnull
+ public SourceToDexComparisonTestHelper setCandidateClasspath(@Nonnull File[] classpath) {
+ candidateClasspath = classpath;
+ return this;
+ }
+
+ @Nonnull
+ public SourceToDexComparisonTestHelper setReferenceClasspath(@Nonnull File[] classpath) {
+ referenceClasspath = classpath;
+ return this;
+ }
+
+ @Nonnull
+ public SourceToDexComparisonTestHelper setWithDebugInfo(boolean withDebugInfo) {
+ this.withDebugInfos = withDebugInfo;
+ return this;
+ }
+
+ @Nonnull
+ public Comparator createDexFileComparator() {
+ ComparatorDex comparator = new ComparatorDex(candidateDex, refDex);
+ comparator.setWithDebugInfo(withDebugInfos);
+ comparator.setStrict(false);
+ comparator.setCompareDebugInfoBinary(false);
+ comparator.setCompareInstructionNumber(false);
+ comparator.setInstructionNumberTolerance(0f);
+ return comparator;
+ }
+
+ @Nonnull
+ public SourceToDexComparisonTestHelper setJarjarRulesFile(@Nonnull File jarjarRulesFile) {
+ this.jarjarRulesFile = jarjarRulesFile;
+ return this;
+ }
+
+ @Nonnull
+ public SourceToDexComparisonTestHelper setProguardFlags(@Nonnull File[] proguardFlags) {
+ this.proguardFlagFiles = proguardFlags;
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ protected void executeCandidateToolchain() throws Exception {
+ if (jarjarRulesFile != null) {
+ candidateTestTools.setJarjarRules(jarjarRulesFile);
+ }
+ candidateTestTools.addProguardFlags(proguardFlagFiles).srcToExe(
+ AbstractTestTools.getClasspathAsString(candidateClasspath), candidateDexDir,
+ fileOrSourceList);
+ }
+
+ @Override
+ @Nonnull
+ protected void executeReferenceToolchain() throws Exception {
+ if (jarjarRulesFile != null) {
+ referenceTestTools.setJarjarRules(jarjarRulesFile);
+ }
+ referenceTestTools.addProguardFlags(proguardFlagFiles).srcToExe(
+ AbstractTestTools.getClasspathAsString(referenceClasspath), refDexDir, fileOrSourceList);
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/runner/AbstractRuntimeRunner.java b/jack-tests/src/com/android/jack/test/runner/AbstractRuntimeRunner.java
new file mode 100644
index 0000000..a20ff93
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runner/AbstractRuntimeRunner.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runner;
+
+
+import java.io.File;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import javax.annotation.Nonnull;
+
+
+/**
+ * This {@link RuntimeRunner} can have its outputs redirected in user defined streams.
+ */
+public abstract class AbstractRuntimeRunner extends RuntimeRunner {
+
+ @Nonnull
+ protected PrintStream outRedirectStream = System.out;
+ @Nonnull
+ protected PrintStream errRedirectStream = System.err;
+
+ protected AbstractRuntimeRunner(@Nonnull File rtEnvRootDir) {
+ super(rtEnvRootDir);
+ }
+
+ @Override
+ public abstract int run(@Nonnull String[] options, @Nonnull String[] mainClasses,
+ @Nonnull File... classpathFiles) throws RuntimeRunnerException;
+
+ @Nonnull
+ public final AbstractRuntimeRunner setOutputStream(@Nonnull OutputStream outputStream) {
+ if (outRedirectStream != null) {
+ outRedirectStream.close();
+ }
+ outRedirectStream = new PrintStream(outputStream);
+ return this;
+ }
+
+ @Nonnull
+ public final AbstractRuntimeRunner setErrorStream(@Nonnull OutputStream errorStream) {
+ if (errRedirectStream != null) {
+ errRedirectStream.close();
+ }
+ errRedirectStream = new PrintStream(errorStream);
+ return this;
+ }
+
+ @Nonnull
+ public PrintStream getOutStream() {
+ return outRedirectStream;
+ }
+
+ @Nonnull
+ public PrintStream getErrStream() {
+ return errRedirectStream;
+ }
+
+}
diff --git a/jack-tests/src/com/android/jack/test/runner/ArtRunnerDevice.java b/jack-tests/src/com/android/jack/test/runner/ArtRunnerDevice.java
new file mode 100644
index 0000000..e93e20b
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runner/ArtRunnerDevice.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runner;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link RuntimeRunner} is used to run tests on art running on device.
+ */
+public class ArtRunnerDevice extends DeviceRunner {
+
+ @Override
+ public int run(@Nonnull String[] options, @Nonnull String[] mainClasses,
+ @Nonnull File... classpathFiles) throws RuntimeRunnerException {
+ return runOnDevice(options, mainClasses, classpathFiles);
+ }
+
+ @Override
+ @Nonnull
+ protected List<String> buildCommandLine(@Nonnull String[] options, @Nonnull String[] mainClasses,
+ @Nonnull File... classpathFiles) {
+ List<String> args = new ArrayList<String>();
+
+ args.add(rtEnvironmentRootDir.getAbsolutePath() + "/bin/dalvikvm");
+
+ for (String option : options) {
+ args.add(option);
+ }
+
+ args.add("-classpath");
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < classpathFiles.length; i++) {
+ if (i > 0) {
+ sb.append(File.pathSeparatorChar);
+ }
+ sb.append(classpathFiles[i].getAbsolutePath());
+ }
+ args.add(sb.toString());
+
+ for (String className : mainClasses) {
+ args.add(className);
+ }
+ return args;
+ }
+
+ @Override
+ @Nonnull
+ protected String getRuntimeName() {
+ return "ART";
+ }
+
+}
diff --git a/jack-tests/src/com/android/jack/test/runner/ArtRunnerHost.java b/jack-tests/src/com/android/jack/test/runner/ArtRunnerHost.java
new file mode 100644
index 0000000..c9a46fb
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runner/ArtRunnerHost.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runner;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link RuntimeRunner} is used to run tests on art running on host.
+ */
+public class ArtRunnerHost extends HostRunner {
+
+ public ArtRunnerHost(@Nonnull File rtEnvironmentRootDir) {
+ super(rtEnvironmentRootDir);
+ }
+
+ @Override
+ public int run(@Nonnull String[] options, @Nonnull String[] mainClasses,
+ @Nonnull File... classpathFiles) throws RuntimeRunnerException {
+ return runOnHost(buildCommandLine(options, mainClasses, classpathFiles), "ANDROID_HOST_OUT");
+ }
+
+ @Nonnull
+ private List<String> buildCommandLine(@Nonnull String[] options, @Nonnull String[] mainClasses,
+ @Nonnull File... classpathFiles) {
+ List<String> args = new ArrayList<String>();
+
+ args.add(rtEnvironmentRootDir.getAbsolutePath() + "/bin/art");
+
+ for (String option : options) {
+ args.add(option);
+ }
+
+ args.add("-classpath");
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < classpathFiles.length; i++) {
+ if (i > 0) {
+ sb.append(File.pathSeparatorChar);
+ }
+ sb.append(classpathFiles[i].getAbsolutePath());
+ }
+ args.add(sb.toString());
+
+ for (String className : mainClasses) {
+ args.add(className);
+ }
+ return args;
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/runner/DalvikRunner.java b/jack-tests/src/com/android/jack/test/runner/DalvikRunner.java
new file mode 100644
index 0000000..e905394
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runner/DalvikRunner.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runner;
+
+import javax.annotation.Nonnull;
+
+
+/**
+ * This interface defines options that can be set to a Dalvik runner.
+ */
+public interface DalvikRunner {
+
+ /**
+ * This enum defines various mode Dalvik can be run into.
+ */
+ enum DalvikMode {
+ JIT("-Xint:jit"),
+ FAST("-Xint:fast");
+
+ @Nonnull
+ String arg;
+
+ DalvikMode(@Nonnull String arg) {
+ this.arg = arg;
+ }
+
+ @Nonnull
+ String getArg() {
+ return arg;
+ }
+ }
+
+ @Nonnull
+ DalvikRunner setMode(@Nonnull DalvikMode mode);
+}
diff --git a/jack-tests/src/com/android/jack/test/runner/DalvikRunnerDevice.java b/jack-tests/src/com/android/jack/test/runner/DalvikRunnerDevice.java
new file mode 100644
index 0000000..c849189
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runner/DalvikRunnerDevice.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runner;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link RuntimeRunner} is used to run tests on dalvik running on device.
+ */
+public class DalvikRunnerDevice extends DeviceRunner implements DalvikRunner {
+
+ @Nonnull
+ private DalvikMode mode = DalvikMode.FAST;
+
+ @Override
+ public int run(@Nonnull String[] options, @Nonnull String[] mainClasses,
+ @Nonnull File... classpathFiles) throws RuntimeRunnerException {
+ return runOnDevice(options, mainClasses, classpathFiles);
+ }
+
+ @Override
+ @Nonnull
+ protected List<String> buildCommandLine(@Nonnull String[] options, @Nonnull String[] mainClasses,
+ @Nonnull File... classpathFiles) {
+ List<String> args = new ArrayList<String>();
+
+ args.add(rtEnvironmentRootDir.getAbsolutePath() + "/bin/dalvikvm");
+
+ args.add(mode.getArg());
+
+ for (String option : options) {
+ args.add(option);
+ }
+
+ args.add("-classpath");
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < classpathFiles.length; i++) {
+ if (i > 0) {
+ sb.append(File.pathSeparatorChar);
+ }
+ sb.append(classpathFiles[i].getAbsolutePath());
+ }
+ args.add(sb.toString());
+
+ for (String className : mainClasses) {
+ args.add(className);
+ }
+ return args;
+ }
+
+ @Override
+ @Nonnull
+ public DalvikRunnerDevice setMode(@Nonnull DalvikMode mode) {
+ this.mode = mode;
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ protected String getRuntimeName() {
+ return "DalvikVM";
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/runner/DalvikRunnerHost.java b/jack-tests/src/com/android/jack/test/runner/DalvikRunnerHost.java
new file mode 100644
index 0000000..7ada39c
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runner/DalvikRunnerHost.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runner;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link RuntimeRunner} is used to run tests on dalvik running on host.
+ */
+public class DalvikRunnerHost extends HostRunner implements DalvikRunner {
+
+ @Nonnull
+ private DalvikMode mode = DalvikMode.FAST;
+
+ public DalvikRunnerHost(@Nonnull File rtEnvironmentRootDir) {
+ super(rtEnvironmentRootDir);
+ }
+
+ @Override
+ public int run(@Nonnull String[] options, @Nonnull String[] mainClasses,
+ @Nonnull File... classpathFiles) throws RuntimeRunnerException {
+ return runOnHost(buildCommandLine(options, mainClasses, classpathFiles), "ANDROID_ROOT");
+ }
+
+ @Nonnull
+ private List<String> buildCommandLine(@Nonnull String[] options, @Nonnull String[] mainClasses,
+ @Nonnull File... classpathFiles) {
+ List<String> args = new ArrayList<String>();
+
+ args.add(rtEnvironmentRootDir.getAbsolutePath() + "/bin/dalvik");
+
+ args.add(mode.getArg());
+
+ for (String option : options) {
+ args.add(option);
+ }
+
+ args.add("-classpath");
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < classpathFiles.length; i++) {
+ if (i > 0) {
+ sb.append(File.pathSeparatorChar);
+ }
+ sb.append(classpathFiles[i].getAbsolutePath());
+ }
+ args.add(sb.toString());
+
+ for (String className : mainClasses) {
+ args.add(className);
+ }
+ return args;
+ }
+
+ @Override
+ @Nonnull
+ public DalvikRunnerHost setMode(@Nonnull DalvikMode mode) {
+ this.mode = mode;
+ return this;
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/runner/DeviceRunner.java b/jack-tests/src/com/android/jack/test/runner/DeviceRunner.java
new file mode 100644
index 0000000..dbb9203
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runner/DeviceRunner.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runner;
+
+import com.google.common.base.Joiner;
+
+import com.android.ddmlib.AdbCommandRejectedException;
+import com.android.ddmlib.AndroidDebugBridge;
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.IShellOutputReceiver;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.SyncException;
+import com.android.ddmlib.TimeoutException;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.TestConfigurationException;
+import com.android.jack.test.util.ExecFileException;
+import com.android.jack.test.util.ExecuteFile;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This runner is used to execute tests on a device.
+ */
+public abstract class DeviceRunner extends AbstractRuntimeRunner {
+
+ @Nonnull
+ public static final File ROOT_DIR = new File("/system");
+ @Nonnull
+ public static final File ANDROID_DATA_DIR = new File("/data");
+
+ private static final long ADB_CONNECTION_TIMEOUT = 5000;
+ private static final long ADB_WAIT_STEP = ADB_CONNECTION_TIMEOUT / 10;
+
+ @Nonnull
+ private MyShellOuputReceiver shellOutput = new MyShellOuputReceiver();
+
+ private class MyShellOuputReceiver implements IShellOutputReceiver {
+
+ @Override
+ public void addOutput(@Nonnull byte[] data, int offset, int length) {
+ outRedirectStream.println(new String(Arrays.copyOfRange(data, offset, offset + length)));
+ }
+
+ @Override
+ public void flush() {
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+ }
+
+ public DeviceRunner() {
+ super(ROOT_DIR);
+ try {
+ AndroidDebugBridge.init(/* clientSupport */ false);
+ } catch (IllegalStateException ex) {
+ // ADB was already initialized, we're fine, so just ignore.
+ }
+ }
+
+ private class ShellOutputToStringReceiver implements IShellOutputReceiver {
+
+ @Nonnull
+ StringBuffer out = new StringBuffer();
+
+ @Override
+ public void addOutput(@Nonnull byte[] data, int offset, int length) {
+ out.append(new String(Arrays.copyOfRange(data, offset, offset + length)));
+ }
+
+ @Override
+ public void flush() {
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @Nonnull
+ public String getOutput() {
+ return out.toString();
+ }
+ }
+
+ protected int runOnDevice(@Nonnull String[] options, @Nonnull String[] mainClasses,
+ @Nonnull File... classpathFiles)
+ throws RuntimeRunnerException {
+
+ // Assumes adb is in PATH
+ AndroidDebugBridge adb = AndroidDebugBridge.createBridge("adb", false);
+
+ long start = System.currentTimeMillis();
+
+ if (isVerbose) {
+ outRedirectStream.println("Initializing adb...");
+ }
+
+ while (!isAdbInitialized(adb)) {
+ long timeLeft = start + ADB_CONNECTION_TIMEOUT - System.currentTimeMillis();
+ if (timeLeft <= 0) {
+ break;
+ }
+ try {
+ Thread.sleep(ADB_WAIT_STEP);
+ } catch (InterruptedException e) {
+ throw new RuntimeRunnerException(e);
+ }
+ }
+ if (!isAdbInitialized(adb)) {
+ throw new RuntimeRunnerException("adb is not initialized");
+ }
+
+ if (isVerbose) {
+ outRedirectStream.println("Done");
+ }
+
+ IDevice[] connectedDevices = adb.getDevices();
+
+ if (connectedDevices.length == 0) {
+ throw new RuntimeRunnerException("No device found");
+ }
+
+ int exitStatus = -1;
+ for (IDevice device : connectedDevices) {
+
+ checkDeviceRuntime(device);
+
+ if (isVerbose) {
+ outRedirectStream.println("Running on device: " + device.getName());
+ }
+
+ ensureAdbRoot(device);
+
+ File testsRootDir = new File(device.getMountPoint(IDevice.MNT_DATA) + "/jack-tests");
+ File[] desFilePaths = new File[classpathFiles.length];
+ try {
+ if (isVerbose) {
+ outRedirectStream.println("adb shell -s " + device.getSerialNumber() + " mkdir "
+ + testsRootDir.getAbsolutePath());
+ }
+ device.executeShellCommand("mkdir " + testsRootDir.getAbsolutePath(), shellOutput);
+
+ if (isVerbose) {
+ outRedirectStream.println("adb -s " + device.getSerialNumber() + " push "
+ + System.getProperty("user.dir") + File.separator + "test-exit-status.sh "
+ + testsRootDir.getAbsolutePath() + "/test-exit-status.sh");
+ }
+ device.pushFile(System.getProperty("user.dir") + File.separator + "test-exit-status.sh",
+ testsRootDir.getAbsolutePath() + "/test-exit-status.sh");
+
+ if (isVerbose) {
+ outRedirectStream.println("adb -s " + device.getSerialNumber() + " shell chmod 777 "
+ + testsRootDir.getAbsolutePath() + "/test-exit-status.sh");
+ }
+ device.executeShellCommand(
+ "chmod 777 " + testsRootDir.getAbsolutePath() + "/test-exit-status.sh", shellOutput);
+
+ int i = 0;
+ for (File f : classpathFiles) {
+ desFilePaths[i] = new File(testsRootDir, "f" + i + "_" + f.getName());
+
+ if (isVerbose) {
+ outRedirectStream.println("adb -s " + device.getSerialNumber() + " push "
+ + f.getAbsolutePath() + " " + desFilePaths[i].getAbsolutePath());
+ }
+ device.pushFile(f.getAbsolutePath(), desFilePaths[i].getAbsolutePath());
+ i++;
+ }
+ } catch (TimeoutException e) {
+ throw new RuntimeRunnerException(e);
+ } catch (AdbCommandRejectedException e) {
+ throw new RuntimeRunnerException(e);
+ } catch (ShellCommandUnresponsiveException e) {
+ throw new RuntimeRunnerException(e);
+ } catch (IOException e) {
+ throw new RuntimeRunnerException(e);
+ } catch (SyncException e) {
+ throw new RuntimeRunnerException(e);
+ }
+
+ String args = Joiner.on(' ').join(buildCommandLine(options, mainClasses, desFilePaths));
+
+ try {
+ // Bug : exit code return by adb shell is wrong (always 0)
+ // https://code.google.com/p/android/issues/detail?id=3254
+ // Use go team hack to work this around
+ // https://code.google.com/p/go/source/browse/misc/arm/a
+
+ if (isVerbose) {
+ outRedirectStream.println("adb -s " + device.getSerialNumber() + " shell "
+ + testsRootDir.getAbsolutePath() + "/test-exit-status.sh " + args);
+ }
+ device.executeShellCommand(
+ testsRootDir.getAbsolutePath() + "/test-exit-status.sh " + args,
+ shellOutput);
+
+ File exitStatusFile = AbstractTestTools.createTempFile("exitStatus", "");
+ if (isVerbose) {
+ outRedirectStream.println("adb -s " + device.getSerialNumber() + " pull "
+ + testsRootDir.getAbsolutePath() + "/exitStatus " + exitStatusFile.getAbsolutePath());
+ }
+ device.pullFile(testsRootDir.getAbsolutePath() + "/exitStatus",
+ exitStatusFile.getAbsolutePath());
+
+ BufferedReader br = new BufferedReader(new FileReader(exitStatusFile));
+ try {
+ String readLine = br.readLine();
+ if (readLine == null) {
+ throw new RuntimeRunnerException("Exit status not found");
+ }
+ exitStatus = Integer.parseInt(readLine);
+ } finally {
+ br.close();
+ }
+
+ if (isVerbose) {
+ outRedirectStream.println("Exit status: " + exitStatus);
+ }
+
+ for (File pushedFile : desFilePaths) {
+ if (isVerbose) {
+ outRedirectStream.println(
+ "adb -s " + device.getSerialNumber() + "rm " + pushedFile.getAbsolutePath());
+ }
+ device.executeShellCommand("rm " + pushedFile.getAbsolutePath(), shellOutput);
+ }
+
+ if (exitStatus != 0) {
+ errRedirectStream.println("Execution failed on device '" + device.getName() + "'");
+ break;
+ }
+
+ } catch (TimeoutException e) {
+ throw new RuntimeRunnerException(e);
+ } catch (AdbCommandRejectedException e) {
+ throw new RuntimeRunnerException(e);
+ } catch (ShellCommandUnresponsiveException e) {
+ throw new RuntimeRunnerException(e);
+ } catch (IOException e) {
+ throw new RuntimeRunnerException(e);
+ } catch (SyncException e) {
+ throw new RuntimeRunnerException(e);
+ }
+ }
+
+ return exitStatus;
+ }
+
+ @Nonnull
+ protected abstract List<String> buildCommandLine(@Nonnull String[] options,
+ @Nonnull String[] mainClasses, @Nonnull File... classpathFiles);
+
+ private boolean isAdbInitialized(@Nonnull AndroidDebugBridge adb) {
+ return adb.isConnected() && adb.hasInitialDeviceList();
+ }
+
+ private void ensureAdbRoot(@Nonnull IDevice device) throws RuntimeRunnerException {
+ ShellOutputToStringReceiver outputToString = new ShellOutputToStringReceiver();
+ try {
+ device.executeShellCommand("id", outputToString);
+
+ if (!outputToString.getOutput().contains("uid=0(root)")) {
+ ExecuteFile ef;
+
+ ef = new ExecuteFile("adb -s " + device.getSerialNumber() + " root");
+ ef.setOut(System.out);
+ ef.setErr(System.err);
+ ef.setVerbose(isVerbose);
+ ef.run();
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e1) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ } catch (TimeoutException e1) {
+ throw new RuntimeRunnerException(e1);
+ } catch (AdbCommandRejectedException e1) {
+ throw new RuntimeRunnerException(e1);
+ } catch (ShellCommandUnresponsiveException e1) {
+ throw new RuntimeRunnerException(e1);
+ } catch (IOException e1) {
+ throw new RuntimeRunnerException(e1);
+ } catch (ExecFileException e) {
+ throw new RuntimeRunnerException("Error while executing 'adb root'", e);
+ }
+ }
+
+ @Nonnull
+ protected abstract String getRuntimeName();
+
+ private void checkDeviceRuntime(@Nonnull IDevice device) throws RuntimeRunnerException {
+ ShellOutputToStringReceiver outputToString = new ShellOutputToStringReceiver();
+ try {
+ device.executeShellCommand("dalvikvm -showversion", outputToString);
+ if (!outputToString.getOutput().contains(getRuntimeName())) {
+ throw new TestConfigurationException(
+ "The plugged device does not run the required runtime: '" + getRuntimeName() + "'");
+ }
+ } catch (TimeoutException e) {
+ throw new RuntimeRunnerException(e);
+ } catch (AdbCommandRejectedException e) {
+ throw new RuntimeRunnerException(e);
+ } catch (ShellCommandUnresponsiveException e) {
+ throw new RuntimeRunnerException(e);
+ } catch (IOException e) {
+ throw new RuntimeRunnerException(e);
+ }
+ }
+
+}
diff --git a/jack-tests/src/com/android/jack/test/runner/HostRunner.java b/jack-tests/src/com/android/jack/test/runner/HostRunner.java
new file mode 100644
index 0000000..a4bca8a
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runner/HostRunner.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runner;
+
+import com.android.jack.test.util.ExecFileException;
+import com.android.jack.test.util.ExecuteFile;
+
+import java.io.File;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This runner is used to execute tests on host.
+ */
+public abstract class HostRunner extends AbstractRuntimeRunner {
+
+ public HostRunner(@Nonnull File rtEnvironmentRootDir) {
+ super(rtEnvironmentRootDir);
+ }
+
+ protected int runOnHost(@Nonnull List<String> args, @Nonnull String rtEnvRootDirVarName)
+ throws RuntimeRunnerException {
+
+ ExecuteFile exec = new ExecuteFile(args.toArray(new String[args.size()]));
+ exec.addEnvVar(rtEnvRootDirVarName, rtEnvironmentRootDir.getAbsolutePath());
+ exec.setOut(outRedirectStream);
+ exec.setErr(errRedirectStream);
+ exec.setVerbose(isVerbose);
+
+ try {
+ int exitStatus = exec.run();
+ return exitStatus;
+ } catch (ExecFileException e) {
+ throw new RuntimeRunnerException(e);
+ }
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/runner/RuntimeRunner.java b/jack-tests/src/com/android/jack/test/runner/RuntimeRunner.java
new file mode 100644
index 0000000..9d8ee5f
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runner/RuntimeRunner.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runner;
+
+import java.io.File;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Common class for tools used to run JUnit tests or main classes.
+ */
+public abstract class RuntimeRunner {
+
+ @Nonnull
+ protected File rtEnvironmentRootDir;
+
+ protected boolean isVerbose = false;
+
+ protected RuntimeRunner(@Nonnull File rtEnvironmentRootDir) {
+ this.rtEnvironmentRootDir = rtEnvironmentRootDir;
+ }
+
+ public abstract int run(@Nonnull String[] options, @Nonnull String[] className,
+ @Nonnull File... classpathFiles) throws RuntimeRunnerException;
+
+ @Nonnull
+ public RuntimeRunner setVerbose(boolean isVerbose) {
+ this.isVerbose = isVerbose;
+ return this;
+ }
+
+}
diff --git a/jack-tests/src/com/android/jack/test/runner/RuntimeRunnerException.java b/jack-tests/src/com/android/jack/test/runner/RuntimeRunnerException.java
new file mode 100644
index 0000000..a353156
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runner/RuntimeRunnerException.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runner;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This exception is thrown when something went wrong with the execution
+ * of the {@link RuntimeRunner}.
+ */
+public class RuntimeRunnerException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public RuntimeRunnerException(@Nonnull String message, @Nonnull Throwable cause) {
+ super(message, cause);
+ }
+
+ public RuntimeRunnerException(@Nonnull Throwable cause) {
+ super(cause);
+ }
+
+ public RuntimeRunnerException(@Nonnull String message) {
+ super(message);
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/runner/RuntimeRunnerFactory.java b/jack-tests/src/com/android/jack/test/runner/RuntimeRunnerFactory.java
new file mode 100644
index 0000000..2d83625
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runner/RuntimeRunnerFactory.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runner;
+
+import com.android.jack.test.runner.DalvikRunner.DalvikMode;
+import com.android.jack.test.toolchain.AbstractTestTools;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A factory to build {@link RuntimeRunner}s.
+ */
+public class RuntimeRunnerFactory {
+
+ private static final char SEPARATOR = '-';
+
+ /**
+ * Runtime names are composed as follows:
+ * <runtime environment name>-<variant>-<kind>
+ * Where runtime environment name is one of Dalvik, ART, ..., variant defines a variant
+ * for the selected environment (e.g. jit or fast for dalvik) and finally target is either
+ * host or device.
+ */
+ @Nonnull
+ public static RuntimeRunner create(@Nonnull String rtName) throws RuntimeRunnerException {
+
+ int firstIndex = rtName.indexOf(SEPARATOR);
+ int lastIndex = rtName.lastIndexOf(SEPARATOR);
+
+ String rtEnvName = null;
+ String variant = null;
+ String runnerKind = null;
+
+ if (firstIndex > -1) {
+ rtEnvName = rtName.substring(0, firstIndex);
+ runnerKind = rtName.substring(lastIndex + 1);
+ }
+ if (firstIndex < lastIndex) {
+ variant =
+ rtName.substring(firstIndex + 1, lastIndex);
+ }
+
+ RuntimeRunner result;
+ if ("dalvik".equals(rtEnvName)) {
+ if ("device".equals(runnerKind)) {
+ result = new DalvikRunnerDevice();
+ } else if ("host".equals(runnerKind)) {
+ result = new DalvikRunnerHost(AbstractTestTools.getRuntimeEnvironmentRootDir(rtName));
+ } else {
+ throw new RuntimeRunnerException("Unkown target for Dalvik: '" + rtName + "'");
+ }
+ if ("jit".equals(variant)) {
+ ((DalvikRunner) result).setMode(DalvikMode.JIT);
+ } else if ("fast".equals(variant)) {
+ ((DalvikRunner) result).setMode(DalvikMode.FAST);
+ } else if (variant != null) {
+ throw new RuntimeRunnerException("Unkown variant for Dalvik: '" + rtName + "'");
+ }
+ } else if ("art".equals(rtEnvName)) {
+ if ("host".equals(runnerKind)) {
+ result = new ArtRunnerHost(AbstractTestTools.getRuntimeEnvironmentRootDir(rtName));
+ } else if ("device".equals(runnerKind)) {
+ result = new ArtRunnerDevice();
+ } else {
+ throw new RuntimeRunnerException("Unkown target for ART: '" + rtName + "'");
+ }
+ } else {
+ throw new RuntimeRunnerException("Unkown runtime environment for ART: '" + rtName + "'");
+ }
+
+ return result;
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/runtime/RuntimeTest.java b/jack-tests/src/com/android/jack/test/runtime/RuntimeTest.java
new file mode 100644
index 0000000..3fdb14a
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runtime/RuntimeTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runtime;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * {@code RuntimeTest}s must extends this class if they are to be passed as
+ * regression tests.
+ */
+public abstract class RuntimeTest {
+
+ @Nonnull
+ protected List<RuntimeTestInfo> rtTestInfos = new ArrayList<RuntimeTestInfo>();
+
+ protected RuntimeTest() {
+ fillRtTestInfos();
+ }
+
+ @Nonnull
+ public final List<RuntimeTestInfo> getRuntimeTestInfos() {
+ return rtTestInfos;
+ }
+
+ protected abstract void fillRtTestInfos();
+} \ No newline at end of file
diff --git a/jack-tests/src/com/android/jack/test/runtime/RuntimeTestInfo.java b/jack-tests/src/com/android/jack/test/runtime/RuntimeTestInfo.java
new file mode 100644
index 0000000..f5ec727
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/runtime/RuntimeTestInfo.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.runtime;
+
+import java.io.File;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This class hold the information needed by the runtime tests framework to execute
+ * a test.
+ */
+public class RuntimeTestInfo {
+
+ @Nonnull
+ public File directory;
+ @Nonnull
+ public String jUnit;
+
+ public RuntimeTestInfo(@Nonnull File directory, @Nonnull String jUnit) {
+ this.directory = directory;
+ this.jUnit = jUnit;
+ }
+
+} \ No newline at end of file
diff --git a/jack-tests/src/com/android/jack/test/toolchain/AbstractTestTools.java b/jack-tests/src/com/android/jack/test/toolchain/AbstractTestTools.java
new file mode 100644
index 0000000..ed0f6b0
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/AbstractTestTools.java
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import com.google.common.io.Files;
+
+import com.android.jack.Sourcelist;
+import com.android.jack.test.runner.RuntimeRunner;
+import com.android.jack.test.runner.RuntimeRunnerException;
+import com.android.jack.test.runner.RuntimeRunnerFactory;
+import com.android.jack.test.util.ExecFileException;
+import com.android.jack.test.util.ExecuteFile;
+import com.android.jack.util.NamingTools;
+
+import org.junit.Assume;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * Utility class that act also as a Factory for toolchains. It holds the global
+ * configuration for tests.
+ */
+public abstract class AbstractTestTools {
+
+ @Nonnull
+ public static final String JUNIT_RUNNER_NAME = "org.junit.runner.JUnitCore";
+ @Nonnull
+ public static final String TESTS_CONFIGURATION_FILE_VARIABLE = "TESTS_CONFIGURATION_FILE";
+
+ @Nonnull
+ private static HashMap<String, ToolchainBuilder> toolchainBuilders;
+
+ @Nonnull
+ private static final String JACK_TESTS_FOLDER =
+ "toolchain" + File.separator + "jack" + File.separator + "jack-tests";
+
+ @Nonnull
+ private static final Properties testsProperties;
+
+ @Nonnull
+ private static final String PROPERTY_VALUE_SEPARATOR = ",";
+ @Nonnull
+ private static final String TOOLCHAIN_REFERENCE_KEY = "toolchain.reference";
+ @Nonnull
+ private static final String TOOLCHAIN_CANDIDATE_KEY = "toolchain.candidate";
+ @Nonnull
+ private static final String RUNTIME_LIST_KEY = "runtime.list";
+ @Nonnull
+ private static final String RUNTIME_LOCATION_PREFIX = "runtime.location.";
+ @Nonnull
+ private static final String TOOL_PREFIX = "tool.";
+ @Nonnull
+ private static final String TOOLCHAIN_PREBUILT_PREFIX = "toolchain.prebuilt.";
+
+ @Nonnull
+ private static final List<RuntimeRunner> runtimes = new ArrayList<RuntimeRunner>();
+
+ @Nonnull
+ private static final Map<String, File> runtimeEnvironmentLocations = new HashMap<String, File>();
+
+
+ private interface ToolchainBuilder {
+ IToolchain build();
+ }
+
+ private static class LegacyToolchainBuilder implements ToolchainBuilder {
+
+ @Override
+ @Nonnull
+ public LegacyToolchain build() {
+ return new LegacyToolchain(getPrebuilt("legacy-java-compiler"), getPrebuilt("jarjar"),
+ getPrebuilt("proguard"));
+ }
+ }
+
+ private static class JackCliToolchainBuilder implements ToolchainBuilder {
+
+ @Override
+ @Nonnull
+ public JackCliToolchain build() {
+ return new JackCliToolchain(getPrebuilt("jack"));
+ }
+ }
+
+ private static class JackApiToolchainBuilder implements ToolchainBuilder {
+
+ @Override
+ @Nonnull
+ public JackApiToolchain build() {
+ return new JackApiToolchain();
+ }
+ }
+
+ private static class LegacyJillToolchainBuilder implements ToolchainBuilder {
+
+ @Override
+ public IToolchain build() {
+ return new LegacyJillToolchain(getPrebuilt("jill"), getPrebuilt("jack"),
+ getPrebuilt("jarjar"), getPrebuilt("proguard"));
+ }
+ }
+
+ private static File getPrebuilt(@Nonnull String prebuiltName) {
+ String prebuiltPath = getProperty(TOOLCHAIN_PREBUILT_PREFIX + prebuiltName);
+
+ if (prebuiltPath == null) {
+ throw new TestConfigurationException(
+ "Cannot find path for prebuilt 'prebuiltName' in test.properties");
+ }
+
+ File result = new File(prebuiltPath);
+ if (!result.isAbsolute()) {
+ result = new File(getJackRootDir(), prebuiltPath);
+ }
+
+ if (!result.exists()) {
+ throw new TestConfigurationException(
+ "Can not find '" + prebuiltName + "' prebuilt at '" + result.getPath() + "'");
+ }
+ return result;
+ }
+
+ static {
+ toolchainBuilders = new HashMap<String, ToolchainBuilder>();
+ toolchainBuilders.put("jack-cli" , new JackCliToolchainBuilder());
+ toolchainBuilders.put("jack-api" , new JackApiToolchainBuilder());
+ toolchainBuilders.put("legacy" , new LegacyToolchainBuilder());
+ toolchainBuilders.put("jill-legacy", new LegacyJillToolchainBuilder());
+
+ testsProperties = new Properties();
+ String filePath = System.getenv(TESTS_CONFIGURATION_FILE_VARIABLE);
+ File propertyFile;
+ if (filePath != null) {
+ propertyFile = new File(filePath);
+ if (!propertyFile.isAbsolute()) {
+ propertyFile = new File(System.getProperty("user.dir"), filePath);
+ }
+ } else {
+ filePath = JACK_TESTS_FOLDER + File.separatorChar + "tests.properties";
+ propertyFile =
+ new File(getJackRootDir(), filePath);
+ }
+
+ if (!propertyFile.exists()) {
+ throw new TestConfigurationException("Configuration file not found: '" + filePath + "'");
+ }
+
+ try {
+ testsProperties.load(new FileInputStream(propertyFile));
+ runtimes.addAll(parseRuntimeList(testsProperties.getProperty(RUNTIME_LIST_KEY)));
+ } catch (FileNotFoundException e) {
+ throw new TestConfigurationException(e);
+ } catch (IOException e) {
+ throw new TestConfigurationException(e);
+ } catch (SecurityException e) {
+ throw new TestConfigurationException(e);
+ } catch (IllegalArgumentException e) {
+ throw new TestConfigurationException(e);
+ } catch (RuntimeRunnerException e) {
+ throw new TestConfigurationException(e);
+ }
+ }
+
+ @Nonnull
+ public static final File getJackRootDir() {
+ String pwdPath = System.getProperty("user.dir");
+ String[] splitPath = pwdPath.split(JACK_TESTS_FOLDER);
+ if (splitPath[0].equals(pwdPath)) {
+ assert splitPath.length == 1;
+ throw new AssertionError("Unable to compute tests root directory");
+ }
+ return new File(splitPath[0]);
+ }
+
+ @Nonnull
+ private static final File getTestsRootDir() {
+ return new File(getJackRootDir(), JACK_TESTS_FOLDER + File.separator + "tests");
+ }
+
+ @Nonnull
+ public static final File getTestRootDir(@Nonnull String packageName) {
+ return new File(getTestsRootDir(), packageName.replace(".", File.separator));
+ }
+
+ /**
+ * Return the {@link IToolchain} specified in the tests configuration file if it matches the
+ * requirements expressed in paramters. Otherwise, test is ignored.
+ *
+ * @param classes Optional list of types. The first one is used to check that the candidate type
+ * is of this type. Otherwise JUnit test will be ignored. If more types are provided, they
+ * serve to narrow the expected type set, and are used for exclusion, i.e. if returned
+ * type is of one of these types, test is ignored.
+ * @return The candidate toolchain that fulfills the requirements.
+ */
+ @SuppressWarnings("unchecked")
+ @Nonnull
+ public static final <T extends IToolchain> T getCandidateToolchain(
+ @Nonnull Class<? extends IToolchain>... classes) {
+ IToolchain result = createToolchain("candidate.toolchain");
+ if (classes.length > 0) {
+ Assume.assumeTrue(classes[0].isAssignableFrom(result.getClass()));
+ for (int i = 1; i < classes.length; i++) {
+ Assume.assumeTrue(!classes[i].isAssignableFrom(result.getClass()));
+ }
+ }
+ return (T) result;
+ }
+
+ @Nonnull
+ public static final IToolchain getReferenceToolchain() {
+ return createToolchain("reference.toolchain");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nonnull
+ public static final <T extends IToolchain> T getReferenceToolchain(
+ @Nonnull Class<?> expectedClass) {
+ IToolchain result = getReferenceToolchain();
+ Assume.assumeTrue(expectedClass.isAssignableFrom(result.getClass()));
+ return (T) result;
+ }
+
+ @Nonnull
+ private static IToolchain createToolchain(@Nonnull String propertyName) {
+ return getToolchainBuilder(getProperty(propertyName)).build();
+ }
+
+ @Nonnull
+ private static String getProperty(@Nonnull String key) {
+ String value = testsProperties.getProperty(key);
+ if (value == null) {
+ throw new TestConfigurationException("Undefined property : '" + key + "'");
+ }
+ return value;
+ }
+
+ @Nonnull
+ private static ToolchainBuilder getToolchainBuilder(@Nonnull String toolchainName) {
+ ToolchainBuilder toolchainBuilder = toolchainBuilders.get(toolchainName);
+ if (toolchainBuilder == null) {
+ throw new TestConfigurationException("Unknown toolchain: '" + toolchainName + "'");
+ }
+ return toolchainBuilder;
+ }
+
+ @Nonnull
+ public static File createTempFile(@Nonnull String prefix, @Nonnull String suffix)
+ throws IOException {
+ File tmp = File.createTempFile(prefix, suffix);
+ tmp.deleteOnExit();
+ return tmp;
+ }
+
+ @Nonnull
+ public static File createTempDir() throws IOException {
+ try {
+ final File tmpDir = Files.createTempDir();
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ try {
+ deleteTempDir(tmpDir);
+ } catch (IOException e) {
+ System.err.println(e.getMessage());
+ }
+ }
+ });
+ return tmpDir;
+ } catch (IllegalStateException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @Nonnull
+ public static File createDir(@Nonnull File directory, @Nonnull String name) throws IOException {
+ if (!directory.exists() || !directory.isDirectory()) {
+ throw new AssertionError();
+ }
+
+ File result = new File(directory, name);
+ if (!result.mkdir()) {
+ throw new IOException("Failed to create dir " + result.getAbsolutePath());
+ }
+ return result;
+ }
+
+ public static void deleteTempDir(@CheckForNull File tmp) throws IOException {
+ if (tmp == null) {
+ return;
+ }
+
+ if (tmp.isDirectory()) {
+ for (File sub : tmp.listFiles()) {
+ deleteTempDir(sub);
+ }
+ }
+ if (!tmp.delete()) {
+ throw new IOException("Failed to delete file " + tmp.getAbsolutePath());
+ }
+ }
+
+ @Nonnull
+ public static String getClasspathAsString(@Nonnull File[] files) {
+ if (files.length == 0) {
+ return "";
+ }
+ StringBuilder classpathStr = new StringBuilder();
+ for (int i = 0; i < files.length; i++) {
+ classpathStr.append(files[i].getAbsolutePath());
+ if (i != files.length - 1) {
+ classpathStr.append(File.pathSeparatorChar);
+ }
+ }
+ return classpathStr.toString();
+ }
+
+ @Nonnull
+ public static Properties getGlobalProperties() {
+ return testsProperties;
+ }
+
+ @Nonnull
+ public static String getClasspathsAsString(
+ @Nonnull File[] bootClasspath, @Nonnull File[] classpath) {
+ if (bootClasspath.length == 0) {
+ return getClasspathAsString(classpath);
+ } else if (classpath.length == 0) {
+ return getClasspathAsString(bootClasspath);
+ } else {
+ return concatClasspathStrings(
+ getClasspathAsString(bootClasspath), getClasspathAsString(classpath));
+ }
+ }
+
+ @Nonnull
+ private static String concatClasspathStrings(
+ @Nonnull String bootclasspath, @Nonnull String classpath) {
+ if (bootclasspath.isEmpty()) {
+ return classpath;
+ } else if (classpath.isEmpty()) {
+ return bootclasspath;
+ } else {
+ StringBuilder classpathStr = new StringBuilder(bootclasspath);
+ classpathStr.append(File.pathSeparatorChar);
+ classpathStr.append(classpath);
+ return classpathStr.toString();
+ }
+ }
+
+ @Nonnull
+ public static File createJavaFile(@Nonnull File folder, @Nonnull String packageName,
+ @Nonnull String fileName, @Nonnull String fileContent) throws IOException {
+ File packageFolder = new File(folder, packageName.replace('.', File.separatorChar));
+ if (!packageFolder.exists() && !packageFolder.mkdirs()) {
+ throw new IOException("Failed to create folder " + packageFolder.getAbsolutePath());
+ }
+ File javaFile = new File(packageFolder, fileName);
+ if (javaFile.exists() && !javaFile.delete()) {
+ throw new IOException("Failed to delete file " + javaFile.getAbsolutePath());
+ }
+ if (!javaFile.createNewFile()) {
+ throw new IOException("Failed to create file " + javaFile.getAbsolutePath());
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(javaFile);
+ fos.write(fileContent.getBytes());
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ return javaFile;
+ }
+
+ public static void deleteJavaFile(@Nonnull File folder, @Nonnull String packageName,
+ @Nonnull String fileName) throws IOException {
+ File packageFolder = new File(folder, NamingTools.getBinaryName(packageName));
+ File javaFile = new File(packageFolder, fileName);
+ deleteFile(javaFile);
+ }
+
+ public static void deleteFile(@Nonnull File file) throws IOException {
+ if (!file.delete()) {
+ throw new IOException("Failed to delete file " + file.getAbsolutePath());
+ }
+ }
+
+ @Nonnull
+ public static File getDir(@Nonnull File file) {
+ if (file.isDirectory()) {
+ return file;
+ } else {
+ return file.getParentFile();
+ }
+ }
+
+ @Nonnull
+ public static List<File> getFiles(@Nonnull File folder, @Nonnull String extension) {
+ assert folder.isDirectory();
+ List<File> jackFiles = new ArrayList<File>();
+ fillWithFiles(folder, jackFiles, extension);
+ return jackFiles;
+ }
+
+ private static void fillWithFiles(@Nonnull File file, @Nonnull List<File> jackFiles,
+ @Nonnull String extension) {
+ if (file.isDirectory()) {
+ for (File subFile : file.listFiles()) {
+ fillWithFiles(subFile, jackFiles, extension);
+ }
+ } else if (extension == null || extension.equals("*") || file.getName().endsWith(extension)) {
+ jackFiles.add(file);
+ }
+ }
+
+ public static void addFile(@Nonnull List<String> args,
+ boolean mustExist, @Nonnull File... filesOrSourceLists) {
+ for (File file : filesOrSourceLists) {
+ addFile(file, args, mustExist);
+ }
+ }
+
+ private static void addFile(@Nonnull File fileOrSourceList, @Nonnull List<String> args,
+ boolean mustExist) {
+ if (fileOrSourceList instanceof Sourcelist) {
+ args.add("@" + fileOrSourceList.getAbsolutePath());
+ } else {
+ List<File> sourceFiles = new ArrayList<File>();
+ try {
+ getJavaFiles(fileOrSourceList, sourceFiles, mustExist);
+ } catch (IOException e) {
+ }
+ for (File sourceFile : sourceFiles) {
+ args.add(sourceFile.getAbsolutePath());
+ }
+ }
+ }
+
+ public static void getJavaFiles(@Nonnull File fileObject, @Nonnull List<File> filePaths,
+ boolean mustExist) throws IOException {
+ if (fileObject.isDirectory()) {
+ File allFiles[] = fileObject.listFiles();
+ for (File aFile : allFiles) {
+ getJavaFiles(aFile, filePaths, mustExist);
+ }
+ } else if (fileObject.getName().endsWith(".java") && (!mustExist || fileObject.isFile())) {
+ filePaths.add(fileObject.getCanonicalFile());
+ }
+ }
+
+ public static void unzip(@Nonnull File jarfile, @Nonnull File outputFolder) {
+ String[] args = new String[] {"unzip", "-qo", jarfile.getAbsolutePath(), "-d",
+ outputFolder.getAbsolutePath()};
+
+ ExecuteFile execFile = new ExecuteFile(args);
+
+ try {
+ if (execFile.run() != 0) {
+ throw new RuntimeException("Unzip exited with an error");
+ }
+ } catch (ExecFileException e) {
+ throw new RuntimeException("An error occured while running unzip", e);
+ }
+ }
+
+ public static void createjar(@Nonnull File jarfile, @Nonnull File inputFiles) {
+ String[] args = new String[] {"jar",
+ "cf",
+ jarfile.getAbsolutePath(),
+ "-C",
+ inputFiles.getAbsolutePath(),
+ "."};
+
+ ExecuteFile execFile = new ExecuteFile(args);
+
+ try {
+ if (execFile.run() != 0) {
+ throw new RuntimeException("Jar exited with an error");
+ }
+ } catch (ExecFileException e) {
+ throw new RuntimeException("An error occured while running jar command", e);
+ }
+ }
+
+ @Nonnull
+ protected static List<String> buildEcjArgs() {
+ List<String> ecjArgs = new ArrayList<String>();
+ ecjArgs.add("-nowarn");
+
+ return ecjArgs;
+ }
+
+ @Nonnull
+ public static List<RuntimeRunner> listRuntimeTestRunners(@CheckForNull Properties properties)
+ throws SecurityException, IllegalArgumentException, RuntimeRunnerException {
+
+ if (properties != null) {
+ String rtAsString = properties.getProperty(RUNTIME_LIST_KEY);
+ if (rtAsString != null) {
+ return parseRuntimeList(rtAsString);
+ }
+ }
+ return runtimes;
+ }
+
+ @Nonnull
+ private static List<RuntimeRunner> parseRuntimeList(@CheckForNull String runtimeList)
+ throws SecurityException, IllegalArgumentException, RuntimeRunnerException {
+ List<RuntimeRunner> result = new ArrayList<RuntimeRunner>(0);
+ if (runtimeList != null) {
+ String[] rtList = runtimeList.split(PROPERTY_VALUE_SEPARATOR);
+ for (String rtName : rtList) {
+ result.add(RuntimeRunnerFactory.create(rtName));
+ }
+ }
+ return result;
+ }
+
+ @Nonnull
+ public static File getRuntimeEnvironmentRootDir(@Nonnull String rtName) {
+ String rtLocationPath = testsProperties.getProperty(RUNTIME_LOCATION_PREFIX + rtName);
+
+ if (rtLocationPath == null) {
+ throw new TestConfigurationException(
+ "Location for runtime '" + rtName + "' is not specified");
+ }
+ File rtLocation = new File(rtLocationPath);
+ if (!rtLocation.exists()) {
+ throw new TestConfigurationException(
+ "Location for runtime " + rtName + " does not exist: '" + rtLocationPath + "'");
+ }
+ if (!rtLocation.isDirectory()) {
+ throw new TestConfigurationException(
+ "Location for runtime " + rtName + " is not a directory: '" + rtLocationPath + "'");
+ }
+
+ return rtLocation;
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/AndroidToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/AndroidToolchain.java
new file mode 100644
index 0000000..12a1215
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/AndroidToolchain.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link Toolchain} to produce libs and executable for the Android platform.
+ */
+public abstract class AndroidToolchain extends Toolchain {
+
+ @Override
+ @Nonnull
+ public final String getExeExtension() {
+ return ".dex";
+ }
+
+ @Override
+ @Nonnull
+ public final String getLibraryExtension() {
+ return ".jar";
+ }
+
+ @Nonnull
+ public final String getBinaryFileName() {
+ return "classes.dex";
+ }
+
+ @Nonnull
+ public abstract AndroidToolchain disableDxOptimizations();
+
+ @Nonnull
+ public abstract AndroidToolchain enableDxOptimizations();
+
+}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/DummyToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/DummyToolchain.java
new file mode 100644
index 0000000..9e13068
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/DummyToolchain.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import java.io.File;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {link AndroidToolchain} actually does nothing. It can be used in a comparison
+ * test to simulate one of the toolchain whereas the data to compare is already
+ * available, such as an expected result in a text file for instance.
+ */
+public class DummyToolchain extends AndroidToolchain {
+
+ @Nonnull
+ private final File[] dummyBootclasspath = new File[0];
+
+ public DummyToolchain() {}
+
+ @Override
+ @Nonnull
+ public void srcToExe(@Nonnull String classpath, @Nonnull File out,
+ @Nonnull File... sources) throws Exception {
+ }
+
+ @Override
+ @Nonnull
+ public void srcToLib(@Nonnull String classpath, @Nonnull File out,
+ boolean zipFiles, @Nonnull File... sources) throws Exception {
+ }
+
+ @Override
+ @Nonnull
+ public void libToDex(@Nonnull File in, @Nonnull File out) throws Exception {
+ }
+
+ @Override
+ @Nonnull
+ public void libToLib(@Nonnull File in, @Nonnull File out) throws Exception {
+ }
+
+ @Override
+ @Nonnull
+ public File[] getDefaultBootClasspath() {
+ return dummyBootclasspath;
+ }
+
+ @Override
+ @Nonnull
+ public DummyToolchain disableDxOptimizations() {
+ // Do nothing
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public DummyToolchain enableDxOptimizations() {
+ // Do nothing
+ return this;
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/IToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/IToolchain.java
new file mode 100644
index 0000000..8c35d1d
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/IToolchain.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import com.android.jack.test.toolchain.Toolchain.SourceLevel;
+
+import java.io.File;
+import java.io.OutputStream;
+
+import javax.annotation.Nonnull;
+import javax.annotation.processing.Processor;
+
+
+/**
+ * Abstraction of a toolchain which takes source files and produce libraries and executables.
+ */
+public interface IToolchain {
+
+ @Nonnull
+ void srcToExe(@Nonnull String classpath, @Nonnull File out, @Nonnull File... sources)
+ throws Exception;
+
+ @Nonnull
+ void srcToLib(@Nonnull String classpath, @Nonnull File out, boolean zipFiles,
+ @Nonnull File... sources) throws Exception;
+
+ @Nonnull
+ void libToDex(@Nonnull File in, @Nonnull File out) throws Exception;
+
+ @Nonnull
+ void libToLib(@Nonnull File in, @Nonnull File out) throws Exception;
+
+ @Nonnull
+ IToolchain addStaticLibs(@Nonnull File... staticLibs);
+
+ @Nonnull
+ File[] getDefaultBootClasspath();
+
+ @Nonnull
+ String getExeExtension();
+
+ @Nonnull
+ String getLibraryExtension();
+
+ @Nonnull
+ IToolchain setWithDebugInfos(boolean withDebugInfos);
+
+ @Nonnull
+ IToolchain setAnnotationProcessorClass(
+ @Nonnull Class<? extends Processor> annotationProcessorClass);
+
+ @Nonnull
+ IToolchain setSourceLevel(@Nonnull SourceLevel sourceLevel);
+
+ @Nonnull
+ IToolchain addProguardFlags(@Nonnull File... proguardFlags);
+
+ @Nonnull
+ IToolchain setJarjarRules(@Nonnull File jarjarRules);
+
+ @Nonnull
+ IToolchain setOutputStream(@Nonnull OutputStream outputStream);
+
+ @Nonnull
+ IToolchain setErrorStream(@Nonnull OutputStream errorStream);
+
+}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/JackApiToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/JackApiToolchain.java
new file mode 100644
index 0000000..7466b93
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/JackApiToolchain.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import com.android.jack.Jack;
+import com.android.jack.Options;
+import com.android.jack.experimental.incremental.JackIncremental;
+import com.android.jack.shrob.spec.Flags;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This class implements a {@link JackBasedToolchain} by calling Jack via API.
+ */
+public class JackApiToolchain extends JackBasedToolchain {
+
+ @Nonnull
+ private Options jackOptions = new Options();
+
+ JackApiToolchain() {}
+
+ @Override
+ @Nonnull
+ public JackApiToolchain disableDxOptimizations() {
+ jackOptions.disableDxOptimizations();
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public JackApiToolchain enableDxOptimizations() {
+ jackOptions.enableDxOptimizations();
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public void srcToExe(@Nonnull String classpath, @Nonnull File out, @Nonnull File... sources)
+ throws Exception {
+
+ try {
+ System.setOut(outRedirectStream);
+ System.setErr(errRedirectStream);
+
+ addProperties(properties, jackOptions);
+
+ if (jackOptions.getFlags() != null) {
+ jackOptions.applyShrobFlags();
+ }
+
+ jackOptions.setEcjArguments(AbstractTestTools.buildEcjArgs());
+
+ if (annotationProcessorClass != null) {
+ jackOptions.getEcjArguments().add("-processor");
+ jackOptions.getEcjArguments().add(annotationProcessorClass.getName());
+ }
+
+ if (annotationProcessorOutDir != null) {
+ jackOptions.getEcjArguments().add("-d");
+ jackOptions.getEcjArguments().add(annotationProcessorOutDir.getAbsolutePath());
+ }
+
+ for (String ecjArg : extraEcjArgs) {
+ jackOptions.getEcjArguments().add(ecjArg);
+ }
+
+ AbstractTestTools.addFile(jackOptions.getEcjArguments(),
+ /* mustExist = */false, sources);
+ jackOptions.setClasspath(classpath);
+
+ // !zip
+ jackOptions.setOutputDir(out);
+
+ jackOptions.setJayceImports(staticLibs);
+
+ jackOptions.setJarjarRulesFile(jarjarRules);
+ List<File> proguardFlagsFiles = new ArrayList<File>();
+
+ for (File flagFile : proguardFlagsFiles) {
+ proguardFlagsFiles.add(flagFile);
+ }
+
+ if (proguardFlagsFiles.size() > 0) {
+ jackOptions.setProguardFlagsFile(proguardFlagsFiles);
+ }
+
+ jackOptions.addProperty(Options.EMIT_LOCAL_DEBUG_INFO.getName(),
+ Boolean.toString(withDebugInfos));
+
+ if (jackOptions.getIncrementalFolder() != null) {
+ JackIncremental.run(jackOptions);
+ } else {
+ Jack.run(jackOptions);
+ }
+
+ } finally {
+ System.setOut(stdOut);
+ System.setErr(stdErr);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public void srcToLib(@Nonnull String classpath, @Nonnull File out, boolean zipFiles,
+ @Nonnull File... sources) throws Exception {
+
+ try {
+ Options options = jackOptions;
+
+ addProperties(properties, options);
+
+ options.setClasspath(classpath);
+
+ if (zipFiles) {
+ options.setJayceOutputZip(out);
+ } else {
+ options.setJayceOutputDir(out);
+ }
+
+ options.setEcjArguments(AbstractTestTools.buildEcjArgs());
+
+ if (annotationProcessorClass != null) {
+ options.getEcjArguments().add("-processor");
+ options.getEcjArguments().add(annotationProcessorClass.getName());
+ }
+
+ if (annotationProcessorOutDir != null) {
+ options.getEcjArguments().add("-d");
+ options.getEcjArguments().add(annotationProcessorOutDir.getAbsolutePath());
+ }
+
+ for (String ecjArg : extraEcjArgs) {
+ options.getEcjArguments().add(ecjArg);
+ }
+
+ AbstractTestTools.addFile(options.getEcjArguments(),
+ /* mustExist = */false, sources);
+
+ options.addProperty(Options.EMIT_LOCAL_DEBUG_INFO.getName(),
+ Boolean.toString(withDebugInfos));
+
+ System.setOut(outRedirectStream);
+ System.setErr(errRedirectStream);
+
+ if (options.getIncrementalFolder() != null) {
+ JackIncremental.run(options);
+ } else {
+ Jack.run(options);
+ }
+
+ } finally {
+ System.setOut(stdOut);
+ System.setErr(stdErr);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public void libToDex(@Nonnull File in, @Nonnull File out) throws Exception {
+ System.setOut(outRedirectStream);
+ System.setErr(errRedirectStream);
+
+ try {
+ Options options = jackOptions;
+ addProperties(properties, options);
+
+ options.getJayceImport().add(in);
+ options.getJayceImport().addAll(staticLibs);
+
+ // !zip
+ options.setOutputDir(out);
+
+ if (options.getIncrementalFolder() != null) {
+ JackIncremental.run(options);
+ } else {
+ Jack.run(options);
+ }
+
+ } finally {
+ System.setOut(stdOut);
+ System.setErr(stdErr);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public void libToLib(@Nonnull File in, @Nonnull File out) throws Exception {
+ throw new AssertionError("Not Yet Implemented");
+ }
+
+ @Nonnull
+ public JackApiToolchain setShrobFlags(@Nonnull Flags shrobFlags) {
+ jackOptions.setFlags(shrobFlags);
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public JackApiToolchain setIncrementalFolder(@Nonnull File incrementalFolder) {
+ jackOptions.setIncrementalFolder(incrementalFolder);
+ return this;
+ }
+
+ private static final void addProperties(@Nonnull Map<String, String> properties,
+ @Nonnull Options jackOptions) {
+ for (Entry<String, String> entry : properties.entrySet()) {
+ jackOptions.addProperty(entry.getKey(), entry.getValue());
+ }
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/JackBasedToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/JackBasedToolchain.java
new file mode 100644
index 0000000..729eb89
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/JackBasedToolchain.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * Defines an {@link AndroidToolchain} built on Jack.
+ */
+public abstract class JackBasedToolchain extends AndroidToolchain {
+
+ @Nonnull
+ protected final Map<String, String> properties = new HashMap<String, String>();
+ @CheckForNull
+ protected File annotationProcessorOutDir;
+ @Nonnull
+ protected List<String> extraEcjArgs = new ArrayList<String>();
+
+ @Nonnull
+ public final JackBasedToolchain addProperty(@Nonnull String propertyName,
+ @Nonnull String propertyValue) {
+ properties.put(propertyName, propertyValue);
+ return this;
+ }
+
+ @Nonnull
+ public final JackBasedToolchain addEcjArgs(@Nonnull String arg) {
+ extraEcjArgs.add(arg);
+ return this;
+ }
+
+ @Nonnull
+ public final JackBasedToolchain setAnnotationProcessorOutDir(
+ @Nonnull File annotationProcessorOutDir) {
+ this.annotationProcessorOutDir = annotationProcessorOutDir;
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public JackBasedToolchain setSourceLevel(@Nonnull SourceLevel sourceLevel) {
+ super.setSourceLevel(sourceLevel);
+ switch (sourceLevel) {
+ case JAVA_6:
+ addProperty("jack.java.source.version", "1.6");
+ break;
+ case JAVA_7:
+ addProperty("jack.java.source.version", "1.7");
+ break;
+ default:
+ throw new AssertionError("Unkown level: '" + sourceLevel.toString() + "'");
+ }
+ return this;
+ }
+
+ @Nonnull
+ public abstract JackBasedToolchain setIncrementalFolder(@Nonnull File incrementalFolder);
+
+ @Override
+ @Nonnull
+ public File[] getDefaultBootClasspath() {
+ return new File[] {new File(AbstractTestTools.getJackRootDir(),
+ "toolchain/jack/jack-tests/libs/core-stubs-mini.jar"), new File(
+ AbstractTestTools.getJackRootDir(),
+ "toolchain/jack/jack-tests/prebuilts/junit4-hostdex.jar")};
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/JackCliToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/JackCliToolchain.java
new file mode 100644
index 0000000..17f11dd
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/JackCliToolchain.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import com.android.jack.backend.dex.rop.CodeItemBuilder;
+import com.android.jack.util.ExecuteFile;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * This class implements a {@link JackBasedToolchain} by calling Jack via command line.
+ */
+public class JackCliToolchain extends JackBasedToolchain {
+
+ @Nonnull
+ protected File jackPrebuilt;
+
+ @Nonnull
+ private List<String> extraJackArgs = new ArrayList<String>(0);
+ @CheckForNull
+ private File incrementalFolder;
+
+ JackCliToolchain(@Nonnull File prebuilt) {
+ this.jackPrebuilt = prebuilt;
+ }
+
+ @Override
+ @Nonnull
+ public void srcToExe(@Nonnull String classpath, @Nonnull File out,
+ @Nonnull File... sources) throws Exception {
+
+ List<String> args = new ArrayList<String>();
+ args.add("java");
+ args.add("-cp");
+ args.add(jackPrebuilt.getAbsolutePath());
+
+ if (incrementalFolder != null) {
+ args.add(com.android.jack.experimental.incremental.Main.class.getName());
+ args.add("--incremental-folder");
+ args.add(incrementalFolder.getAbsolutePath());
+ } else {
+ args.add(com.android.jack.Main.class.getName());
+ }
+
+ if (withDebugInfos) {
+ args.add("-D");
+ args.add("jack.dex.optimize=false");
+ } else {
+ args.add("-D");
+ args.add("jack.dex.optimize=true");
+ }
+
+ addProperties(properties, args);
+
+ args.add("--classpath");
+ args.add(classpath);
+
+ args.add("-o");
+ args.add(out.getAbsolutePath());
+
+ if (jarjarRules != null) {
+ args.add("--jarjar-rules");
+ args.add(jarjarRules.getAbsolutePath());
+ }
+
+ for (File flags : proguardFlags) {
+ args.add("--proguard-flags");
+ args.add(flags.getAbsolutePath());
+ }
+
+ for (File staticLib : staticLibs) {
+ args.add("--import-jack");
+ args.add(staticLib.getAbsolutePath());
+ }
+
+ args.addAll(extraJackArgs);
+
+ args.add("--ecj");
+
+ if (withDebugInfos) {
+ args.add("-g");
+ }
+
+ if (annotationProcessorClass != null) {
+ args.add("-processor");
+ args.add(annotationProcessorClass.getName());
+ }
+ if (annotationProcessorOutDir != null) {
+ args.add("-d");
+ args.add(annotationProcessorOutDir.getAbsolutePath());
+ }
+ for (String ecjArg : extraEcjArgs) {
+ args.add(ecjArg);
+ }
+
+ AbstractTestTools.addFile(args, /* mustExist = */ false, sources);
+
+ ExecuteFile exec = new ExecuteFile(args.toArray(new String[args.size()]));
+ exec.setErr(outRedirectStream);
+ exec.setOut(errRedirectStream);
+ exec.setVerbose(true);
+
+ if (!exec.run()) {
+ throw new RuntimeException("Jack compiler exited with an error");
+ }
+
+ }
+
+ @Override
+ @Nonnull
+ public void srcToLib(@Nonnull String classpath, @Nonnull File out,
+ boolean zipFiles, @Nonnull File... sources) throws Exception {
+
+ List<String> args = new ArrayList<String>();
+ args.add("java");
+ args.add("-cp");
+ args.add(jackPrebuilt.getAbsolutePath());
+
+ if (incrementalFolder != null) {
+ args.add(com.android.jack.experimental.incremental.Main.class.getName());
+ args.add("--incremental-folder");
+ args.add(incrementalFolder.getAbsolutePath());
+ } else {
+ args.add(com.android.jack.Main.class.getName());
+ }
+
+ addProperties(properties, args);
+
+ args.add("--classpath");
+ args.add(classpath);
+
+ if (zipFiles) {
+ args.add("--jack-output-zip");
+ } else {
+ args.add("--jack-output");
+ }
+ args.add(out.getAbsolutePath());
+
+ args.addAll(extraJackArgs);
+
+ args.add("--ecj");
+
+ if (withDebugInfos) {
+ args.add("-g");
+ }
+
+ if (annotationProcessorClass != null) {
+ args.add("-processor");
+ args.add(annotationProcessorClass.getName());
+ }
+ if (annotationProcessorOutDir != null) {
+ args.add("-d");
+ args.add(annotationProcessorOutDir.getAbsolutePath());
+ }
+ for (String ecjArg : extraEcjArgs) {
+ args.add(ecjArg);
+ }
+
+ AbstractTestTools.addFile(args, /* mustExist = */ false, sources);
+
+ ExecuteFile exec = new ExecuteFile(args.toArray(new String[args.size()]));
+ exec.setErr(outRedirectStream);
+ exec.setOut(errRedirectStream);
+ exec.setVerbose(true);
+
+ if (!exec.run()) {
+ throw new RuntimeException("Jack compiler exited with an error");
+ }
+
+ }
+
+ @Override
+ @Nonnull
+ public void libToDex(@Nonnull File in, @Nonnull File out) throws Exception {
+
+ List<String> args = new ArrayList<String>();
+ args.add("java");
+ args.add("-cp");
+ args.add(jackPrebuilt.getAbsolutePath());
+
+ if (incrementalFolder != null) {
+ args.add(com.android.jack.experimental.incremental.Main.class.getName());
+ args.add("--incremental-folder");
+ args.add(incrementalFolder.getAbsolutePath());
+ } else {
+ args.add(com.android.jack.Main.class.getName());
+ }
+
+ if (withDebugInfos) {
+ args.add("-D");
+ args.add("jack.dex.optimize=false");
+ } else {
+ args.add("-D");
+ args.add("jack.dex.optimize=true");
+ }
+
+ addProperties(properties, args);
+
+ args.add("--import-jack");
+ args.add(in.getAbsolutePath());
+
+ for (File staticLib : staticLibs) {
+ args.add("--import-jack");
+ args.add(staticLib.getAbsolutePath());
+ }
+
+ args.add("-o");
+ args.add(out.getAbsolutePath());
+
+ ExecuteFile exec = new ExecuteFile(args.toArray(new String[args.size()]));
+ exec.setErr(outRedirectStream);
+ exec.setOut(errRedirectStream);
+ exec.setVerbose(true);
+
+ if (!exec.run()) {
+ throw new RuntimeException("Jack compiler exited with an error");
+ }
+ }
+
+ @Override
+ @Nonnull
+ public void libToLib(@Nonnull File in, @Nonnull File out) throws Exception {
+ throw new AssertionError("Not Yet Implemented");
+ }
+
+ @Override
+ @Nonnull
+ public JackCliToolchain disableDxOptimizations() {
+ addProperty(CodeItemBuilder.DEX_OPTIMIZE.getName(), "false");
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public JackCliToolchain enableDxOptimizations() {
+ addProperty(CodeItemBuilder.DEX_OPTIMIZE.getName(), "true");
+ return this;
+ }
+
+ @Nonnull
+ public JackCliToolchain addJackArg(@Nonnull String arg) {
+ extraJackArgs.add(arg);
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public JackCliToolchain setIncrementalFolder(@Nonnull File incrementalFolder) {
+ this.incrementalFolder = incrementalFolder;
+ return this;
+ }
+
+ private static void addProperties(@Nonnull Map<String, String> properties,
+ @Nonnull List<String> args) {
+ for (Entry<String, String> entry : properties.entrySet()) {
+ args.add("-D");
+ args.add(entry.getKey() + "=" + entry.getValue());
+ }
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/JillBasedToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/JillBasedToolchain.java
new file mode 100644
index 0000000..dbcc528
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/JillBasedToolchain.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import com.android.jack.test.util.ExecFileException;
+import com.android.jack.test.util.ExecuteFile;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link AndroidToolchain} uses Jill to convert legacy library format
+ * to dex format.
+ */
+public abstract class JillBasedToolchain extends JackCliToolchain {
+
+ @Nonnull
+ private File jillPrebuilt;
+
+ JillBasedToolchain(@Nonnull File jillPrebuilt, @Nonnull File jackPrebuilt) {
+ super(jackPrebuilt);
+ this.jillPrebuilt = jillPrebuilt;
+ }
+
+ protected void executeJill(@Nonnull File in, @Nonnull File out, boolean zipFiles) {
+ List<String> args = new ArrayList<String>();
+ args.add("java");
+ args.add("-jar");
+ args.add(jillPrebuilt.getAbsolutePath());
+ if (zipFiles) {
+ args.add("--container");
+ args.add("zip");
+ }
+ args.add(in.getAbsolutePath());
+ args.add("-o");
+ args.add(out.getAbsolutePath());
+
+ ExecuteFile execFile = new ExecuteFile(args.toArray(new String[args.size()]));
+ execFile.setOut(outRedirectStream);
+ execFile.setErr(errRedirectStream);
+ execFile.setVerbose(true);
+
+ try {
+ if (execFile.run() != 0) {
+ throw new RuntimeException("Jill exited with an error");
+ }
+ } catch (ExecFileException e) {
+ throw new RuntimeException("An error occured while running Jill", e);
+ }
+ }
+
+}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/LegacyJillToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/LegacyJillToolchain.java
new file mode 100644
index 0000000..5ebf6e4
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/LegacyJillToolchain.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import com.android.jack.test.util.ExecFileException;
+import com.android.jack.test.util.ExecuteFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link JillBasedToolchain} uses legacy java compiler as a frontend.
+ */
+public class LegacyJillToolchain extends JillBasedToolchain {
+
+ @Nonnull
+ private File jarjarPrebuilt;
+ @Nonnull
+ private File proguardPrebuilt;
+
+ public LegacyJillToolchain(@Nonnull File jillPrebuilt, @Nonnull File jackPrebuilt,
+ @Nonnull File jarjarPrebuilt, @Nonnull File proguardPrebuilt) {
+ super(jillPrebuilt, jackPrebuilt);
+ this.jarjarPrebuilt = jarjarPrebuilt;
+ this.proguardPrebuilt = proguardPrebuilt;
+ }
+
+ @Override
+ @Nonnull
+ public void srcToExe(@Nonnull String classpath, @Nonnull File out, @Nonnull File... sources)
+ throws Exception {
+ try {
+
+ File jarFile = AbstractTestTools.createTempFile("legacyLib", ".jar");
+ File jarFileJarjar = AbstractTestTools.createTempFile("legacyLibJarjar", ".jar");
+ File jarFileProguard = AbstractTestTools.createTempFile("legacyLibProguard", ".jar");
+
+ srcToLib(classpath, jarFile, true /* zipFiles = */, sources);
+
+ if (jarjarRules != null) {
+ processWithJarJar(jarjarRules, jarFile, jarFileJarjar);
+ } else {
+ jarFileJarjar = jarFile;
+ }
+
+ if (proguardFlags.size() > 0) {
+ processWithProguard(classpath, proguardFlags, jarFileJarjar,
+ jarFileProguard);
+ } else {
+ jarFileProguard = jarFileJarjar;
+ }
+
+ File jillLib = AbstractTestTools.createTempFile("jillLib", ".jar");
+ executeJill(jarFileProguard, jillLib, true);
+
+ libToDex(jillLib, out);
+
+ } catch (IOException e) {
+ throw new RuntimeException("Legacy toolchain exited with an error", e);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public void srcToLib(@Nonnull String classpath, @Nonnull File out, boolean zipFiles,
+ @Nonnull File... sources) throws Exception {
+
+ if (withDebugInfos) {
+ // TODO(jmhenaff): warning log?
+ }
+
+ try {
+ File classesDir;
+ if (zipFiles) {
+ classesDir = AbstractTestTools.createTempDir();
+ } else {
+ classesDir = out;
+ }
+
+ compileWithExternalRefCompiler(sources, classpath, classesDir);
+
+ if (staticLibs.size() > 0) {
+ for (File staticLib : staticLibs) {
+ AbstractTestTools.unzip(staticLib, classesDir);
+ }
+ }
+ if (zipFiles) {
+ AbstractTestTools.createjar(out, classesDir);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Legacy toolchain exited with an error", e);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public void libToLib(@Nonnull File in, @Nonnull File out) throws Exception {
+ throw new AssertionError("Not Yet Implemented");
+ }
+
+ private void compileWithExternalRefCompiler(@Nonnull File[] sources,
+ @Nonnull String classpath, @Nonnull File out) {
+
+ List<String> arguments = new ArrayList<String>();
+ String refCompilerPath = System.getenv("REF_JAVA_COMPILER");
+
+ if (refCompilerPath == null) {
+ throw new RuntimeException("REF_JAVA_COMPILER environment variable not set");
+ }
+
+ arguments.add(refCompilerPath.trim());
+
+ addSourceLevel(sourceLevel, arguments);
+
+ if (annotationProcessorClass != null) {
+ arguments.add("-processor");
+ arguments.add(annotationProcessorClass.getName());
+ }
+
+ if (classpath != null) {
+ arguments.add("-classpath");
+ arguments.add(classpath);
+ }
+
+ AbstractTestTools.addFile(arguments, false, sources);
+
+ arguments.add("-d");
+ arguments.add(out.getAbsolutePath());
+
+ ExecuteFile execFile = new ExecuteFile(arguments.toArray(new String[arguments.size()]));
+ execFile.setErr(outRedirectStream);
+ execFile.setOut(errRedirectStream);
+ execFile.setVerbose(true);
+ try {
+ if (execFile.run() != 0) {
+ throw new RuntimeException("Reference compiler exited with an error");
+ }
+ } catch (ExecFileException e) {
+ throw new RuntimeException("An error occured while running reference compiler", e);
+ }
+ }
+
+ private void processWithJarJar(@Nonnull File jarjarRules,
+ @Nonnull File inJar, @Nonnull File outJar) {
+ String[] args = new String[]{"java", "-jar", jarjarPrebuilt.getAbsolutePath(),
+ "process", jarjarRules.getAbsolutePath(),
+ inJar.getAbsolutePath(), outJar.getAbsolutePath()};
+
+ ExecuteFile execFile = new ExecuteFile(args);
+ execFile.setOut(outRedirectStream);
+ execFile.setErr(errRedirectStream);
+ execFile.setVerbose(true);
+
+ try {
+ if (execFile.run() != 0) {
+ throw new RuntimeException("JarJar exited with an error");
+ }
+ } catch (ExecFileException e) {
+ throw new RuntimeException("An error occured while running Jarjar", e);
+ }
+ }
+
+ private void processWithProguard(@Nonnull String bootclasspathStr,
+ @Nonnull List<File> proguardFlags, @Nonnull File inJar, @Nonnull File outJar) {
+
+ List<String> args = new ArrayList<String>();
+ args.add("java");
+ args.add("-jar");
+ args.add(proguardPrebuilt.getAbsolutePath());
+ args.add("-injar");
+ args.add(inJar.getAbsolutePath());
+ args.add("-outjars");
+ args.add(outJar.getAbsolutePath());
+ args.add("-libraryjars");
+ args.add(bootclasspathStr);
+ args.add("-verbose");
+ args.add("-forceprocessing");
+ args.add("-dontoptimize");
+ for (File flags : proguardFlags) {
+ args.add("-include");
+ args.add(flags.getAbsolutePath());
+ }
+
+ ExecuteFile execFile = new ExecuteFile(args.toArray(new String[args.size()]));
+ execFile.setOut(outRedirectStream);
+ execFile.setErr(errRedirectStream);
+ execFile.setVerbose(true);
+
+ try {
+ if (execFile.run() != 0) {
+ throw new RuntimeException("Proguard exited with an error");
+ }
+ } catch (ExecFileException e) {
+ throw new RuntimeException("An error occured while running Proguard", e);
+ }
+ }
+
+ private static void addSourceLevel(@Nonnull SourceLevel level, @Nonnull List<String> args) {
+ args.add("-source");
+ switch (level) {
+ case JAVA_6:
+ args.add("1.6");
+ break;
+ case JAVA_7:
+ args.add("1.7");
+ break;
+ default:
+ throw new AssertionError("Unkown level: '" + level.toString() + "'");
+ }
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/LegacyToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/LegacyToolchain.java
new file mode 100644
index 0000000..3a5a231
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/LegacyToolchain.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import com.android.dx.command.dexer.Main.Arguments;
+import com.android.jack.test.util.ExecFileException;
+import com.android.jack.test.util.ExecuteFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * The legacy android toolchain.
+ */
+public class LegacyToolchain extends AndroidToolchain {
+
+ @Nonnull
+ private final File legacyCompilerPrebuilt;
+ @Nonnull
+ private final File jarjarPrebuilt;
+ @Nonnull
+ private final File proguardPrebuilt;
+
+ private boolean useDxOptimization = true;
+
+ LegacyToolchain(@Nonnull File legacyCompilerPrebuilt, @Nonnull File jarjarPrebuilt,
+ @Nonnull File proguardPrebuilt) {
+ this.legacyCompilerPrebuilt = legacyCompilerPrebuilt;
+ this.jarjarPrebuilt = jarjarPrebuilt;
+ this.proguardPrebuilt = proguardPrebuilt;
+ }
+
+ @Override
+ @Nonnull
+ public void srcToExe(@Nonnull String classpath, @Nonnull File out,
+ @Nonnull File... sources) throws Exception {
+
+ try {
+
+ File jarFile = AbstractTestTools.createTempFile("legacyLib", ".jar");
+ File jarFileJarjar = AbstractTestTools.createTempFile("legacyLibJarjar", ".jar");
+ File jarFileProguard = AbstractTestTools.createTempFile("legacyLibProguard", ".jar");
+
+ srcToLib(classpath, jarFile, true /* zipFiles = */, sources);
+
+ if (jarjarRules != null) {
+ processWithJarJar(jarjarRules, jarFile, jarFileJarjar);
+ } else {
+ jarFileJarjar = jarFile;
+ }
+
+ if (proguardFlags.size() > 0) {
+ processWithProguard(classpath, proguardFlags, jarFileJarjar,
+ jarFileProguard);
+ } else {
+ jarFileProguard = jarFileJarjar;
+ }
+
+ libToDex(jarFileProguard, out);
+
+ } catch (IOException e) {
+ throw new RuntimeException("Legacy toolchain exited with an error", e);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public void srcToLib(@Nonnull String classpath, @Nonnull File out,
+ boolean zipFiles, @Nonnull File... sources) throws Exception {
+
+ try {
+ File classesDir;
+ if (zipFiles) {
+ classesDir = AbstractTestTools.createTempDir();
+ } else {
+ classesDir = out;
+ }
+ if (withDebugInfos) {
+ compileWithEcj(sources, classpath, classesDir);
+ } else {
+ compileWithExternalRefCompiler(sources, classpath, classesDir);
+ }
+ if (staticLibs.size() > 0) {
+ for (File staticLib : staticLibs) {
+ AbstractTestTools.unzip(staticLib, classesDir);
+ }
+ }
+ if (zipFiles) {
+ AbstractTestTools.createjar(out, classesDir);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Legacy toolchain exited with an error", e);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public void libToDex(@Nonnull File in, @Nonnull File out) throws Exception {
+
+ try {
+ compileWithDx(in, out);
+ } catch (IOException e) {
+ throw new RuntimeException("Legacy toolchain exited with an error", e);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public void libToLib(@Nonnull File in, @Nonnull File out) throws Exception {
+ throw new AssertionError("Not Yet Implemented");
+ }
+
+ @Override
+ @Nonnull
+ public File[] getDefaultBootClasspath() {
+ return new File[] {
+ new File(AbstractTestTools.getJackRootDir(),
+ "toolchain/jack/jack-tests/libs/core-stubs-mini.jar"),
+ new File(AbstractTestTools.getJackRootDir(),
+ "toolchain/jack/jack-tests/libs/junit4.jar")
+ };
+ }
+
+ private void processWithJarJar(@Nonnull File jarjarRules,
+ @Nonnull File inJar, @Nonnull File outJar) {
+ String[] args = new String[]{"java", "-jar", jarjarPrebuilt.getAbsolutePath(),
+ "process", jarjarRules.getAbsolutePath(),
+ inJar.getAbsolutePath(), outJar.getAbsolutePath()};
+
+ ExecuteFile execFile = new ExecuteFile(args);
+ execFile.setOut(outRedirectStream);
+ execFile.setErr(errRedirectStream);
+ execFile.setVerbose(true);
+
+ try {
+ if (execFile.run() != 0) {
+ throw new RuntimeException("JarJar exited with an error");
+ }
+ } catch (ExecFileException e) {
+ throw new RuntimeException("An error occured while running Jarjar", e);
+ }
+ }
+
+ private void processWithProguard(@Nonnull String bootclasspathStr,
+ @Nonnull List<File> proguardFlags, @Nonnull File inJar, @Nonnull File outJar) {
+
+ List<String> args = new ArrayList<String>();
+ args.add("java");
+ args.add("-jar");
+ args.add(proguardPrebuilt.getAbsolutePath());
+ args.add("-injar");
+ args.add(inJar.getAbsolutePath());
+ args.add("-outjars");
+ args.add(outJar.getAbsolutePath());
+ args.add("-libraryjars");
+ args.add(bootclasspathStr);
+ args.add("-verbose");
+ args.add("-forceprocessing");
+ args.add("-dontoptimize");
+ for (File flags : proguardFlags) {
+ args.add("-include");
+ args.add(flags.getAbsolutePath());
+ }
+
+ ExecuteFile execFile = new ExecuteFile(args.toArray(new String[args.size()]));
+ execFile.setOut(outRedirectStream);
+ execFile.setErr(errRedirectStream);
+ execFile.setVerbose(true);
+
+ try {
+ if (execFile.run() != 0) {
+ throw new RuntimeException("Proguard exited with an error");
+ }
+ } catch (ExecFileException e) {
+ throw new RuntimeException("An error occured while running Proguard", e);
+ }
+ }
+
+ private void compileWithEcj(@Nonnull File[] sources, @Nonnull String classpath,
+ @Nonnull File out) {
+
+ throw new AssertionError("Not yet implemented");
+ }
+
+ @Override
+ @Nonnull
+ public LegacyToolchain disableDxOptimizations() {
+ useDxOptimization = false;
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public LegacyToolchain enableDxOptimizations() {
+ useDxOptimization = true;
+ return this;
+ }
+
+ private static void addSourceLevel(@Nonnull SourceLevel level, @Nonnull List<String> args) {
+ args.add("-source");
+ switch (level) {
+ case JAVA_6:
+ args.add("1.6");
+ break;
+ case JAVA_7:
+ args.add("1.7");
+ break;
+ default:
+ throw new AssertionError("Unkown level: '" + level.toString() + "'");
+ }
+ }
+
+ private void compileWithExternalRefCompiler(@Nonnull File[] sources,
+ @Nonnull String classpath, @Nonnull File out) {
+
+ List<String> arguments = new ArrayList<String>();
+
+ arguments.add(legacyCompilerPrebuilt.getAbsolutePath());
+
+ addSourceLevel(sourceLevel, arguments);
+
+ if (annotationProcessorClass != null) {
+ arguments.add("-processor");
+ arguments.add(annotationProcessorClass.getName());
+ }
+
+ if (classpath != null) {
+ arguments.add("-classpath");
+ arguments.add(classpath);
+ }
+
+ AbstractTestTools.addFile(arguments, false, sources);
+
+ arguments.add("-d");
+ arguments.add(out.getAbsolutePath());
+
+ ExecuteFile execFile = new ExecuteFile(arguments.toArray(new String[arguments.size()]));
+ execFile.setErr(outRedirectStream);
+ execFile.setOut(errRedirectStream);
+ execFile.setVerbose(true);
+ try {
+ if (execFile.run() != 0) {
+ throw new RuntimeException("Reference compiler exited with an error");
+ }
+ } catch (ExecFileException e) {
+ throw new RuntimeException("An error occured while running reference compiler", e);
+ }
+ }
+
+ private void compileWithDx(File in, File out)
+ throws IOException {
+
+ try {
+ System.setOut(outRedirectStream);
+ System.setErr(errRedirectStream);
+
+ Arguments arguments = new Arguments();
+
+ arguments.jarOutput = false;
+ arguments.outName = new File(out, getBinaryFileName()).getAbsolutePath();
+ arguments.optimize = !withDebugInfos && useDxOptimization;
+ // this only means we deactivate the check that no core classes are included
+ arguments.coreLibrary = true;
+ arguments.parse(new String[] {in.getAbsolutePath()});
+
+ int retValue = com.android.dx.command.dexer.Main.run(arguments);
+ if (retValue != 0) {
+ throw new RuntimeException("Dx failed and returned " + retValue);
+ }
+ } finally {
+ System.setOut(stdOut);
+ System.setErr(stdErr);
+ }
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/TestConfigurationException.java b/jack-tests/src/com/android/jack/test/toolchain/TestConfigurationException.java
new file mode 100644
index 0000000..a329b78
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/TestConfigurationException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This {@code Exception} is thrown when something is wrong with the configuration
+ * of the test framework (unset variables, ...)
+ */
+public class TestConfigurationException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public TestConfigurationException() {
+ }
+
+ public TestConfigurationException(@Nonnull String message) {
+ super(message);
+ }
+
+ public TestConfigurationException(@Nonnull Throwable cause) {
+ super(cause);
+ }
+
+ public TestConfigurationException(@Nonnull String message, @Nonnull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/Toolchain.java b/jack-tests/src/com/android/jack/test/toolchain/Toolchain.java
new file mode 100644
index 0000000..d35d814
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/toolchain/Toolchain.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.toolchain;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.processing.Processor;
+
+/**
+ * A toolchain the ouptut of which can be redirected to user defined streams.
+ */
+public abstract class Toolchain implements IToolchain {
+
+ protected boolean withDebugInfos = false;
+
+ @CheckForNull
+ protected Class<? extends Processor> annotationProcessorClass;
+
+ /**
+ * Java source level.
+ */
+ public static enum SourceLevel {
+ JAVA_6,
+ JAVA_7,
+ }
+
+ @Nonnull
+ protected SourceLevel sourceLevel = SourceLevel.JAVA_6;
+ @Nonnull
+ protected List<File> staticLibs = Collections.emptyList();
+ @Nonnull
+ protected List<File> proguardFlags = Collections.emptyList();
+ @CheckForNull
+ protected File jarjarRules;
+
+ @Nonnull
+ protected PrintStream stdOut = System.out;
+ @Nonnull
+ protected PrintStream stdErr = System.err;
+ @Nonnull
+ protected PrintStream outRedirectStream = System.out;
+ @Nonnull
+ protected PrintStream errRedirectStream = System.err;
+
+ Toolchain() {}
+
+ @Override
+ @Nonnull
+ public abstract void srcToExe(@Nonnull String classpath, @Nonnull File out,
+ @Nonnull File... sources) throws Exception;
+
+ @Override
+ @Nonnull
+ public abstract void srcToLib(@Nonnull String classpath, @Nonnull File out,
+ boolean zipFiles, @Nonnull File... sources) throws Exception;
+
+ @Override
+ @Nonnull
+ public abstract void libToDex(@Nonnull File in, @Nonnull File out) throws Exception;
+
+ @Override
+ @Nonnull
+ public abstract void libToLib(@Nonnull File in, @Nonnull File out) throws Exception;
+
+ @Override
+ @Nonnull
+ public Toolchain setWithDebugInfos(boolean withDebugInfos) {
+ this.withDebugInfos = withDebugInfos;
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public final Toolchain setAnnotationProcessorClass(
+ @Nonnull Class<? extends Processor> annotationProcessorClass) {
+ this.annotationProcessorClass = annotationProcessorClass;
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public Toolchain setSourceLevel(@Nonnull SourceLevel sourceLevel) {
+ this.sourceLevel = sourceLevel;
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public final Toolchain addProguardFlags(@Nonnull File... proguardFlags) {
+ if (this.proguardFlags == Collections.EMPTY_LIST) {
+ this.proguardFlags = new ArrayList<File>(proguardFlags.length);
+ }
+ Collections.addAll(this.proguardFlags, proguardFlags);
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public final Toolchain setJarjarRules(@Nonnull File jarjarRules) {
+ this.jarjarRules = jarjarRules;
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public final Toolchain addStaticLibs(@Nonnull File... staticLibs) {
+ if (this.staticLibs == Collections.EMPTY_LIST) {
+ this.staticLibs = new ArrayList<File>(staticLibs.length);
+ }
+ Collections.addAll(this.staticLibs, staticLibs);
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public final Toolchain setOutputStream(@Nonnull OutputStream outputStream) {
+ if (outRedirectStream != null) {
+ outRedirectStream.close();
+ }
+ outRedirectStream = new PrintStream(outputStream);
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public final Toolchain setErrorStream(@Nonnull OutputStream errorStream) {
+ if (errRedirectStream != null) {
+ errRedirectStream.close();
+ }
+ errRedirectStream = new PrintStream(errorStream);
+ return this;
+ }
+}
diff --git a/jack-tests/src/com/android/jack/test/util/BytesStreamSucker.java b/jack-tests/src/com/android/jack/test/util/BytesStreamSucker.java
new file mode 100644
index 0000000..3f74378
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/util/BytesStreamSucker.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.util;
+
+import com.google.common.io.NullOutputStream;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Class that continuously read an {@link InputStream} and optionally could write the input in a
+ * {@link OutputStream}.
+ */
+public class BytesStreamSucker {
+
+ private static final int BUFFER_SIZE = 4096;
+
+ @Nonnull
+ private final byte[] buffer = new byte[BUFFER_SIZE];
+
+ @Nonnull
+ private final InputStream is;
+
+ @Nonnull
+ private final OutputStream os;
+
+ private final boolean toBeClose;
+
+ public BytesStreamSucker(
+ @Nonnull InputStream is, @Nonnull OutputStream os, boolean toBeClose) {
+ this.is = is;
+ this.os = os;
+ this.toBeClose = toBeClose;
+ }
+
+ public BytesStreamSucker(@Nonnull InputStream is, @Nonnull OutputStream os) {
+ this(is, os, false);
+ }
+
+ public BytesStreamSucker(@Nonnull InputStream is) {
+ this(is, new NullOutputStream(), false);
+ }
+
+ public void suck() throws IOException {
+ try {
+ int bytesRead;
+ while ((bytesRead = is.read(buffer)) >= 0) {
+ os.write(buffer, 0, bytesRead);
+ os.flush();
+ }
+ } finally {
+ if (toBeClose) {
+ os.close();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/jack-tests/src/com/android/jack/test/util/CharactersStreamSucker.java b/jack-tests/src/com/android/jack/test/util/CharactersStreamSucker.java
new file mode 100644
index 0000000..7e5b9f2
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/util/CharactersStreamSucker.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Class that continuously read an {@link InputStream} and optionally could print the input in a
+ * {@link PrintStream}.
+ */
+public class CharactersStreamSucker {
+
+ @Nonnull
+ private final InputStream is;
+ @Nonnull
+ private final PrintStream os;
+
+ private final boolean toBeClose;
+
+ public CharactersStreamSucker(
+ @Nonnull InputStream is, @Nonnull PrintStream os, boolean toBeClose) {
+ this.is = is;
+ this.os = os;
+ this.toBeClose = toBeClose;
+ }
+
+ public CharactersStreamSucker(@Nonnull InputStream is, @Nonnull PrintStream os) {
+ this(is, os, false);
+ }
+
+ public CharactersStreamSucker(@Nonnull InputStream is) {
+ this(is, new NullPrintStream(), false);
+ }
+
+ public void suck() throws IOException {
+ int readChar;
+ try {
+ while ((readChar = is.read()) != -1) {
+ os.write(readChar);
+ }
+ } finally {
+ if (toBeClose) {
+ os.close();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/jack-tests/src/com/android/jack/test/util/ExecFileException.java b/jack-tests/src/com/android/jack/test/util/ExecFileException.java
new file mode 100644
index 0000000..8852f85
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/util/ExecFileException.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.util;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * Exception report during execution of an external process handle by {@link ExecuteFile}
+ */
+public class ExecFileException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ @CheckForNull
+ String errorMsg;
+
+ public ExecFileException() {
+ super();
+ }
+
+ public ExecFileException(@Nonnull String[] cmdLine, @Nonnull Exception e) {
+ super();
+
+ errorMsg = "Error during execution of ";
+
+ for (String arg : cmdLine) {
+ errorMsg += ' ' + arg;
+ }
+
+ errorMsg += ": " + e.getMessage();
+ }
+
+ public ExecFileException(@Nonnull String[] cmdLine, int value) {
+ super();
+
+ errorMsg = "Return value of ";
+
+ for (String arg : cmdLine) {
+ errorMsg += ' ' + arg;
+ }
+
+ errorMsg += " is " + value;
+
+ }
+
+ @Override
+ @CheckForNull
+ public String getMessage() {
+ return errorMsg;
+ }
+} \ No newline at end of file
diff --git a/jack-tests/src/com/android/jack/test/util/ExecuteFile.java b/jack-tests/src/com/android/jack/test/util/ExecuteFile.java
new file mode 100644
index 0000000..1f59b63
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/util/ExecuteFile.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.util;
+
+import com.android.sched.util.log.LoggerFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * Class to handle the execution of an external process
+ */
+public class ExecuteFile {
+ @Nonnull
+ private final String[] cmdLine;
+
+ @Nonnull
+ List<String> env = new ArrayList<String>(0);
+
+ @CheckForNull
+ private File workDir;
+
+ @CheckForNull
+ private InputStream inStream;
+ private boolean inToBeClose;
+
+ @CheckForNull
+ private OutputStream outStream;
+ private boolean outToBeClose;
+
+ @CheckForNull
+ private OutputStream errStream;
+ private boolean errToBeClose;
+ private boolean verbose;
+
+ @Nonnull
+ private final Logger logger;
+
+ public void setErr(@Nonnull File file) throws FileNotFoundException {
+ errStream = new FileOutputStream(file);
+ errToBeClose = true;
+ }
+
+ public void setOut(@Nonnull File file) throws FileNotFoundException {
+ outStream = new FileOutputStream(file);
+ outToBeClose = true;
+ }
+
+ public void setIn(@Nonnull File file) throws FileNotFoundException {
+ inStream = new FileInputStream(file);
+ inToBeClose = true;
+ }
+
+ public void setErr(@Nonnull OutputStream stream) {
+ errStream = stream;
+ }
+
+ public void setOut(@Nonnull OutputStream stream) {
+ outStream = stream;
+ }
+
+ public void setIn(@Nonnull InputStream stream) {
+ inStream = stream;
+ }
+
+ public void setWorkingDir(@Nonnull File dir, boolean create) throws IOException {
+ if (!dir.isDirectory()) {
+ if (create && !dir.exists()) {
+ if (!dir.mkdirs()) {
+ throw new IOException("Directory creation failed");
+ }
+ } else {
+ throw new FileNotFoundException(dir.getPath() + " is not a directory");
+ }
+ }
+
+ workDir = dir;
+ }
+
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ public void addEnvVar(@Nonnull String key, @Nonnull String value) {
+ env.add(key + "=" + value);
+ }
+
+ public ExecuteFile(@Nonnull File exec, @Nonnull String[] args) {
+ cmdLine = new String[args.length + 1];
+ System.arraycopy(args, 0, cmdLine, 1, args.length);
+
+ cmdLine[0] = exec.getAbsolutePath();
+ logger = LoggerFactory.getLogger();
+ }
+
+ public ExecuteFile(@Nonnull String exec, @Nonnull String[] args) {
+ cmdLine = new String[args.length + 1];
+ System.arraycopy(args, 0, cmdLine, 1, args.length);
+
+ cmdLine[0] = exec;
+ logger = LoggerFactory.getLogger();
+ }
+
+ public ExecuteFile(@Nonnull File exec) {
+ cmdLine = new String[1];
+ cmdLine[0] = exec.getAbsolutePath();
+ logger = LoggerFactory.getLogger();
+ }
+
+ public ExecuteFile(@Nonnull String[] cmdLine) {
+ this.cmdLine = cmdLine.clone();
+ logger = LoggerFactory.getLogger();
+ }
+
+ public ExecuteFile(@Nonnull String cmdLine) throws IOException {
+ StringReader reader = new StringReader(cmdLine);
+ StreamTokenizer tokenizer = new StreamTokenizer(reader);
+ tokenizer.resetSyntax();
+ // Only standard spaces are recognized as whitespace chars
+ tokenizer.whitespaceChars(' ', ' ');
+ // Matches alphanumerical and common special symbols like '(' and ')'
+ tokenizer.wordChars('!', 'z');
+ // Quote chars will be ignored when parsing strings
+ tokenizer.quoteChar('\'');
+ tokenizer.quoteChar('\"');
+ ArrayList<String> tokens = new ArrayList<String>();
+ while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {
+ String token = tokenizer.sval;
+ if (token != null) {
+ tokens.add(token);
+ }
+ }
+ this.cmdLine = tokens.toArray(new String[0]);
+ logger = LoggerFactory.getLogger();
+ }
+
+ public int run() throws ExecFileException {
+ int ret;
+ Process proc = null;
+ Thread suckOut = null;
+ Thread suckErr = null;
+ Thread suckIn = null;
+
+ try {
+ StringBuilder cmdLineBuilder = new StringBuilder();
+ for (String envElt : env) {
+ cmdLineBuilder.append(envElt).append(' ');
+ }
+ for (String arg : cmdLine) {
+ cmdLineBuilder.append(arg).append(' ');
+ }
+ if (verbose) {
+ PrintStream printStream;
+ if (outStream instanceof PrintStream) {
+ printStream = (PrintStream) outStream;
+ } else {
+ printStream = System.out;
+ }
+
+ if (printStream != null) {
+ printStream.println(cmdLineBuilder);
+ }
+ } else {
+ logger.log(Level.INFO, "Execute: {0}", cmdLineBuilder);
+ }
+
+ proc = Runtime.getRuntime().exec(cmdLine, env.toArray(new String[env.size()]), workDir);
+
+ InputStream localInStream = inStream;
+ if (localInStream != null) {
+ suckIn = new Thread(
+ new ThreadBytesStreamSucker(localInStream, proc.getOutputStream(), inToBeClose));
+ } else {
+ proc.getOutputStream().close();
+ }
+
+ OutputStream localOutStream = outStream;
+ if (localOutStream != null) {
+ if (localOutStream instanceof PrintStream) {
+ suckOut = new Thread(new ThreadCharactersStreamSucker(proc.getInputStream(),
+ (PrintStream) localOutStream, outToBeClose));
+ } else {
+ suckOut = new Thread(
+ new ThreadBytesStreamSucker(proc.getInputStream(), localOutStream, outToBeClose));
+ }
+ }
+
+ OutputStream localErrStream = errStream;
+ if (localErrStream != null) {
+ if (localErrStream instanceof PrintStream) {
+ suckErr = new Thread(new ThreadCharactersStreamSucker(proc.getErrorStream(),
+ (PrintStream) localErrStream, errToBeClose));
+ } else {
+ suckErr = new Thread(
+ new ThreadBytesStreamSucker(proc.getErrorStream(), localErrStream, errToBeClose));
+ }
+ }
+
+ if (suckIn != null) {
+ suckIn.start();
+ }
+ if (suckOut != null) {
+ suckOut.start();
+ }
+ if (suckErr != null) {
+ suckErr.start();
+ }
+
+ proc.waitFor();
+ if (suckIn != null) {
+ suckIn.join();
+ }
+ if (suckOut != null) {
+ suckOut.join();
+ }
+ if (suckErr != null) {
+ suckErr.join();
+ }
+
+ ret = proc.exitValue();
+ proc.destroy();
+
+ return ret;
+ } catch (Exception e) {
+ throw new ExecFileException(cmdLine, e);
+ }
+ }
+
+ private static class ThreadBytesStreamSucker extends BytesStreamSucker implements Runnable {
+
+ public ThreadBytesStreamSucker(@Nonnull InputStream is, @Nonnull OutputStream os,
+ boolean toBeClose) {
+ super(is, os, toBeClose);
+ }
+
+ @Override
+ public void run() {
+ try {
+ suck();
+ } catch (IOException e) {
+ // Best effort
+ }
+ }
+ }
+
+ private static class ThreadCharactersStreamSucker extends CharactersStreamSucker implements
+ Runnable {
+
+ public ThreadCharactersStreamSucker(@Nonnull InputStream is, @Nonnull PrintStream ps,
+ boolean toBeClose) {
+ super(is, ps, toBeClose);
+ }
+
+ @Override
+ public void run() {
+ try {
+ suck();
+ } catch (IOException e) {
+ // Best effort
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/jack-tests/src/com/android/jack/test/util/NullPrintStream.java b/jack-tests/src/com/android/jack/test/util/NullPrintStream.java
new file mode 100644
index 0000000..730153f
--- /dev/null
+++ b/jack-tests/src/com/android/jack/test/util/NullPrintStream.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.test.util;
+
+import com.google.common.io.NullOutputStream;
+
+import java.io.PrintStream;
+import java.util.Locale;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Implementation of {@link PrintStream} that simply discards all data.
+ */
+public class NullPrintStream extends PrintStream {
+ public NullPrintStream() {
+ super(new NullOutputStream());
+ }
+
+ @Override
+ public void flush() {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public boolean checkError() {
+ return false;
+ }
+
+ @Override
+ protected void setError() {
+ }
+
+ @Override
+ protected void clearError() {
+ }
+
+ @Override
+ public void write(int b) {
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) {
+ }
+
+ @Override
+ public void print(boolean b) {
+ }
+
+ @Override
+ public void print(char c) {
+ }
+
+ @Override
+ public void print(int i) {
+ }
+
+ @Override
+ public void print(long l) {
+ }
+
+ @Override
+ public void print(float f) {
+ }
+
+ @Override
+ public void print(double d) {
+ }
+
+ @Override
+ public void print(char[] s) {
+ }
+
+ @Override
+ public void print(String s) {
+ }
+
+ @Override
+ public void print(Object obj) {
+ }
+
+ @Override
+ public void println() {
+ }
+
+ @Override
+ public void println(boolean x) {
+ }
+
+ @Override
+ public void println(char x) {
+ }
+
+ @Override
+ public void println(int x) {
+ }
+
+ @Override
+ public void println(long x) {
+ }
+
+ @Override
+ public void println(float x) {
+ }
+
+ @Override
+ public void println(double x) {
+ }
+
+ @Override
+ public void println(char[] x) {
+ }
+
+ @Override
+ public void println(String x) {
+ }
+
+ @Override
+ public void println(Object x) {
+ }
+
+ @Override
+ @Nonnull
+ public PrintStream printf(String format, Object... args) {
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public PrintStream printf(Locale l, String format, Object... args) {
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public PrintStream format(String format, Object... args) {
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public PrintStream format(Locale l, String format, Object... args) {
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public PrintStream append(CharSequence csq) {
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public PrintStream append(CharSequence csq, int start, int end) {
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public PrintStream append(char c) {
+ return this;
+ }
+
+}
diff --git a/jack-tests/test-exit-status.sh b/jack-tests/test-exit-status.sh
new file mode 100755
index 0000000..2eaccfe
--- /dev/null
+++ b/jack-tests/test-exit-status.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"$@"
+echo $? > /data/jack-tests/exitStatus
+
diff --git a/jack-tests/tests.properties b/jack-tests/tests.properties
new file mode 100644
index 0000000..34ce165
--- /dev/null
+++ b/jack-tests/tests.properties
@@ -0,0 +1,12 @@
+reference.toolchain=legacy
+candidate.toolchain=jack-api
+#candidate.toolchain=jill-legacy
+toolchain.prebuilt.jack=toolchain/jack/jack/dist/jack.jar
+toolchain.prebuilt.jill=toolchain/jill/jill/dist/jill.jar
+toolchain.prebuilt.jarjar=toolchain/jack/jack-tests/prebuilts/jarjar.jar
+toolchain.prebuilt.proguard=toolchain/jack/jack-tests/prebuilts/proguard.jar
+toolchain.prebuilt.legacy-java-compiler=/usr/lib/jvm/java-6-sun/bin/javac
+runtime.list=dalvik-fast-host,art-host,dalvik-fast-device
+runtime.location.dalvik-fast-host=/disk2/tmp/dalvik-host.rt
+runtime.location.dalvik-jit-host=/disk2/tmp/dalvik-host.rt
+runtime.location.art-host=/disk2/tmp/art-host.rt
diff --git a/jack-tests/tests/com/android/jack/AllTests.java b/jack-tests/tests/com/android/jack/AllTests.java
new file mode 100644
index 0000000..091867b
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/AllTests.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack;
+
+import com.android.jack.annotation.AnnotationTests;
+import com.android.jack.arithmetic.ArithmeticTests;
+import com.android.jack.classpath.ClasspathTest;
+import com.android.jack.enums.EnumTests;
+import com.android.jack.error.AnnotationProcessorErrorTest;
+import com.android.jack.error.CommandLineErrorTest;
+import com.android.jack.error.FileAccessErrorTest;
+import com.android.jack.experimenal.incremental.DependenciesTests005;
+import com.android.jack.jarjar.JarjarTests;
+import com.android.jack.shrob.ObfuscationWithoutMappingTests;
+import com.android.jack.tools.merger.MergerAllTests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * Test suite containing all tests (except for regression tests that must be run from the command
+ * line).
+ */
+@RunWith(Suite.class)
+@SuiteClasses(value = {
+ AnnotationTests.class,
+ ArithmeticTests.class,
+ ClasspathTest.class,
+ DependenciesTests005.class,
+ EnumTests.class,
+ JarjarTests.class,
+ MergerAllTests.class,
+ ObfuscationWithoutMappingTests.class,
+ AnnotationProcessorErrorTest.class,
+ FileAccessErrorTest.class,
+ CommandLineErrorTest.class
+ })
+public class AllTests {
+}
diff --git a/jack-tests/tests/com/android/jack/AllWithRegressionTests.java b/jack-tests/tests/com/android/jack/AllWithRegressionTests.java
new file mode 100644
index 0000000..4b89472
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/AllWithRegressionTests.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack;
+
+
+import com.android.jack.test.category.RuntimeRegressionTest;
+
+import org.junit.experimental.categories.Categories;
+import org.junit.experimental.categories.Categories.ExcludeCategory;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * Test suite containing tests that are too time-consuming and cannot be run before submitting each
+ * CL.
+ */
+@RunWith(Categories.class)
+@ExcludeCategory(RuntimeRegressionTest.class)
+@SuiteClasses(value = {AllTests.class, RegressionTests.class})
+public class AllWithRegressionTests {
+}
diff --git a/jack-tests/tests/com/android/jack/RegressionTests.java b/jack-tests/tests/com/android/jack/RegressionTests.java
new file mode 100644
index 0000000..3a7ecc6
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/RegressionTests.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack;
+
+import com.android.jack.annotation.AnnotationTests;
+import com.android.jack.arithmetic.ArithmeticTests;
+import com.android.jack.test.helper.RuntimeTestHelper;
+import com.android.jack.test.runtime.RuntimeTest;
+import com.android.jack.test.runtime.RuntimeTestInfo;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RegressionTests {
+
+ public RuntimeTest[] tests = {
+ new AnnotationTests(),
+ new ArithmeticTests()
+ };
+
+ @BeforeClass
+ public static void setUpClass() {
+ Main.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ @Test
+ public void runRegressionTests() throws Exception {
+ List<RuntimeTestInfo> rtTestInfos = new ArrayList<RuntimeTestInfo>();
+
+ for (RuntimeTest test : tests) {
+ for (RuntimeTestInfo testInfos : test.getRuntimeTestInfos()) {
+ rtTestInfos.add(testInfos);
+ }
+ }
+ new RuntimeTestHelper(rtTestInfos.toArray(new RuntimeTestInfo[rtTestInfos.size()]))
+ .compileAndRunTest();
+ }
+
+}
diff --git a/jack-tests/tests/com/android/jack/annotation/AnnotationTests.java b/jack-tests/tests/com/android/jack/annotation/AnnotationTests.java
new file mode 100644
index 0000000..e68228e
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/annotation/AnnotationTests.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.annotation;
+
+import com.android.jack.Main;
+import com.android.jack.test.category.RuntimeRegressionTest;
+import com.android.jack.test.helper.CheckDexStructureTestHelper;
+import com.android.jack.test.helper.RuntimeTestHelper;
+import com.android.jack.test.runtime.RuntimeTest;
+import com.android.jack.test.runtime.RuntimeTestInfo;
+import com.android.jack.test.toolchain.AbstractTestTools;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.File;
+
+public class AnnotationTests extends RuntimeTest {
+
+ private static final File ANNOTATION001_PATH =
+ AbstractTestTools.getTestRootDir("com.android.jack.annotation.test001.jack");
+
+ private RuntimeTestInfo TEST001 = new RuntimeTestInfo(
+ AbstractTestTools.getTestRootDir("com.android.jack.annotation.test001"),
+ "com.android.jack.annotation.test001.dx.Tests");
+
+ @BeforeClass
+ public static void setUpClass() {
+ Main.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ @Test
+ public void checkStructure() throws Exception {
+ CheckDexStructureTestHelper env =
+ new CheckDexStructureTestHelper(new File(ANNOTATION001_PATH, "Annotation2.java"));
+ env.setWithDebugInfo(true);
+ env.compare();
+ }
+
+ @Test
+ @Category(RuntimeRegressionTest.class)
+ public void runtimeTest001() throws Exception {
+ new RuntimeTestHelper(TEST001).compileAndRunTest();
+ }
+
+ @Override
+ protected void fillRtTestInfos() {
+ rtTestInfos.add(TEST001);
+ }
+
+}
diff --git a/jack-tests/tests/com/android/jack/arithmetic/ArithmeticTests.java b/jack-tests/tests/com/android/jack/arithmetic/ArithmeticTests.java
new file mode 100644
index 0000000..1b6ee1a
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/arithmetic/ArithmeticTests.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.arithmetic;
+
+import com.android.jack.test.category.RuntimeRegressionTest;
+import com.android.jack.test.helper.RuntimeTestHelper;
+import com.android.jack.test.runtime.RuntimeTest;
+import com.android.jack.test.runtime.RuntimeTestInfo;
+import com.android.jack.test.toolchain.AbstractTestTools;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+public class ArithmeticTests extends RuntimeTest {
+
+ private RuntimeTestInfo TEST001 = new RuntimeTestInfo(
+ AbstractTestTools.getTestRootDir("com.android.jack.arithmetic.test001"),
+ "com.android.jack.arithmetic.test001.dx.Tests");
+
+ @BeforeClass
+ public static void setUpClass() {
+ ArithmeticTests.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ @Test
+ @Category(RuntimeRegressionTest.class)
+ public void test001() throws Exception {
+ new RuntimeTestHelper(TEST001).compileAndRunTest();
+ }
+
+ @Override
+ protected void fillRtTestInfos() {
+ rtTestInfos.add(TEST001);
+ }
+}
diff --git a/jack-tests/tests/com/android/jack/classpath/ClasspathTest.java b/jack-tests/tests/com/android/jack/classpath/ClasspathTest.java
new file mode 100644
index 0000000..8fde038
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/classpath/ClasspathTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.classpath;
+
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.IToolchain;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+
+public class ClasspathTest {
+
+ @BeforeClass
+ public static void setUpClass() {
+ ClasspathTest.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ @Test
+ public void test001() throws Exception {
+ File libOut = AbstractTestTools.createTempDir();
+
+ IToolchain toolchain = AbstractTestTools.getCandidateToolchain();
+ toolchain.srcToLib(AbstractTestTools.getClasspathAsString(toolchain.getDefaultBootClasspath()),
+ libOut, false,
+ new File(AbstractTestTools.getTestRootDir("com.android.jack.classpath.test001"), "lib"));
+
+ File testOut = AbstractTestTools.createTempDir();
+ toolchain.srcToLib(AbstractTestTools.getClasspathAsString(toolchain.getDefaultBootClasspath())
+ + File.pathSeparatorChar + libOut.getAbsolutePath(), testOut, false,
+ new File(AbstractTestTools.getTestRootDir("com.android.jack.classpath.test001"), "jack"));
+ }
+
+ @Test
+ public void test002() throws Exception {
+ IToolchain toolchain = AbstractTestTools.getCandidateToolchain();
+
+ File testFolder = AbstractTestTools.getTestRootDir("com.android.jack.classpath.test002");
+ File outFolder = AbstractTestTools.createTempDir();
+
+ File lib1Out = AbstractTestTools.createDir(outFolder, "lib1");
+ toolchain.srcToLib(AbstractTestTools.getClasspathAsString(toolchain.getDefaultBootClasspath()),
+ lib1Out,
+ /* zipFiles = */ false, new File(testFolder, "lib1"));
+
+ File lib1BisOut = AbstractTestTools.createDir(outFolder, "lib1override");
+ toolchain.srcToLib(AbstractTestTools.getClasspathAsString(toolchain.getDefaultBootClasspath()),
+ lib1BisOut,
+ /* zipFiles = */false, new File(testFolder, "lib1override"));
+
+ File lib2Out = AbstractTestTools.createDir(outFolder, "lib2");
+ toolchain.srcToLib(AbstractTestTools.getClasspathAsString(toolchain.getDefaultBootClasspath())
+ + File.pathSeparatorChar + lib1Out.getAbsolutePath(), lib2Out,
+ /* zipFiles = */false, new File(testFolder, "lib2"));
+
+ toolchain.addStaticLibs(lib2Out);
+ toolchain.srcToExe(AbstractTestTools.getClasspathAsString(toolchain.getDefaultBootClasspath())
+ + File.pathSeparatorChar + lib1BisOut.getAbsolutePath(), outFolder,
+ new File(testFolder, "jack"));
+
+ }
+}
diff --git a/jack-tests/tests/com/android/jack/enums/EnumTests.java b/jack-tests/tests/com/android/jack/enums/EnumTests.java
new file mode 100644
index 0000000..361e6a6
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/enums/EnumTests.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.enums;
+
+import com.android.jack.test.helper.RuntimeTestHelper;
+import com.android.jack.test.runtime.RuntimeTestInfo;
+import com.android.jack.test.toolchain.AbstractTestTools;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+
+public class EnumTests {
+
+ private File baseDir;
+
+ @Before
+ public void setUp() {
+ baseDir = AbstractTestTools.getTestRootDir("com.android.jack.enums.test003");
+ }
+
+ @Test
+ public void compileAndRunTest() throws Exception {
+ new RuntimeTestHelper(new RuntimeTestInfo(baseDir, "com.android.jack.enums.test003.dx.Tests"))
+ .compileAndRunTest();
+ }
+
+}
diff --git a/jack-tests/tests/com/android/jack/enums/test003/test.properties b/jack-tests/tests/com/android/jack/enums/test003/test.properties
new file mode 100644
index 0000000..e3646b8
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/enums/test003/test.properties
@@ -0,0 +1,4 @@
+rt.args.DalvikRunnerHost=-Xdexopt:none -Xverify:none
+rt.args.DalvikRunnerDevice=-Xdexopt:none -Xverify:none
+rt.args.ArtRunnerHost=-Xdexopt:none -Xverify:none
+rt.args.ArtRunnerDevice=-Xdexopt:none -Xverify:none
diff --git a/jack-tests/tests/com/android/jack/error/AnnotationProcessorErrorTest.java b/jack-tests/tests/com/android/jack/error/AnnotationProcessorErrorTest.java
new file mode 100644
index 0000000..fea5b18
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/error/AnnotationProcessorErrorTest.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.error;
+
+import com.google.common.io.Files;
+
+import com.android.jack.JackUserException;
+import com.android.jack.Main;
+import com.android.jack.errorhandling.annotationprocessor.ResourceAnnotationProcessor;
+import com.android.jack.errorhandling.annotationprocessor.ResourceAnnotationTest;
+import com.android.jack.errorhandling.annotationprocessor.SourceAnnotationProcessor;
+import com.android.jack.errorhandling.annotationprocessor.SourceAnnotationTest;
+import com.android.jack.errorhandling.annotationprocessor.SourceErrorAnnotationTest;
+import com.android.jack.frontend.FrontendCompilationException;
+import com.android.jack.test.helper.ErrorTestHelper;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.JackApiToolchain;
+
+import junit.framework.Assert;
+
+import org.jf.dexlib.ClassDefItem;
+import org.jf.dexlib.DexFile;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileReader;
+import java.io.LineNumberReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * JUnit test checking Jack behavior when using annotation processor.
+ */
+public class AnnotationProcessorErrorTest {
+
+ @BeforeClass
+ public static void setUpClass() {
+ Main.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ /**
+ * Checks that compilation fails correctly when annotation processor is called without specifying
+ * output folder.
+ */
+ @Test
+ public void testAnnotationProcessorError001() throws Exception {
+ ErrorTestHelper te = new ErrorTestHelper();
+
+ AbstractTestTools.createJavaFile(te.getSourceFolder(),"jack.incremental", "A.java",
+ "package jack.incremental; \n"+
+ "public class A {} \n");
+
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+ jackApiToolchain.setAnnotationProcessorClass(ResourceAnnotationProcessor.class);
+
+ try {
+ jackApiToolchain.srcToExe(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath()),
+ te.getOutputDexFolder(), te.getSourceFolder());
+ Assert.fail();
+ } catch (JackUserException e) {
+ // Failure is ok since output for annotation processor is not specify.
+ Assert.assertTrue(e.getMessage().contains("Unknown location"));
+ }
+ }
+
+ /**
+ * Checks that compilation succeed when running annotation processor to generate resource file.
+ */
+ @Test
+ public void testAnnotationProcessorError002() throws Exception {
+ runAnnotProcBuildingResource(new ErrorTestHelper());
+ }
+
+ /**
+ * Checks that last compilation failed since the resource created by annotation processor already
+ * exist.
+ */
+ @Test
+ public void testAnnotationProcessorError003() throws Exception {
+ ErrorTestHelper te = new ErrorTestHelper();
+
+ runAnnotProcBuildingResource(te);
+
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+ jackApiToolchain.setAnnotationProcessorClass(ResourceAnnotationProcessor.class);
+ jackApiToolchain.setAnnotationProcessorOutDir(te.getTestingFolder());
+ ByteArrayOutputStream errOut = new ByteArrayOutputStream();
+ jackApiToolchain.setErrorStream(errOut);
+
+ try {
+
+ jackApiToolchain.srcToExe(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath())
+ + File.pathSeparator + te.getJackFolder(), te.getOutputDexFolder(), te.getSourceFolder());
+
+ Assert.fail();
+ } catch (FrontendCompilationException e) {
+ // Failure is ok since created file already exists
+ } finally {
+ Assert.assertTrue(errOut.toString().contains("Resource already created"));
+ }
+ }
+
+ /**
+ * Checks that compilation failed since the source file generated by the annotation processor
+ * does not compile.
+ */
+ @Test
+ public void testAnnotationProcessorError004() throws Exception {
+ ErrorTestHelper te = new ErrorTestHelper();
+
+ buildAnnotationRequiredByAnnotationProc(te, new Class<?>[] {SourceAnnotationTest.class,
+ SourceErrorAnnotationTest.class});
+
+ AbstractTestTools.createJavaFile(te.getSourceFolder(), "jack.incremental", "A.java", "package jack.incremental;\n"
+ + "import " + SourceErrorAnnotationTest.class.getName() + ";\n"
+ + "@" + SourceErrorAnnotationTest.class.getSimpleName() + "\n"
+ + "public class A {}\n");
+
+
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+ jackApiToolchain.setAnnotationProcessorClass(SourceAnnotationProcessor.class);
+ jackApiToolchain.setAnnotationProcessorOutDir(te.getTestingFolder());
+ ByteArrayOutputStream errOut = new ByteArrayOutputStream();
+ jackApiToolchain.setErrorStream(errOut);
+
+ try {
+ jackApiToolchain.srcToExe(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath())
+ + File.pathSeparator + te.getJackFolder(), te.getOutputDexFolder(), te.getSourceFolder());
+ Assert.fail();
+ } catch (FrontendCompilationException ex) {
+ // Failure is ok since source generated by annotation processor does not compile.
+ } finally {
+ Assert.assertTrue(errOut.toString().contains("Syntax error on tokens, delete these tokens"));
+ }
+ }
+
+ /**
+ * Checks that compilation succeed to compile source file generated by the annotation processor.
+ */
+ @Test
+ public void testAnnotationProcessorError005() throws Exception {
+ ErrorTestHelper te = new ErrorTestHelper();
+
+ buildAnnotationRequiredByAnnotationProc(te, new Class<?>[] {SourceAnnotationTest.class,
+ SourceErrorAnnotationTest.class});
+
+ AbstractTestTools.createJavaFile(te.getSourceFolder(), "jack.incremental", "A.java", "package jack.incremental;\n"
+ + "import " + SourceAnnotationTest.class.getName() + ";\n"
+ + "@" + SourceAnnotationTest.class.getSimpleName() + "\n"
+ + "public class A {}\n");
+
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+ jackApiToolchain.setAnnotationProcessorClass(SourceAnnotationProcessor.class);
+ jackApiToolchain.setAnnotationProcessorOutDir(te.getTestingFolder());
+
+ File dexOutput = te.getOutputDexFolder();
+ jackApiToolchain.srcToExe(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath())
+ + File.pathSeparator + te.getJackFolder(), dexOutput, te.getSourceFolder());
+
+ DexFile dexFile = new DexFile(new File(dexOutput, jackApiToolchain.getBinaryFileName()));
+ List<String> sourceFileInDex = new ArrayList<String>();
+ for (ClassDefItem classDef : dexFile.ClassDefsSection.getItems()) {
+ sourceFileInDex.add(classDef.getSourceFile().getStringValue());
+ }
+
+ Assert.assertTrue(sourceFileInDex.contains("ADuplicated.java"));
+ Assert.assertTrue(sourceFileInDex.contains("A.java"));
+ }
+
+ private void runAnnotProcBuildingResource(@Nonnull ErrorTestHelper te) throws Exception {
+
+ buildAnnotationRequiredByAnnotationProc(te, new Class<?>[] {ResourceAnnotationTest.class});
+
+ AbstractTestTools.createJavaFile(te.getSourceFolder(), "jack.incremental", "A.java", "package jack.incremental;\n"
+ + "import " + ResourceAnnotationTest.class.getName() + ";\n"
+ + "@" + ResourceAnnotationTest.class.getSimpleName() + "\n"
+ + "public class A {}\n");
+
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+ jackApiToolchain.setAnnotationProcessorClass(ResourceAnnotationProcessor.class);
+ jackApiToolchain.setAnnotationProcessorOutDir(te.getTestingFolder());
+
+ jackApiToolchain.srcToExe(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath())
+ + File.pathSeparator + te.getJackFolder(), te.getOutputDexFolder(), te.getSourceFolder());
+
+ File discoverFile = new File(te.getTestingFolder(), ResourceAnnotationProcessor.FILENAME);
+ Assert.assertTrue(discoverFile.exists());
+ LineNumberReader lnr = new LineNumberReader(new FileReader(discoverFile));
+ Assert.assertEquals(ResourceAnnotationTest.class.getName(), lnr.readLine());
+ Assert.assertEquals("jack.incremental.A", lnr.readLine());
+ Assert.assertNull(lnr.readLine());
+ lnr.close();
+ }
+
+ private void buildAnnotationRequiredByAnnotationProc(@Nonnull ErrorTestHelper te,
+ Class<?>[] annotationClasses) throws Exception {
+ File targetAnnotationFileFolder =
+ new File(te.getSourceFolder(), "com/android/jack/errorhandling/annotationprocessor/");
+ if (!targetAnnotationFileFolder.mkdirs()) {
+ Assert.fail("Fail to create folder " + targetAnnotationFileFolder.getAbsolutePath());
+ }
+
+ for (Class<?> annotationClass : annotationClasses) {
+ Files.copy(new File(AbstractTestTools.getJackRootDir(),
+ "toolchain/jack/jack/tests/com/android/jack/errorhandling/annotationprocessor/"
+ + annotationClass.getSimpleName() + ".java"), new File(
+ targetAnnotationFileFolder, annotationClass.getSimpleName() + ".java"));
+ }
+
+ // Compile annotation to a jack file
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+ jackApiToolchain.srcToLib(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath()),
+ te.getJackFolder(), false /* zipFiles = */, te.getSourceFolder());
+
+ AbstractTestTools.deleteTempDir(te.getSourceFolder());
+ }
+}
diff --git a/jack-tests/tests/com/android/jack/error/CommandLineErrorTest.java b/jack-tests/tests/com/android/jack/error/CommandLineErrorTest.java
new file mode 100644
index 0000000..3e72329
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/error/CommandLineErrorTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.error;
+
+import com.android.jack.IllegalOptionsException;
+import com.android.jack.Main;
+import com.android.jack.NothingToDoException;
+import com.android.jack.test.helper.ErrorTestHelper;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.JackApiToolchain;
+
+import junit.framework.Assert;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+
+/**
+ * JUnit test checking Jack behavior on exceptions.
+ */
+public class CommandLineErrorTest {
+
+ @BeforeClass
+ public static void setUpClass() {
+ Main.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ /**
+ * Checks that compilation fails correctly when an unsupported options is passed to ecj.
+ */
+ @Test
+ public void testCommandLineError001() throws Exception {
+ ErrorTestHelper ite = new ErrorTestHelper();
+
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+ ByteArrayOutputStream errOut = new ByteArrayOutputStream();
+ jackApiToolchain.setErrorStream(errOut);
+ jackApiToolchain.addEcjArgs("-unsupported");
+ try {
+ jackApiToolchain.srcToExe(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath())
+ + File.pathSeparator + ite.getJackFolder(), ite.getOutputDexFolder(),
+ ite.getSourceFolder());
+ Assert.fail();
+ } catch (IllegalOptionsException e) {
+ // Failure is ok since a bad options is passed to ecj.
+ } finally {
+ Assert.assertEquals("", errOut.toString());
+ }
+ }
+
+ /**
+ * Checks that compilation fails correctly when no source files are passed to ecj.
+ */
+ @Test
+ public void testCommandLineError002() throws Exception {
+ ErrorTestHelper ite = new ErrorTestHelper();
+
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+ ByteArrayOutputStream errOut = new ByteArrayOutputStream();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ jackApiToolchain.setErrorStream(errOut);
+ jackApiToolchain.setOutputStream(out);
+
+ try {
+ jackApiToolchain.srcToExe(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath())
+ + File.pathSeparator + ite.getJackFolder(), ite.getOutputDexFolder(),
+ ite.getSourceFolder());
+ Assert.fail();
+ } catch (NothingToDoException e) {
+ // Failure is ok since there is no source files.
+ } finally {
+ Assert.assertEquals("", errOut.toString());
+ Assert.assertTrue(out.toString().contains("Usage:"));
+ }
+ }
+
+}
diff --git a/jack-tests/tests/com/android/jack/error/FileAccessErrorTest.java b/jack-tests/tests/com/android/jack/error/FileAccessErrorTest.java
new file mode 100644
index 0000000..f9ce418
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/error/FileAccessErrorTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.error;
+
+import com.android.jack.JackUserException;
+import com.android.jack.Main;
+import com.android.jack.frontend.FrontendCompilationException;
+import com.android.jack.load.JackLoadingException;
+import com.android.jack.test.helper.ErrorTestHelper;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.JackApiToolchain;
+import com.android.sched.util.config.PropertyIdException;
+
+import junit.framework.Assert;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+
+/**
+ * JUnit test checking Jack behavior on file access error.
+ */
+public class FileAccessErrorTest {
+
+ @BeforeClass
+ public static void setUpClass() {
+ Main.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ /**
+ * Checks that compilation fails correctly when folder to generate jack files is not readable.
+ */
+ @Test
+ public void testFileAccessError001() throws Exception {
+ ErrorTestHelper te = new ErrorTestHelper();
+
+ AbstractTestTools.createJavaFile(te.getSourceFolder(), "jack.incremental", "A.java",
+ "package jack.incremental; \n"+
+ "public class A {} \n");
+
+ File jackOutputFile = AbstractTestTools.createTempDir();
+ if (!jackOutputFile.setReadable(false)) {
+ Assert.fail("Fails to change file permissions of " + jackOutputFile.getAbsolutePath());
+ }
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+
+ try {
+ jackApiToolchain.srcToLib(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath()),
+ jackOutputFile, false, te.getSourceFolder());
+ Assert.fail();
+ } catch (PropertyIdException e) {
+ // Failure is ok since jack output folder is not readable
+ } finally {
+ if (!jackOutputFile.setReadable(true)) {
+ Assert.fail("Fails to change file permissions of " + jackOutputFile.getAbsolutePath());
+ }
+ }
+ }
+
+ /**
+ * Checks that compilation fails correctly when source file is not readable.
+ */
+ @Test
+ public void testFileAccessError003() throws Exception {
+ ErrorTestHelper te = new ErrorTestHelper();
+
+ File a = AbstractTestTools.createJavaFile(te.getSourceFolder(), "jack.incremental", "A.java",
+ "package jack.incremental; \n"+
+ "public class A {} \n");
+ if (!a.setReadable(false)) {
+ Assert.fail("Fails to change file permissions of " + a.getAbsolutePath());
+ }
+
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+ ByteArrayOutputStream errOut = new ByteArrayOutputStream();
+ jackApiToolchain.setErrorStream(errOut);
+
+ try {
+ jackApiToolchain.srcToExe(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath()),
+ te.getOutputDexFolder(), te.getSourceFolder());
+ Assert.fail();
+ } catch (FrontendCompilationException e) {
+ // Failure is ok since source file is not readable
+ } finally {
+ if (!a.setReadable(true)) {
+ Assert.fail("Fails to change file permissions of " + a.getAbsolutePath());
+ }
+ Assert.assertTrue(errOut.toString().contains("Permission denied"));
+ }
+ }
+
+ /**
+ * Checks that compilation fails correctly when jack file is not readable.
+ */
+ @Test
+ public void testFileAccessError004() throws Exception {
+ ErrorTestHelper te = new ErrorTestHelper();
+
+ AbstractTestTools.createJavaFile(te.getSourceFolder(), "jack.incremental", "A.java",
+ "package jack.incremental; \n"+
+ "public class A {} \n");
+
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+
+ jackApiToolchain.srcToLib(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath()),
+ te.getJackFolder(), false, te.getSourceFolder());
+
+ AbstractTestTools.deleteJavaFile(te.getSourceFolder(), "jack.incremental", "A.java");
+
+ AbstractTestTools.createJavaFile(te.getSourceFolder(),"jack.incremental", "B.java",
+ "package jack.incremental; \n"+
+ "public class B extends A {} \n");
+
+ ByteArrayOutputStream errOut = new ByteArrayOutputStream();
+ try {
+ for (File jackFile : AbstractTestTools.getFiles(te.getJackFolder(), ".jack")) {
+ if (!jackFile.setReadable(false)) {
+ Assert.fail("Fails to change file permissions of " + jackFile.getAbsolutePath());
+ }
+ }
+
+ jackApiToolchain.setErrorStream(errOut);
+ jackApiToolchain.srcToLib(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath())
+ + File.pathSeparator + te.getJackFolder().getAbsolutePath(),
+ AbstractTestTools.createTempDir(), false, te.getSourceFolder());
+ Assert.fail();
+ } catch (JackLoadingException e) {
+ // Failure is ok since jack file is not readable
+ } finally {
+ Assert.assertEquals("", errOut.toString());
+ for (File jackFile : AbstractTestTools.getFiles(te.getJackFolder(), ".jack")) {
+ if (!jackFile.setReadable(true)) {
+ Assert.fail("Fails to change file permissions of " + jackFile.getAbsolutePath());
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks that compilation fails correctly when source file does not exist.
+ */
+ @Test
+ public void testFileAccessError005() throws Exception {
+ ErrorTestHelper te = new ErrorTestHelper();
+
+ JackApiToolchain jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+
+ try {
+
+ jackApiToolchain.srcToExe(
+ AbstractTestTools.getClasspathAsString(jackApiToolchain.getDefaultBootClasspath()),
+ te.getOutputDexFolder(), new File(te.getSourceFolder(), "A.java"));
+
+ Assert.fail();
+ } catch (JackUserException e) {
+ // Failure is ok since source file is not readable
+ Assert.assertTrue(e.getMessage().contains("A.java is missing"));
+ }
+ }
+}
diff --git a/jack-tests/tests/com/android/jack/experimenal/incremental/DependenciesTests005.java b/jack-tests/tests/com/android/jack/experimenal/incremental/DependenciesTests005.java
new file mode 100644
index 0000000..6b50799
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/experimenal/incremental/DependenciesTests005.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.experimenal.incremental;
+
+import com.android.jack.Main;
+import com.android.jack.test.helper.IncrementalTestHelper;
+import com.android.jack.test.toolchain.AbstractTestTools;
+
+import junit.framework.Assert;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * JUnit test checking dependencies between Java files.
+ */
+public class DependenciesTests005 {
+
+ @BeforeClass
+ public static void setUpClass() {
+ Main.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ /**
+ * Check that runtime is correct after incremental compilation due to a constant modification.
+ */
+ @Test
+ public void testDependency001() throws Exception {
+ IncrementalTestHelper ite =
+ new IncrementalTestHelper(AbstractTestTools.createTempDir());
+
+ ite.addJavaFile("jack.incremental", "A.java",
+ "package jack.incremental; \n"+
+ "public class A { public static void main(String[] args) {" +
+ "System.out.print(C.str + B.str);} " +
+ "} \n");
+
+ ite.addJavaFile("jack.incremental", "B.java",
+ "package jack.incremental; \n"+
+ "public class B { public static final String str = \"HELLO\"; } \n");
+
+ ite.addJavaFile("jack.incremental", "C.java",
+ "package jack.incremental; \n"+
+ "public class C { public static final String str = \"STRING:\"; } \n");
+
+ ite.incrementalBuildFromFolder();
+ ite.snapshotJackFilesModificationDate();
+
+ ite.addJavaFile("jack.incremental", "B.java",
+ "package jack.incremental; \n"+
+ "public class B { public static final String str = \"INCREMENTAL\"; } \n");
+
+ ite.incrementalBuildFromFolder();
+
+ List<String> fqnOfRebuiltTypes = ite.getFQNOfRebuiltTypes();
+ Assert.assertEquals(2, fqnOfRebuiltTypes.size());
+ Assert.assertTrue(fqnOfRebuiltTypes.contains("jack.incremental.A"));
+ Assert.assertTrue(fqnOfRebuiltTypes.contains("jack.incremental.B"));
+
+ Assert.assertEquals("STRING:INCREMENTAL", ite.run("jack.incremental.A"));
+ }
+
+
+}
diff --git a/jack-tests/tests/com/android/jack/invoke/test001/jack/InvokeClone.java b/jack-tests/tests/com/android/jack/invoke/test001/jack/InvokeClone.java
index 8d1296f..f06857a 100644
--- a/jack-tests/tests/com/android/jack/invoke/test001/jack/InvokeClone.java
+++ b/jack-tests/tests/com/android/jack/invoke/test001/jack/InvokeClone.java
@@ -19,7 +19,7 @@ package com.android.jack.invoke.test001.jack;
public class InvokeClone {
public static int[] getArray() {
- int []a = new int[] {1,2,3};
+ int[] a = new int[] {1,2,3};
return (a.clone());
}
}
diff --git a/jack-tests/tests/com/android/jack/jarjar/JarjarTests.java b/jack-tests/tests/com/android/jack/jarjar/JarjarTests.java
new file mode 100644
index 0000000..6bac5cc
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/jarjar/JarjarTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.jarjar;
+
+import com.android.jack.test.helper.RuntimeTestHelper;
+import com.android.jack.test.runtime.RuntimeTestInfo;
+import com.android.jack.test.toolchain.AbstractTestTools;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+
+import javax.annotation.Nonnull;
+
+public class JarjarTests {
+
+ @Nonnull
+ private File baseDir;
+
+ @Before
+ public void setUp() {
+ baseDir = AbstractTestTools.getTestRootDir("com.android.jack.jarjar.test001");
+ }
+
+ @Test
+ public void compileAndRunTest() throws Exception {
+ RuntimeTestHelper rtEnv = new RuntimeTestHelper(
+ new RuntimeTestInfo(baseDir, "com.android.jack.jarjar.test001.dx.Tests"));
+ rtEnv.setJarjarRulesFileName("jarjar-rules.txt");
+ rtEnv.compileAndRunTest();
+ }
+
+}
diff --git a/jack-tests/tests/com/android/jack/java7/ExceptionsTest.java b/jack-tests/tests/com/android/jack/java7/ExceptionsTest.java
new file mode 100644
index 0000000..ecbe578
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/java7/ExceptionsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.java7;
+
+import com.android.jack.Main;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.JackBasedToolchain;
+import com.android.jack.test.toolchain.Toolchain.SourceLevel;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+
+import javax.annotation.Nonnull;
+
+/**
+ * JUnit test for compilation of Java 7 features
+ */
+public class ExceptionsTest {
+
+ @BeforeClass
+ public static void setUpClass() {
+ Main.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ @Test
+ public void java7Exception001() throws Exception {
+ compileJava7Test("test001");
+ }
+
+ @Test
+ public void java7Exception002() throws Exception {
+ compileJava7Test("test002");
+ }
+
+ @Test
+ public void java7Exception003() throws Exception {
+ compileJava7Test("test003");
+ }
+
+ @Test
+ public void java7Exception004() throws Exception {
+ compileJava7Test("test004");
+ }
+
+ @Test
+ public void java7Exception005() throws Exception {
+ compileJava7Test("test005");
+ }
+
+ private void compileJava7Test(@Nonnull String name) throws Exception {
+ JackBasedToolchain jackBasedToolchain =
+ AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ jackBasedToolchain.setSourceLevel(SourceLevel.JAVA_7).srcToExe(
+ AbstractTestTools.getClasspathAsString(jackBasedToolchain.getDefaultBootClasspath()),
+ AbstractTestTools.createTempDir(), new File(
+ AbstractTestTools.getTestRootDir("com.android.jack.java7.exceptions." + name), "jack"));
+ }
+}
diff --git a/jack-tests/tests/com/android/jack/shrob/AbstractTest.java b/jack-tests/tests/com/android/jack/shrob/AbstractTest.java
new file mode 100644
index 0000000..319abaf
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/AbstractTest.java
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.shrob;
+
+import com.android.jack.Main;
+import com.android.jack.ProguardFlags;
+import com.android.jack.TestTools;
+import com.android.jack.category.KnownBugs;
+import com.android.jack.category.SlowTests;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Abstract class for running shrob tests
+ */
+public abstract class AbstractTest {
+
+ @BeforeClass
+ public static void setUpClass() {
+ Main.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ protected abstract void runTest(
+ @Nonnull String testNumber,
+ @Nonnull String flagNumber,
+ @Nonnull String mappingNumber)
+ throws Exception;
+
+ protected ProguardFlags generateApplyMapping(@Nonnull File mappingFile) throws IOException {
+ File applyMapping = TestTools.createTempFile("mapping.flags", null);
+ BufferedWriter writer = new BufferedWriter(new FileWriter(applyMapping));
+ writer.append("-applymapping ");
+ writer.append(mappingFile.getAbsolutePath());
+ writer.close();
+ return new ProguardFlags(applyMapping);
+ }
+
+ protected ProguardFlags generateInjars(@Nonnull File injar) throws IOException {
+ File injarFlags = TestTools.createTempFile("injars", ".flags");
+ BufferedWriter writer = new BufferedWriter(new FileWriter(injarFlags));
+ writer.append("-injars ");
+ writer.append(injar.getAbsolutePath());
+ writer.close();
+ return new ProguardFlags(injarFlags);
+ }
+
+ @Test
+ public void test1_001() throws Exception {
+ runTest("001", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_002() throws Exception {
+ runTest("001", "002", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_003() throws Exception {
+ runTest("001", "003", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_004() throws Exception {
+ runTest("001", "004", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_005() throws Exception {
+ runTest("001", "005", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_005_002() throws Exception {
+ runTest("001", "005", "002");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_005_003() throws Exception {
+ runTest("001", "005", "003");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_006() throws Exception {
+ runTest("001", "006", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_007() throws Exception {
+ runTest("001", "007", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_008() throws Exception {
+ runTest("001", "008", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_009() throws Exception {
+ runTest("001", "009", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_010() throws Exception {
+ runTest("001", "010", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_011() throws Exception {
+ runTest("001", "011", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_012() throws Exception {
+ runTest("001", "012", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_013() throws Exception {
+ runTest("001", "013", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_014() throws Exception {
+ runTest("001", "014", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_015() throws Exception {
+ runTest("001", "015", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_016() throws Exception {
+ runTest("001", "016", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_017() throws Exception {
+ runTest("001", "017", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_018() throws Exception {
+ runTest("001", "018", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_019() throws Exception {
+ runTest("001", "019", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_020() throws Exception {
+ runTest("001", "020", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_021() throws Exception {
+ runTest("001", "021", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test1_022() throws Exception {
+ runTest("001", "022", "");
+ }
+
+ @Test
+ public void test2_001() throws Exception {
+ runTest("002", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test2_002() throws Exception {
+ runTest("002", "002", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test2_003() throws Exception {
+ runTest("002", "003", "");
+ }
+
+ @Test
+ public void test4_001() throws Exception {
+ runTest("004", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test4_002() throws Exception {
+ runTest("004", "002", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test4_003() throws Exception {
+ runTest("004", "003", "");
+ }
+
+ @Test
+ public void test5_001() throws Exception {
+ runTest("005", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test5_002() throws Exception {
+ runTest("005", "002", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test5_003() throws Exception {
+ runTest("005", "003", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test5_004() throws Exception {
+ runTest("005", "004", "");
+ }
+
+ @Test
+ public void test5_005() throws Exception {
+ runTest("005", "005", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test5_006() throws Exception {
+ runTest("005", "006", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test5_007() throws Exception {
+ runTest("005", "007", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test5_008() throws Exception {
+ runTest("005", "008", "");
+ }
+
+ @Test
+ public void test6_001() throws Exception {
+ runTest("006", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test6_002() throws Exception {
+ runTest("006", "002", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test6_003() throws Exception {
+ runTest("006", "003", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test6_004() throws Exception {
+ runTest("006", "004", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test6_005() throws Exception {
+ runTest("006", "005", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test6_006() throws Exception {
+ runTest("006", "006", "");
+ }
+
+ @Test
+ public void test7_001() throws Exception {
+ runTest("007", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test7_002() throws Exception {
+ runTest("007", "002", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test7_003() throws Exception {
+ runTest("007", "003", "");
+ }
+
+ @Test
+ public void test8_001() throws Exception {
+ runTest("008", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test8_002() throws Exception {
+ runTest("008", "002", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test8_003() throws Exception {
+ runTest("008", "003", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test8_004() throws Exception {
+ runTest("008", "004", "");
+ }
+
+ @Test
+ public void test9_001() throws Exception {
+ runTest("009", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test9_002() throws Exception {
+ runTest("009", "002", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test9_003() throws Exception {
+ runTest("009", "003", "");
+ }
+
+ @Test
+ public void test10_001() throws Exception {
+ runTest("010", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test10_002() throws Exception {
+ runTest("010", "002", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test10_003() throws Exception {
+ runTest("010", "003", "");
+ }
+
+ @Test
+ public void test11_001() throws Exception {
+ runTest("011", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test11_002() throws Exception {
+ runTest("011", "002", "");
+ }
+
+ @Test
+ public void test12_001() throws Exception {
+ runTest("012", "001", "");
+ }
+
+ @Test
+ public void test13_001() throws Exception {
+ runTest("013", "001", "");
+ }
+
+ @Test
+ public void test14_001() throws Exception {
+ runTest("014", "001", "");
+ }
+
+ @Test
+ public void test15_001() throws Exception {
+ runTest("015", "001", "");
+ }
+
+ @Test
+ public void test16_001() throws Exception {
+ runTest("016", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test16_002() throws Exception {
+ runTest("016", "002", "");
+ }
+
+ @Test
+ public void test17_001() throws Exception {
+ runTest("017", "001", "");
+ }
+
+ @Test
+ public void test18_001() throws Exception {
+ runTest("018", "001", "");
+ }
+
+ @Test
+ public void test19_001() throws Exception {
+ runTest("019", "001", "");
+ }
+
+ @Test
+ public void test21_001() throws Exception {
+ runTest("021", "001", "");
+ }
+
+ @Test
+ public void test22_001() throws Exception {
+ runTest("022", "001", "");
+ }
+
+ @Test
+ public void test23_001() throws Exception {
+ runTest("023", "001", "");
+ }
+
+ @Test
+ public void test25_001() throws Exception {
+ runTest("025", "001", "");
+ }
+
+ @Test
+ public void test26_001() throws Exception {
+ runTest("026", "001", "");
+ }
+
+ @Test
+ public void test29_001() throws Exception {
+ runTest("029", "001", "");
+ }
+
+ @Test
+ public void test30_001() throws Exception {
+ runTest("030", "001", "");
+ }
+
+ @Test
+ public void test31_001() throws Exception {
+ runTest("031", "001", "");
+ }
+
+ @Test
+ public void test31_002() throws Exception {
+ runTest("031", "002", "");
+ }
+
+ @Test
+ public void test32_001() throws Exception {
+ runTest("032", "001", "");
+ }
+
+ @Test
+ public void test33_001() throws Exception {
+ runTest("033", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test33_002() throws Exception {
+ runTest("033", "002", "");
+ }
+
+ @Test
+ public void test34_001() throws Exception {
+ runTest("034", "001", "");
+ }
+
+ @Test
+ public void test35_001() throws Exception {
+ runTest("035", "001", "");
+ }
+
+ @Test
+ public void test36_001() throws Exception {
+ runTest("036", "001", "");
+ }
+
+ @Test
+ public void test37_001() throws Exception {
+ runTest("037", "001", "");
+ }
+
+ @Test
+ public void test38_001() throws Exception {
+ runTest("038", "001", "");
+ }
+
+ @Test
+ public void test39_001() throws Exception {
+ runTest("039", "001", "");
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void test40_001() throws Exception {
+ runTest("040", "001", "");
+ }
+
+ @Test
+ @Category(KnownBugs.class)
+ public void test41_001() throws Exception {
+ runTest("041", "001", "");
+ }
+}
diff --git a/jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java b/jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java
new file mode 100644
index 0000000..26cba49
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.shrob;
+
+import com.android.jack.Options;
+import com.android.jack.category.KnownBugs;
+import com.android.jack.shrob.obfuscation.NameProviderFactory;
+import com.android.jack.shrob.proguard.GrammarActions;
+import com.android.jack.shrob.spec.Flags;
+import com.android.jack.test.comparator.ComparatorMapping;
+import com.android.jack.test.helper.SourceToDexComparisonTestHelper;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.DummyToolchain;
+import com.android.jack.test.toolchain.JackApiToolchain;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.File;
+
+import javax.annotation.Nonnull;
+
+public class ObfuscationWithoutMappingTests extends AbstractTest {
+
+ @Override
+ protected void runTest(
+ @Nonnull String testNumber,
+ @Nonnull String flagNumber,
+ @Nonnull String mappingNumber)
+ throws Exception {
+
+ String testName = "shrob/test" + testNumber;
+
+ String testPackageName = "com.android.jack.shrob.test" + testNumber;
+ File testFolder = AbstractTestTools.getTestRootDir(testPackageName);
+
+ JackApiToolchain toolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchain.class);
+ Flags flags = new Flags();
+ toolchain.setShrobFlags(flags);
+ GrammarActions.parse("proguard.flags" + flagNumber, testFolder.getAbsolutePath(), flags);
+ File refFolder = new File(testFolder, "refsObfuscationWithoutMapping");
+
+ toolchain.addProperty(NameProviderFactory.NAMEPROVIDER.getName(), "rot13");
+ toolchain.addProperty(Options.METHOD_FILTER.getName(), "supported-methods");
+
+ File candidateOutputMapping = AbstractTestTools.createTempFile("mapping", ".txt");
+ File refOutputMapping = new File(refFolder, "expected-" + flagNumber + ".txt");
+ flags.setOutputMapping(candidateOutputMapping);
+ flags.setPrintMapping(true);
+
+ SourceToDexComparisonTestHelper env =
+ new SourceToDexComparisonTestHelper(new File(testFolder, "jack"));
+
+ env.setCandidateTestTools(toolchain);
+ env.setReferenceTestTools(new DummyToolchain());
+
+ env.runTest(new ComparatorMapping(candidateOutputMapping, refOutputMapping));
+
+ // // ==============================================================
+
+ /*
+ * Comment for reviewers: the following code is an attempt to use jack based toolchain.
+ * It works, but requires to manipulate (copy, write...) shrob flags.
+ * Here I added a shrob option manually, but ideally to be able to use
+ * a Flags like object for CLI based toochains, we must be able to dump
+ * the flags as a file (TBD). Plus, if flags have "-include" directives with relative
+ * paths, files must be in the same location.
+ */
+
+//
+// String testName = "shrob/test" + testNumber;
+// File testFolder = TestTools.getJackTestFolder(testName);
+// File refFolder = new File(testFolder, "refsObfuscationWithoutMapping");
+//
+// JackBasedToolchain jackToolchain = AbstractTestTools.getJackBasedToolchainAsCandidate();
+//
+// jackToolchain.addProperty(NameProviderFactory.NAMEPROVIDER.getName(), "rot13");
+// jackToolchain.addProperty(Options.METHOD_FILTER.getName(), "supported-methods");
+//
+// File candidateOutputMapping = TestTools.createTempFile("mapping", ".txt");
+// File refOutputMapping = new File(refFolder, "expected-" + flagNumber + ".txt");
+//
+// jackToolchain.getCompilationResult().proguardMappingFile = candidateOutputMapping;
+//
+// // TODO(jmhenaff): having to seems like a no go for JackBasedToolchain (i.e. cli)
+// File candidateFlags = new File(testFolder.getAbsolutePath(), "tmp-proguard.flags" + flagNumber);
+// candidateFlags.deleteOnExit();
+// appendStringToFileCopy(new File(testFolder.getAbsolutePath(), "proguard.flags" + flagNumber),
+// candidateFlags, "-printmapping " + candidateOutputMapping.getAbsolutePath());
+//
+// SourceToDexComparisonTestEnv env = new SourceToDexComparisonTestEnv(bootclasspath, classpath,
+// TestTools.getJackTestsWithJackFolder(testName));
+//
+// env.setProguardFlags(new ProguardFlags[] {new ProguardFlags(candidateFlags)});
+//
+// CompilationResult compilationResult = new CompilationResult();
+// compilationResult.proguardMappingFile = refOutputMapping;
+//
+// env.setCandidateTestTools(jackToolchain);
+// env.setReferenceTestTools(new DummyTestTools(compilationResult));
+//
+// env.addComparator(env.createMappingComparator());
+// env.compare();
+
+ }
+
+ @Override
+ @Test
+ @Category(KnownBugs.class)
+ public void test33_001() throws Exception {
+ super.test33_001();
+ }
+
+ @Override
+ @Test
+ @Category(KnownBugs.class)
+ public void test34_001() throws Exception {
+ super.test34_001();
+ }
+
+ @Override
+ @Test
+ @Category(KnownBugs.class)
+ public void test35_001() throws Exception {
+ super.test35_001();
+ }
+
+// private void appendStringToFileCopy(File source, File dest, String appended) throws IOException {
+// BufferedReader reader = null;
+// BufferedWriter writer = null;
+// try {
+// reader = new BufferedReader(new FileReader(source));
+// writer = new BufferedWriter(new FileWriter(dest));
+// String line;
+// while ((line = reader.readLine()) != null) {
+// writer.write(line);
+// writer.write("\n");
+// }
+// writer.write(appended);
+// } finally {
+// try {
+// reader.close();
+// } catch (IOException e) {
+// }
+// try {
+// writer.close();
+// } catch (IOException e) {
+// }
+// }
+// }
+
+}
diff --git a/jack-tests/tests/com/android/jack/tools/merger/MergerAllTests.java b/jack-tests/tests/com/android/jack/tools/merger/MergerAllTests.java
new file mode 100644
index 0000000..6d222de
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/tools/merger/MergerAllTests.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.jack.tools.merger;
+
+import com.android.jack.tools.merger.test011.MergerTest011;
+
+import org.junit.experimental.categories.Categories;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Categories.class)
+@SuiteClasses(
+value = {MergerTest011.class})
+public class MergerAllTests {
+} \ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/tools/merger/MergerTestTools.java b/jack-tests/tests/com/android/jack/tools/merger/MergerTestTools.java
new file mode 100644
index 0000000..dab9e7e
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/tools/merger/MergerTestTools.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.tools.merger;
+
+import com.android.jack.Options;
+import com.android.jack.TestTools;
+import com.android.jack.backend.dex.DexFileWriter;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.JackBasedToolchain;
+import com.android.sched.scheduler.ScheduleInstance;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+public class MergerTestTools {
+
+ @Nonnull
+ protected File buildOneDexPerType(@CheckForNull String classpath, @Nonnull File sourceFolder,
+ boolean withDebug) throws Exception {
+ JackBasedToolchain toolchain =
+ AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ try {
+ File multiDexFolder = TestTools.createTempDir("multi", "dex");
+ File multiDex = new File(multiDexFolder, DexFileWriter.DEX_FILENAME);
+ File multiDexOnTypePerTypeFolder = TestTools.createTempDir("multiOnDexPerType", "dex");
+
+ toolchain.addProperty(Options.EMIT_LINE_NUMBER_DEBUG_INFO.getName(),
+ Boolean.toString(withDebug));
+ toolchain.addProperty(ScheduleInstance.DEFAULT_RUNNER.getName(), "single-threaded");
+ toolchain.addProperty(Options.TYPEDEX_DIR.getName(),
+ multiDexOnTypePerTypeFolder.getAbsolutePath());
+
+ toolchain.srcToExe(classpath, multiDexFolder, sourceFolder);
+
+ return multiDex;
+
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+}
diff --git a/jack-tests/tests/com/android/jack/tools/merger/test011/MergerTest011.java b/jack-tests/tests/com/android/jack/tools/merger/test011/MergerTest011.java
new file mode 100644
index 0000000..f00da22
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/tools/merger/test011/MergerTest011.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.tools.merger.test011;
+
+import com.android.jack.JackUserException;
+import com.android.jack.Main;
+import com.android.jack.TestTools;
+import com.android.jack.category.SlowTests;
+import com.android.jack.tools.merger.FieldIdOverflowException;
+import com.android.jack.tools.merger.MergerTestTools;
+import com.android.jack.tools.merger.MethodIdOverflowException;
+import com.android.jack.tools.merger.TypeIdOverflowException;
+
+import junit.framework.Assert;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+/**
+ * JUnit test checking that merging can throw overflow exceptions.
+ */
+public class MergerTest011 extends MergerTestTools {
+
+ private static int fileCount = 655;
+
+ private static final String expectedExceptionMessage =
+ "Index overflow while merging dex files. Try using multidex";
+
+ @BeforeClass
+ public static void setUpClass() {
+ Main.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ @Test
+ public void testMergerWithHighNumberOfMethods() throws Exception {
+ File srcFolder = TestTools.createTempDir("oneDexPerType", "SrcFolder");
+
+ // One CstMethodRef is also created for call to object.init()
+ for (int fileIdx = 0; fileIdx < fileCount; fileIdx++) {
+ generateJavaFileWithMethods(srcFolder, fileIdx, 100);
+ }
+ generateJavaFileWithMethods(srcFolder, fileCount, 36);
+
+ try {
+ buildOneDexPerType(TestTools.getDefaultBootclasspathString(), srcFolder, false /* withDebug */);
+ Assert.fail();
+ } catch (JackUserException e) {
+ Assert.assertEquals(expectedExceptionMessage, e.getMessage());
+ Throwable cause = e.getCause();
+ Assert.assertTrue(cause instanceof MethodIdOverflowException);
+ }
+ }
+
+ @Test
+ public void testMergerWithHighNumberOfFields() throws Exception {
+ File srcFolder = TestTools.createTempDir("oneDexPerType", "SrcFolder");
+
+ for (int fileIdx = 0; fileIdx < fileCount; fileIdx++) {
+ generateJavaFileWithFields(srcFolder, fileIdx, 100);
+ }
+ generateJavaFileWithFields(srcFolder, fileCount, 37);
+
+ try {
+ buildOneDexPerType(TestTools.getDefaultBootclasspathString(), srcFolder, false /* withDebug */);
+ Assert.fail();
+ } catch (JackUserException e) {
+ Assert.assertEquals(expectedExceptionMessage, e.getMessage());
+ Throwable cause = e.getCause();
+ Assert.assertTrue(cause instanceof FieldIdOverflowException);
+ }
+ }
+
+ @Test
+ @Category(SlowTests.class)
+ public void testMergerWithHighNumberOfTypes() throws Exception {
+ File srcFolder = TestTools.createTempDir("oneDexPerType", "SrcFolder");
+
+ for (int fileIdx = 0; fileIdx < fileCount; fileIdx++) {
+ generateJavaFileWithTypes(srcFolder, fileIdx, 100);
+ }
+ generateJavaFileWithTypes(srcFolder, fileCount, 36);
+
+ try {
+ buildOneDexPerType(TestTools.getDefaultBootclasspathString(), srcFolder, false /* withDebug */);
+ Assert.fail();
+ } catch (JackUserException e) {
+ Assert.assertEquals(expectedExceptionMessage, e.getMessage());
+ Throwable cause = e.getCause();
+ Assert.assertTrue(cause instanceof TypeIdOverflowException);
+ }
+ }
+
+ private void generateJavaFileWithMethods(@Nonnull File srcFolder, @Nonnegative int fileIdx,
+ @Nonnegative int methodCount) throws IOException, FileNotFoundException {
+ File javaFile = new File(srcFolder, "A" + fileIdx + ".java");
+ if (!javaFile.createNewFile()) {
+ throw new IOException("Failed to create file " + javaFile.getAbsolutePath());
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(javaFile);
+ StringBuilder content =
+ new StringBuilder("package jack.merger; \n" + "public class A" + fileIdx+ " {");
+ // -1 due to implicit init method
+ for (int mthIdx = 0; mthIdx < methodCount - 1; mthIdx++) {
+ content.append("public void m" + mthIdx + "() {}");
+ }
+ content.append("} \n");
+ fos.write(content.toString().getBytes());
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ }
+
+ private void generateJavaFileWithFields(@Nonnull File srcFolder, @Nonnegative int fileIdx,
+ @Nonnegative int fieldCount) throws IOException, FileNotFoundException {
+ File javaFile = new File(srcFolder, "A" + fileIdx + ".java");
+ if (!javaFile.createNewFile()) {
+ throw new IOException("Failed to create file " + javaFile.getAbsolutePath());
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(javaFile);
+ StringBuilder content =
+ new StringBuilder("package jack.merger; \n" + "public class A" + fileIdx+ " {");
+ for (int fieldIdx = 0; fieldIdx < fieldCount; fieldIdx++) {
+ content.append("public int f" + fieldIdx + ";");
+ }
+ content.append("} \n");
+ fos.write(content.toString().getBytes());
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ }
+
+ private void generateJavaFileWithTypes(@Nonnull File srcFolder, @Nonnegative int fileIdx,
+ @Nonnegative int typeCount) throws IOException, FileNotFoundException {
+ File javaFile = new File(srcFolder, "A" + fileIdx + ".java");
+ if (!javaFile.createNewFile()) {
+ throw new IOException("Failed to create file " + javaFile.getAbsolutePath());
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(javaFile);
+ StringBuilder content =
+ new StringBuilder("package jack.merger; \n" + "public class A" + fileIdx+ " {");
+ for (int typeIdx = 0; typeIdx < typeCount; typeIdx++) {
+ content.append("public class c" + typeIdx + " {}");
+ }
+ content.append("} \n");
+ fos.write(content.toString().getBytes());
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ }
+}
diff --git a/jack/src/com/android/jack/Options.java b/jack/src/com/android/jack/Options.java
index 4eebae8..f6166eb 100644
--- a/jack/src/com/android/jack/Options.java
+++ b/jack/src/com/android/jack/Options.java
@@ -699,6 +699,15 @@ public class Options {
return outZip != null || jayceOutZip != null;
}
+ @CheckForNull
+ public Flags getFlags() {
+ return flags;
+ }
+
+ public void setFlags(@Nonnull Flags flags) {
+ this.flags = flags;
+ }
+
public void applyShrobFlags() {
assert flags != null;
List<File> inJars = flags.getInJars();
@@ -761,6 +770,15 @@ public class Options {
this.proguardFlagsFiles = proguardFlagsFiles;
}
+ @CheckForNull
+ public File getJarjarRulesFile() {
+ return jarjarRulesFile;
+ }
+
+ public void setJarjarRulesFile(@Nonnull File jarjarRulesFile) {
+ this.jarjarRulesFile = jarjarRulesFile;
+ }
+
public void setNameProvider(@Nonnull String nameProvider) {
properties.put(NameProviderFactory.NAMEPROVIDER.getName(), nameProvider);
}
diff --git a/jack/tests/com/android/jack/AllTestsWithoutKnownBugs.java b/jack/tests/com/android/jack/AllTestsWithoutKnownBugs.java
new file mode 100644
index 0000000..683e265
--- /dev/null
+++ b/jack/tests/com/android/jack/AllTestsWithoutKnownBugs.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack;
+
+import com.android.jack.category.KnownBugs;
+
+import org.junit.experimental.categories.Categories;
+import org.junit.experimental.categories.Categories.ExcludeCategory;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * Test suite containing all tests (except for regression tests that must be run from the command
+ * line).
+ */
+@RunWith(Categories.class)
+@ExcludeCategory(KnownBugs.class)
+@SuiteClasses(value = {AllTests.class})
+public class AllTestsWithoutKnownBugs {
+}
diff --git a/junit4/Android.mk b/junit4/Android.mk
index aeb9366..321f2fa 100644
--- a/junit4/Android.mk
+++ b/junit4/Android.mk
@@ -42,3 +42,20 @@ LOCAL_MODULE_TAGS := optional
LOCAL_BUILD_HOST_DEX := true
include $(BUILD_HOST_JAVA_LIBRARY)
+
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
+
+LOCAL_JAVA_LIBRARIES := core
+
+LOCAL_JAVA_LIBRARIES := hamcrest-core-target-jack
+
+LOCAL_STATIC_JAVA_LIBRARIES := hamcrest-core-target-jack
+
+LOCAL_MODULE := junit4-targetdex-jack
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_JAVA_LIBRARY)