blob: 380703c5796815251d381cea96c12a0b960a6e8a [file] [log] [blame]
// Copyright (c) 2020, 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.desugar.desugaredlibrary;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfigurationParser;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.List;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class BufferedReaderTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
private final boolean shrinkDesugaredLibrary;
@Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
public static List<Object[]> data() {
return buildParameters(
BooleanUtils.values(),
getTestParameters()
.withAllRuntimes()
.withAllApiLevelsAlsoForCf()
.withApiLevel(AndroidApiLevel.N)
.build());
}
public BufferedReaderTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
this.parameters = parameters;
}
private String expectedOutput() {
return StringUtils.lines(
"Hello",
"Larry",
"Page",
parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)
? "Caught java.io.UncheckedIOException"
: "Caught j$.io.UncheckedIOException");
}
DesugaredLibraryConfiguration configurationWithBufferedReader(
InternalOptions options, boolean libraryCompilation, TestParameters parameters) {
// Parse the current configuration and amend the configuration for BufferedReader.lines. The
// configuration is the same for both program and library.
return new DesugaredLibraryConfigurationParser(
options.dexItemFactory(),
options.reporter,
libraryCompilation,
parameters.getApiLevel().getLevel())
.parse(
StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING),
builder -> {
if (parameters.getApiLevel().isLessThan(AndroidApiLevel.N)) {
builder.putRewritePrefix(
"java.io.DesugarBufferedReader", "j$.io.DesugarBufferedReader");
builder.putRewritePrefix(
"java.io.UncheckedIOException", "j$.io.UncheckedIOException");
builder.putRetargetCoreLibMember(
"java.io.BufferedReader#lines", "java.io.DesugarBufferedReader");
}
});
}
private void configurationForProgramCompilation(InternalOptions options) {
options.desugaredLibraryConfiguration =
configurationWithBufferedReader(options, false, parameters);
}
private void configurationForLibraryCompilation(InternalOptions options) {
options.desugaredLibraryConfiguration =
configurationWithBufferedReader(options, true, parameters);
}
@Test
public void testBufferedReaderD8Cf() throws Exception {
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
// Use D8 to desugar with Java classfile output.
Path jar =
testForD8(Backend.CF)
.addOptionsModification(this::configurationForProgramCompilation)
.addInnerClasses(BufferedReaderTest.class)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
// .inspect(this::checkRewrittenInvokes)
.writeToZip();
if (parameters.getRuntime().isDex()) {
// Collection keep rules is only implemented in the DEX writer.
String desugaredLibraryKeepRules = keepRuleConsumer.get();
if (desugaredLibraryKeepRules != null) {
assertEquals(0, desugaredLibraryKeepRules.length());
desugaredLibraryKeepRules = "-keep class * { *; }";
}
// Convert to DEX without desugaring and run.
testForD8()
.addProgramFiles(jar)
.setMinApi(parameters.getApiLevel())
.disableDesugaring()
.compile()
.addDesugaredCoreLibraryRunClassPath(
(apiLevel, keepRules, shrink) ->
buildDesugaredLibrary(
apiLevel,
keepRules,
shrink,
ImmutableList.of(),
this::configurationForLibraryCompilation),
parameters.getApiLevel(),
desugaredLibraryKeepRules,
shrinkDesugaredLibrary)
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expectedOutput());
} else {
// Build the desugared library in class file format.
Path desugaredLib =
getDesugaredLibraryInCF(parameters, this::configurationForLibraryCompilation);
// Run on the JVM with desuagred library on classpath.
testForJvm()
.addProgramFiles(jar)
.addRunClasspathFiles(desugaredLib)
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expectedOutput());
}
}
@Test
public void testBufferedReaderD8() throws Exception {
expectThrowsWithHorizontalClassMergingIf(
shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
Assume.assumeTrue(parameters.getRuntime().isDex());
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForD8()
.addOptionsModification(
options ->
options.desugaredLibraryConfiguration =
configurationWithBufferedReader(options, false, parameters))
.addInnerClasses(BufferedReaderTest.class)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
.addDesugaredCoreLibraryRunClassPath(
(apiLevel, keepRules, shrink) ->
buildDesugaredLibrary(
apiLevel,
keepRules,
shrink,
ImmutableList.of(),
this::configurationForLibraryCompilation),
parameters.getApiLevel(),
keepRuleConsumer.get(),
shrinkDesugaredLibrary)
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expectedOutput());
}
@Test
public void testBufferedReaderR8() throws Exception {
expectThrowsWithHorizontalClassMergingIf(
shrinkDesugaredLibrary && parameters.getApiLevel().isLessThan(AndroidApiLevel.N));
Assume.assumeTrue(parameters.getRuntime().isDex());
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForR8(parameters.getBackend())
.addOptionsModification(
options ->
options.desugaredLibraryConfiguration =
configurationWithBufferedReader(options, false, parameters))
.addInnerClasses(BufferedReaderTest.class)
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.enableInliningAnnotations()
.compile()
.addDesugaredCoreLibraryRunClassPath(
(apiLevel, keepRules, shrink) ->
buildDesugaredLibrary(
apiLevel,
keepRules,
shrink,
ImmutableList.of(),
this::configurationForLibraryCompilation),
parameters.getApiLevel(),
keepRuleConsumer.get(),
shrinkDesugaredLibrary)
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expectedOutput());
}
static class TestClass {
@NeverInline
public static void testBufferedReaderLines() throws Exception {
try (BufferedReader reader = new BufferedReader(new StringReader("Hello\nLarry\nPage"))) {
reader.lines().forEach(System.out::println);
}
}
@NeverInline
public static void testBufferedReaderLines_uncheckedIoException() throws Exception {
BufferedReader reader = new BufferedReader(new StringReader(""));
reader.close();
try {
reader.lines().count();
System.out.println("UncheckedIOException expected");
} catch (UncheckedIOException expected) {
System.out.println("Caught " + expected.getClass().getName());
} catch (Throwable t) {
System.out.println("Caught unexpected" + t.getClass().getName());
}
}
public static void main(String[] args) throws Exception {
testBufferedReaderLines();
testBufferedReaderLines_uncheckedIoException();
}
}
}