blob: 060bdbbcf98bf94b19d199d4396773a4a7f1aa97 [file] [log] [blame]
// Copyright (c) 2019, 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.AssertionsConfiguration.AssertionTransformation;
import com.android.tools.r8.AssertionsConfiguration.AssertionTransformationScope;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class L8CommandTest {
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
@Test(expected = CompilationFailedException.class)
public void emptyBuilder() throws Throwable {
verifyEmptyCommand(L8Command.builder().build());
}
@Test
public void emptyCommand() throws Throwable {
verifyEmptyCommand(
L8Command.builder()
.setProgramConsumer(DexIndexedConsumer.emptyConsumer())
.addDesugaredLibraryConfiguration(
StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
.build());
}
private void verifyEmptyCommand(L8Command command) {
BaseCompilerCommand compilationCommand =
command.getD8Command() == null ? command.getR8Command() : command.getD8Command();
assertNotNull(compilationCommand);
assertTrue(command.getProgramConsumer() instanceof ClassFileConsumer);
assertTrue(compilationCommand.getProgramConsumer() instanceof DexIndexedConsumer);
}
@Test
public void testMarker() throws Throwable {
Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
L8.run(
L8Command.builder()
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
.addProgramFiles(ToolHelper.getDesugarJDKLibs())
.setMinApiLevel(20)
.addDesugaredLibraryConfiguration(
StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
.setOutput(output, OutputMode.DexIndexed)
.build());
Collection<Marker> markers = ExtractMarker.extractMarkerFromDexFile(output);
// TODO(b/134732760): Shouldn't we remove the D8/R8 marker?
assertEquals(2, markers.size());
Marker marker = markers.iterator().next();
}
@Test
public void testMarkerCommandLine() throws Throwable {
Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
L8Command l8Command =
parse(
ToolHelper.getDesugarJDKLibs().toString(),
"--lib",
ToolHelper.getAndroidJar(AndroidApiLevel.P).toString(),
"--min-api",
"20",
"--desugared-lib",
ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(),
"--output",
output.toString());
L8.run(l8Command);
Collection<Marker> markers = ExtractMarker.extractMarkerFromDexFile(output);
// TODO(b/134732760): Shouldn't we remove the D8/R8 marker?
assertEquals(2, markers.size());
Marker marker = markers.iterator().next();
}
private L8Command.Builder prepareBuilder(DiagnosticsHandler handler) {
return L8Command.builder(handler)
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
.addProgramFiles(ToolHelper.getDesugarJDKLibs())
.setMinApiLevel(20);
}
@Test(expected = CompilationFailedException.class)
public void mainDexListNotSupported() throws Throwable {
Path mainDexList = temp.newFile("main-dex-list.txt").toPath();
DiagnosticsChecker.checkErrorsContains(
"L8 does not support a main dex list",
(handler) ->
prepareBuilder(handler)
.setProgramConsumer(DexIndexedConsumer.emptyConsumer())
.addMainDexListFiles(mainDexList)
.build());
}
@Test(expected = CompilationFailedException.class)
public void dexPerClassNotSupported() throws Throwable {
DiagnosticsChecker.checkErrorsContains(
"L8 does not support compiling to dex per class",
(handler) ->
prepareBuilder(handler)
.setProgramConsumer(DexFilePerClassFileConsumer.emptyConsumer())
.build());
}
@Test(expected = CompilationFailedException.class)
public void classFileOutputNotSupported() throws Throwable {
DiagnosticsChecker.checkErrorsContains(
"L8 does not support compiling to class files",
(handler) ->
prepareBuilder(handler).setProgramConsumer(ClassFileConsumer.emptyConsumer()).build());
}
@Test(expected = CompilationFailedException.class)
public void desugaredLibraryConfigurationRequired() throws Throwable {
DiagnosticsChecker.checkErrorsContains(
"L8 requires a desugared library configuration",
(handler) ->
prepareBuilder(handler).setProgramConsumer(ClassFileConsumer.emptyConsumer()).build());
}
@Test
@Ignore("b/143431384: Re-enable shrinking")
public void addProguardConfigurationString() throws Throwable {
String keepRule = "-keep class java.time.*";
List<String> keepRules = new ArrayList<>();
keepRules.add(keepRule);
L8Command.Builder builder =
prepareBuilder(new TestDiagnosticMessagesImpl())
.setProgramConsumer(DexIndexedConsumer.emptyConsumer())
.addDesugaredLibraryConfiguration(
StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
.addProguardConfiguration(keepRules, Origin.unknown());
assertTrue(builder.isShrinking());
assertNotNull(builder.build().getR8Command());
}
@Test
@Ignore("b/143431384: Re-enable shrinking")
public void addProguardConfigurationFile() throws Throwable {
String keepRule = "-keep class java.time.*";
Path keepRuleFile = temp.newFile("keepRuleFile.txt").toPath();
Files.write(keepRuleFile, Collections.singletonList(keepRule), StandardCharsets.UTF_8);
L8Command.Builder builder1 =
prepareBuilder(new TestDiagnosticMessagesImpl())
.setProgramConsumer(DexIndexedConsumer.emptyConsumer())
.addDesugaredLibraryConfiguration(
StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
.addProguardConfigurationFiles(keepRuleFile);
assertTrue(builder1.isShrinking());
assertNotNull(builder1.build().getR8Command());
List<Path> keepRuleFiles = new ArrayList<>();
keepRuleFiles.add(keepRuleFile);
L8Command.Builder builder2 =
prepareBuilder(new TestDiagnosticMessagesImpl())
.setProgramConsumer(DexIndexedConsumer.emptyConsumer())
.addDesugaredLibraryConfiguration(
StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
.addProguardConfigurationFiles(keepRuleFiles);
assertTrue(builder2.isShrinking());
assertNotNull(builder2.build().getR8Command());
}
@Test
public void desugaredLibrary() throws CompilationFailedException {
L8Command l8Command =
parse("--desugared-lib", ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString());
assertFalse(
l8Command.getInternalOptions().desugaredLibraryConfiguration.getRewritePrefix().isEmpty());
}
private void checkSingleForceAllAssertion(
List<AssertionsConfiguration> entries, AssertionTransformation transformation) {
assertEquals(1, entries.size());
assertEquals(transformation, entries.get(0).getTransformation());
assertEquals(AssertionTransformationScope.ALL, entries.get(0).getScope());
}
private void checkSingleForceClassAndPackageAssertion(
List<AssertionsConfiguration> entries, AssertionTransformation transformation) {
assertEquals(2, entries.size());
assertEquals(transformation, entries.get(0).getTransformation());
assertEquals(AssertionTransformationScope.CLASS, entries.get(0).getScope());
assertEquals("ClassName", entries.get(0).getValue());
assertEquals(transformation, entries.get(1).getTransformation());
assertEquals(AssertionTransformationScope.PACKAGE, entries.get(1).getScope());
assertEquals("PackageName", entries.get(1).getValue());
}
@Test
public void forceAssertionOption() throws Exception {
checkSingleForceAllAssertion(
parse(
"--force-enable-assertions",
"--desugared-lib",
ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
.getAssertionsConfiguration(),
AssertionTransformation.ENABLE);
checkSingleForceAllAssertion(
parse(
"--force-disable-assertions",
"--desugared-lib",
ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
.getAssertionsConfiguration(),
AssertionTransformation.DISABLE);
checkSingleForceAllAssertion(
parse(
"--force-passthrough-assertions",
"--desugared-lib",
ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
.getAssertionsConfiguration(),
AssertionTransformation.PASSTHROUGH);
checkSingleForceClassAndPackageAssertion(
parse(
"--force-enable-assertions:ClassName",
"--force-enable-assertions:PackageName...",
"--desugared-lib",
ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
.getAssertionsConfiguration(),
AssertionTransformation.ENABLE);
checkSingleForceClassAndPackageAssertion(
parse(
"--force-disable-assertions:ClassName",
"--force-disable-assertions:PackageName...",
"--desugared-lib",
ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
.getAssertionsConfiguration(),
AssertionTransformation.DISABLE);
checkSingleForceClassAndPackageAssertion(
parse(
"--force-passthrough-assertions:ClassName",
"--force-passthrough-assertions:PackageName...",
"--desugared-lib",
ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
.getAssertionsConfiguration(),
AssertionTransformation.PASSTHROUGH);
}
private L8Command parse(String... args) throws CompilationFailedException {
return L8Command.parse(args, EmbeddedOrigin.INSTANCE).build();
}
}