| // 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.repackage; | |
| import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY; | |
| import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES; | |
| import com.android.tools.r8.TestBase; | |
| import com.android.tools.r8.TestParameters; | |
| import com.android.tools.r8.TestShrinkerBuilder; | |
| import com.android.tools.r8.utils.codeinspector.ClassSubject; | |
| import com.android.tools.r8.utils.codeinspector.CodeInspector; | |
| import com.android.tools.r8.utils.internal.StringUtils; | |
| import com.google.common.collect.ImmutableList; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import org.hamcrest.Description; | |
| import org.hamcrest.Matcher; | |
| import org.hamcrest.TypeSafeMatcher; | |
| import org.junit.runners.Parameterized.Parameters; | |
| public abstract class RepackageTestBase extends TestBase { | |
| private final String flattenPackageHierarchyOrRepackageClasses; | |
| protected final TestParameters parameters; | |
| @Parameters(name = "{1}, kind: {0}") | |
| public static List<Object[]> data() { | |
| return buildParameters( | |
| ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES), | |
| getTestParameters().withAllRuntimesAndApiLevels().build()); | |
| } | |
| public RepackageTestBase( | |
| String flattenPackageHierarchyOrRepackageClasses, | |
| TestParameters parameters) { | |
| this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses; | |
| this.parameters = parameters; | |
| } | |
| protected String getRepackagePackage() { | |
| return "foo"; | |
| } | |
| protected Matcher<Class<?>> isRepackaged(CodeInspector inspector) { | |
| return isRepackagedAsExpected(inspector, null, true); | |
| } | |
| protected Matcher<Class<?>> isRepackagedIf( | |
| CodeInspector inspector, boolean eligibleForRepackaging) { | |
| return isRepackagedAsExpected(inspector, null, eligibleForRepackaging); | |
| } | |
| protected Matcher<Class<?>> isNotRepackaged(CodeInspector inspector) { | |
| return isRepackagedAsExpected(inspector, null, false); | |
| } | |
| /** | |
| * Checks that the class of interest is repackaged as expected. | |
| * | |
| * <p>If building with -repackageclasses, it is checked that the given class of interest is | |
| * repackaged into "foo" (unless getRepackagePackage() is overridden). In this case, {@param | |
| * packageName} is unused. | |
| * | |
| * <p>If building with -flattenpackagehierarchy, it is checked that the given class is repackaged | |
| * into "foo.<packageName>". | |
| */ | |
| protected Matcher<Class<?>> isRepackagedAsExpected(CodeInspector inspector, String packageName) { | |
| return isRepackagedAsExpected(inspector, packageName, true); | |
| } | |
| private Matcher<Class<?>> isRepackagedAsExpected( | |
| CodeInspector inspector, String packageName, boolean eligibleForRepackaging) { | |
| return new TypeSafeMatcher<Class<?>>() { | |
| @Override | |
| public boolean matchesSafely(Class<?> clazz) { | |
| ClassSubject classSubject = inspector.clazz(clazz); | |
| if (!classSubject.isPresent()) { | |
| return false; | |
| } | |
| return getActualPackage(classSubject).equals(getExpectedPackage(clazz)); | |
| } | |
| @Override | |
| public void describeTo(Description description) { | |
| if (eligibleForRepackaging) { | |
| description.appendText( | |
| "class to be repackaged to '" + getExpectedPackageForEligibleClass() + "'"); | |
| } else { | |
| description.appendText("class to be ineligible for repackaging"); | |
| } | |
| } | |
| @Override | |
| public void describeMismatchSafely(Class<?> clazz, Description description) { | |
| ClassSubject classSubject = inspector.clazz(clazz); | |
| if (classSubject.isPresent()) { | |
| description | |
| .appendText("class ") | |
| .appendValue(clazz.getTypeName()) | |
| .appendText(" was not (actual: '" + getActualPackage(classSubject) + "')"); | |
| } else { | |
| description | |
| .appendText("class ") | |
| .appendValue(clazz.getTypeName()) | |
| .appendText(" was absent"); | |
| } | |
| } | |
| private String getActualPackage(ClassSubject classSubject) { | |
| return classSubject.getDexProgramClass().getType().getPackageName(); | |
| } | |
| private String getExpectedPackage(Class<?> clazz) { | |
| return eligibleForRepackaging | |
| ? getExpectedPackageForEligibleClass() | |
| : clazz.getPackage().getName(); | |
| } | |
| private String getExpectedPackageForEligibleClass() { | |
| List<String> expectedPackageNames = new ArrayList<>(); | |
| expectedPackageNames.add(getRepackagePackage()); | |
| if (isFlattenPackageHierarchy()) { | |
| expectedPackageNames.add(packageName != null ? packageName : "a"); | |
| } | |
| return StringUtils.join(".", expectedPackageNames); | |
| } | |
| }; | |
| } | |
| protected void configureRepackaging(TestShrinkerBuilder<?, ?, ?, ?, ?> testBuilder) { | |
| testBuilder.addKeepRules( | |
| "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + getRepackagePackage() + "\""); | |
| } | |
| protected void configureNoRepackaging(TestShrinkerBuilder<?, ?, ?, ?, ?> testBuilder) { | |
| testBuilder.addKeepRules("-dontrepackage"); | |
| } | |
| protected boolean isFlattenPackageHierarchy() { | |
| return flattenPackageHierarchyOrRepackageClasses.equals(FLATTEN_PACKAGE_HIERARCHY); | |
| } | |
| } |