/* * Copyright 2013-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package com.facebook.buck.android; import static com.facebook.buck.jvm.java.JavaCompilationConstants.ANDROID_JAVAC_OPTIONS; import static com.facebook.buck.jvm.java.JavaCompilationConstants.DEFAULT_JAVAC; import static com.facebook.buck.jvm.java.JavaCompilationConstants.DEFAULT_JAVA_CONFIG; import static org.easymock.EasyMock.createStrictMock; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import com.facebook.buck.android.AndroidBinary.ExopackageMode; import com.facebook.buck.android.aapt.RDotTxtEntry.RType; import com.facebook.buck.cli.FakeBuckConfig; import com.facebook.buck.cxx.CxxPlatformUtils; import com.facebook.buck.jvm.core.HasJavaClassHashes; import com.facebook.buck.jvm.java.JavaLibrary; import com.facebook.buck.jvm.java.JavaLibraryBuilder; import com.facebook.buck.jvm.java.Keystore; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.BuildTargetFactory; import com.facebook.buck.model.BuildTargets; import com.facebook.buck.model.Flavor; import com.facebook.buck.model.InternalFlavor; import com.facebook.buck.rules.BuildRule; import com.facebook.buck.rules.BuildRuleParams; import com.facebook.buck.rules.BuildRuleResolver; import com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer; import com.facebook.buck.rules.FakeBuildRule; import com.facebook.buck.rules.FakeBuildRuleParamsBuilder; import com.facebook.buck.rules.FakeSourcePath; import com.facebook.buck.rules.PathSourcePath; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.rules.SourcePathRuleFinder; import com.facebook.buck.rules.TargetGraph; import com.facebook.buck.rules.TargetNode; import com.facebook.buck.rules.coercer.BuildConfigFields; import com.facebook.buck.rules.coercer.ManifestEntries; import com.facebook.buck.testutil.FakeProjectFilesystem; import com.facebook.buck.testutil.MoreAsserts; import com.facebook.buck.testutil.TargetGraphFactory; import com.facebook.buck.util.MoreCollectors; import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import com.google.common.util.concurrent.MoreExecutors; import java.nio.file.Paths; import java.util.EnumSet; import java.util.Optional; import org.hamcrest.Matchers; import org.junit.Test; public class AndroidBinaryGraphEnhancerTest { @Test public void testCreateDepsForPreDexing() throws Exception { // Create three Java rules, :dep1, :dep2, and :lib. :lib depends on :dep1 and :dep2. BuildTarget javaDep1BuildTarget = BuildTargetFactory.newInstance("//java/com/example:dep1"); TargetNode<?, ?> javaDep1Node = JavaLibraryBuilder.createBuilder(javaDep1BuildTarget) .addSrc(Paths.get("java/com/example/Dep1.java")) .build(); BuildTarget javaDep2BuildTarget = BuildTargetFactory.newInstance("//java/com/example:dep2"); TargetNode<?, ?> javaDep2Node = JavaLibraryBuilder.createBuilder(javaDep2BuildTarget) .addSrc(Paths.get("java/com/example/Dep2.java")) .build(); BuildTarget javaLibBuildTarget = BuildTargetFactory.newInstance("//java/com/example:lib"); TargetNode<?, ?> javaLibNode = JavaLibraryBuilder.createBuilder(javaLibBuildTarget) .addSrc(Paths.get("java/com/example/Lib.java")) .addDep(javaDep1Node.getBuildTarget()) .addDep(javaDep2Node.getBuildTarget()) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(javaDep1Node, javaDep2Node, javaLibNode); BuildRuleResolver ruleResolver = new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(ruleResolver); BuildRule javaDep1 = ruleResolver.requireRule(javaDep1BuildTarget); BuildRule javaDep2 = ruleResolver.requireRule(javaDep2BuildTarget); BuildRule javaLib = ruleResolver.requireRule(javaLibBuildTarget); // Assume we are enhancing an android_binary rule whose only dep // is //java/com/example:lib, and that //java/com/example:dep2 is in its no_dx list. ImmutableSortedSet<BuildRule> originalDeps = ImmutableSortedSet.of(javaLib); ImmutableSet<BuildTarget> buildRulesToExcludeFromDex = ImmutableSet.of(javaDep2BuildTarget); BuildTarget apkTarget = BuildTargetFactory.newInstance("//java/com/example:apk"); FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); BuildRuleParams originalParams = new BuildRuleParams( apkTarget, Suppliers.ofInstance(originalDeps), Suppliers.ofInstance(originalDeps), ImmutableSortedSet.of(), filesystem); AndroidBinaryGraphEnhancer graphEnhancer = new AndroidBinaryGraphEnhancer( originalParams, ruleResolver, AndroidBinary.AaptMode.AAPT1, ResourcesFilter.ResourceCompressionMode.DISABLED, FilterResourcesStep.ResourceFilter.EMPTY_FILTER, /* bannedDuplicateResourceTypes */ EnumSet.noneOf(RType.class), Optional.empty(), /* locales */ ImmutableSet.of(), createStrictMock(PathSourcePath.class), AndroidBinary.PackageType.DEBUG, /* cpuFilters */ ImmutableSet.of(), /* shouldBuildStringSourceMap */ false, /* shouldPreDex */ true, BuildTargets.getScratchPath( originalParams.getProjectFilesystem(), apkTarget, "%s/classes.dex"), DexSplitMode.NO_SPLIT, buildRulesToExcludeFromDex, /* resourcesToExclude */ ImmutableSet.of(), /* skipCrunchPngs */ false, /* includesVectorDrawables */ false, DEFAULT_JAVA_CONFIG, DEFAULT_JAVAC, ANDROID_JAVAC_OPTIONS, EnumSet.noneOf(ExopackageMode.class), /* buildConfigValues */ BuildConfigFields.empty(), /* buildConfigValuesFile */ Optional.empty(), /* xzCompressionLevel */ Optional.empty(), /* trimResourceIds */ false, /* keepResourcePattern */ Optional.empty(), /* nativePlatforms */ ImmutableMap.of(), /* nativeLibraryMergeMap */ Optional.empty(), /* nativeLibraryMergeGlue */ Optional.empty(), /* nativeLibraryMergeCodeGenerator */ Optional.empty(), /* nativeLibraryProguardConfigGenerator */ Optional.empty(), AndroidBinary.RelinkerMode.DISABLED, MoreExecutors.newDirectExecutorService(), /* manifestEntries */ ManifestEntries.empty(), CxxPlatformUtils.DEFAULT_CONFIG, new APKModuleGraph( TargetGraph.EMPTY, originalParams.getBuildTarget(), Optional.empty()), new DxConfig(FakeBuckConfig.builder().build()), Optional.empty()); BuildTarget aaptPackageResourcesTarget = BuildTargetFactory.newInstance("//java/com/example:apk#aapt_package"); BuildRuleParams aaptPackageResourcesParams = new FakeBuildRuleParamsBuilder(aaptPackageResourcesTarget).build(); AaptPackageResources aaptPackageResources = new AaptPackageResources( aaptPackageResourcesParams, ruleFinder, ruleResolver, /* manifest */ new FakeSourcePath("java/src/com/facebook/base/AndroidManifest.xml"), new IdentityResourcesProvider(ImmutableList.of()), ImmutableList.of(), /* resourceUnionPackage */ Optional.empty(), false, /* skipCrunchPngs */ false, /* includesVectorDrawables */ false, /* bannedDuplicateResourceTypes */ EnumSet.noneOf(RType.class), /* manifestEntries */ ManifestEntries.empty()); ruleResolver.addToIndex(aaptPackageResources); AndroidPackageableCollection collection = new AndroidPackageableCollector( /* collectionRoot */ apkTarget, ImmutableSet.of(javaDep2BuildTarget), /* resourcesToExclude */ ImmutableSet.of(), new APKModuleGraph(TargetGraph.EMPTY, apkTarget, Optional.empty())) .addClasspathEntry(((HasJavaClassHashes) javaDep1), new FakeSourcePath("ignored")) .addClasspathEntry(((HasJavaClassHashes) javaDep2), new FakeSourcePath("ignored")) .addClasspathEntry(((HasJavaClassHashes) javaLib), new FakeSourcePath("ignored")) .build(); ImmutableMultimap<APKModule, DexProducedFromJavaLibrary> preDexedLibraries = graphEnhancer.createPreDexRulesForLibraries( /* additionalJavaLibrariesToDex */ ImmutableList.of(), collection); BuildTarget fakeUberRDotJavaCompileTarget = BuildTargetFactory.newInstance("//fake:uber_r_dot_java#compile"); JavaLibrary fakeUberRDotJavaCompile = JavaLibraryBuilder.createBuilder(fakeUberRDotJavaCompileTarget).build(ruleResolver); BuildTarget fakeUberRDotJavaDexTarget = BuildTargetFactory.newInstance("//fake:uber_r_dot_java#dex"); DexProducedFromJavaLibrary fakeUberRDotJavaDex = new DexProducedFromJavaLibrary( new FakeBuildRuleParamsBuilder(fakeUberRDotJavaDexTarget).build(), fakeUberRDotJavaCompile); ruleResolver.addToIndex(fakeUberRDotJavaDex); BuildRule preDexMergeRule = graphEnhancer.createPreDexMergeRule(preDexedLibraries, fakeUberRDotJavaDex); BuildTarget dexMergeTarget = BuildTargetFactory.newInstance("//java/com/example:apk#dex_merge"); BuildRule dexMergeRule = ruleResolver.getRule(dexMergeTarget); assertEquals(dexMergeRule, preDexMergeRule); BuildTarget javaDep1DexBuildTarget = BuildTarget.builder(javaDep1BuildTarget) .addFlavors(AndroidBinaryGraphEnhancer.DEX_FLAVOR) .build(); BuildTarget javaDep2DexBuildTarget = BuildTarget.builder(javaDep2BuildTarget) .addFlavors(AndroidBinaryGraphEnhancer.DEX_FLAVOR) .build(); BuildTarget javaLibDexBuildTarget = BuildTarget.builder(javaLibBuildTarget) .addFlavors(AndroidBinaryGraphEnhancer.DEX_FLAVOR) .build(); assertThat( "There should be a #dex rule for dep1 and lib, but not dep2 because it is in the no_dx " + "list. And we should depend on uber_r_dot_java", Iterables.transform(dexMergeRule.getBuildDeps(), BuildRule::getBuildTarget), Matchers.allOf( Matchers.not(Matchers.hasItem(javaDep1BuildTarget)), Matchers.hasItem(javaDep1DexBuildTarget), Matchers.not(Matchers.hasItem(javaDep2BuildTarget)), Matchers.not(Matchers.hasItem(javaDep2DexBuildTarget)), Matchers.hasItem(javaLibDexBuildTarget), Matchers.hasItem(fakeUberRDotJavaDex.getBuildTarget()))); } @Test public void testAllBuildablesExceptPreDexRule() throws Exception { // Create an android_build_config() as a dependency of the android_binary(). BuildTarget buildConfigBuildTarget = BuildTargetFactory.newInstance("//java/com/example:cfg"); BuildRuleParams buildConfigParams = new FakeBuildRuleParamsBuilder(buildConfigBuildTarget).build(); BuildRuleResolver ruleResolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); AndroidBuildConfigJavaLibrary buildConfigJavaLibrary = AndroidBuildConfigDescription.createBuildRule( buildConfigParams, "com.example.buck", /* values */ BuildConfigFields.empty(), /* valuesFile */ Optional.empty(), /* useConstantExpressions */ false, DEFAULT_JAVAC, ANDROID_JAVAC_OPTIONS, ruleResolver); BuildTarget apkTarget = BuildTargetFactory.newInstance("//java/com/example:apk"); BuildRuleParams originalParams = new FakeBuildRuleParamsBuilder(apkTarget) .setDeclaredDeps(ImmutableSortedSet.of(buildConfigJavaLibrary)) .build(); // set it up. Keystore keystore = createStrictMock(Keystore.class); AndroidBinaryGraphEnhancer graphEnhancer = new AndroidBinaryGraphEnhancer( originalParams, ruleResolver, AndroidBinary.AaptMode.AAPT1, ResourcesFilter.ResourceCompressionMode.ENABLED_WITH_STRINGS_AS_ASSETS, FilterResourcesStep.ResourceFilter.EMPTY_FILTER, /* bannedDuplicateResourceTypes */ EnumSet.noneOf(RType.class), Optional.empty(), /* locales */ ImmutableSet.of(), new FakeSourcePath("AndroidManifest.xml"), AndroidBinary.PackageType.DEBUG, /* cpuFilters */ ImmutableSet.of(), /* shouldBuildStringSourceMap */ false, /* shouldPreDex */ false, BuildTargets.getScratchPath( originalParams.getProjectFilesystem(), apkTarget, "%s/classes.dex"), DexSplitMode.NO_SPLIT, /* buildRulesToExcludeFromDex */ ImmutableSet.of(), /* resourcesToExclude */ ImmutableSet.of(), /* skipCrunchPngs */ false, /* includesVectorDrawables */ false, DEFAULT_JAVA_CONFIG, DEFAULT_JAVAC, ANDROID_JAVAC_OPTIONS, EnumSet.of(ExopackageMode.SECONDARY_DEX), /* buildConfigValues */ BuildConfigFields.empty(), /* buildConfigValuesFiles */ Optional.empty(), /* xzCompressionLevel */ Optional.empty(), /* trimResourceIds */ false, /* keepResourcePattern */ Optional.empty(), /* nativePlatforms */ ImmutableMap.of(), /* nativeLibraryMergeMap */ Optional.empty(), /* nativeLibraryMergeGlue */ Optional.empty(), /* nativeLibraryMergeCodeGenerator */ Optional.empty(), /* nativeLibraryProguardConfigGenerator */ Optional.empty(), AndroidBinary.RelinkerMode.DISABLED, MoreExecutors.newDirectExecutorService(), /* manifestEntries */ ManifestEntries.empty(), CxxPlatformUtils.DEFAULT_CONFIG, new APKModuleGraph( TargetGraph.EMPTY, originalParams.getBuildTarget(), Optional.empty()), new DxConfig(FakeBuckConfig.builder().build()), Optional.empty()); replay(keystore); AndroidGraphEnhancementResult result = graphEnhancer.createAdditionalBuildables(); // Verify that android_build_config() was processed correctly. Flavor flavor = InternalFlavor.of("buildconfig_com_example_buck"); final SourcePathResolver pathResolver = new SourcePathResolver(new SourcePathRuleFinder(ruleResolver)); BuildTarget enhancedBuildConfigTarget = BuildTarget.builder(apkTarget).addFlavors(flavor).build(); assertEquals( "The only classpath entry to dex should be the one from the AndroidBuildConfigJavaLibrary" + " created via graph enhancement.", ImmutableSet.of( BuildTargets.getGenPath( originalParams.getProjectFilesystem(), enhancedBuildConfigTarget, "lib__%s__output") .resolve(enhancedBuildConfigTarget.getShortNameAndFlavorPostfix() + ".jar")), result .getClasspathEntriesToDex() .stream() .map(pathResolver::getRelativePath) .collect(MoreCollectors.toImmutableSet())); BuildRule enhancedBuildConfigRule = ruleResolver.getRule(enhancedBuildConfigTarget); assertTrue(enhancedBuildConfigRule instanceof AndroidBuildConfigJavaLibrary); AndroidBuildConfigJavaLibrary enhancedBuildConfigJavaLibrary = (AndroidBuildConfigJavaLibrary) enhancedBuildConfigRule; AndroidBuildConfig androidBuildConfig = enhancedBuildConfigJavaLibrary.getAndroidBuildConfig(); assertEquals("com.example.buck", androidBuildConfig.getJavaPackage()); assertTrue(androidBuildConfig.isUseConstantExpressions()); assertEquals( "IS_EXOPACKAGE defaults to false, but should now be true. DEBUG should still be true.", BuildConfigFields.fromFields( ImmutableList.of( BuildConfigFields.Field.of("boolean", "DEBUG", "true"), BuildConfigFields.Field.of("boolean", "IS_EXOPACKAGE", "true"), BuildConfigFields.Field.of("int", "EXOPACKAGE_FLAGS", "1"))), androidBuildConfig.getBuildConfigFields()); ImmutableSortedSet<BuildRule> finalDeps = result.getFinalDeps(); BuildRule computeExopackageDepsAbiRule = findRuleOfType(ruleResolver, ComputeExopackageDepsAbi.class); assertThat(finalDeps, Matchers.hasItem(computeExopackageDepsAbiRule)); BuildRule resourcesFilterRule = findRuleOfType(ruleResolver, ResourcesFilter.class); BuildRule aaptPackageResourcesRule = findRuleOfType(ruleResolver, AaptPackageResources.class); MoreAsserts.assertDepends( "AaptPackageResources must depend on ResourcesFilter", aaptPackageResourcesRule, resourcesFilterRule); BuildRule packageStringAssetsRule = findRuleOfType(ruleResolver, PackageStringAssets.class); MoreAsserts.assertDepends( "PackageStringAssets must depend on ResourcesFilter", packageStringAssetsRule, aaptPackageResourcesRule); assertFalse(result.getPreDexMerge().isPresent()); MoreAsserts.assertDepends( "ComputeExopackageDepsAbi must depend on ResourcesFilter", computeExopackageDepsAbiRule, resourcesFilterRule); MoreAsserts.assertDepends( "ComputeExopackageDepsAbi must depend on PackageStringAssets", computeExopackageDepsAbiRule, packageStringAssetsRule); MoreAsserts.assertDepends( "ComputeExopackageDepsAbi must depend on AaptPackageResources", computeExopackageDepsAbiRule, aaptPackageResourcesRule); assertTrue(result.getPackageStringAssets().isPresent()); assertTrue(result.getComputeExopackageDepsAbi().isPresent()); verify(keystore); } @Test public void testResourceRulesBecomeDepsOfAaptPackageResources() throws Exception { TargetNode<?, ?> resourceNode = AndroidResourceBuilder.createBuilder(BuildTargetFactory.newInstance("//:resource")) .setRDotJavaPackage("package") .setRes(Paths.get("res")) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(resourceNode); BuildRuleResolver ruleResolver = new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer()); AndroidResource resource = (AndroidResource) ruleResolver.requireRule(resourceNode.getBuildTarget()); // set it up. BuildTarget target = BuildTargetFactory.newInstance("//:target"); BuildRuleParams originalParams = new FakeBuildRuleParamsBuilder(target) .setDeclaredDeps(ImmutableSortedSet.of(resource)) .build(); AndroidBinaryGraphEnhancer graphEnhancer = new AndroidBinaryGraphEnhancer( originalParams, ruleResolver, AndroidBinary.AaptMode.AAPT1, ResourcesFilter.ResourceCompressionMode.ENABLED_WITH_STRINGS_AS_ASSETS, FilterResourcesStep.ResourceFilter.EMPTY_FILTER, /* bannedDuplicateResourceTypes */ EnumSet.noneOf(RType.class), Optional.empty(), /* locales */ ImmutableSet.of(), new FakeSourcePath("AndroidManifest.xml"), AndroidBinary.PackageType.DEBUG, /* cpuFilters */ ImmutableSet.of(), /* shouldBuildStringSourceMap */ false, /* shouldPreDex */ false, BuildTargets.getScratchPath( originalParams.getProjectFilesystem(), target, "%s/classes.dex"), DexSplitMode.NO_SPLIT, /* buildRulesToExcludeFromDex */ ImmutableSet.of(), /* resourcesToExclude */ ImmutableSet.of(), /* skipCrunchPngs */ false, /* includesVectorDrawables */ false, DEFAULT_JAVA_CONFIG, DEFAULT_JAVAC, ANDROID_JAVAC_OPTIONS, EnumSet.of(ExopackageMode.SECONDARY_DEX), /* buildConfigValues */ BuildConfigFields.empty(), /* buildConfigValuesFiles */ Optional.empty(), /* xzCompressionLevel */ Optional.empty(), /* trimResourceIds */ false, /* keepResourcePattern */ Optional.empty(), /* nativePlatforms */ ImmutableMap.of(), /* nativeLibraryMergeMap */ Optional.empty(), /* nativeLibraryMergeGlue */ Optional.empty(), /* nativeLibraryMergeCodeGenerator */ Optional.empty(), /* nativeLibraryProguardConfigGenerator */ Optional.empty(), AndroidBinary.RelinkerMode.DISABLED, MoreExecutors.newDirectExecutorService(), /* manifestEntries */ ManifestEntries.empty(), CxxPlatformUtils.DEFAULT_CONFIG, new APKModuleGraph( TargetGraph.EMPTY, originalParams.getBuildTarget(), Optional.empty()), new DxConfig(FakeBuckConfig.builder().build()), Optional.empty()); graphEnhancer.createAdditionalBuildables(); BuildRule aaptPackageResourcesRule = findRuleOfType(ruleResolver, AaptPackageResources.class); MoreAsserts.assertDepends( "AaptPackageResources must depend on resource rules", aaptPackageResourcesRule, resource); } @Test public void testPackageStringsDependsOnResourcesFilter() throws Exception { BuildRuleResolver ruleResolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); // set it up. BuildTarget target = BuildTargetFactory.newInstance("//:target"); BuildRuleParams originalParams = new FakeBuildRuleParamsBuilder(target).build(); AndroidBinaryGraphEnhancer graphEnhancer = new AndroidBinaryGraphEnhancer( originalParams, ruleResolver, AndroidBinary.AaptMode.AAPT1, ResourcesFilter.ResourceCompressionMode.ENABLED_WITH_STRINGS_AS_ASSETS, FilterResourcesStep.ResourceFilter.EMPTY_FILTER, /* bannedDuplicateResourceTypes */ EnumSet.noneOf(RType.class), Optional.empty(), /* locales */ ImmutableSet.of(), new FakeSourcePath("AndroidManifest.xml"), AndroidBinary.PackageType.DEBUG, /* cpuFilters */ ImmutableSet.of(), /* shouldBuildStringSourceMap */ false, /* shouldPreDex */ false, BuildTargets.getScratchPath( originalParams.getProjectFilesystem(), target, "%s/classes.dex"), DexSplitMode.NO_SPLIT, /* buildRulesToExcludeFromDex */ ImmutableSet.of(), /* resourcesToExclude */ ImmutableSet.of(), /* skipCrunchPngs */ false, /* includesVectorDrawables */ false, DEFAULT_JAVA_CONFIG, DEFAULT_JAVAC, ANDROID_JAVAC_OPTIONS, EnumSet.of(ExopackageMode.SECONDARY_DEX), /* buildConfigValues */ BuildConfigFields.empty(), /* buildConfigValuesFiles */ Optional.empty(), /* xzCompressionLevel */ Optional.empty(), /* trimResourceIds */ false, /* keepResourcePattern */ Optional.empty(), /* nativePlatforms */ ImmutableMap.of(), /* nativeLibraryMergeMap */ Optional.empty(), /* nativeLibraryMergeGlue */ Optional.empty(), /* nativeLibraryMergeCodeGenerator */ Optional.empty(), /* nativeLibraryProguardConfigGenerator */ Optional.empty(), AndroidBinary.RelinkerMode.DISABLED, MoreExecutors.newDirectExecutorService(), /* manifestEntries */ ManifestEntries.empty(), CxxPlatformUtils.DEFAULT_CONFIG, new APKModuleGraph( TargetGraph.EMPTY, originalParams.getBuildTarget(), Optional.empty()), new DxConfig(FakeBuckConfig.builder().build()), Optional.empty()); graphEnhancer.createAdditionalBuildables(); ResourcesFilter resourcesFilter = findRuleOfType(ruleResolver, ResourcesFilter.class); PackageStringAssets packageStringAssetsRule = findRuleOfType(ruleResolver, PackageStringAssets.class); MoreAsserts.assertDepends( "PackageStringAssets must depend on AaptPackageResources", packageStringAssetsRule, resourcesFilter); } @Test public void testResourceRulesDependOnRulesBehindResourceSourcePaths() throws Exception { BuildRuleResolver ruleResolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(ruleResolver); SourcePathResolver pathResolver = new SourcePathResolver(ruleFinder); FakeBuildRule resourcesDep = ruleResolver.addToIndex( new FakeBuildRule(BuildTargetFactory.newInstance("//:resource_dep"), pathResolver)); resourcesDep.setOutputFile("foo"); AndroidResource resource = ruleResolver.addToIndex( new AndroidResource( new FakeBuildRuleParamsBuilder("//:resources") .build() .copyAppendingExtraDeps(ImmutableSortedSet.of(resourcesDep)), ruleFinder, ImmutableSortedSet.of(), resourcesDep.getSourcePathToOutput(), ImmutableSortedMap.of(), null, null, ImmutableSortedMap.of(), new FakeSourcePath("manifest"), false)); // set it up. BuildTarget target = BuildTargetFactory.newInstance("//:target"); BuildRuleParams originalParams = new FakeBuildRuleParamsBuilder(target) .setDeclaredDeps(ImmutableSortedSet.of(resource)) .build(); AndroidBinaryGraphEnhancer graphEnhancer = new AndroidBinaryGraphEnhancer( originalParams, ruleResolver, AndroidBinary.AaptMode.AAPT1, ResourcesFilter.ResourceCompressionMode.ENABLED_WITH_STRINGS_AS_ASSETS, FilterResourcesStep.ResourceFilter.EMPTY_FILTER, /* bannedDuplicateResourceTypes */ EnumSet.noneOf(RType.class), Optional.empty(), /* locales */ ImmutableSet.of(), new FakeSourcePath("AndroidManifest.xml"), AndroidBinary.PackageType.DEBUG, /* cpuFilters */ ImmutableSet.of(), /* shouldBuildStringSourceMap */ false, /* shouldPreDex */ false, BuildTargets.getScratchPath( originalParams.getProjectFilesystem(), target, "%s/classes.dex"), DexSplitMode.NO_SPLIT, /* buildRulesToExcludeFromDex */ ImmutableSet.of(), /* resourcesToExclude */ ImmutableSet.of(), /* skipCrunchPngs */ false, /* includesVectorDrawables */ false, DEFAULT_JAVA_CONFIG, DEFAULT_JAVAC, ANDROID_JAVAC_OPTIONS, EnumSet.of(ExopackageMode.SECONDARY_DEX), /* buildConfigValues */ BuildConfigFields.empty(), /* buildConfigValuesFiles */ Optional.empty(), /* xzCompressionLevel */ Optional.empty(), /* trimResourceIds */ false, /* keepResourcePattern */ Optional.empty(), /* nativePlatforms */ ImmutableMap.of(), /* nativeLibraryMergeMap */ Optional.empty(), /* nativeLibraryMergeGlue */ Optional.empty(), /* nativeLibraryMergeCodeGenerator */ Optional.empty(), /* nativeLibraryProguardConfigGenerator */ Optional.empty(), AndroidBinary.RelinkerMode.DISABLED, MoreExecutors.newDirectExecutorService(), /* manifestEntries */ ManifestEntries.empty(), CxxPlatformUtils.DEFAULT_CONFIG, new APKModuleGraph( TargetGraph.EMPTY, originalParams.getBuildTarget(), Optional.empty()), new DxConfig(FakeBuckConfig.builder().build()), Optional.empty()); graphEnhancer.createAdditionalBuildables(); ResourcesFilter resourcesFilter = findRuleOfType(ruleResolver, ResourcesFilter.class); MoreAsserts.assertDepends( "ResourcesFilter must depend on rules behind resources source paths", resourcesFilter, resourcesDep); } private <T extends BuildRule> T findRuleOfType( BuildRuleResolver ruleResolver, Class<T> ruleClass) { for (BuildRule rule : ruleResolver.getBuildRules()) { if (ruleClass.isAssignableFrom(rule.getClass())) { return ruleClass.cast(rule); } } fail("Could not find build rule of type " + ruleClass.getCanonicalName()); return null; } }