blob: fbe40d6cfee1327a0719ebdd2092b94038a2d717 [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.shaking;
import static com.android.tools.r8.ToolHelper.EXAMPLES_BUILD_DIR;
import static com.android.tools.r8.ToolHelper.EXAMPLES_DIR;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.ToolHelper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class TreeShakingSpecificTest {
private Backend backend;
@Parameters(name = "Backend: {0}")
public static Collection<Backend> data() {
return Arrays.asList(Backend.values());
}
public TreeShakingSpecificTest(Backend backend) {
this.backend = backend;
}
private static final String VALID_PROGUARD_DIR = "src/test/proguard/valid/";
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
@Rule
public ExpectedException thrown = ExpectedException.none();
private void finishBuild(R8Command.Builder builder, Path out, String test) throws IOException {
Path input;
if (backend == Backend.DEX) {
builder.setOutput(out, OutputMode.DexIndexed);
input = Paths.get(EXAMPLES_BUILD_DIR, test, "classes.dex");
} else {
builder.setOutput(out, OutputMode.ClassFile);
input = Paths.get(EXAMPLES_BUILD_DIR, test + ".jar");
}
ToolHelper.getAppBuilder(builder).addProgramFiles(input);
}
@Test
public void testIgnoreWarnings() throws Exception {
// Generate R8 processed version without library option.
Path out = temp.getRoot().toPath();
String test = "shaking2";
Path keepRules = Paths.get(EXAMPLES_DIR, test, "keep-rules.txt");
Path ignoreWarnings = Paths.get(VALID_PROGUARD_DIR, "ignorewarnings.flags");
R8Command.Builder builder = R8Command.builder()
.addProguardConfigurationFiles(keepRules, ignoreWarnings);
finishBuild(builder, out, test);
R8.run(builder.build());
}
@Test(expected = CompilationFailedException.class)
public void testMissingLibrary() throws Exception {
// Generate R8 processed version without library option.
Path out = temp.getRoot().toPath();
String test = "shaking2";
Path keepRules = Paths.get(EXAMPLES_DIR, test, "keep-rules.txt");
DiagnosticsHandler handler =
new DiagnosticsHandler() {
@Override
public void error(Diagnostic error) {
String expectedErrorMessage =
"Compilation can't be completed because the class `java.lang.Object` is missing";
if (error.getDiagnosticMessage().contains(expectedErrorMessage)) {
return;
}
throw new RuntimeException("Unexpected compilation error");
}
};
R8Command.Builder builder = R8Command.builder(handler)
.addProguardConfigurationFiles(keepRules);
finishBuild(builder, out, test);
R8.run(builder.build());
}
@Test
public void testPrintMapping() throws Exception {
// Generate R8 processed version without library option.
String test = "shaking1";
Path out = temp.getRoot().toPath();
Path keepRules = Paths.get(EXAMPLES_DIR, test, "keep-rules.txt");
// Create a flags file in temp dir requesting dump of the mapping.
// The mapping file will be created alongside the flags file in temp dir.
Path printMapping = out.resolve("printmapping.flags");
try (PrintStream mapping = new PrintStream(printMapping.toFile())) {
mapping.println("-printmapping mapping.txt");
}
R8Command.Builder builder = R8Command.builder()
.addProguardConfigurationFiles(keepRules, printMapping);
// Turn off inlining, as we want the mapping that is printed to be stable.
finishBuild(builder, out, test);
if (backend == Backend.DEX) {
builder.addLibraryFiles(ToolHelper.getDefaultAndroidJar());
} else {
assert backend == Backend.CF;
builder.addLibraryFiles(ToolHelper.getJava8RuntimeJar());
}
ToolHelper.runR8(builder.build(), options -> options.enableInlining = false);
Path outputmapping = out.resolve("mapping.txt");
// Remove comments.
String actualMapping =
Stream.of(new String(Files.readAllBytes(outputmapping), StandardCharsets.UTF_8).split("\n"))
.filter(line -> !line.startsWith("#"))
.collect(Collectors.joining("\n"));
String refMapping =
new String(
Files.readAllBytes(Paths.get(EXAMPLES_DIR, "shaking1", "print-mapping.ref")),
StandardCharsets.UTF_8);
Assert.assertEquals(sorted(refMapping), sorted(actualMapping));
}
private static String sorted(String str) {
return new BufferedReader(new StringReader(str))
.lines().sorted().filter(s -> !s.isEmpty()).collect(Collectors.joining("\n"));
}
}