diff options
author | ajmichael <ajmichael@google.com> | 2017-10-05 23:06:41 +0200 |
---|---|---|
committer | Klaus Aehlig <aehlig@google.com> | 2017-10-06 19:48:18 +0200 |
commit | 7569bd0cab3a7eec863f48caee69d47f6260211a (patch) | |
tree | bd9d8a6a802e05e7be84f6fd23154f30822f1fde /src/test/java/com/google/devtools/build | |
parent | 104eb04bc709859a31079e77b397d3efa786968f (diff) |
Open-source unit tests for proguard actions.
RELNOTES: None
PiperOrigin-RevId: 171205009
Diffstat (limited to 'src/test/java/com/google/devtools/build')
3 files changed, 602 insertions, 4 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java index b97b27aadd..c50042c52c 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java @@ -17,11 +17,13 @@ import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.getFirstArtifactEndingWith; +import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.prettyArtifactNames; import static com.google.devtools.build.lib.testutil.MoreAsserts.expectThrows; import com.google.common.base.Joiner; import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -2760,8 +2762,7 @@ public class AndroidBinaryTest extends AndroidBuildViewTestCase { ")"); ConfiguredTarget binary = getConfiguredTarget("//java/com/foo"); List<String> inputs = - actionsTestUtil() - .prettyArtifactNames(actionsTestUtil().artifactClosureOf(getFinalUnsignedApk(binary))); + prettyArtifactNames(actionsTestUtil().artifactClosureOf(getFinalUnsignedApk(binary))); assertThat(inputs).containsAllOf("java/com/foo/Flag1On.java", "java/com/foo/Flag2Off.java"); assertThat(inputs).containsNoneOf("java/com/foo/Flag1Off.java", "java/com/foo/Flag2On.java"); @@ -2806,8 +2807,7 @@ public class AndroidBinaryTest extends AndroidBuildViewTestCase { ")"); ConfiguredTarget binary = getConfiguredTarget("//java/com/foo"); List<String> inputs = - actionsTestUtil() - .prettyArtifactNames(actionsTestUtil().artifactClosureOf(getFinalUnsignedApk(binary))); + prettyArtifactNames(actionsTestUtil().artifactClosureOf(getFinalUnsignedApk(binary))); assertThat(inputs).containsAllOf("java/com/foo/Flag1On.java", "java/com/foo/Flag2Off.java"); assertThat(inputs).containsNoneOf("java/com/foo/Flag1Off.java", "java/com/foo/Flag2On.java"); @@ -3344,4 +3344,417 @@ public class AndroidBinaryTest extends AndroidBuildViewTestCase { " manifest = 'AndroidManifest.xml')"); checkDebugKey(debugKeyTarget, false); } + + @Test + public void testOnlyProguardSpecs() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_library(name = 'l2',", + " srcs = ['MoreMaps.java'],", + " neverlink = 1)", + "android_library(name = 'l3',", + " idl_srcs = ['A.aidl'],", + " deps = [':l2'])", + "android_library(name = 'l4',", + " srcs = ['SubMoreMaps.java'],", + " neverlink = 1)", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " deps = [':l3', ':l4'],", + " manifest = 'AndroidManifest.xml',", + " proguard_specs = ['proguard-spec.pro', 'proguard-spec1.pro',", + " 'proguard-spec2.pro'])"); + checkProguardUse( + "//java/com/google/android/hello:b", "b_proguard.jar", false, null, + targetConfig.getBinFragment() + + "/java/com/google/android/hello/proguard/b/legacy_b_combined_library_jars.jar"); + } + + @Test + public void testOnlyProguardSpecsProguardJar() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_library(name = 'l2',", + " srcs = ['MoreMaps.java'],", + " neverlink = 1)", + "android_library(name = 'l3',", + " idl_srcs = ['A.aidl'],", + " deps = [':l2'])", + "android_library(name = 'l4',", + " srcs = ['SubMoreMaps.java'],", + " neverlink = 1)", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " deps = [':l3', ':l4'],", + " manifest = 'AndroidManifest.xml',", + " proguard_generate_mapping = 1,", + " proguard_specs = ['proguard-spec.pro', 'proguard-spec1.pro',", + " 'proguard-spec2.pro'])"); + + ConfiguredTarget output = getConfiguredTarget("//java/com/google/android/hello:b_proguard.jar"); + assertProguardUsed(output); + + output = getConfiguredTarget("//java/com/google/android/hello:b_proguard.map"); + assertWithMessage("proguard.map is not in the rule output") + .that( + actionsTestUtil() + .getActionForArtifactEndingWith(getFilesToBuild(output), "_proguard.map")) + .isNotNull(); + } + + @Test + public void testCommandLineForMultipleProguardSpecs() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_library(name = 'l1',", + " srcs = ['Maps.java'],", + " neverlink = 1)", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " deps = [':l1'],", + " manifest = 'AndroidManifest.xml',", + " proguard_specs = ['proguard-spec.pro', 'proguard-spec1.pro',", + " 'proguard-spec2.pro'])"); + ConfiguredTarget binary = getConfiguredTarget("//java/com/google/android/hello:b"); + SpawnAction action = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith( + getFilesToBuild(binary), "_proguard.jar"); + + assertWithMessage("Proguard action does not contain expected inputs.") + .that(ActionsTestUtil.prettyArtifactNames(action.getInputs())) + .containsAllOf( + "java/com/google/android/hello/proguard-spec.pro", + "java/com/google/android/hello/proguard-spec1.pro", + "java/com/google/android/hello/proguard-spec2.pro"); + + assertThat(action.getArguments()) + .containsExactly( + getProguardBinary().getExecPathString(), + "-forceprocessing", + "-injars", + execPathEndingWith(action.getInputs(), "b_deploy.jar"), + "-outjars", + execPathEndingWith(action.getOutputs(), "b_proguard.jar"), + // Only one combined library jar + "-libraryjars", + execPathEndingWith(action.getInputs(), "legacy_b_combined_library_jars.jar"), + "@" + execPathEndingWith(action.getInputs(), "b_proguard.cfg"), + "@java/com/google/android/hello/proguard-spec.pro", + "@java/com/google/android/hello/proguard-spec1.pro", + "@java/com/google/android/hello/proguard-spec2.pro", + "-printseeds", + execPathEndingWith(action.getOutputs(), "_proguard.seeds"), + "-printusage", + execPathEndingWith(action.getOutputs(), "_proguard.usage"), + "-printconfiguration", + execPathEndingWith(action.getOutputs(), "_proguard.config")) + .inOrder(); + } + + /** Regression test for b/17790639 */ + @Test + public void testNoDuplicatesInProguardCommand() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_library(name = 'l1',", + " srcs = ['Maps.java'],", + " neverlink = 1)", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " deps = [':l1'],", + " manifest = 'AndroidManifest.xml',", + " proguard_specs = ['proguard-spec.pro', 'proguard-spec1.pro',", + " 'proguard-spec2.pro'])"); + ConfiguredTarget binary = getConfiguredTarget("//java/com/google/android/hello:b"); + SpawnAction action = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith( + getFilesToBuild(binary), "_proguard.jar"); + assertThat(action.getArguments()) + .containsExactly( + getProguardBinary().getExecPathString(), + "-forceprocessing", + "-injars", + execPathEndingWith(action.getInputs(), "b_deploy.jar"), + "-outjars", + execPathEndingWith(action.getOutputs(), "b_proguard.jar"), + // Only one combined library jar + "-libraryjars", + execPathEndingWith(action.getInputs(), "legacy_b_combined_library_jars.jar"), + "@" + execPathEndingWith(action.getInputs(), "b_proguard.cfg"), + "@java/com/google/android/hello/proguard-spec.pro", + "@java/com/google/android/hello/proguard-spec1.pro", + "@java/com/google/android/hello/proguard-spec2.pro", + "-printseeds", + execPathEndingWith(action.getOutputs(), "_proguard.seeds"), + "-printusage", + execPathEndingWith(action.getOutputs(), "_proguard.usage"), + "-printconfiguration", + execPathEndingWith(action.getOutputs(), "_proguard.config")) + .inOrder(); + } + + @Test + public void testProguardMapping() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " manifest = 'AndroidManifest.xml',", + " proguard_specs = ['proguard-spec.pro'],", + " proguard_generate_mapping = 1)"); + checkProguardUse( + "//java/com/google/android/hello:b", "b_proguard.jar", true, null, getAndroidJarPath()); + } + + @Test + public void testProguardMappingProvider() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_library(name = 'l2',", + " srcs = ['MoreMaps.java'],", + " neverlink = 1)", + "android_library(name = 'l3',", + " idl_srcs = ['A.aidl'],", + " deps = [':l2'])", + "android_library(name = 'l4',", + " srcs = ['SubMoreMaps.java'],", + " neverlink = 1)", + "android_binary(name = 'b1',", + " srcs = ['HelloApp.java'],", + " deps = [':l3', ':l4'],", + " manifest = 'AndroidManifest.xml',", + " proguard_generate_mapping = 1,", + " proguard_specs = ['proguard-spec.pro', 'proguard-spec1.pro',", + " 'proguard-spec2.pro'])", + "android_binary(name = 'b2',", + " srcs = ['HelloApp.java'],", + " deps = [':l3', ':l4'],", + " manifest = 'AndroidManifest.xml',", + " proguard_specs = ['proguard-spec.pro', 'proguard-spec1.pro',", + " 'proguard-spec2.pro'])"); + + ConfiguredTarget output = getConfiguredTarget("//java/com/google/android/hello:b1"); + assertProguardUsed(output); + Artifact mappingArtifact = getBinArtifact("b1_proguard.map", output); + ProguardMappingProvider mappingProvider = output.getProvider(ProguardMappingProvider.class); + assertThat(mappingProvider.getProguardMapping()).isEqualTo(mappingArtifact); + + output = getConfiguredTarget("//java/com/google/android/hello:b2"); + assertProguardUsed(output); + assertThat(output.getProvider(ProguardMappingProvider.class)).isNull(); + } + + @Test + public void testLegacyOptimizationModeUsesExtraProguardSpecs() throws Exception { + useConfiguration("--extra_proguard_specs=java/com/google/android/hello:extra.pro"); + scratch.file("java/com/google/android/hello/BUILD", + "exports_files(['extra.pro'])", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " manifest = 'AndroidManifest.xml',", + " proguard_specs = ['proguard-spec.pro'])"); + checkProguardUse( + "//java/com/google/android/hello:b", "b_proguard.jar", false, null, getAndroidJarPath()); + + SpawnAction action = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith( + getFilesToBuild(getConfiguredTarget("//java/com/google/android/hello:b")), "_proguard.jar"); + assertThat(ActionsTestUtil.prettyArtifactNames(action.getInputs())).containsNoDuplicates(); + assertThat(Collections2.filter(action.getArguments(), arg -> arg.startsWith("@"))) + .containsExactly( + "@" + execPathEndingWith(action.getInputs(), "/proguard-spec.pro"), + "@" + execPathEndingWith(action.getInputs(), "/_b_proguard.cfg"), + "@java/com/google/android/hello/extra.pro"); + } + + @Test + public void testExtraProguardSpecsDontDuplicateProguardInputFiles() throws Exception { + useConfiguration("--extra_proguard_specs=java/com/google/android/hello:proguard-spec.pro"); + scratch.file("java/com/google/android/hello/BUILD", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " manifest = 'AndroidManifest.xml',", + " proguard_specs = ['proguard-spec.pro'])"); + checkProguardUse( + "//java/com/google/android/hello:b", "b_proguard.jar", false, null, getAndroidJarPath()); + + SpawnAction action = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith( + getFilesToBuild(getConfiguredTarget("//java/com/google/android/hello:b")), "_proguard.jar"); + assertThat(ActionsTestUtil.prettyArtifactNames(action.getInputs())).containsNoDuplicates(); + assertThat(Collections2.filter(action.getArguments(), arg -> arg.startsWith("@"))) + .containsExactly( + "@java/com/google/android/hello/proguard-spec.pro", + "@" + execPathEndingWith(action.getInputs(), "/_b_proguard.cfg")); + } + + @Test + public void testLegacyLinkingProguardNotUsedWithoutSpecOnBinary() throws Exception { + useConfiguration( + "--java_optimization_mode=legacy", + "--extra_proguard_specs=//java/com/google/android/hello:ignored.pro"); + scratch.file("java/com/google/android/hello/BUILD", + "exports_files(['ignored.pro'])", + "android_library(name = 'l2',", + " srcs = ['MoreMaps.java'],", + " neverlink = 1)", + "android_library(name = 'l3',", + " idl_srcs = ['A.aidl'],", + // Having a library spec should not trigger proguard on the binary target. + " proguard_specs = ['library_spec.cfg'],", + " deps = [':l2'])", + "android_library(name = 'l4',", + " srcs = ['SubMoreMaps.java'],", + " neverlink = 1)", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " deps = [':l3', ':l4'],", + " manifest = 'AndroidManifest.xml',)"); + assertProguardNotUsed(getConfiguredTarget("//java/com/google/android/hello:b")); + } + + @Test + public void testFullOptimizationModeForcesProguard() throws Exception { + useConfiguration("--java_optimization_mode=optimize_minify"); + SpawnAction action = testProguardOptimizationMode(); + // Expect spec generated from resources as well as library's (validated) spec as usual + assertThat(Collections2.filter(action.getArguments(), arg -> arg.startsWith("@"))) + .containsExactly( + "@" + execPathEndingWith(action.getInputs(), "/_b_proguard.cfg"), + "@" + execPathEndingWith(action.getInputs(), "library_spec.cfg_valid")); + } + + @Test + public void testOptimizingModesIncludeExtraProguardSpecs() throws Exception { + useConfiguration( + "--java_optimization_mode=fast_minify", + "--extra_proguard_specs=//java/com/google/android/hello:extra.pro"); + SpawnAction action = testProguardOptimizationMode(); + assertThat(action.getArguments()).contains("@java/com/google/android/hello/extra.pro"); + } + + @Test + public void testRenameModeForcesProguardWithSpecForMode() throws Exception { + testProguardPartialOptimizationMode("rename", "-dontshrink\n-dontoptimize\n"); + } + + @Test + public void testMinimizingModeForcesProguardWithSpecForMode() throws Exception { + testProguardPartialOptimizationMode("fast_minify", "-dontoptimize\n"); + } + + public void testProguardPartialOptimizationMode(String mode, String expectedSpecForMode) + throws Exception { + useConfiguration("--java_optimization_mode=" + mode); + SpawnAction action = testProguardOptimizationMode(); + // Expect spec generated from resources, library's (validated) spec, and spec for mode + String modeSpecFileSuffix = "/" + mode + "_b_proguard.cfg"; + assertThat(Collections2.filter(action.getArguments(), arg -> arg.startsWith("@"))) + .containsExactly( + "@" + execPathEndingWith(action.getInputs(), modeSpecFileSuffix), + "@" + execPathEndingWith(action.getInputs(), "/_b_proguard.cfg"), + "@" + execPathEndingWith(action.getInputs(), "library_spec.cfg_valid")); + + FileWriteAction modeSpec = (FileWriteAction) actionsTestUtil().getActionForArtifactEndingWith( + action.getInputs(), modeSpecFileSuffix); + assertThat(modeSpec.getFileContents()).isEqualTo(expectedSpecForMode); + } + + public SpawnAction testProguardOptimizationMode() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "exports_files(['extra.pro'])", + "android_library(name = 'l',", + " idl_srcs = ['A.aidl'],", + " proguard_specs = ['library_spec.cfg'])", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " deps = [':l'],", + " manifest = 'AndroidManifest.xml',)"); + checkProguardUse( + "//java/com/google/android/hello:b", + "b_proguard.jar", + /*expectMapping*/ true, + /*passes*/ null, + getAndroidJarPath()); + + SpawnAction action = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith( + getFilesToBuild(getConfiguredTarget("//java/com/google/android/hello:b")), "_proguard.jar"); + assertThat(ActionsTestUtil.prettyArtifactNames(action.getInputs())).containsNoDuplicates(); + return action; + } + + @Test + public void testProguardSpecFromLibraryUsedInBinary() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_library(name = 'l2',", + " srcs = ['MoreMaps.java'],", + " proguard_specs = ['library_spec.cfg'])", + "android_library(name = 'l3',", + " idl_srcs = ['A.aidl'],", + " proguard_specs = ['library_spec.cfg'],", + " deps = [':l2'])", + "android_library(name = 'l4',", + " srcs = ['SubMoreMaps.java'],", + " neverlink = 1)", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " deps = [':l3', ':l4'],", + " proguard_specs = ['proguard-spec.pro'],", + " manifest = 'AndroidManifest.xml',)"); + assertProguardUsed(getConfiguredTarget("//java/com/google/android/hello:b")); + assertProguardGenerated(getConfiguredTarget("//java/com/google/android/hello:b")); + SpawnAction action = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith( + getFilesToBuild(getConfiguredTarget("//java/com/google/android/hello:b")), "_proguard.jar"); + assertThat(prettyArtifactNames(action.getInputs())).contains( + "java/com/google/android/hello/proguard-spec.pro"); + assertThat(prettyArtifactNames(action.getInputs())).contains( + "java/com/google/android/hello/validated_proguard/l2/java/com/google/android/hello/library_spec.cfg_valid"); + assertThat(ActionsTestUtil.prettyArtifactNames(action.getInputs())).containsNoDuplicates(); + } + + @Test + public void testResourcesUsedInProguardGenerate() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " manifest = 'AndroidManifest.xml',", + " resource_files = ['res/values/strings.xml'],", + " proguard_specs = ['proguard-spec.pro', 'proguard-spec1.pro',", + " 'proguard-spec2.pro'])"); + scratch.file("java/com/google/android/hello/res/values/strings.xml", + "<resources><string name = 'hello'>Hello Android!</string></resources>"); + ConfiguredTarget binary = getConfiguredTarget("//java/com/google/android/hello:b"); + SpawnAction action = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith( + actionsTestUtil().artifactClosureOf(getFilesToBuild(binary)), "_proguard.cfg"); + + assertProguardGenerated(binary); + assertWithMessage("Generate proguard action does not contain expected input.") + .that(ActionsTestUtil.prettyArtifactNames(action.getInputs())) + .contains("java/com/google/android/hello/res/values/strings.xml"); + } + + @Test + public void testUseSingleJarForLibraryJars() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_library(name = 'l1',", + " srcs = ['Maps.java'],", + " neverlink = 1)", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " deps = [':l1'],", + " manifest = 'AndroidManifest.xml',", + " proguard_specs = ['proguard-spec.pro', 'proguard-spec1.pro',", + " 'proguard-spec2.pro'])"); + ConfiguredTarget binary = getConfiguredTarget("//java/com/google/android/hello:b"); + SpawnAction action = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith( + getFilesToBuild(binary), "_proguard.jar"); + + checkProguardLibJars(action, targetConfig.getBinFragment() + + "/java/com/google/android/hello/proguard/b/legacy_b_combined_library_jars.jar"); + } + + @Test + public void testOnlyOneLibraryJar() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " manifest = 'AndroidManifest.xml',", + " proguard_specs = ['proguard-spec.pro'],", + " proguard_generate_mapping = 1)"); + ConfiguredTarget binary = getConfiguredTarget("//java/com/google/android/hello:b"); + SpawnAction action = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith( + getFilesToBuild(binary), "_proguard.jar"); + + checkProguardLibJars(action, getAndroidJarPath()); + } } diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java index f6f6bd44c4..5ae85d5c54 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java @@ -26,6 +26,7 @@ import com.google.common.collect.Sets; import com.google.devtools.build.lib.actions.Action; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.CommandLineExpansionException; +import com.google.devtools.build.lib.actions.util.ActionsTestUtil; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.FileProvider; @@ -39,7 +40,10 @@ import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider; import com.google.devtools.build.lib.testutil.TestRuleClassProvider; import com.google.devtools.build.lib.util.Preconditions; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Set; import javax.annotation.Nullable; @@ -274,4 +278,120 @@ public abstract class AndroidBuildViewTestCase extends BuildViewTestCase { return hasKey && !doesNotHaveKey; } + + protected String getAndroidJarPath() throws Exception { + return getAndroidSdk().getAndroidJar().getRootRelativePathString(); + } + + protected Artifact getProguardBinary() throws Exception { + return getAndroidSdk().getProguard().getExecutable(); + } + + private AndroidSdkProvider getAndroidSdk() { + Label sdk = targetConfig.getFragment(AndroidConfiguration.class).getSdk(); + return getConfiguredTarget(sdk, targetConfig).getProvider(AndroidSdkProvider.class); + } + + protected void checkProguardUse(String target, String artifact, boolean expectMapping, + @Nullable Integer passes, + String... expectedlibraryJars) throws Exception { + ConfiguredTarget binary = getConfiguredTarget(target); + assertProguardUsed(binary); + assertProguardGenerated(binary); + + Action dexAction = actionsTestUtil().getActionForArtifactEndingWith( + actionsTestUtil().artifactClosureOf(getFilesToBuild(binary)), "classes.dex"); + Artifact trimmedJar = + getFirstArtifactEndingWith(dexAction.getInputs(), artifact); + assertWithMessage("Dex should be built from jar trimmed with Proguard.") + .that(trimmedJar) + .isNotNull(); + SpawnAction proguardAction = getGeneratingSpawnAction(trimmedJar); + + if (passes == null) { + // Verify proguard as a single action. + Action proguardMap = actionsTestUtil().getActionForArtifactEndingWith(getFilesToBuild(binary), + "_proguard.map"); + if (expectMapping) { + assertWithMessage("proguard.map is not in the rule output").that(proguardMap).isNotNull(); + } else { + assertWithMessage("proguard.map is in the rule output").that(proguardMap).isNull(); + } + checkProguardLibJars(proguardAction, expectedlibraryJars); + } else { + // Verify the multi-stage system generated the correct number of stages. + Artifact proguardMap = ActionsTestUtil.getFirstArtifactEndingWith( + proguardAction.getOutputs(), "_proguard.map"); + if (expectMapping) { + assertWithMessage("proguard.map is not in the rule output").that(proguardMap).isNotNull(); + } else { + assertWithMessage("proguard.map is in the rule output").that(proguardMap).isNull(); + } + + assertThat(proguardAction.getArguments()).contains("-runtype FINAL"); + checkProguardLibJars(proguardAction, expectedlibraryJars); + + SpawnAction lastStageAction = proguardAction; + // Verify Obfuscation config. + for (int pass = passes; pass > 0; pass--) { + Artifact lastStageOutput = ActionsTestUtil.getFirstArtifactEndingWith( + lastStageAction.getInputs(), + "Proguard_optimization_" + pass + ".jar"); + assertWithMessage("Proguard_optimization_" + pass + ".jar is not in rule output") + .that(lastStageOutput) + .isNotNull(); + lastStageAction = getGeneratingSpawnAction(lastStageOutput); + + // Verify Optimization pass config. + assertThat(lastStageAction.getArguments()).contains("-runtype OPTIMIZATION"); + checkProguardLibJars(lastStageAction, expectedlibraryJars); + } + + Artifact preoptimizationOutput = ActionsTestUtil.getFirstArtifactEndingWith( + lastStageAction.getInputs(), "proguard_preoptimization.jar"); + assertWithMessage("proguard_preoptimization.jar is not in rule output") + .that(preoptimizationOutput) + .isNotNull(); + SpawnAction proOptimization = getGeneratingSpawnAction(preoptimizationOutput); + + // Verify intitial step. + assertThat(proOptimization.getArguments()).contains("-runtype INITIAL"); + checkProguardLibJars(proOptimization, expectedlibraryJars); + } + } + + void checkProguardLibJars(SpawnAction proguardAction, String... expectedlibraryJars) + throws Exception { + Collection<String> libraryJars = new ArrayList<>(); + Iterator<String> argsIterator = proguardAction.getArguments().iterator(); + for (String argument = argsIterator.next(); argsIterator.hasNext(); + argument = argsIterator.next()) { + if (argument.equals("-libraryjars")) { + libraryJars.add(argsIterator.next()); + } + } + assertThat(libraryJars).containsExactly((Object[]) expectedlibraryJars); + } + + protected void assertProguardGenerated(ConfiguredTarget binary) { + Action generateProguardAction = actionsTestUtil().getActionForArtifactEndingWith( + actionsTestUtil().artifactClosureOf(getFilesToBuild(binary)), "_proguard.cfg"); + assertWithMessage("proguard generating action not spawned") + .that(generateProguardAction) + .isNotNull(); + Action proguardAction = + actionsTestUtil().getActionForArtifactEndingWith(getFilesToBuild(binary), "_proguard.jar"); + actionsTestUtil(); + assertWithMessage("Generated config not in inputs to proguard action") + .that(proguardAction.getInputs()).contains(ActionsTestUtil.getFirstArtifactEndingWith( + generateProguardAction.getOutputs(), "_proguard.cfg")); + } + + protected void assertProguardNotUsed(ConfiguredTarget binary) { + assertWithMessage("proguard.jar is in the rule output") + .that( + actionsTestUtil() + .getActionForArtifactEndingWith(getFilesToBuild(binary), "_proguard.jar")) + .isNull(); + } } diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidLibraryTest.java index 7c7d821479..0f76cd20d1 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidLibraryTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidLibraryTest.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.rules.android; import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import com.google.common.base.Function; import com.google.common.base.Joiner; @@ -26,6 +27,7 @@ import com.google.devtools.build.lib.actions.Action; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.util.ActionsTestUtil; import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.OutputGroupProvider; import com.google.devtools.build.lib.analysis.actions.FileWriteAction; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; @@ -1588,4 +1590,67 @@ public class AndroidLibraryTest extends AndroidBuildViewTestCase { .allowSrcsLessAndroidLibraryDeps()) .isTrue(); } + + @Test + public void testAndroidLibraryValidatesProguardSpec() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_library(name = 'l2',", + " srcs = ['MoreMaps.java'],", + " proguard_specs = ['library_spec.cfg'])", + "android_binary(name = 'b',", + " srcs = ['HelloApp.java'],", + " manifest = 'AndroidManifest.xml',", + " deps = [':l2'],", + " proguard_specs = ['proguard-spec.pro'])"); + Set<Artifact> transitiveArtifacts = + actionsTestUtil() + .artifactClosureOf( + getFilesToBuild(getConfiguredTarget("//java/com/google/android/hello:b"))); + Action action = + actionsTestUtil() + .getActionForArtifactEndingWith(transitiveArtifacts, "library_spec.cfg_valid"); + assertWithMessage("proguard validate action was spawned for binary target.") + .that( + actionsTestUtil() + .getActionForArtifactEndingWith(transitiveArtifacts, "proguard-spec.pro_valid")) + .isNull(); + assertWithMessage("Proguard validate action was not spawned.") + .that(ActionsTestUtil.prettyArtifactNames(action.getInputs())) + .contains("java/com/google/android/hello/library_spec.cfg"); + } + + @Test + public void testAndroidLibraryValidatesProguardSpecWithoutBinary() throws Exception { + scratch.file("java/com/google/android/hello/BUILD", + "android_library(name = 'l2',", + " srcs = ['MoreMaps.java'],", + " proguard_specs = ['library_spec.cfg'])", + "android_library(name = 'l3',", + " srcs = ['MoreMaps.java'],", + " deps = [':l2'])"); + Action action = + actionsTestUtil() + .getActionForArtifactEndingWith( + getOutputGroup( + getConfiguredTarget("//java/com/google/android/hello:l2"), + OutputGroupProvider.HIDDEN_TOP_LEVEL), + "library_spec.cfg_valid"); + assertWithMessage("Proguard validate action was not spawned.").that(action).isNotNull(); + assertWithMessage("Proguard validate action was spawned without correct input.") + .that(ActionsTestUtil.prettyArtifactNames(action.getInputs())) + .contains("java/com/google/android/hello/library_spec.cfg"); + Action transitiveAction = + actionsTestUtil() + .getActionForArtifactEndingWith( + getOutputGroup( + getConfiguredTarget("//java/com/google/android/hello:l3"), + OutputGroupProvider.HIDDEN_TOP_LEVEL), + "library_spec.cfg_valid"); + assertWithMessage("Proguard validate action was not spawned.") + .that(transitiveAction) + .isNotNull(); + assertWithMessage("Proguard validate action was spawned without correct input.") + .that(ActionsTestUtil.prettyArtifactNames(transitiveAction.getInputs())) + .contains("java/com/google/android/hello/library_spec.cfg"); + } } |