|  | // 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.naming; | 
|  |  | 
|  | import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage; | 
|  | import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; | 
|  | import static org.hamcrest.CoreMatchers.containsString; | 
|  | import static org.hamcrest.MatcherAssert.assertThat; | 
|  | import static org.junit.Assert.assertEquals; | 
|  | import static org.junit.Assert.assertThrows; | 
|  | import static org.junit.Assume.assumeTrue; | 
|  |  | 
|  | import com.android.tools.r8.CompilationFailedException; | 
|  | import com.android.tools.r8.R8TestCompileResult; | 
|  | import com.android.tools.r8.TestBase; | 
|  | import com.android.tools.r8.TestParameters; | 
|  | import com.android.tools.r8.TestParametersCollection; | 
|  | import com.android.tools.r8.naming.testclasses.A; | 
|  | import com.android.tools.r8.naming.testclasses.B; | 
|  | import com.android.tools.r8.utils.FileUtils; | 
|  | import java.io.IOException; | 
|  | import java.nio.file.Path; | 
|  | import java.util.concurrent.ExecutionException; | 
|  | import java.util.function.Function; | 
|  | import org.junit.Test; | 
|  | import org.junit.runner.RunWith; | 
|  | import org.junit.runners.Parameterized; | 
|  | import org.junit.runners.Parameterized.Parameters; | 
|  |  | 
|  | /** This test is designed to test the workaround for b/149946708. */ | 
|  | @RunWith(Parameterized.class) | 
|  | public class ClassNameMinifierOriginalClassNameTest extends TestBase { | 
|  |  | 
|  | private final TestParameters parameters; | 
|  |  | 
|  | @Parameters(name = "{0}") | 
|  | public static TestParametersCollection data() { | 
|  | return getTestParameters().withAllRuntimesAndApiLevels().build(); | 
|  | } | 
|  |  | 
|  | public ClassNameMinifierOriginalClassNameTest(TestParameters parameters) { | 
|  | this.parameters = parameters; | 
|  | } | 
|  |  | 
|  | private static Function<TestParameters, R8TestCompileResult> compilationResults = | 
|  | memoizeFunction(ClassNameMinifierOriginalClassNameTest::compile); | 
|  |  | 
|  | private static R8TestCompileResult compile(TestParameters parameters) | 
|  | throws CompilationFailedException, IOException, ExecutionException { | 
|  | // Adding the obfuscation dictionary just ensures that we assign a name to B that will collide | 
|  | // independent of minification scheme. | 
|  | Path dictionary = getStaticTemp().newFolder().toPath().resolve("dictionary.txt"); | 
|  | FileUtils.writeTextFile(dictionary, "A"); | 
|  | return testForR8(getStaticTemp(), parameters.getBackend()) | 
|  | .addProgramClasses(A.class, B.class) | 
|  | .addKeepClassAndMembersRulesWithAllowObfuscation(B.class) | 
|  | .addKeepRules("-classobfuscationdictionary " + dictionary.toString(), "-keeppackagenames") | 
|  | .setMinApi(parameters.getApiLevel()) | 
|  | .compile() | 
|  | .inspect( | 
|  | inspector -> { | 
|  | assertEquals(1, inspector.allClasses().size()); | 
|  | assertThat(inspector.clazz(B.class), isPresentAndRenamed()); | 
|  | assertEquals(A.class.getTypeName(), inspector.clazz(B.class).getFinalName()); | 
|  | }); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testR8() throws ExecutionException, CompilationFailedException, IOException { | 
|  | R8TestCompileResult libraryCompileResult = compilationResults.apply(parameters); | 
|  | testForR8(parameters.getBackend()) | 
|  | .addProgramClasses(Main.class) | 
|  | .setMinApi(parameters.getApiLevel()) | 
|  | .addKeepMainRule(Main.class) | 
|  | .noMinification() | 
|  | .addClasspathClasses(A.class, B.class) | 
|  | .addApplyMapping(libraryCompileResult.getProguardMap()) | 
|  | .compile() | 
|  | .addRunClasspathFiles(libraryCompileResult.writeToZip()) | 
|  | .run(parameters.getRuntime(), Main.class) | 
|  | .assertSuccessWithOutputLines("B.foo"); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testR8WithReferenceToNotMapped() { | 
|  | assumeTrue(parameters.isDexRuntime()); | 
|  | R8TestCompileResult libraryCompileResult = compilationResults.apply(parameters); | 
|  | assertThrows( | 
|  | CompilationFailedException.class, | 
|  | () -> | 
|  | testForR8(parameters.getBackend()) | 
|  | .addProgramClasses(MainWithReferenceToNotMapped.class) | 
|  | .setMinApi(parameters.getApiLevel()) | 
|  | .addKeepMainRule(MainWithReferenceToNotMapped.class) | 
|  | .noMinification() | 
|  | .addClasspathClasses(A.class, B.class) | 
|  | .addApplyMapping(libraryCompileResult.getProguardMap()) | 
|  | .allowDiagnosticWarningMessages() | 
|  | .compileWithExpectedDiagnostics( | 
|  | diagnostics -> | 
|  | diagnostics.assertAllWarningsMatch( | 
|  | diagnosticMessage( | 
|  | containsString( | 
|  | "'" | 
|  | + B.class.getTypeName() | 
|  | + "' cannot be mapped to '" | 
|  | + A.class.getTypeName() | 
|  | + "' because it is in conflict"))))); | 
|  | } | 
|  |  | 
|  | public static class Main { | 
|  |  | 
|  | public static void main(String[] args) { | 
|  | new B().foo(); | 
|  | } | 
|  | } | 
|  |  | 
|  | public static class MainWithReferenceToNotMapped { | 
|  |  | 
|  | public static void main(String[] args) { | 
|  | System.out.println(new A()); | 
|  | new B().foo(); | 
|  | } | 
|  | } | 
|  | } |