blob: 9c9a977463c50ebfba11eac2bfc9cf5dcee5fd92 [file] [log] [blame]
// 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.ProgramResource.Kind;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.debug.CfDebugTestConfig;
import com.android.tools.r8.debug.DebugTestConfig;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.ListUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class JvmTestBuilder extends TestBuilder<JvmTestRunResult, JvmTestBuilder> {
private static class ClassFileResource implements ProgramResource {
private final Path file;
private final String descriptor;
private final Origin origin;
ClassFileResource(Class<?> clazz) {
this(
ToolHelper.getClassFileForTestClass(clazz),
DescriptorUtils.javaTypeToDescriptor(clazz.getTypeName()));
}
ClassFileResource(Path file, String descriptor) {
this.file = file;
this.descriptor = descriptor;
origin = new PathOrigin(file);
}
@Override
public Kind getKind() {
return Kind.CF;
}
@Override
public InputStream getByteStream() throws ResourceException {
try {
return Files.newInputStream(file);
} catch (IOException e) {
throw new ResourceException(getOrigin(), e);
}
}
@Override
public Set<String> getClassDescriptors() {
return Collections.singleton(descriptor);
}
@Override
public Origin getOrigin() {
return origin;
}
}
private static class ClassFileResourceProvider implements ProgramResourceProvider {
private final List<ProgramResource> resources;
public ClassFileResourceProvider(List<ProgramResource> resources) {
this.resources = resources;
}
@Override
public Collection<ProgramResource> getProgramResources() throws ResourceException {
return resources;
}
@Override
public DataResourceProvider getDataResourceProvider() {
return null;
}
}
// Ordered list of classpath entries.
private List<Path> classpath = new ArrayList<>();
private AndroidApp.Builder builder = AndroidApp.builder();
private JvmTestBuilder(TestState state) {
super(state);
}
public static JvmTestBuilder create(TestState state) {
return new JvmTestBuilder(state);
}
@Override
JvmTestBuilder self() {
return this;
}
@Override
public JvmTestRunResult run(String mainClass) throws IOException {
ProcessResult result = ToolHelper.runJava(classpath, mainClass);
return new JvmTestRunResult(builder.build(), result);
}
@Override
public DebugTestConfig debugConfig() {
return new CfDebugTestConfig().addPaths(classpath);
}
@Override
public JvmTestBuilder addLibraryFiles(Collection<Path> files) {
throw new Unimplemented("No support for changing the Java runtime library.");
}
@Override
public JvmTestBuilder addProgramClasses(Collection<Class<?>> classes) {
addProgramResources(ListUtils.map(classes, ClassFileResource::new));
return self();
}
@Override
public JvmTestBuilder addProgramFiles(Collection<Path> files) {
throw new Unimplemented(
"No support for adding paths directly (we need to compute the descriptor)");
}
@Override
public JvmTestBuilder addProgramClassFileData(Collection<byte[]> files) {
addProgramResources(
ListUtils.map(files, data ->
ProgramResource.fromBytes(
Origin.unknown(),
Kind.CF,
data,
Collections.singleton(TestBase.extractClassDescriptor(data)))));
return self();
}
public JvmTestBuilder addClasspath(Path... paths) {
return addClasspath(Arrays.asList(paths));
}
public JvmTestBuilder addClasspath(List<Path> paths) {
for (Path path : paths) {
assert Files.isDirectory(path) || FileUtils.isArchive(path);
classpath.add(path);
}
return self();
}
public JvmTestBuilder addTestClasspath() {
return addClasspath(ToolHelper.getClassPathForTests());
}
// Adding a collection of resources will build a jar of exactly those classes so that no other
// classes are made available via a too broad classpath directory.
private void addProgramResources(List<ProgramResource> resources) {
AndroidApp build =
AndroidApp.builder()
.addProgramResourceProvider(new ClassFileResourceProvider(resources))
.build();
Path out;
try {
out = getState().getNewTempFolder().resolve("out.zip");
build.writeToZip(out, OutputMode.ClassFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
classpath.add(out);
builder.addProgramFiles(out);
}
}