|  | // 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 configurationAlternative3( | 
|  | 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.getDesugarLibJsonForTestingAlternative3())); | 
|  | } | 
|  |  | 
|  | private void configurationForProgramCompilation(InternalOptions options) { | 
|  | options.desugaredLibraryConfiguration = configurationAlternative3(options, false, parameters); | 
|  | } | 
|  |  | 
|  | private void configurationForLibraryCompilation(InternalOptions options) { | 
|  | options.desugaredLibraryConfiguration = configurationAlternative3(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 { | 
|  | Assume.assumeTrue(parameters.getRuntime().isDex()); | 
|  | KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters); | 
|  | testForD8() | 
|  | .addOptionsModification( | 
|  | options -> | 
|  | options.desugaredLibraryConfiguration = | 
|  | configurationAlternative3(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 { | 
|  | Assume.assumeTrue(parameters.getRuntime().isDex()); | 
|  | KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters); | 
|  | testForR8(parameters.getBackend()) | 
|  | .addOptionsModification( | 
|  | options -> | 
|  | options.desugaredLibraryConfiguration = | 
|  | configurationAlternative3(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(); | 
|  | } | 
|  | } | 
|  | } |