/* * Copyright 2014-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.apple; import static com.facebook.buck.apple.AppleResources.IS_APPLE_BUNDLE_RESOURCE_NODE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import com.facebook.buck.cxx.CxxDescriptionEnhancer; import com.facebook.buck.cxx.NativeLinkable; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.BuildTargetFactory; import com.facebook.buck.model.Either; import com.facebook.buck.rules.BuildRule; import com.facebook.buck.rules.BuildRuleParams; import com.facebook.buck.rules.BuildRuleResolver; import com.facebook.buck.rules.Cell; import com.facebook.buck.rules.DefaultBuildTargetSourcePath; import com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer; import com.facebook.buck.rules.FakeBuildRuleParamsBuilder; import com.facebook.buck.rules.FakeSourcePath; import com.facebook.buck.rules.TargetGraph; import com.facebook.buck.rules.TargetNode; import com.facebook.buck.rules.TestCellBuilder; import com.facebook.buck.shell.GenruleBuilder; import com.facebook.buck.testutil.FakeProjectFilesystem; import com.facebook.buck.testutil.TargetGraphFactory; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import java.util.Collection; import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public class AppleBuildRulesTest { @Parameterized.Parameters(name = "useCache: {0}") public static Collection<Object[]> data() { return ImmutableList.of(new Object[] {false}, new Object[] {true}); } @Parameterized.Parameter(0) public boolean useCache; @Test public void testAppleLibraryIsXcodeTargetDescription() throws Exception { Cell rootCell = (new TestCellBuilder()).build(); BuildTarget libraryTarget = BuildTarget.builder(rootCell.getRoot(), "//foo", "lib").build(); TargetNode<AppleLibraryDescriptionArg, ?> library = AppleLibraryBuilder.createBuilder(libraryTarget).setSrcs(ImmutableSortedSet.of()).build(); assertTrue(AppleBuildRules.isXcodeTargetDescription(library.getDescription())); } @Test public void testIosResourceIsNotXcodeTargetDescription() throws Exception { Cell rootCell = (new TestCellBuilder()).build(); BuildTarget resourceTarget = BuildTarget.builder(rootCell.getRoot(), "//foo", "res").build(); TargetNode<?, ?> resourceNode = AppleResourceBuilder.createBuilder(resourceTarget) .setFiles(ImmutableSet.of()) .setDirs(ImmutableSet.of()) .build(); assertFalse(AppleBuildRules.isXcodeTargetDescription(resourceNode.getDescription())); } @Test public void testAppleTestIsXcodeTargetTestBuildRuleType() throws Exception { BuildTarget target = BuildTargetFactory.newInstance("//foo:xctest#iphoneos-i386"); BuildTarget sandboxTarget = BuildTargetFactory.newInstance("//foo:xctest#iphoneos-i386") .withFlavors(CxxDescriptionEnhancer.SANDBOX_TREE_FLAVOR); BuildRuleResolver resolver = new BuildRuleResolver( TargetGraphFactory.newInstance( new AppleTestBuilder(sandboxTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build()), new DefaultTargetNodeToBuildRuleTransformer()); AppleTestBuilder appleTestBuilder = new AppleTestBuilder(target) .setContacts(ImmutableSortedSet.of()) .setLabels(ImmutableSortedSet.of()) .setDeps(ImmutableSortedSet.of()) .setInfoPlist(new FakeSourcePath("Info.plist")); TargetNode<?, ?> appleTestNode = appleTestBuilder.build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(ImmutableSet.<TargetNode<?, ?>>of(appleTestNode)); BuildRule testRule = appleTestBuilder.build(resolver, new FakeProjectFilesystem(), targetGraph); assertTrue(AppleBuildRules.isXcodeTargetTestBuildRule(testRule)); } @Test public void testAppleLibraryIsNotXcodeTargetTestBuildRuleType() throws Exception { BuildRuleParams params = new FakeBuildRuleParamsBuilder(BuildTargetFactory.newInstance("//foo:lib")).build(); BuildRule libraryRule = FakeAppleRuleDescriptions.LIBRARY_DESCRIPTION.createBuildRule( TargetGraph.EMPTY, params, new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()), TestCellBuilder.createCellRoots(params.getProjectFilesystem()), AppleLibraryDescriptionArg.builder().setName("lib").build()); assertFalse(AppleBuildRules.isXcodeTargetTestBuildRule(libraryRule)); } @Test public void testXctestIsTestBundleExtension() throws Exception { assertTrue(AppleBuildRules.isXcodeTargetTestBundleExtension(AppleBundleExtension.XCTEST)); } @Test public void testRecursiveTargetsIncludesBundleBinaryFromOutsideBundle() throws Exception { BuildTarget libraryTarget = BuildTargetFactory.newInstance("//foo:lib"); TargetNode<?, ?> libraryNode = AppleLibraryBuilder.createBuilder(libraryTarget).build(); BuildTarget bundleTarget = BuildTargetFactory.newInstance("//foo:bundle"); TargetNode<?, ?> bundleNode = AppleBundleBuilder.createBuilder(bundleTarget) .setExtension(Either.ofLeft(AppleBundleExtension.XCTEST)) .setBinary(libraryTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); BuildTarget rootTarget = BuildTargetFactory.newInstance("//foo:root"); TargetNode<?, ?> rootNode = AppleLibraryBuilder.createBuilder(rootTarget) .setDeps(ImmutableSortedSet.of(libraryTarget, bundleTarget)) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(ImmutableSet.of(libraryNode, bundleNode, rootNode)); Optional<AppleDependenciesCache> cache = useCache ? Optional.of(new AppleDependenciesCache(targetGraph)) : Optional.empty(); for (int i = 0; i < (useCache ? 2 : 1); i++) { Iterable<TargetNode<?, ?>> rules = AppleBuildRules.getRecursiveTargetNodeDependenciesOfTypes( targetGraph, cache, AppleBuildRules.RecursiveDependenciesMode.BUILDING, rootNode, Optional.empty()); assertTrue(Iterables.elementsEqual(ImmutableSortedSet.of(libraryNode, bundleNode), rules)); } } @Test public void exportedDepsOfDylibsAreCollectedForLinking() throws Exception { BuildTarget fooLibTarget = BuildTargetFactory.newInstance("//foo:lib#" + CxxDescriptionEnhancer.SHARED_FLAVOR); TargetNode<?, ?> fooLibNode = AppleLibraryBuilder.createBuilder(fooLibTarget).build(); BuildTarget fooFrameworkTarget = BuildTargetFactory.newInstance("//foo:framework"); TargetNode<?, ?> fooFrameworkNode = AppleBundleBuilder.createBuilder(fooFrameworkTarget) .setExtension(Either.ofLeft(AppleBundleExtension.FRAMEWORK)) .setBinary(fooLibTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); BuildTarget barLibTarget = BuildTargetFactory.newInstance("//bar:lib#" + CxxDescriptionEnhancer.SHARED_FLAVOR); TargetNode<?, ?> barLibNode = AppleLibraryBuilder.createBuilder(barLibTarget) .setDeps(ImmutableSortedSet.of(fooFrameworkTarget)) .setExportedDeps(ImmutableSortedSet.of(fooFrameworkTarget)) .build(); BuildTarget barFrameworkTarget = BuildTargetFactory.newInstance("//bar:framework"); TargetNode<?, ?> barFrameworkNode = AppleBundleBuilder.createBuilder(barFrameworkTarget) .setExtension(Either.ofLeft(AppleBundleExtension.FRAMEWORK)) .setBinary(barLibTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); BuildTarget rootTarget = BuildTargetFactory.newInstance("//foo:root"); TargetNode<?, ?> rootNode = AppleLibraryBuilder.createBuilder(rootTarget) .setDeps(ImmutableSortedSet.of(barFrameworkTarget)) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance( ImmutableSet.of(rootNode, fooLibNode, fooFrameworkNode, barLibNode, barFrameworkNode)); Optional<AppleDependenciesCache> cache = useCache ? Optional.of(new AppleDependenciesCache(targetGraph)) : Optional.empty(); for (int i = 0; i < (useCache ? 2 : 1); i++) { Iterable<TargetNode<?, ?>> rules = AppleBuildRules.getRecursiveTargetNodeDependenciesOfTypes( targetGraph, cache, AppleBuildRules.RecursiveDependenciesMode.LINKING, rootNode, Optional.empty()); assertEquals( ImmutableSortedSet.of(barFrameworkNode, fooFrameworkNode), ImmutableSortedSet.copyOf(rules)); } } @Test public void resourceDepsOfDylibsAreNotIncludedInMainBundle() throws Exception { BuildTarget sharedResourceTarget = BuildTargetFactory.newInstance("//shared:resource"); TargetNode<?, ?> sharedResourceNode = AppleResourceBuilder.createBuilder(sharedResourceTarget).build(); // no preferredLinkage, shared flavor BuildTarget fooLibTarget = BuildTargetFactory.newInstance("//foo:lib#" + CxxDescriptionEnhancer.SHARED_FLAVOR); TargetNode<?, ?> fooLibNode = AppleLibraryBuilder.createBuilder(fooLibTarget) .setDeps(ImmutableSortedSet.of(sharedResourceTarget)) .build(); // shared preferredLinkage, no flavor BuildTarget foo2LibTarget = BuildTargetFactory.newInstance("//foo2:lib"); TargetNode<?, ?> foo2LibNode = AppleLibraryBuilder.createBuilder(foo2LibTarget) .setDeps(ImmutableSortedSet.of(sharedResourceTarget)) .setPreferredLinkage(NativeLinkable.Linkage.SHARED) .build(); BuildTarget fooFrameworkTarget = BuildTargetFactory.newInstance("//foo:framework#default"); TargetNode<?, ?> fooFrameworkNode = AppleBundleBuilder.createBuilder(fooFrameworkTarget) .setExtension(Either.ofLeft(AppleBundleExtension.FRAMEWORK)) .setBinary(fooLibTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); // shared preferredLinkage overriden by static flavor should still propagate dependencies. BuildTarget staticResourceTarget = BuildTargetFactory.newInstance("//static:resource"); TargetNode<?, ?> staticResourceNode = AppleResourceBuilder.createBuilder(staticResourceTarget).build(); BuildTarget bazLibTarget = BuildTargetFactory.newInstance("//baz:lib#" + CxxDescriptionEnhancer.STATIC_FLAVOR); TargetNode<?, ?> bazLibNode = AppleLibraryBuilder.createBuilder(bazLibTarget) .setDeps(ImmutableSortedSet.of(staticResourceTarget)) .setPreferredLinkage(NativeLinkable.Linkage.SHARED) .build(); BuildTarget barBinaryTarget = BuildTargetFactory.newInstance("//bar:binary"); TargetNode<?, ?> barBinaryNode = AppleBinaryBuilder.createBuilder(barBinaryTarget) .setDeps(ImmutableSortedSet.of(fooLibTarget, foo2LibTarget, bazLibTarget)) .build(); BuildTarget barAppTarget = BuildTargetFactory.newInstance("//bar:app"); TargetNode<?, ?> barAppNode = AppleBundleBuilder.createBuilder(barAppTarget) .setExtension(Either.ofLeft(AppleBundleExtension.APP)) .setBinary(barBinaryTarget) .setDeps(ImmutableSortedSet.of(fooFrameworkTarget)) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); ImmutableSet<TargetNode<?, ?>> targetNodes = ImmutableSet.<TargetNode<?, ?>>builder() .add( sharedResourceNode, staticResourceNode, fooLibNode, foo2LibNode, bazLibNode, fooFrameworkNode, barBinaryNode, barAppNode) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(targetNodes); Optional<AppleDependenciesCache> cache = useCache ? Optional.of(new AppleDependenciesCache(targetGraph)) : Optional.empty(); for (int i = 0; i < (useCache ? 2 : 1); i++) { Iterable<TargetNode<?, ?>> rules = AppleBuildRules.getRecursiveTargetNodeDependenciesOfTypes( targetGraph, cache, AppleBuildRules.RecursiveDependenciesMode.COPYING, fooFrameworkNode, IS_APPLE_BUNDLE_RESOURCE_NODE); assertEquals(ImmutableSortedSet.of(sharedResourceNode), ImmutableSortedSet.copyOf(rules)); rules = AppleBuildRules.getRecursiveTargetNodeDependenciesOfTypes( targetGraph, cache, AppleBuildRules.RecursiveDependenciesMode.COPYING, barAppNode, IS_APPLE_BUNDLE_RESOURCE_NODE); assertEquals(ImmutableSortedSet.of(staticResourceNode), ImmutableSortedSet.copyOf(rules)); } } @Test public void exportedDepsAreCollectedForCopying() throws Exception { BuildTarget fooLibTarget = BuildTargetFactory.newInstance("//foo:lib#" + CxxDescriptionEnhancer.SHARED_FLAVOR); TargetNode<?, ?> fooLibNode = AppleLibraryBuilder.createBuilder(fooLibTarget).build(); BuildTarget fooFrameworkTarget = BuildTargetFactory.newInstance("//foo:framework"); TargetNode<?, ?> fooFrameworkNode = AppleBundleBuilder.createBuilder(fooFrameworkTarget) .setExtension(Either.ofLeft(AppleBundleExtension.FRAMEWORK)) .setBinary(fooLibTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); BuildTarget barLibTarget = BuildTargetFactory.newInstance("//bar:lib#" + CxxDescriptionEnhancer.SHARED_FLAVOR); TargetNode<?, ?> barLibNode = AppleLibraryBuilder.createBuilder(barLibTarget) .setDeps(ImmutableSortedSet.of(fooFrameworkTarget)) .setExportedDeps(ImmutableSortedSet.of(fooFrameworkTarget)) .build(); BuildTarget barFrameworkTarget = BuildTargetFactory.newInstance("//bar:framework"); TargetNode<?, ?> barFrameworkNode = AppleBundleBuilder.createBuilder(barFrameworkTarget) .setExtension(Either.ofLeft(AppleBundleExtension.FRAMEWORK)) .setBinary(barLibTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); BuildTarget bazLibTarget = BuildTargetFactory.newInstance("//baz:lib#" + CxxDescriptionEnhancer.SHARED_FLAVOR); TargetNode<?, ?> bazLibNode = AppleLibraryBuilder.createBuilder(bazLibTarget) .setDeps(ImmutableSortedSet.of(barFrameworkTarget)) .build(); BuildTarget bazFrameworkTarget = BuildTargetFactory.newInstance("//baz:framework"); TargetNode<?, ?> bazFrameworkNode = AppleBundleBuilder.createBuilder(bazFrameworkTarget) .setExtension(Either.ofLeft(AppleBundleExtension.FRAMEWORK)) .setBinary(bazLibTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); ImmutableSet<TargetNode<?, ?>> targetNodes = ImmutableSet.<TargetNode<?, ?>>builder() .add( fooLibNode, fooFrameworkNode, barLibNode, barFrameworkNode, bazLibNode, bazFrameworkNode) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(targetNodes); Optional<AppleDependenciesCache> cache = useCache ? Optional.of(new AppleDependenciesCache(targetGraph)) : Optional.empty(); for (int i = 0; i < (useCache ? 2 : 1); i++) { Iterable<TargetNode<?, ?>> rules = AppleBuildRules.getRecursiveTargetNodeDependenciesOfTypes( targetGraph, cache, AppleBuildRules.RecursiveDependenciesMode.COPYING, bazFrameworkNode, Optional.empty()); assertEquals( ImmutableSortedSet.of(barFrameworkNode, fooFrameworkNode), ImmutableSortedSet.copyOf(rules)); } } @Test public void linkingStopsAtGenruleDep() throws Exception { // Pass a random static lib in a genrule and make sure a framework // depending on the genrule doesn't link against or copy in the static lib. BuildTarget fooLibTarget = BuildTargetFactory.newInstance("//foo:lib"); TargetNode<?, ?> fooLibNode = AppleLibraryBuilder.createBuilder(fooLibTarget).build(); BuildTarget fooGenruleTarget = BuildTargetFactory.newInstance("//foo:genrule"); TargetNode<?, ?> fooGenruleNode = GenruleBuilder.newGenruleBuilder(fooGenruleTarget) .setOut("foo") .setCmd("echo hi > $OUT") .setSrcs(ImmutableList.of(new DefaultBuildTargetSourcePath(fooLibTarget))) .build(); BuildTarget barLibTarget = BuildTargetFactory.newInstance("//bar:lib#" + CxxDescriptionEnhancer.SHARED_FLAVOR); TargetNode<?, ?> barLibNode = AppleLibraryBuilder.createBuilder(barLibTarget) .setDeps(ImmutableSortedSet.of(fooGenruleTarget)) .build(); BuildTarget barFrameworkTarget = BuildTargetFactory.newInstance("//bar:framework"); TargetNode<?, ?> barFrameworkNode = AppleBundleBuilder.createBuilder(barFrameworkTarget) .setExtension(Either.ofLeft(AppleBundleExtension.FRAMEWORK)) .setBinary(barLibTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); ImmutableSet<TargetNode<?, ?>> targetNodes = ImmutableSet.<TargetNode<?, ?>>builder() .add(fooLibNode, fooGenruleNode, barLibNode, barFrameworkNode) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(targetNodes); Optional<AppleDependenciesCache> cache = useCache ? Optional.of(new AppleDependenciesCache(targetGraph)) : Optional.empty(); for (int i = 0; i < (useCache ? 2 : 1); i++) { Iterable<TargetNode<?, ?>> rules = AppleBuildRules.getRecursiveTargetNodeDependenciesOfTypes( targetGraph, cache, AppleBuildRules.RecursiveDependenciesMode.LINKING, barFrameworkNode, Optional.empty()); assertEquals(ImmutableSortedSet.of(fooGenruleNode), ImmutableSortedSet.copyOf(rules)); } } @Test public void copyingStopsAtGenruleDep() throws Exception { // Pass a random static lib in a genrule and make sure a framework // depending on the genrule doesn't link against or copy in the static lib. BuildTarget fooLibTarget = BuildTargetFactory.newInstance("//foo:lib"); TargetNode<?, ?> fooLibNode = AppleLibraryBuilder.createBuilder(fooLibTarget).build(); BuildTarget fooGenruleTarget = BuildTargetFactory.newInstance("//foo:genrule"); TargetNode<?, ?> fooGenruleNode = GenruleBuilder.newGenruleBuilder(fooGenruleTarget) .setOut("foo") .setCmd("echo hi > $OUT") .setSrcs(ImmutableList.of(new DefaultBuildTargetSourcePath(fooLibTarget))) .build(); BuildTarget barLibTarget = BuildTargetFactory.newInstance("//bar:lib#" + CxxDescriptionEnhancer.SHARED_FLAVOR); TargetNode<?, ?> barLibNode = AppleLibraryBuilder.createBuilder(barLibTarget) .setDeps(ImmutableSortedSet.of(fooGenruleTarget)) .build(); BuildTarget barFrameworkTarget = BuildTargetFactory.newInstance("//bar:framework"); TargetNode<?, ?> barFrameworkNode = AppleBundleBuilder.createBuilder(barFrameworkTarget) .setExtension(Either.ofLeft(AppleBundleExtension.FRAMEWORK)) .setBinary(barLibTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); ImmutableSet<TargetNode<?, ?>> targetNodes = ImmutableSet.<TargetNode<?, ?>>builder() .add(fooLibNode, fooGenruleNode, barLibNode, barFrameworkNode) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(targetNodes); Optional<AppleDependenciesCache> cache = useCache ? Optional.of(new AppleDependenciesCache(targetGraph)) : Optional.empty(); for (int i = 0; i < (useCache ? 2 : 1); i++) { Iterable<TargetNode<?, ?>> rules = AppleBuildRules.getRecursiveTargetNodeDependenciesOfTypes( targetGraph, cache, AppleBuildRules.RecursiveDependenciesMode.COPYING, barFrameworkNode, Optional.empty()); assertEquals(ImmutableSortedSet.of(fooGenruleNode), ImmutableSortedSet.copyOf(rules)); } } @Test public void buildingStopsAtGenruleDepButNotAtBundleDep() throws Exception { // Pass a random static lib in a genrule and make sure a framework // depending on the genrule doesn't build the dependencies of that genrule. BuildTarget fooLibTarget = BuildTargetFactory.newInstance("//foo:lib"); TargetNode<?, ?> fooLibNode = AppleLibraryBuilder.createBuilder(fooLibTarget).build(); BuildTarget fooGenruleTarget = BuildTargetFactory.newInstance("//foo:genrule"); TargetNode<?, ?> fooGenruleNode = GenruleBuilder.newGenruleBuilder(fooGenruleTarget) .setOut("foo") .setCmd("echo hi > $OUT") .setSrcs(ImmutableList.of(new DefaultBuildTargetSourcePath(fooLibTarget))) .build(); BuildTarget barLibTarget = BuildTargetFactory.newInstance("//bar:lib#" + CxxDescriptionEnhancer.SHARED_FLAVOR); TargetNode<?, ?> barLibNode = AppleLibraryBuilder.createBuilder(barLibTarget) .setDeps(ImmutableSortedSet.of(fooGenruleTarget)) .build(); BuildTarget barFrameworkTarget = BuildTargetFactory.newInstance("//bar:framework"); TargetNode<?, ?> barFrameworkNode = AppleBundleBuilder.createBuilder(barFrameworkTarget) .setExtension(Either.ofLeft(AppleBundleExtension.FRAMEWORK)) .setBinary(barLibTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); BuildTarget bazLibTarget = BuildTargetFactory.newInstance("//baz:lib#" + CxxDescriptionEnhancer.SHARED_FLAVOR); TargetNode<?, ?> bazLibNode = AppleLibraryBuilder.createBuilder(bazLibTarget) .setDeps(ImmutableSortedSet.of(barFrameworkTarget)) .build(); BuildTarget bazFrameworkTarget = BuildTargetFactory.newInstance("//baz:framework"); TargetNode<?, ?> bazFrameworkNode = AppleBundleBuilder.createBuilder(bazFrameworkTarget) .setExtension(Either.ofLeft(AppleBundleExtension.FRAMEWORK)) .setBinary(bazLibTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); ImmutableSet<TargetNode<?, ?>> targetNodes = ImmutableSet.<TargetNode<?, ?>>builder() .add( fooLibNode, fooGenruleNode, barLibNode, barFrameworkNode, bazLibNode, bazFrameworkNode) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(targetNodes); Optional<AppleDependenciesCache> cache = useCache ? Optional.of(new AppleDependenciesCache(targetGraph)) : Optional.empty(); for (int i = 0; i < (useCache ? 2 : 1); i++) { Iterable<TargetNode<?, ?>> rules = AppleBuildRules.getRecursiveTargetNodeDependenciesOfTypes( targetGraph, cache, AppleBuildRules.RecursiveDependenciesMode.BUILDING, bazFrameworkNode, Optional.empty()); assertEquals( ImmutableSortedSet.of(barFrameworkNode, fooGenruleNode), ImmutableSortedSet.copyOf(rules)); } } @Test public void testDependenciesCache() throws Exception { BuildTarget libraryTarget = BuildTargetFactory.newInstance("//foo:lib"); TargetNode<?, ?> libraryNode = AppleLibraryBuilder.createBuilder(libraryTarget).build(); BuildTarget bundleTarget = BuildTargetFactory.newInstance("//foo:bundle"); TargetNode<?, ?> bundleNode = AppleBundleBuilder.createBuilder(bundleTarget) .setExtension(Either.ofLeft(AppleBundleExtension.XCTEST)) .setBinary(libraryTarget) .setInfoPlist(new FakeSourcePath("Info.plist")) .build(); BuildTarget rootTarget = BuildTargetFactory.newInstance("//foo:root"); TargetNode<?, ?> rootNode = AppleLibraryBuilder.createBuilder(rootTarget) .setDeps(ImmutableSortedSet.of(libraryTarget, bundleTarget)) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(ImmutableSet.of(libraryNode, bundleNode, rootNode)); AppleDependenciesCache cache = new AppleDependenciesCache(targetGraph); ImmutableSortedSet<TargetNode<?, ?>> cachedDefaultDeps = cache.getDefaultDeps(rootNode); ImmutableSortedSet<TargetNode<?, ?>> cachedExportedDeps = cache.getExportedDeps(rootNode); assertEquals(cachedDefaultDeps, ImmutableSortedSet.of(bundleNode, libraryNode)); assertEquals(cachedExportedDeps, ImmutableSortedSet.of()); ImmutableSortedSet<TargetNode<?, ?>> defaultDeps = cache.getDefaultDeps(rootNode); ImmutableSortedSet<TargetNode<?, ?>> exportedDeps = cache.getExportedDeps(rootNode); assertSame(cachedDefaultDeps, defaultDeps); assertSame(cachedExportedDeps, exportedDeps); } }