| // Copyright (c) 2018, 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 com.android.tools.r8.TestBase.Backend; | |
| import com.android.tools.r8.debug.DebugTestConfig; | |
| import com.android.tools.r8.errors.Unimplemented; | |
| import com.android.tools.r8.utils.ListUtils; | |
| import com.google.common.collect.ImmutableList; | |
| import java.io.IOException; | |
| import java.nio.file.Path; | |
| import java.util.Arrays; | |
| import java.util.Collection; | |
| import java.util.List; | |
| import java.util.concurrent.ExecutionException; | |
| import java.util.function.BiFunction; | |
| public abstract class TestBuilder<RR extends TestRunResult<RR>, T extends TestBuilder<RR, T>> { | |
| private final TestState state; | |
| public TestBuilder(TestState state) { | |
| this.state = state; | |
| } | |
| public TestState getState() { | |
| return state; | |
| } | |
| abstract T self(); | |
| public <S, E extends Throwable> S map(ThrowingFunction<T, S, E> fn) { | |
| return fn.applyWithRuntimeException(self()); | |
| } | |
| public T apply(ThrowableConsumer<T> fn) { | |
| if (fn != null) { | |
| fn.acceptWithRuntimeException(self()); | |
| } | |
| return self(); | |
| } | |
| public T applyIf(boolean value, ThrowableConsumer<T> consumer) { | |
| T self = self(); | |
| if (value) { | |
| consumer.acceptWithRuntimeException(self); | |
| } | |
| return self; | |
| } | |
| public T applyIf( | |
| boolean value, ThrowableConsumer<T> trueConsumer, ThrowableConsumer<T> falseConsumer) { | |
| T self = self(); | |
| if (value) { | |
| trueConsumer.acceptWithRuntimeException(self); | |
| } else { | |
| falseConsumer.acceptWithRuntimeException(self); | |
| } | |
| return self; | |
| } | |
| @Deprecated | |
| public RR run(String mainClass) | |
| throws CompilationFailedException, ExecutionException, IOException { | |
| throw new Unimplemented("Deprecated"); | |
| } | |
| public abstract RR run(TestRuntime runtime, String mainClass, String... args) | |
| throws CompilationFailedException, ExecutionException, IOException; | |
| @Deprecated | |
| public RR run(Class<?> mainClass) | |
| throws CompilationFailedException, ExecutionException, IOException { | |
| return run(mainClass.getTypeName()); | |
| } | |
| public RR run(TestRuntime runtime, Class<?> mainClass, String... args) | |
| throws CompilationFailedException, ExecutionException, IOException { | |
| return run(runtime, mainClass.getTypeName(), args); | |
| } | |
| public abstract DebugTestConfig debugConfig(); | |
| public abstract T addProgramFiles(Collection<Path> files); | |
| public abstract T addProgramClassFileData(Collection<byte[]> classes); | |
| public T addProgramClassFileData(byte[]... classes) { | |
| return addProgramClassFileData(Arrays.asList(classes)); | |
| } | |
| public abstract T addProgramDexFileData(Collection<byte[]> data); | |
| public T addProgramDexFileData(byte[]... data) { | |
| return addProgramDexFileData(Arrays.asList(data)); | |
| } | |
| public T addProgramClasses(Class<?>... classes) { | |
| return addProgramClasses(Arrays.asList(classes)); | |
| } | |
| public T addProgramClasses(Collection<Class<?>> classes) { | |
| return addProgramFiles(getFilesForClasses(classes)); | |
| } | |
| public T addProgramFiles(Path... files) { | |
| return addProgramFiles(Arrays.asList(files)); | |
| } | |
| public T addProgramClassesAndInnerClasses(Class<?>... classes) throws IOException { | |
| return addProgramClassesAndInnerClasses(Arrays.asList(classes)); | |
| } | |
| public T addProgramClassesAndInnerClasses(Collection<Class<?>> classes) throws IOException { | |
| return addProgramClasses(classes).addInnerClasses(classes); | |
| } | |
| public T addInnerClasses(Class<?>... classes) throws IOException { | |
| return addInnerClasses(Arrays.asList(classes)); | |
| } | |
| public T addInnerClasses(Collection<Class<?>> classes) throws IOException { | |
| return addProgramFiles(getFilesForInnerClasses(classes)); | |
| } | |
| public abstract T addLibraryFiles(Collection<Path> files); | |
| public T addLibraryClasses(Class<?>... classes) { | |
| return addLibraryClasses(Arrays.asList(classes)); | |
| } | |
| public abstract T addLibraryClasses(Collection<Class<?>> classes); | |
| public T addLibraryFiles(Path... files) { | |
| return addLibraryFiles(Arrays.asList(files)); | |
| } | |
| public T addDefaultRuntimeLibrary(TestParameters parameters) { | |
| if (parameters.getBackend() == Backend.DEX) { | |
| addLibraryFiles(ToolHelper.getFirstSupportedAndroidJar(parameters.getApiLevel())); | |
| } else { | |
| assert parameters.getBackend() == Backend.CF; | |
| addLibraryFiles(ToolHelper.getJava8RuntimeJar()); | |
| } | |
| return self(); | |
| } | |
| public T addClasspathClasses(Class<?>... classes) { | |
| return addClasspathClasses(Arrays.asList(classes)); | |
| } | |
| public abstract T addClasspathClasses(Collection<Class<?>> classes); | |
| public T addClasspathFiles(Path... files) { | |
| return addClasspathFiles(Arrays.asList(files)); | |
| } | |
| public abstract T addClasspathFiles(Collection<Path> files); | |
| public final T addTestingAnnotationsAsProgramClasses() { | |
| return addProgramClasses(getTestingAnnotations()); | |
| } | |
| public final T addTestingAnnotationsAsLibraryClasses() { | |
| return addLibraryClasses(getTestingAnnotations()); | |
| } | |
| public static List<Class<?>> getTestingAnnotations() { | |
| return ImmutableList.of( | |
| AlwaysInline.class, | |
| AssumeMayHaveSideEffects.class, | |
| ForceInline.class, | |
| KeepConstantArguments.class, | |
| KeepUnusedArguments.class, | |
| NeverClassInline.class, | |
| NeverInline.class, | |
| NoVerticalClassMerging.class, | |
| NoHorizontalClassMerging.class, | |
| NeverPropagateValue.class); | |
| } | |
| static Collection<Path> getFilesForClasses(Collection<Class<?>> classes) { | |
| return ListUtils.map(classes, ToolHelper::getClassFileForTestClass); | |
| } | |
| static Collection<Path> getFilesForInnerClasses(Collection<Class<?>> classes) throws IOException { | |
| return ToolHelper.getClassFilesForInnerClasses(classes); | |
| } | |
| public abstract T addRunClasspathFiles(Collection<Path> files); | |
| public T addRunClasspathFiles(Path... files) { | |
| return addRunClasspathFiles(Arrays.asList(files)); | |
| } | |
| public T setDiagnosticsLevelModifier( | |
| BiFunction<DiagnosticsLevel, Diagnostic, DiagnosticsLevel> modifier) { | |
| getState().setDiagnosticsLevelModifier(modifier); | |
| return self(); | |
| } | |
| } |