blob: afaf999a68eee1cd24f87a5d58bfcae8e605b88d [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.proguard.configuration;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestRunResult;
import com.android.tools.r8.TestShrinkerBuilder;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.google.common.collect.ImmutableList;
import java.util.List;
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 RepackagingCompatibilityTest extends TestBase {
private enum Quote {
SINGLE,
DOUBLE,
NONE
}
private static final String expectedOutput = StringUtils.lines("Hello world!");
private static final Class<?> mainClass = RepackagingCompatabilityTestClass.class;
private final String directive;
private final Quote quote;
private final boolean repackageToRoot;
@Parameters(name = "Directive: {0}, quote: {1}, repackage to root: {2}")
public static List<Object[]> data() {
return buildParameters(
ImmutableList.of("-flattenpackagehierarchy", "-repackageclasses"),
Quote.values(),
BooleanUtils.values());
}
public RepackagingCompatibilityTest(String directive, Quote quote, boolean repackageToRoot) {
this.directive = directive;
this.quote = quote;
this.repackageToRoot = repackageToRoot;
}
@Test
public void testR8() throws Exception {
runTest(testForR8(Backend.DEX), "R8");
}
@Test
public void testProguard() throws Exception {
runTest(testForProguard(), "Proguard");
}
private void runTest(TestShrinkerBuilder<?, ?, ?, ?, ?> builder, String shrinker)
throws Exception {
assumeFalse(
String.format(
"Only repackage to root when there are no quotes"
+ " (repackageToRoot: %s, quote: %s, shrinker: %s)",
repackageToRoot, quote, shrinker),
repackageToRoot && quote != Quote.NONE);
TestRunResult<?> result =
builder
.addProgramClasses(mainClass)
.addKeepRules(getKeepRules())
.run(mainClass)
.assertSuccessWithOutput(expectedOutput);
ClassSubject testClassSubject = result.inspector().clazz(mainClass);
assertThat(testClassSubject, isPresent());
if (repackageToRoot) {
if (directive.equals("-flattenpackagehierarchy")) {
assertThat(testClassSubject.getFinalName(), startsWith("a."));
} else if (directive.equals("-repackageclasses")) {
assertThat(testClassSubject.getFinalName(), not(containsString(".")));
} else {
fail();
}
} else {
assertThat(testClassSubject.getFinalName(), startsWith("greeter."));
}
}
private List<String> getKeepRules() {
return ImmutableList.of(
// Keep main(), but allow obfuscation
"-keep,allowobfuscation class " + mainClass.getTypeName() + " {",
" public static void main(...);",
"}",
// Ensure main() is not renamed
"-keepclassmembernames class " + mainClass.getTypeName() + " {",
" public static void main(...);",
"}",
getRepackagingRule());
}
private String getRepackagingRule() {
if (repackageToRoot) {
return directive;
}
switch (quote) {
case SINGLE:
return directive + " 'greeter'";
case DOUBLE:
return directive + " \"greeter\"";
case NONE:
return directive + " greeter";
default:
throw new Unreachable();
}
}
}
class RepackagingCompatabilityTestClass {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}