blob: f681673c0881786efbdb1d2a6c8a32e9ed56aa3c [file] [log] [blame]
// 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.utils;
import static com.android.tools.r8.ToolHelper.EXAMPLES_BUILD_DIR;
import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.DiagnosticsChecker;
import com.android.tools.r8.GenerateMainDexList;
import com.android.tools.r8.GenerateMainDexListCommand;
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.origin.Origin;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
public class GenerateMainDexListCommandTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
private Path getOutputPath(GenerateMainDexListCommand command) {
StringConsumer consumer = command.getMainDexListConsumer();
if (consumer instanceof JoiningStringConsumer) {
consumer = ((JoiningStringConsumer) consumer).getConsumer();
}
if (consumer instanceof StringConsumer.FileConsumer) {
return ((StringConsumer.FileConsumer) consumer).getOutputPath();
}
return null;
}
@Test
public void emptyCommand() throws Throwable {
verifyEmptyCommand(GenerateMainDexListCommand.builder().build());
verifyEmptyCommand(parse());
verifyEmptyCommand(parse(""));
verifyEmptyCommand(parse("", ""));
verifyEmptyCommand(parse(" "));
verifyEmptyCommand(parse(" ", " "));
verifyEmptyCommand(parse("\t"));
verifyEmptyCommand(parse("\t", "\t"));
}
private void verifyEmptyCommand(GenerateMainDexListCommand command) throws IOException {
assertEquals(0, ToolHelper.getApp(command).getDexProgramResourcesForTesting().size());
assertEquals(0, ToolHelper.getApp(command).getClassProgramResourcesForTesting().size());
assertFalse(ToolHelper.getApp(command).hasMainDexListResources());
}
private void addAndroidJarsToCommandLine(List<String> args) {
args.add("--lib");
args.add(ToolHelper.getAndroidJar(AndroidApiLevel.K).toAbsolutePath().toString());
}
// Add the jars used in the com.android.tools.r8.maindexlist.MainDexTracingTest test.
private void addInputJarsToCommandLine(List<String> args) {
args.add(Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "multidex001" + JAR_EXTENSION)
.toAbsolutePath().toString());
args.add(Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "multidexfakeframeworks" + JAR_EXTENSION)
.toAbsolutePath().toString());
}
// Add main-dex rules used in the com.android.tools.r8.maindexlist.MainDexTracingTest test.
private void addMainDexRuleToCommandLine(List<String> args) {
args.add("--main-dex-rules");
args.add(Paths.get(ToolHelper.EXAMPLES_DIR, "multidex", "main-dex-rules.txt")
.toAbsolutePath().toString());
}
@Test
public void defaultOutIsCwd() throws Throwable {
Path working = temp.getRoot().toPath();
String mainDexListOutput = "main-dex-list.txt";
Path output = working.resolve(mainDexListOutput);
assertFalse(Files.exists(output));
List<String> args = new ArrayList<>();
addAndroidJarsToCommandLine(args);
addInputJarsToCommandLine(args);
addMainDexRuleToCommandLine(args);
ProcessResult result =
ToolHelper.forkGenerateMainDexList(
working, args, "--main-dex-list-output", mainDexListOutput);
assertEquals(result.stderr, 0, result.exitCode);
assertTrue(Files.exists(output));
assertTrue(Files.size(output) > 0);
}
@Test
public void validOutputPath() throws Throwable {
Path existingFile = temp.getRoot().toPath().resolve("existing_output");
try (OutputStream existingFileOut = Files.newOutputStream(existingFile,
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
PrintWriter writer = new PrintWriter(existingFileOut);
writer.println("Hello, world!");
writer.flush();
}
Path nonExistingFile = temp.getRoot().toPath().resolve("non_existing_output");
assertEquals(
existingFile,
getOutputPath(
GenerateMainDexListCommand.builder().setMainDexListOutputPath(existingFile).build()));
assertEquals(
nonExistingFile,
getOutputPath(
GenerateMainDexListCommand.builder()
.setMainDexListOutputPath(nonExistingFile).build()));
assertEquals(
existingFile,
getOutputPath(parse("--main-dex-list-output", existingFile.toString())));
assertEquals(
nonExistingFile,
getOutputPath(parse("--main-dex-list-output", nonExistingFile.toString())));
}
@Test
public void nonExistingOutputFileInNonExistingDir() throws Throwable {
Path nonExistingFileInNonExistingDir =
temp.getRoot().toPath().resolve("a/path/that/does/not/exist");
assertEquals(
nonExistingFileInNonExistingDir,
getOutputPath(
GenerateMainDexListCommand.builder()
.setMainDexListOutputPath(nonExistingFileInNonExistingDir).build()));
assertEquals(
nonExistingFileInNonExistingDir,
getOutputPath(
parse("--main-dex-list-output", nonExistingFileInNonExistingDir.toString())));
}
@Test
public void mainDexRules() throws Throwable {
Path mainDexRules1 = temp.newFile("main-dex-1.rules").toPath();
Path mainDexRules2 = temp.newFile("main-dex-2.rules").toPath();
parse("--main-dex-rules", mainDexRules1.toString());
parse(
"--main-dex-rules", mainDexRules1.toString(), "--main-dex-rules", mainDexRules2.toString());
}
@Test
public void mainDexList() throws Throwable {
Path mainDexList1 = temp.newFile("main-dex-list-1.txt").toPath();
Path mainDexList2 = temp.newFile("main-dex-list-2.txt").toPath();
parse("--main-dex-list", mainDexList1.toString());
parse("--main-dex-list", mainDexList1.toString(), "--main-dex-list", mainDexList2.toString());
}
@Test(expected = CompilationFailedException.class)
public void missingAndroidJar() throws Throwable {
DiagnosticsChecker.checkErrorsContains(
"Tracing for legacy multi dex is not possible without all classpath libraries",
handler ->
GenerateMainDexList.run(
GenerateMainDexListCommand.builder(handler).build()));
}
@Test(expected = CompilationFailedException.class)
public void duplicateProgramClasses() throws Throwable {
Path input = Paths.get(EXAMPLES_BUILD_DIR, "arithmetic.jar");
DiagnosticsChecker.checkErrorsContains(
"defined multiple times",
handler ->
GenerateMainDexList.run(
GenerateMainDexListCommand.builder(handler)
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
.addProgramFiles(input)
.addProgramFiles(input)
.build()));
}
@Test
public void emptyMainDex() throws Throwable {
Path input = Paths.get(EXAMPLES_BUILD_DIR, "arithmetic.jar");
List<String> result = GenerateMainDexList.run(
GenerateMainDexListCommand.builder()
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
.addProgramFiles(input)
.build());
assertEquals(0, result.size());
}
@Test
public void nonEmptyMainDex() throws Throwable {
Path input = Paths.get(EXAMPLES_BUILD_DIR, "arithmetic.jar");
List<String> result = GenerateMainDexList.run(
GenerateMainDexListCommand.builder()
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
.addProgramFiles(input)
.addMainDexRules(
ImmutableList.of("-keep class arithmetic.Arithmetic"), Origin.unknown())
.build());
assertEquals(1, result.size());
}
private GenerateMainDexListCommand parse(String... args) throws Throwable {
return GenerateMainDexListCommand.parse(args).build();
}
}