|  | // 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(); | 
|  | } | 
|  | } |