| // Copyright (c) 2016, 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.shaking; |
| |
| import static com.android.tools.r8.shaking.ProguardConfigurationSourceStrings.createConfigurationForTesting; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import com.android.tools.r8.DiagnosticsHandler; |
| import com.android.tools.r8.TestBase; |
| import com.android.tools.r8.ToolHelper; |
| import com.android.tools.r8.graph.DexAccessFlags; |
| import com.android.tools.r8.graph.DexItemFactory; |
| import com.android.tools.r8.utils.DefaultDiagnosticsHandler; |
| import com.android.tools.r8.utils.FileUtils; |
| import com.android.tools.r8.utils.InternalOptions.KeepAttributeOptions; |
| import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode; |
| import com.google.common.collect.ImmutableList; |
| import java.io.IOException; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.util.Collections; |
| import java.util.List; |
| import org.junit.Test; |
| |
| public class ProguardConfigurationParserTest extends TestBase { |
| |
| private static final String VALID_PROGUARD_DIR = "src/test/proguard/valid/"; |
| private static final String INVALID_PROGUARD_DIR = "src/test/proguard/invalid/"; |
| private static final String PROGUARD_SPEC_FILE = VALID_PROGUARD_DIR + "proguard.flags"; |
| private static final String MULTIPLE_NAME_PATTERNS_FILE = |
| VALID_PROGUARD_DIR + "multiple-name-patterns.flags"; |
| private static final String ACCESS_FLAGS_FILE = VALID_PROGUARD_DIR + "access-flags.flags"; |
| private static final String WHY_ARE_YOU_KEEPING_FILE = |
| VALID_PROGUARD_DIR + "why-are-you-keeping.flags"; |
| private static final String ASSUME_NO_SIDE_EFFECTS = |
| VALID_PROGUARD_DIR + "assume-no-side-effects.flags"; |
| private static final String ASSUME_NO_SIDE_EFFECTS_WITH_RETURN_VALUE = |
| VALID_PROGUARD_DIR + "assume-no-side-effects-with-return-value.flags"; |
| private static final String ASSUME_VALUES_WITH_RETURN_VALUE = |
| VALID_PROGUARD_DIR + "assume-values-with-return-value.flags"; |
| private static final String INCLUDING = |
| VALID_PROGUARD_DIR + "including.flags"; |
| private static final String INVALID_INCLUDING_1 = |
| INVALID_PROGUARD_DIR + "including-1.flags"; |
| private static final String INVALID_INCLUDING_2 = |
| INVALID_PROGUARD_DIR + "including-2.flags"; |
| private static final String LIBRARY_JARS = |
| VALID_PROGUARD_DIR + "library-jars.flags"; |
| private static final String LIBRARY_JARS_WIN = |
| VALID_PROGUARD_DIR + "library-jars-win.flags"; |
| private static final String SEEDS = |
| VALID_PROGUARD_DIR + "seeds.flags"; |
| private static final String SEEDS_2 = |
| VALID_PROGUARD_DIR + "seeds-2.flags"; |
| private static final String VERBOSE = |
| VALID_PROGUARD_DIR + "verbose.flags"; |
| private static final String KEEPDIRECTORIES = |
| VALID_PROGUARD_DIR + "keepdirectories.flags"; |
| private static final String DONT_OBFUSCATE = |
| VALID_PROGUARD_DIR + "dontobfuscate.flags"; |
| private static final String PACKAGE_OBFUSCATION_1 = |
| VALID_PROGUARD_DIR + "package-obfuscation-1.flags"; |
| private static final String PACKAGE_OBFUSCATION_2 = |
| VALID_PROGUARD_DIR + "package-obfuscation-2.flags"; |
| private static final String PACKAGE_OBFUSCATION_3 = |
| VALID_PROGUARD_DIR + "package-obfuscation-3.flags"; |
| private static final String PACKAGE_OBFUSCATION_4 = |
| VALID_PROGUARD_DIR + "package-obfuscation-4.flags"; |
| private static final String PACKAGE_OBFUSCATION_5 = |
| VALID_PROGUARD_DIR + "package-obfuscation-5.flags"; |
| private static final String PACKAGE_OBFUSCATION_6 = |
| VALID_PROGUARD_DIR + "package-obfuscation-6.flags"; |
| private static final String APPLY_MAPPING = |
| VALID_PROGUARD_DIR + "applymapping.flags"; |
| private static final String APPLY_MAPPING_WITHOUT_FILE = |
| INVALID_PROGUARD_DIR + "applymapping-without-file.flags"; |
| private static final String DONT_SHRINK = |
| VALID_PROGUARD_DIR + "dontshrink.flags"; |
| private static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES = |
| VALID_PROGUARD_DIR + "dontskipnonpubliclibraryclasses.flags"; |
| private static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS = |
| VALID_PROGUARD_DIR + "dontskipnonpubliclibraryclassmembers.flags"; |
| private static final String OVERLOAD_AGGRESIVELY = |
| VALID_PROGUARD_DIR + "overloadaggressively.flags"; |
| private static final String DONT_OPTIMIZE = |
| VALID_PROGUARD_DIR + "dontoptimize.flags"; |
| private static final String DONT_OPTIMIZE_OVERRIDES_PASSES = |
| VALID_PROGUARD_DIR + "dontoptimize-overrides-optimizationpasses.flags"; |
| private static final String OPTIMIZATION_PASSES = |
| VALID_PROGUARD_DIR + "optimizationpasses.flags"; |
| private static final String OPTIMIZATION_PASSES_WITHOUT_N = |
| INVALID_PROGUARD_DIR + "optimizationpasses-without-n.flags"; |
| private static final String SKIP_NON_PUBLIC_LIBRARY_CLASSES = |
| VALID_PROGUARD_DIR + "skipnonpubliclibraryclasses.flags"; |
| private static final String PARSE_AND_SKIP_SINGLE_ARGUMENT = |
| VALID_PROGUARD_DIR + "parse-and-skip-single-argument.flags"; |
| private static final String PRINT_USAGE = |
| VALID_PROGUARD_DIR + "printusage.flags"; |
| private static final String PRINT_USAGE_TO_FILE = |
| VALID_PROGUARD_DIR + "printusage-to-file.flags"; |
| private static final String TARGET = |
| VALID_PROGUARD_DIR + "target.flags"; |
| |
| private static final DiagnosticsHandler diagnosticsHandler = new DefaultDiagnosticsHandler(); |
| |
| @Test |
| public void parse() throws Exception { |
| ProguardConfigurationParser parser; |
| |
| // Parse from file. |
| parser = new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(PROGUARD_SPEC_FILE)); |
| List<ProguardConfigurationRule> rules = parser.getConfig().getRules(); |
| assertEquals(24, rules.size()); |
| assertEquals(1, rules.get(0).getMemberRules().size()); |
| |
| // Parse from strings. |
| parser = new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| List<String> lines = FileUtils.readTextFile(Paths.get(PROGUARD_SPEC_FILE)); |
| parser.parse(createConfigurationForTesting(lines)); |
| rules = parser.getConfig().getRules(); |
| assertEquals(24, rules.size()); |
| assertEquals(1, rules.get(0).getMemberRules().size()); |
| } |
| |
| @Test |
| public void parseMultipleNamePatterns() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(MULTIPLE_NAME_PATTERNS_FILE)); |
| List<ProguardConfigurationRule> rules = parser.getConfig().getRules(); |
| assertEquals(1, rules.size()); |
| ProguardConfigurationRule rule = rules.get(0); |
| assertEquals(1, rule.getMemberRules().size()); |
| assertEquals("com.company.hello.**,com.company.world.**", rule.getClassNames().toString()); |
| assertEquals(ProguardKeepRuleType.KEEP, ((ProguardKeepRule) rule).getType()); |
| assertTrue(rule.getInheritanceIsExtends()); |
| assertEquals("some.library.Class", rule.getInheritanceClassName().toString()); |
| ProguardMemberRule memberRule = rule.getMemberRules().iterator().next(); |
| assertTrue(memberRule.getAccessFlags().isProtected()); |
| assertEquals(ProguardNameMatcher.create("getContents"), memberRule.getName()); |
| assertEquals("java.lang.Object[][]", memberRule.getType().toString()); |
| assertEquals(ProguardMemberType.METHOD, memberRule.getRuleType()); |
| assertEquals(0, memberRule.getArguments().size()); |
| } |
| |
| @Test |
| public void testDontWarn() throws Exception { |
| DexItemFactory dexItemFactory = new DexItemFactory(); |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(dexItemFactory, diagnosticsHandler); |
| String dontwarn = "-dontwarn !foobar,*bar"; |
| parser.parse(createConfigurationForTesting(ImmutableList.of(dontwarn))); |
| ProguardConfiguration config = parser.getConfig(); |
| assertFalse( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobaz;"))); |
| assertTrue( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobar;"))); |
| assertFalse( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lfoobar;"))); |
| } |
| |
| @Test |
| public void testDontWarnMultiple() throws Exception { |
| DexItemFactory dexItemFactory = new DexItemFactory(); |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(dexItemFactory, diagnosticsHandler); |
| List<String> configuration1 = ImmutableList.of("-dontwarn foo.**, bar.**"); |
| List<String> configuration2 = ImmutableList.of("-dontwarn foo.**", "-dontwarn bar.**"); |
| for (List<String> configuration : ImmutableList.of(configuration1, configuration2)) { |
| parser.parse(createConfigurationForTesting(configuration)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lfoo/Bar;"))); |
| assertTrue( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lfoo/bar7Bar;"))); |
| assertTrue( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lbar/Foo;"))); |
| } |
| } |
| |
| @Test |
| public void testDontWarnAllExplicitly() throws Exception { |
| DexItemFactory dexItemFactory = new DexItemFactory(); |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(dexItemFactory, diagnosticsHandler); |
| String dontwarnAll = "-dontwarn *"; |
| parser.parse(createConfigurationForTesting(ImmutableList.of(dontwarnAll))); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobaz;"))); |
| assertTrue( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobar;"))); |
| assertTrue( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lfoobar;"))); |
| } |
| |
| @Test |
| public void testDontWarnAllImplicitly() throws Exception { |
| DexItemFactory dexItemFactory = new DexItemFactory(); |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(dexItemFactory, diagnosticsHandler); |
| String dontwarnAll = "-dontwarn"; |
| parser.parse(createConfigurationForTesting(ImmutableList.of(dontwarnAll))); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobaz;"))); |
| assertTrue( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobar;"))); |
| assertTrue( |
| config.getDontWarnPatterns().matches(dexItemFactory.createType("Lfoobar;"))); |
| } |
| |
| @Test |
| public void parseAccessFlags() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(ACCESS_FLAGS_FILE)); |
| List<ProguardConfigurationRule> rules = parser.getConfig().getRules(); |
| assertEquals(1, rules.size()); |
| ProguardConfigurationRule rule = rules.get(0); |
| DexAccessFlags publicAndFinalFlags = new DexAccessFlags(0); |
| publicAndFinalFlags.setPublic(); |
| publicAndFinalFlags.setFinal(); |
| assertTrue(rule.getClassAccessFlags().containsNoneOf(publicAndFinalFlags)); |
| assertTrue(rule.getNegatedClassAccessFlags().containsAllOf(publicAndFinalFlags)); |
| DexAccessFlags abstractFlags = new DexAccessFlags(0); |
| abstractFlags.setAbstract(); |
| assertTrue(rule.getClassAccessFlags().containsAllOf(abstractFlags)); |
| assertTrue(rule.getNegatedClassAccessFlags().containsNoneOf(abstractFlags)); |
| for (ProguardMemberRule member : rule.getMemberRules()) { |
| if (member.getRuleType() == ProguardMemberType.ALL_FIELDS) { |
| DexAccessFlags publicFlags = new DexAccessFlags(0); |
| publicAndFinalFlags.setPublic(); |
| assertTrue(member.getAccessFlags().containsAllOf(publicFlags)); |
| assertTrue(member.getNegatedAccessFlags().containsNoneOf(publicFlags)); |
| DexAccessFlags staticFlags = new DexAccessFlags(0); |
| staticFlags.setStatic(); |
| assertTrue(member.getAccessFlags().containsNoneOf(staticFlags)); |
| assertTrue(member.getNegatedAccessFlags().containsAllOf(staticFlags)); |
| } else { |
| assertTrue(member.getRuleType() == ProguardMemberType.ALL_METHODS); |
| DexAccessFlags publicProtectedVolatileFlags = new DexAccessFlags(0); |
| publicProtectedVolatileFlags.setPublic(); |
| publicProtectedVolatileFlags.setProtected(); |
| publicProtectedVolatileFlags.setVolatile(); |
| assertTrue(member.getAccessFlags().containsNoneOf(publicProtectedVolatileFlags)); |
| assertTrue(member.getNegatedAccessFlags().containsAllOf(publicProtectedVolatileFlags)); |
| } |
| } |
| } |
| |
| @Test |
| public void parseWhyAreYouKeeping() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(WHY_ARE_YOU_KEEPING_FILE)); |
| List<ProguardConfigurationRule> rules = parser.getConfig().getRules(); |
| assertEquals(1, rules.size()); |
| ProguardConfigurationRule rule = rules.get(0); |
| assertEquals(1, rule.getClassNames().size()); |
| assertEquals("*", rule.getClassNames().toString()); |
| assertTrue(rule.getInheritanceIsExtends()); |
| assertEquals("foo.bar", rule.getInheritanceClassName().toString()); |
| } |
| |
| @Test |
| public void parseAssumeNoSideEffects() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(ASSUME_NO_SIDE_EFFECTS)); |
| List<ProguardConfigurationRule> assumeNoSideEffects = parser.getConfig().getRules(); |
| assertEquals(1, assumeNoSideEffects.size()); |
| assumeNoSideEffects.get(0).getMemberRules().forEach(rule -> { |
| assertFalse(rule.hasReturnValue()); |
| }); |
| } |
| |
| @Test |
| public void parseAssumeNoSideEffectsWithReturnValue() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(ASSUME_NO_SIDE_EFFECTS_WITH_RETURN_VALUE)); |
| List<ProguardConfigurationRule> assumeNoSideEffects = parser.getConfig().getRules(); |
| assertEquals(1, assumeNoSideEffects.size()); |
| assumeNoSideEffects.get(0).getMemberRules().forEach(rule -> { |
| assertTrue(rule.hasReturnValue()); |
| if (rule.getName().matches("returnsTrue") || rule.getName().matches("returnsFalse")) { |
| assertTrue(rule.getReturnValue().isBoolean()); |
| assertFalse(rule.getReturnValue().isValueRange()); |
| assertFalse(rule.getReturnValue().isField()); |
| assertEquals(rule.getName().matches("returnsTrue"), rule.getReturnValue().getBoolean()); |
| } else if (rule.getName().matches("returns1")) { |
| assertFalse(rule.getReturnValue().isBoolean()); |
| assertTrue(rule.getReturnValue().isValueRange()); |
| assertFalse(rule.getReturnValue().isField()); |
| assertTrue(rule.getReturnValue().isSingleValue()); |
| assertEquals(1, rule.getReturnValue().getValueRange().getMin()); |
| assertEquals(1, rule.getReturnValue().getValueRange().getMax()); |
| assertEquals(1, rule.getReturnValue().getSingleValue()); |
| } else if (rule.getName().matches("returns2To4")) { |
| assertFalse(rule.getReturnValue().isBoolean()); |
| assertTrue(rule.getReturnValue().isValueRange()); |
| assertFalse(rule.getReturnValue().isField()); |
| assertFalse(rule.getReturnValue().isSingleValue()); |
| assertEquals(2, rule.getReturnValue().getValueRange().getMin()); |
| assertEquals(4, rule.getReturnValue().getValueRange().getMax()); |
| } else if (rule.getName().matches("returnsField")) { |
| assertFalse(rule.getReturnValue().isBoolean()); |
| assertFalse(rule.getReturnValue().isValueRange()); |
| assertTrue(rule.getReturnValue().isField()); |
| assertEquals("com.google.C", rule.getReturnValue().getField().clazz.toString()); |
| assertEquals("int", rule.getReturnValue().getField().type.toString()); |
| assertEquals("X", rule.getReturnValue().getField().name.toString()); |
| } |
| }); |
| } |
| |
| @Test |
| public void parseAssumeValuesWithReturnValue() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(ASSUME_VALUES_WITH_RETURN_VALUE)); |
| List<ProguardConfigurationRule> assumeValues = parser.getConfig().getRules(); |
| assertEquals(1, assumeValues.size()); |
| assumeValues.get(0).getMemberRules().forEach(rule -> { |
| assertTrue(rule.hasReturnValue()); |
| if (rule.getName().matches("isTrue") || rule.getName().matches("isFalse")) { |
| assertTrue(rule.getReturnValue().isBoolean()); |
| assertFalse(rule.getReturnValue().isValueRange()); |
| assertFalse(rule.getReturnValue().isField()); |
| assertEquals(rule.getName().matches("isTrue"), rule.getReturnValue().getBoolean()); |
| } else if (rule.getName().matches("is1")) { |
| assertFalse(rule.getReturnValue().isBoolean()); |
| assertTrue(rule.getReturnValue().isValueRange()); |
| assertFalse(rule.getReturnValue().isField()); |
| assertTrue(rule.getReturnValue().isSingleValue()); |
| assertEquals(1, rule.getReturnValue().getValueRange().getMin()); |
| assertEquals(1, rule.getReturnValue().getValueRange().getMax()); |
| assertEquals(1, rule.getReturnValue().getSingleValue()); |
| } else if (rule.getName().matches("is2To4")) { |
| assertFalse(rule.getReturnValue().isBoolean()); |
| assertTrue(rule.getReturnValue().isValueRange()); |
| assertFalse(rule.getReturnValue().isField()); |
| assertFalse(rule.getReturnValue().isSingleValue()); |
| assertEquals(2, rule.getReturnValue().getValueRange().getMin()); |
| assertEquals(4, rule.getReturnValue().getValueRange().getMax()); |
| } else if (rule.getName().matches("isField")) { |
| assertFalse(rule.getReturnValue().isBoolean()); |
| assertFalse(rule.getReturnValue().isValueRange()); |
| assertTrue(rule.getReturnValue().isField()); |
| assertEquals("com.google.C", rule.getReturnValue().getField().clazz.toString()); |
| assertEquals("int", rule.getReturnValue().getField().type.toString()); |
| assertEquals("X", rule.getReturnValue().getField().name.toString()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testAdaptClassStrings() throws Exception { |
| DexItemFactory dexItemFactory = new DexItemFactory(); |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(dexItemFactory, diagnosticsHandler); |
| String adaptClassStrings = "-adaptclassstrings !foobar,*bar"; |
| parser.parse(createConfigurationForTesting(ImmutableList.of(adaptClassStrings))); |
| ProguardConfiguration config = parser.getConfig(); |
| assertFalse( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;"))); |
| assertTrue( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobar;"))); |
| assertFalse( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoobar;"))); |
| } |
| |
| @Test |
| public void testAdaptClassStringsMultiple() throws Exception { |
| DexItemFactory dexItemFactory = new DexItemFactory(); |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(dexItemFactory, diagnosticsHandler); |
| List<String> configuration1 = ImmutableList.of("-adaptclassstrings foo.**, bar.**"); |
| List<String> configuration2 = |
| ImmutableList.of("-adaptclassstrings foo.**", "-adaptclassstrings bar.**"); |
| for (List<String> configuration : ImmutableList.of(configuration1, configuration2)) { |
| parser.parse(createConfigurationForTesting(configuration)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoo/Bar;"))); |
| assertTrue( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoo/bar7Bar;"))); |
| assertTrue( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lbar/Foo;"))); |
| } |
| } |
| |
| @Test |
| public void testAdaptClassStringsAllExplicitly() throws Exception { |
| DexItemFactory dexItemFactory = new DexItemFactory(); |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(dexItemFactory, diagnosticsHandler); |
| String adaptAll = "-adaptclassstrings *"; |
| parser.parse(createConfigurationForTesting(ImmutableList.of(adaptAll))); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;"))); |
| assertTrue( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;"))); |
| assertTrue( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoobar;"))); |
| } |
| |
| @Test |
| public void testAdaptClassStringsAllImplicitly() throws Exception { |
| DexItemFactory dexItemFactory = new DexItemFactory(); |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(dexItemFactory, diagnosticsHandler); |
| String adaptAll = "-adaptclassstrings"; |
| parser.parse(createConfigurationForTesting(ImmutableList.of(adaptAll))); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;"))); |
| assertTrue( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;"))); |
| assertTrue( |
| config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoobar;"))); |
| } |
| |
| @Test |
| public void testIdentifierNameString() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| String config1 = |
| "-identifiernamestring class a.b.c.*GeneratedClass {\n" |
| + " static java.lang.String CONTAINING_TYPE_*;\n" |
| + "}"; |
| String config2 = |
| "-identifiernamestring class x.y.z.ReflectionBasedFactory {\n" |
| + " private static java.lang.reflect.Field field(java.lang.Class,java.lang.String);\n" |
| + "}"; |
| String config3 = |
| "-identifiernamestring class * {\n" |
| + " @my.annotations.IdentifierNameString *;\n" |
| + "}"; |
| parser.parse(createConfigurationForTesting(ImmutableList.of(config1, config2, config3))); |
| ProguardConfiguration config = parser.getConfig(); |
| List<ProguardConfigurationRule> identifierNameStrings = config.getRules(); |
| assertEquals(3, identifierNameStrings.size()); |
| assertEquals(1, identifierNameStrings.get(0).getClassNames().size()); |
| assertEquals( |
| "a.b.c.*GeneratedClass", |
| identifierNameStrings.get(0).getClassNames().toString()); |
| identifierNameStrings.get(0).getMemberRules().forEach(memberRule -> { |
| assertTrue(memberRule.getRuleType().includesFields()); |
| assertTrue(memberRule.getName().matches("CONTAINING_TYPE_ABC")); |
| }); |
| assertEquals(1, identifierNameStrings.get(1).getClassNames().size()); |
| assertEquals( |
| "x.y.z.ReflectionBasedFactory", |
| identifierNameStrings.get(1).getClassNames().toString()); |
| identifierNameStrings.get(1).getMemberRules().forEach(memberRule -> { |
| assertTrue(memberRule.getRuleType().includesMethods()); |
| assertTrue(memberRule.getName().matches("field")); |
| }); |
| assertEquals(1, identifierNameStrings.get(2).getClassNames().size()); |
| assertEquals("*", identifierNameStrings.get(2).getClassNames().toString()); |
| identifierNameStrings.get(2).getMemberRules().forEach(memberRule -> { |
| assertEquals(ProguardMemberType.ALL, memberRule.getRuleType()); |
| assertTrue(memberRule.getAnnotation().toString().endsWith("IdentifierNameString")); |
| }); |
| } |
| |
| @Test |
| public void parseDontobfuscate() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(DONT_OBFUSCATE)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertFalse(config.isObfuscating()); |
| } |
| |
| @Test |
| public void parseRepackageClassesEmpty() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(PACKAGE_OBFUSCATION_1)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode()); |
| assertNotNull(config.getPackagePrefix()); |
| assertEquals("", config.getPackagePrefix()); |
| } |
| |
| @Test |
| public void parseRepackageClassesNonEmpty() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(PACKAGE_OBFUSCATION_2)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode()); |
| assertNotNull(config.getPackagePrefix()); |
| assertEquals("p.q.r", config.getPackagePrefix()); |
| } |
| |
| @Test |
| public void parseFlattenPackageHierarchyEmpty() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(PACKAGE_OBFUSCATION_3)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertEquals(PackageObfuscationMode.FLATTEN, config.getPackageObfuscationMode()); |
| assertNotNull(config.getPackagePrefix()); |
| assertEquals("", config.getPackagePrefix()); |
| } |
| |
| @Test |
| public void parseFlattenPackageHierarchyNonEmpty() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(PACKAGE_OBFUSCATION_4)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertEquals(PackageObfuscationMode.FLATTEN, config.getPackageObfuscationMode()); |
| assertNotNull(config.getPackagePrefix()); |
| assertEquals("p.q.r", config.getPackagePrefix()); |
| } |
| |
| @Test |
| public void flattenPackageHierarchyCannotOverrideRepackageClasses() |
| throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(PACKAGE_OBFUSCATION_5)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode()); |
| assertNotNull(config.getPackagePrefix()); |
| assertEquals("top", config.getPackagePrefix()); |
| } |
| |
| @Test |
| public void repackageClassesOverridesFlattenPackageHierarchy() |
| throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(PACKAGE_OBFUSCATION_6)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertEquals(PackageObfuscationMode.REPACKAGE, config.getPackageObfuscationMode()); |
| assertNotNull(config.getPackagePrefix()); |
| assertEquals("top", config.getPackagePrefix()); |
| } |
| |
| @Test |
| public void parseApplyMapping() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(APPLY_MAPPING)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue(config.hasApplyMappingFile()); |
| } |
| |
| @Test |
| public void parseApplyMappingWithoutFile() throws Exception { |
| try { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(APPLY_MAPPING_WITHOUT_FILE)); |
| fail("Expect to fail due to the lack of file name."); |
| } catch (ProguardRuleParserException e) { |
| assertTrue(e.getMessage().contains("File name expected")); |
| } |
| } |
| |
| @Test |
| public void parseIncluding() throws Exception { |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler) |
| .parse(Paths.get(INCLUDING)); |
| } |
| |
| @Test |
| public void parseInvalidIncluding1() throws IOException { |
| try { |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler) |
| .parse(Paths.get(INVALID_INCLUDING_1)); |
| fail(); |
| } catch (ProguardRuleParserException e) { |
| assertTrue(e.getMessage().contains("6")); // line |
| assertTrue(e.getMessage().contains("including-1.flags")); // file in error |
| assertTrue(e.getMessage().contains("does-not-exist.flags")); // missing file |
| } |
| } |
| |
| @Test |
| public void parseInvalidIncluding2() throws IOException { |
| try { |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler) |
| .parse(Paths.get(INVALID_INCLUDING_2)); |
| fail(); |
| } catch (ProguardRuleParserException e) { |
| String message = e.getMessage(); |
| assertTrue(message, message.contains("6")); // line |
| assertTrue(message, message.contains("including-2.flags")); // file in error |
| assertTrue(message, message.contains("does-not-exist.flags")); // missing file |
| } |
| } |
| |
| @Test |
| public void parseLibraryJars() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| if (!ToolHelper.isLinux() && !ToolHelper.isMac()) { |
| parser.parse(Paths.get(LIBRARY_JARS_WIN)); |
| } else { |
| parser.parse(Paths.get(LIBRARY_JARS)); |
| } |
| assertEquals(4, parser.getConfig().getLibraryjars().size()); |
| } |
| |
| @Test |
| public void parseInvalidFilePattern() throws IOException { |
| try { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(createConfigurationForTesting( |
| Collections.singletonList("-injars abc.jar(*.zip;*.class)"))); |
| } catch (ProguardRuleParserException e) { |
| return; |
| } |
| fail(); |
| } |
| |
| @Test |
| public void parseSeeds() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(SEEDS)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue(config.isPrintSeeds()); |
| assertNull(config.getSeedFile()); |
| } |
| |
| @Test |
| public void parseSeeds2() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(SEEDS_2)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue(config.isPrintSeeds()); |
| assertNotNull(config.getSeedFile()); |
| } |
| |
| @Test |
| public void parseVerbose() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(VERBOSE)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue(config.isVerbose()); |
| } |
| |
| @Test |
| public void parseKeepdirectories() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(KEEPDIRECTORIES)); |
| } |
| |
| @Test |
| public void parseDontshrink() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(DONT_SHRINK)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertFalse(config.isShrinking()); |
| } |
| |
| @Test |
| public void parseDontSkipNonPublicLibraryClasses() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES)); |
| } |
| |
| @Test |
| public void parseDontskipnonpubliclibraryclassmembers() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS)); |
| } |
| |
| @Test |
| public void parseOverloadAggressively() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(OVERLOAD_AGGRESIVELY)); |
| } |
| |
| @Test |
| public void parseDontOptimize() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(DONT_OPTIMIZE)); |
| ProguardConfiguration config = parser.getConfig(); |
| } |
| |
| @Test |
| public void parseDontOptimizeOverridesPasses() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(DONT_OPTIMIZE_OVERRIDES_PASSES)); |
| ProguardConfiguration config = parser.getConfig(); |
| } |
| |
| @Test |
| public void parseOptimizationPasses() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(OPTIMIZATION_PASSES)); |
| ProguardConfiguration config = parser.getConfig(); |
| } |
| |
| @Test |
| public void parseOptimizationPassesError() throws Exception { |
| try { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(OPTIMIZATION_PASSES_WITHOUT_N)); |
| fail(); |
| } catch (ProguardRuleParserException e) { |
| assertTrue(e.getMessage().contains("Missing n")); |
| } |
| } |
| |
| @Test |
| public void parseSkipNonPublicLibraryClasses() throws IOException { |
| try { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(SKIP_NON_PUBLIC_LIBRARY_CLASSES)); |
| fail(); |
| } catch (ProguardRuleParserException e) { |
| assertTrue(e.getMessage().contains("Unsupported option: -skipnonpubliclibraryclasses")); |
| } |
| } |
| |
| @Test |
| public void parseAndskipSingleArgument() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(PARSE_AND_SKIP_SINGLE_ARGUMENT)); |
| } |
| |
| @Test |
| public void parsePrintUsage() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(PRINT_USAGE)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue(config.isPrintUsage()); |
| assertNull(config.getPrintUsageFile()); |
| } |
| |
| @Test |
| public void parsePrintUsageToFile() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(PRINT_USAGE_TO_FILE)); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue(config.isPrintUsage()); |
| assertNotNull(config.getPrintUsageFile()); |
| } |
| |
| @Test |
| public void parseTarget() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(Paths.get(TARGET)); |
| } |
| |
| @Test |
| public void parseInvalidKeepClassOption() throws Exception { |
| try { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| Path proguardConfig = writeTextToTempFile( |
| "-keepclassx public class * { ", |
| " native <methods>; ", |
| "} " |
| ); |
| parser.parse(proguardConfig); |
| fail(); |
| } catch (ProguardRuleParserException e) { |
| assertTrue(e.getMessage().contains("Unknown option at ")); |
| } |
| } |
| |
| @Test |
| public void parseCustomFlags() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| // Custom Proguard flags -runtype and -laststageoutput are ignored. |
| Path proguardConfig = writeTextToTempFile( |
| "-runtype FINAL ", |
| "-laststageoutput /some/file/name " |
| ); |
| parser.parse(proguardConfig); |
| } |
| |
| @Test |
| public void testRenameSourceFileAttribute() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| String config1 = "-renamesourcefileattribute PG\n"; |
| String config2 = "-keepattributes SourceFile,SourceDir\n"; |
| parser.parse(createConfigurationForTesting(ImmutableList.of(config1, config2))); |
| ProguardConfiguration config = parser.getConfig(); |
| assertEquals("PG", config.getRenameSourceFileAttribute()); |
| assertTrue(config.getKeepAttributesPatterns().contains(KeepAttributeOptions.SOURCE_FILE)); |
| assertTrue(config.getKeepAttributesPatterns().contains(KeepAttributeOptions.SOURCE_DIR)); |
| } |
| |
| @Test |
| public void testRenameSourceFileAttributeEmpty() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| String config1 = "-renamesourcefileattribute\n"; |
| String config2 = "-keepattributes SourceFile\n"; |
| parser.parse(createConfigurationForTesting(ImmutableList.of(config1, config2))); |
| ProguardConfiguration config = parser.getConfig(); |
| assertEquals("", config.getRenameSourceFileAttribute()); |
| assertTrue(config.getKeepAttributesPatterns().contains(KeepAttributeOptions.SOURCE_FILE)); |
| } |
| |
| private void testKeepattributes(List<String> expected, String config) throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(createConfigurationForTesting(ImmutableList.of(config))); |
| assertEquals(expected, parser.getConfig().getKeepAttributesPatterns()); |
| } |
| |
| @Test |
| public void parseKeepattributes() throws Exception { |
| List<String> xxxYYY = ImmutableList.of("xxx", "yyy"); |
| testKeepattributes(xxxYYY, "-keepattributes xxx,yyy"); |
| testKeepattributes(xxxYYY, "-keepattributes xxx, yyy"); |
| testKeepattributes(xxxYYY, "-keepattributes xxx ,yyy"); |
| testKeepattributes(xxxYYY, "-keepattributes xxx , yyy"); |
| testKeepattributes(xxxYYY, "-keepattributes xxx , yyy "); |
| testKeepattributes(xxxYYY, "-keepattributes xxx , yyy \n"); |
| String config = "-keepattributes Exceptions,InnerClasses,Signature,Deprecated,\n" + |
| " SourceFile,LineNumberTable,*Annotation*,EnclosingMethod\n"; |
| List<String> expected = ImmutableList.of("Exceptions", "InnerClasses", "Signature", "Deprecated", |
| "SourceFile", "LineNumberTable", "*Annotation*", "EnclosingMethod"); |
| testKeepattributes(expected, config); |
| } |
| |
| @Test |
| public void parseInvalidKeepattributes() throws Exception { |
| try { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(createConfigurationForTesting(ImmutableList.of("-keepattributes xxx,"))); |
| fail(); |
| } catch (ProguardRuleParserException e) { |
| assertTrue(e.getMessage().contains("Expected list element at ")); |
| } |
| } |
| |
| @Test |
| public void parseUseUniqueClassMemberNames() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(createConfigurationForTesting(ImmutableList.of( |
| "-useuniqueclassmembernames" |
| ))); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue(config.isUseUniqueClassMemberNames()); |
| } |
| |
| @Test |
| public void parseKeepParameterNames() throws Exception { |
| try { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(createConfigurationForTesting(ImmutableList.of( |
| "-keepparameternames" |
| ))); |
| parser.getConfig(); |
| fail(); |
| } catch (ProguardRuleParserException e) { |
| System.out.println(e); |
| assertTrue(e.getMessage().contains("-keepparameternames is not supported")); |
| } |
| } |
| |
| @Test |
| public void parseKeepParameterNamesWithoutMinification() throws Exception { |
| ProguardConfigurationParser parser = |
| new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(createConfigurationForTesting(ImmutableList.of( |
| "-keepparameternames", |
| "-dontobfuscate" |
| ))); |
| ProguardConfiguration config = parser.getConfig(); |
| assertTrue(config.isKeepParameterNames()); |
| |
| parser = new ProguardConfigurationParser(new DexItemFactory(), diagnosticsHandler); |
| parser.parse(createConfigurationForTesting(ImmutableList.of( |
| "-keepparameternames" |
| ))); |
| parser.parse(createConfigurationForTesting(ImmutableList.of( |
| "-dontobfuscate" |
| ))); |
| config = parser.getConfig(); |
| assertTrue(config.isKeepParameterNames()); |
| } |
| } |