| // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| package com.android.tools.r8; | |
| import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; | |
| import static com.android.tools.r8.utils.FileUtils.ZIP_EXTENSION; | |
| import static org.junit.Assert.assertEquals; | |
| import static org.junit.Assert.assertTrue; | |
| import com.android.tools.r8.ToolHelper.DexVm; | |
| import com.android.tools.r8.ToolHelper.ProcessResult; | |
| import com.android.tools.r8.utils.AndroidApiLevel; | |
| import com.android.tools.r8.utils.InternalOptions; | |
| import com.android.tools.r8.utils.OffOrAuto; | |
| import com.android.tools.r8.utils.TestDescriptionWatcher; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.ImmutableMap; | |
| import java.nio.file.Path; | |
| import java.nio.file.Paths; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.function.Consumer; | |
| import java.util.function.UnaryOperator; | |
| import org.junit.Rule; | |
| import org.junit.Test; | |
| import org.junit.rules.ExpectedException; | |
| import org.junit.rules.TemporaryFolder; | |
| public abstract class RunExamplesAndroidNTest<B> { | |
| private static final String EXAMPLE_DIR = ToolHelper.EXAMPLES_ANDROID_N_BUILD_DIR; | |
| abstract class TestRunner { | |
| final String testName; | |
| final String packageName; | |
| final String mainClass; | |
| final List<Consumer<InternalOptions>> optionConsumers = new ArrayList<>(); | |
| final List<UnaryOperator<B>> builderTransformations = new ArrayList<>(); | |
| TestRunner(String testName, String packageName, String mainClass) { | |
| this.testName = testName; | |
| this.packageName = packageName; | |
| this.mainClass = mainClass; | |
| } | |
| TestRunner withOptionConsumer(Consumer<InternalOptions> consumer) { | |
| optionConsumers.add(consumer); | |
| return this; | |
| } | |
| TestRunner withInterfaceMethodDesugaring(OffOrAuto behavior) { | |
| return withOptionConsumer(o -> o.interfaceMethodDesugaring = behavior); | |
| } | |
| TestRunner withBuilderTransformation(UnaryOperator<B> builderTransformation) { | |
| builderTransformations.add(builderTransformation); | |
| return this; | |
| } | |
| void combinedOptionConsumer(InternalOptions options) { | |
| for (Consumer<InternalOptions> consumer : optionConsumers) { | |
| consumer.accept(options); | |
| } | |
| } | |
| void run() throws Throwable { | |
| String qualifiedMainClass = packageName + "." + mainClass; | |
| Path inputFile = Paths.get(EXAMPLE_DIR, packageName + JAR_EXTENSION); | |
| Path out = temp.getRoot().toPath().resolve(testName + ZIP_EXTENSION); | |
| build(inputFile, out); | |
| if (!ToolHelper.artSupported() && !ToolHelper.dealsWithGoldenFiles()) { | |
| return; | |
| } | |
| boolean expectedToFail = false; | |
| if (failsOn.containsKey(ToolHelper.getDexVm()) | |
| && failsOn.get(ToolHelper.getDexVm()).contains(testName)) { | |
| expectedToFail = true; | |
| thrown.expect(Throwable.class); | |
| } | |
| String output = ToolHelper.runArtNoVerificationErrors(out.toString(), qualifiedMainClass); | |
| if (!expectedToFail) { | |
| ProcessResult javaResult = ToolHelper.runJava(inputFile, qualifiedMainClass); | |
| assertEquals("JVM run failed", javaResult.exitCode, 0); | |
| assertTrue( | |
| "JVM output does not match art output.\n\tjvm: " | |
| + javaResult.stdout | |
| + "\n\tart: " | |
| + output, | |
| output.equals(javaResult.stdout)); | |
| } | |
| } | |
| abstract TestRunner withMinApiLevel(int minApiLevel); | |
| TestRunner withKeepAll() { | |
| return this; | |
| } | |
| abstract void build(Path inputFile, Path out) throws Throwable; | |
| } | |
| private static Map<DexVm.Version, List<String>> failsOn = | |
| ImmutableMap.of( | |
| DexVm.Version.V4_4_4, | |
| ImmutableList.of(), | |
| DexVm.Version.V5_1_1, | |
| ImmutableList.of(), | |
| DexVm.Version.V6_0_1, | |
| ImmutableList.of(), | |
| DexVm.Version.V7_0_0, | |
| ImmutableList.of(), | |
| DexVm.Version.DEFAULT, | |
| ImmutableList.of()); | |
| @Rule public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest(); | |
| @Rule public ExpectedException thrown = ExpectedException.none(); | |
| @Rule public TestDescriptionWatcher watcher = new TestDescriptionWatcher(); | |
| @Test | |
| public void staticInterfaceMethods() throws Throwable { | |
| test("staticinterfacemethods", "interfacemethods", "StaticInterfaceMethods") | |
| .withMinApiLevel(AndroidApiLevel.K.getLevel()) | |
| .withInterfaceMethodDesugaring(OffOrAuto.Auto) | |
| .withKeepAll() | |
| .run(); | |
| } | |
| @Test(expected = CompilationFailedException.class) | |
| public void staticInterfaceMethodsErrorDueToMinSdk() throws Throwable { | |
| test("staticinterfacemethods-error-due-to-min-sdk", "interfacemethods", | |
| "StaticInterfaceMethods") | |
| .withInterfaceMethodDesugaring(OffOrAuto.Off) | |
| .withKeepAll() | |
| .run(); | |
| } | |
| @Test | |
| public void defaultMethods() throws Throwable { | |
| test("defaultmethods", "interfacemethods", "DefaultMethods") | |
| .withMinApiLevel(AndroidApiLevel.K.getLevel()) | |
| .withInterfaceMethodDesugaring(OffOrAuto.Auto) | |
| .withKeepAll() | |
| .run(); | |
| } | |
| @Test(expected = CompilationFailedException.class) | |
| public void defaultMethodsErrorDueToMinSdk() throws Throwable { | |
| test("defaultmethods-error-due-to-min-sdk", "interfacemethods", | |
| "DefaultMethods") | |
| .withInterfaceMethodDesugaring(OffOrAuto.Off) | |
| .withKeepAll() | |
| .run(); | |
| } | |
| abstract TestRunner test(String testName, String packageName, String mainClass); | |
| } |