diff options
author | 2017-07-05 18:03:47 -0400 | |
---|---|---|
committer | 2017-07-06 07:14:09 -0400 | |
commit | 478f763599828f88724ee8b3e59f38539cbdd73d (patch) | |
tree | cb3f07a7e5ac4b8590a5331e494ed4f4f0be85fb /src/test/java/com/google/devtools/build/lib/rules/objc/IosApplicationTest.java | |
parent | 6508e317b76ef2f26cff5d95a4a82c13a1913b78 (diff) |
Open source unit tests for the objc rules.
PiperOrigin-RevId: 161010594
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/rules/objc/IosApplicationTest.java')
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/rules/objc/IosApplicationTest.java | 1175 |
1 files changed, 1175 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/IosApplicationTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/IosApplicationTest.java new file mode 100644 index 0000000000..a7dda26d2a --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/rules/objc/IosApplicationTest.java @@ -0,0 +1,1175 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// 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.google.devtools.build.lib.rules.objc; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.ReleaseBundlingRule.APP_ICON_ATTR; +import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.ReleaseBundlingRule.LAUNCH_IMAGE_ATTR; + +import com.google.common.base.Function; +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.ImmutableMultiset; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Multiset; +import com.google.devtools.build.lib.actions.Action; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.CommandAction; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.FileProvider; +import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.RunfilesProvider; +import com.google.devtools.build.lib.analysis.actions.SpawnAction; +import com.google.devtools.build.lib.analysis.config.BuildConfiguration; +import com.google.devtools.build.lib.rules.apple.AppleConfiguration; +import com.google.devtools.build.lib.rules.apple.AppleConfiguration.ConfigurationDistinguisher; +import com.google.devtools.build.lib.rules.apple.DottedVersion; +import com.google.devtools.build.lib.testutil.Scratch; +import com.google.devtools.build.xcode.bundlemerge.proto.BundleMergeProtos; +import com.google.devtools.build.xcode.bundlemerge.proto.BundleMergeProtos.BundleFile; +import com.google.devtools.build.xcode.plmerge.proto.PlMergeProtos; +import java.io.IOException; +import java.util.List; +import java.util.Set; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Test case for ios_application. */ +@RunWith(JUnit4.class) +public class IosApplicationTest extends ObjcRuleTestCase { + protected static final RuleType RULE_TYPE = + new RuleType("ios_application") { + @Override + Iterable<String> requiredAttributes( + Scratch scratch, String packageDir, Set<String> alreadyAdded) throws IOException { + ImmutableList.Builder<String> attributes = new ImmutableList.Builder<>(); + if (!alreadyAdded.contains("binary")) { + scratch.file(packageDir + "/bin/a.m"); + scratch.file(packageDir + "/bin/BUILD", "objc_binary(name = 'bin', srcs = ['a.m'])"); + attributes.add("binary = '//" + packageDir + "/bin:bin'"); + } + return attributes.build(); + } + }; + + protected static final BinaryRuleTypePair RULE_TYPE_PAIR = + new BinaryRuleTypePair( + ObjcBinaryTest.RULE_TYPE, RULE_TYPE, ReleaseBundlingSupport.APP_BUNDLE_DIR_FORMAT); + + private ConfiguredTarget addMockAppAndLibs(String... extraAppAttributes) + throws Exception { + createLibraryTargetWriter("//lib1:lib1") + .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") + .setAndCreateFiles("hdrs", "hdr.h") + .write(); + createLibraryTargetWriter("//lib2:lib2") + .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") + .setAndCreateFiles("hdrs", "hdr.h") + .write(); + scratch.file("x/a.m"); + scratch.file("x/x-Info.plist"); + scratch.file("x/BUILD", + "objc_binary(", + " name = 'bin',", + " srcs = ['a.m'],", + " deps = ['//lib1:lib1', '//lib2:lib2'],", + ")", + "", + "ios_application(", + " name = 'x',", + " binary = ':bin',", + Joiner.on(',').join(extraAppAttributes), + ")"); + return getConfiguredTarget("//x:x"); + } + + @Test + public void testSplitConfigurationProviders() throws Exception { + useConfiguration("--ios_multi_cpus=i386,x86_64"); + scratch.file("x/BUILD", + "objc_binary(", + " name = 'bin',", + " srcs = ['a.m'],", + ")", + "", + "ios_application(", + " name = 'x',", + " infoplist = 'Info.plist',", + " binary = ':bin',", + ")"); + RuleContext ruleContext = getRuleContext(getConfiguredTarget("//x:x")); + ImmutableListMultimap<BuildConfiguration, ObjcProvider> prereqByConfig = + ruleContext.getPrerequisitesByConfiguration("binary", Mode.SPLIT, ObjcProvider.class); + List<String> childCpus = Lists.transform(prereqByConfig.keySet().asList(), + new Function<BuildConfiguration, String>() { + @Override + public String apply(BuildConfiguration config) { + return config.getFragment(AppleConfiguration.class).getIosCpu(); + } + }); + assertThat(childCpus).containsExactly("i386", "x86_64"); + } + + @Test + public void testRunfiles() throws Exception { + ConfiguredTarget application = addMockAppAndLibs(); + RunfilesProvider runfiles = application.getProvider(RunfilesProvider.class); + assertThat(runfiles.getDefaultRunfiles().getArtifacts()).isEmpty(); + assertThat(Artifact.toRootRelativePaths(runfiles.getDataRunfiles().getArtifacts())) + .containsExactly("x/x.ipa"); + } + + @Test + public void testFilesToRun() throws Exception { + checkFilesToRun(RULE_TYPE); + } + + @Test + public void testNoRunfilesSupportForDevice() throws Exception { + checkNoRunfilesSupportForDevice(RULE_TYPE); + } + + @Test + public void testGenerateRunnerScriptAction() throws Exception { + checkGenerateRunnerScriptAction(RULE_TYPE); + } + + @Test + public void testGenerateRunnerScriptAction_escaped() throws Exception { + checkGenerateRunnerScriptAction_escaped(RULE_TYPE); + } + + @Test + public void testSigningAction() throws Exception { + checkDeviceSigningAction(RULE_TYPE); + } + + @Test + public void testSigningWithCertName() throws Exception { + checkSigningWithCertName(RULE_TYPE); + } + + @Test + public void testPostProcessingAction() throws Exception { + checkPostProcessingAction(RULE_TYPE); + } + + @Test + public void testSigningAndPostProcessing() throws Exception { + checkSigningAndPostProcessing(RULE_TYPE); + } + + @Test + public void testSigning_simulatorBuild() throws Exception { + checkSigningSimulatorBuild(RULE_TYPE_PAIR, false); + } + + @Test + public void testSigning_simulatorBuild_multiCpu() throws Exception { + checkSigningSimulatorBuild(RULE_TYPE_PAIR, true); + } + + @Test + public void testProvisioningProfile_deviceBuild() throws Exception { + checkProvisioningProfileDeviceBuild(RULE_TYPE_PAIR, false); + } + + @Test + public void testProvisioningProfile_deviceBuild_multiCpu() throws Exception { + checkProvisioningProfileDeviceBuild(RULE_TYPE_PAIR, true); + } + + @Test + public void testUserSpecifiedProvisioningProfile_deviceBuild() throws Exception { + checkProvisioningProfileUserSpecified(RULE_TYPE_PAIR, false); + } + + @Test + public void testUserSpecifiedProvisioningProfile_deviceBuild_multiCpu() throws Exception { + checkProvisioningProfileUserSpecified(RULE_TYPE_PAIR, true); + } + + @Test + public void testMergeControlAction() throws Exception { + addMockAppAndLibs("infoplist = 'Info.plist'"); + Action mergeAction = bundleMergeAction("//x:x"); + Action action = bundleMergeControlAction("//x:x"); + assertThat(action.getInputs()).isEmpty(); + assertThat(Artifact.toRootRelativePaths(action.getOutputs())) + .containsExactly("x/x.ipa-control"); + assertThat(bundleMergeControl("//x:x")) + .isEqualTo( + BundleMergeProtos.Control.newBuilder() + .addBundleFile( + BundleFile.newBuilder() + .setSourceFile(execPathEndingWith(mergeAction.getInputs(), "x_lipobin")) + .setBundlePath("x") + .setExternalFileAttribute(BundleableFile.EXECUTABLE_EXTERNAL_FILE_ATTRIBUTE) + .build()) + .setBundleRoot(String.format(ReleaseBundlingSupport.APP_BUNDLE_DIR_FORMAT, "x")) + .setBundleInfoPlistFile(execPathEndingWith(mergeAction.getInputs(), "Info.plist")) + .setOutFile(execPathEndingWith(mergeAction.getOutputs(), "x.unprocessed.ipa")) + .setMinimumOsVersion(DEFAULT_IOS_SDK_VERSION.toString()) + .setSdkVersion(DEFAULT_IOS_SDK_VERSION.toString()) + .setPlatform("IOS_SIMULATOR") + .setFallbackBundleIdentifier("example.x") + .build()); + } + + @Test + public void testMergeBundleAction() throws Exception { + checkMergeBundleAction(RULE_TYPE_PAIR); + } + + @Test + public void testCheckPrimaryBundleIdInMergedPlist() throws Exception { + checkPrimaryBundleIdInMergedPlist(RULE_TYPE_PAIR); + } + + @Test + public void testCheckFallbackBundleIdInMergedPlist() throws Exception { + checkFallbackBundleIdInMergedPlist(RULE_TYPE_PAIR); + } + + @Test + public void testErrorForLaunchImageGivenWithNoAssetCatalog() throws Exception { + checkAssetCatalogAttributeError(RULE_TYPE, LAUNCH_IMAGE_ATTR); + } + + @Test + public void testErrorForAppIconGivenWithNoAssetCatalog() throws Exception { + checkAssetCatalogAttributeError(RULE_TYPE, APP_ICON_ATTR); + } + + @Test + public void testCollectsAssetCatalogsTransitively() throws Exception { + checkCollectsAssetCatalogsTransitively(RULE_TYPE_PAIR); + } + + @Test + public void testSpecifyAppIconAndLaunchImageUsingXcassetsOfDependency() throws Exception { + checkSpecifyAppIconAndLaunchImageUsingXcassetsOfDependency( + RULE_TYPE_PAIR, DEFAULT_IOS_SDK_VERSION); + } + + private void addTargetWithAssetCatalogs() throws IOException { + scratch.file("x/foo.xcassets/foo"); + scratch.file("x/foo.xcassets/bar"); + scratch.file("x/a.m"); + scratch.file("x/BUILD", + "objc_binary(", + " name = 'bin',", + " asset_catalogs = ['foo.xcassets/foo', 'bar.xcassets/bar'],", + " srcs = ['a.m'],", + ")", + "", + "ios_application(", + " name = 'x',", + " binary = ':bin',", + ")"); + } + + @Test + public void testActoolAction() throws Exception { + addTargetWithAssetCatalogs(); + checkActoolActionCorrectness(DEFAULT_IOS_SDK_VERSION); + } + + @Test + public void testPassesFamiliesToActool() throws Exception { + checkPassesFamiliesToActool(RULE_TYPE_PAIR); + } + + @Test + public void testPassesFamiliesToIbtool() throws Exception { + checkPassesFamiliesToIbtool(RULE_TYPE_PAIR); + } + + @Test + public void testReportsErrorsForInvalidFamiliesAttribute() throws Exception { + checkReportsErrorsForInvalidFamiliesAttribute(RULE_TYPE); + } + + @Test + public void testMergeActionsWithAssetCatalog() throws Exception { + // TODO(matvore): add this test to IosTestTest.java. + addTargetWithAssetCatalogs(); + checkMergeActionsWithAssetCatalog(RULE_TYPE_PAIR); + } + + private void addBinAndLibWithRawResources() throws Exception { + addBinAndLibWithResources( + "resources", "resource1.txt", "ja.lproj/resource2.txt", "objc_binary"); + scratch.file("x/BUILD", + "ios_application(", + " name = 'x',", + " binary = '//bin:bin',", + ")"); + } + + private void addBinAndLibWithStrings() throws Exception { + addBinAndLibWithResources( + "strings", "foo.strings", "ja.lproj/bar.strings", "objc_binary"); + scratch.file("x/BUILD", + "ios_application(", + " name = 'x',", + " binary = '//bin:bin',", + ")"); + } + + @Test + public void testCollectsRawResourceFilesTransitively() throws Exception { + addBinAndLibWithRawResources(); + checkCollectsResourceFilesTransitively( + "//x:x", + ImmutableList.of("lib/resource1.txt", "bin/ja.lproj/resource2.txt"), + ImmutableList.of("lib/resource1.txt"), + ImmutableSetMultimap.<String, Multiset<String>>of( + "bin_bin", + ImmutableMultiset.of("bin/ja.lproj/resource2.txt", "lib/resource1.txt"), + "bin_static_lib_bin", + ImmutableMultiset.of("bin/ja.lproj/resource2.txt", "lib/resource1.txt"), + "x_x", + ImmutableMultiset.of("bin/ja.lproj/resource2.txt", "lib/resource1.txt"), + "lib_lib", + ImmutableMultiset.of("lib/resource1.txt"))); + } + + @Test + public void testCollectsStringsFilesTransitively() throws Exception { + addBinAndLibWithStrings(); + checkCollectsResourceFilesTransitively( + "//x:x", + ImmutableList.of("x/lib/foo.strings.binary", "x/bin/ja.lproj/bar.strings.binary"), + ImmutableList.of("x/lib/foo.strings.binary"), + ImmutableSetMultimap.<String, Multiset<String>>of( + "bin_bin", + ImmutableMultiset.of("bin/ja.lproj/bar.strings", "lib/foo.strings"), + "bin_static_lib_bin", + ImmutableMultiset.of("bin/ja.lproj/bar.strings", "lib/foo.strings"), + "x_x", + ImmutableMultiset.of("bin/ja.lproj/bar.strings", "lib/foo.strings"), + "lib_lib", + ImmutableMultiset.of("lib/foo.strings"))); + } + + @Test + public void testResourceFilesMergedInBundle() throws Exception { + addBinAndLibWithRawResources(); + checkBundleablesAreMerged("//x:x", + ImmutableListMultimap.of( + "resource1.txt", "resource1.txt", + "ja.lproj/resource2.txt", "ja.lproj/resource2.txt")); + } + + @Test + public void testResourceFlattenedInBundle() throws Exception { + addBinAndLibWithResources( + "resources", "libres/resource1.txt", "binres/resource2.txt", "objc_binary"); + scratch.file("x/BUILD", + "ios_application(", + " name = 'x',", + " binary = '//bin:bin',", + ")"); + checkBundleablesAreMerged("//x:x", + ImmutableListMultimap.of( + "libres/resource1.txt", "resource1.txt", + "binres/resource2.txt", "resource2.txt")); + } + + @Test + public void testStructuredResourceFilesMergedInBundle() throws Exception { + addBinAndLibWithResources( + "structured_resources", "libres/resource1.txt", "binres/resource2.txt", "objc_binary"); + scratch.file("x/BUILD", + "ios_application(", + " name = 'x',", + " binary = '//bin:bin',", + ")"); + checkBundleablesAreMerged("//x:x", + ImmutableListMultimap.of( + "libres/resource1.txt", "libres/resource1.txt", + "binres/resource2.txt", "binres/resource2.txt")); + } + + @Test + public void testStringsFilesMergedInBundle() throws Exception { + addBinAndLibWithStrings(); + checkBundleablesAreMerged("//x:x", + ImmutableListMultimap.of( + "foo.strings.binary", "foo.strings", + "ja.lproj/bar.strings.binary", "ja.lproj/bar.strings")); + } + + @Test + public void testMergesXcdatamodelZips() throws Exception { + checkMergesXcdatamodelZips(RULE_TYPE_PAIR); + } + + @Test + public void testPlistRequiresDotInName() throws Exception { + checkError("x", "x", + "'//x:Infoplist' does not produce any ios_application infoplist files (expected .plist)", + "objc_binary(", + " name = 'bin',", + " srcs = ['a.m'],", + ")", + "", + "ios_application(", + " name = 'x',", + " infoplist = 'Infoplist',", + " binary = ':bin',", + ")"); + } + + @Test + public void testPopulatesBundling() throws Exception { + scratch.file("x/x-Info.plist"); + scratch.file("x/a.m"); + scratch.file("x/assets.xcassets/1"); + scratch.file("x/BUILD", + "objc_binary(", + " name = 'bin',", + " srcs = ['a.m'],", + " asset_catalogs = ['assets.xcassets/1']", + ")", + "ios_application(", + " name = 'x',", + " binary = ':bin',", + " infoplist = 'x-Info.plist',", + ")"); + + PlMergeProtos.Control control = plMergeControl("//x:x"); + assertThat(control.getSourceFileList()) + .contains(getSourceArtifact("x/x-Info.plist").getExecPathString()); + + Artifact actoolzipOutput = getBinArtifact("x.actool.zip", "//x:x"); + assertThat(getGeneratingAction(actoolzipOutput).getInputs()) + .contains(getSourceArtifact("x/assets.xcassets/1")); + } + + @Test + public void testMergesPartialInfoplists() throws Exception { + checkMergesPartialInfoplists(RULE_TYPE_PAIR); + } + + @Test + public void testNibZipsMergedIntoBundle() throws Exception { + checkNibZipsMergedIntoBundle(RULE_TYPE_PAIR); + } + + @Test + public void testNoEntitlementsDefined() throws Exception { + checkNoEntitlementsDefined(RULE_TYPE); + } + + @Test + public void testEntitlementsDefined() throws Exception { + checkEntitlementsDefined(RULE_TYPE); + } + + @Test + public void testExtraEntitlements() throws Exception { + checkExtraEntitlements(RULE_TYPE); + } + + @Test + public void testDebugEntitlements() throws Exception { + checkDebugEntitlements(RULE_TYPE); + } + + @Test + public void testFastbuildDebugEntitlements() throws Exception { + checkFastbuildDebugEntitlements(RULE_TYPE); + } + + @Test + public void testOptNoDebugEntitlements() throws Exception { + checkOptNoDebugEntitlements(RULE_TYPE); + } + + @Test + public void testExplicitNoDebugEntitlements() throws Exception { + checkExplicitNoDebugEntitlements(RULE_TYPE); + } + + @Test + public void testMultiPlatformBuild_fails() throws Exception { + checkBinaryActionMultiPlatform_fails(RULE_TYPE_PAIR); + } + + @Test + public void testMultiArchitectureResources() throws Exception { + checkMultiCpuResourceInheritance(RULE_TYPE_PAIR); + } + + /** + * Regression test for b/27946171. Verifies that nodistinct_host_configuration functions in + * builds with more than one split transition. (In this case, both ios_application and + * ios_extension split into two child configurations.) + */ + @Test + public void testNoDistinctHostConfiguration() throws Exception { + useConfiguration("--ios_multi_cpus=i386,x86_64", "--nodistinct_host_configuration"); + scratch.file("x/BUILD", + "ios_extension_binary(", + " name = 'ext_bin',", + " srcs = ['ebin.m'],", + ")", + "", + "ios_extension(", + " name = 'ext',", + " binary = ':ext_bin',", + ")", + "", + "objc_binary(", + " name = 'bin',", + " srcs = ['bin.m'],", + ")", + "", + "ios_application(", + " name = 'app',", + " binary = ':bin',", + " extensions = [':ext'],", + ")"); + + getConfiguredTarget("//x:app"); + + // Assert that only the deprecation warnings are emitted, but no other events. + assertContainsEventWithFrequency( + "This rule is deprecated. Please use the new Apple build rules " + + "(https://github.com/bazelbuild/rules_apple) to build Apple targets.", + 4); + } + + @Test + public void testApplicationExtensionSharedDependencyResourceActions() throws Exception { + useConfiguration("--ios_multi_cpus=i386,x86_64"); + scratch.file("x/BUILD", + "objc_library(", + " name = 'res',", + " xibs = ['interface.xib'],", + " storyboards = ['story.storyboard'],", + " datamodels = ['data.xcdatamodel/1'],", + " asset_catalogs = ['assets.xcassets/foo'],", + ")", + "", + "ios_extension_binary(", + " name = 'ext_bin',", + " srcs = ['ebin.m'],", + " deps = [':res'],", + ")", + "", + "ios_extension(", + " name = 'ext',", + " binary = ':ext_bin',", + ")", + "", + "objc_binary(", + " name = 'bin',", + " srcs = ['bin.m'],", + " deps = [':res'],", + ")", + "", + "ios_application(", + " name = 'app',", + " binary = ':bin',", + " extensions = [':ext'],", + ")"); + + Action appIpaAction = bundleMergeAction("//x:app"); + + Action extIpaAction = bundleMergeAction("//x:ext"); + + Artifact appNibZip = Iterables.getOnlyElement(inputsEndingWith(appIpaAction, "nib.zip")); + Artifact extNibZip = Iterables.getOnlyElement(inputsEndingWith(extIpaAction, "nib.zip")); + assertThat(appNibZip.getExecPath()).isNotEqualTo(extNibZip.getExecPath()); + + Artifact appStoryboardZip = + Iterables.getOnlyElement(inputsEndingWith(appIpaAction, "story.storyboard.zip")); + Artifact extStoryboardZip = + Iterables.getOnlyElement(inputsEndingWith(extIpaAction, "story.storyboard.zip")); + assertThat(appStoryboardZip.getExecPath()).isNotEqualTo(extStoryboardZip.getExecPath()); + + Artifact appDatamodelZip = Iterables.getOnlyElement(inputsEndingWith(appIpaAction, "data.zip")); + Artifact extDatamodelZip = Iterables.getOnlyElement(inputsEndingWith(extIpaAction, "data.zip")); + assertThat(appDatamodelZip.getExecPath()).isNotEqualTo(extDatamodelZip.getExecPath()); + + Artifact appAssetZip = Iterables.getOnlyElement(inputsEndingWith(appIpaAction, "actool.zip")); + Artifact extAssetZip = Iterables.getOnlyElement(inputsEndingWith(extIpaAction, "actool.zip")); + assertThat(appAssetZip.getExecPath()).isNotEqualTo(extAssetZip.getExecPath()); + } + + @Test + public void testMultiCpuCompiledResources() throws Exception { + checkMultiCpuCompiledResources(RULE_TYPE_PAIR); + } + + @Test + public void testMomczipActions() throws Exception { + checkMomczipActions(RULE_TYPE_PAIR, DEFAULT_IOS_SDK_VERSION); + } + + @Test + public void testConvertStringsActions() throws Exception { + checkConvertStringsAction(RULE_TYPE_PAIR); + } + + @Test + public void testCompileXibActions() throws Exception { + checkCompileXibActions(RULE_TYPE_PAIR, DEFAULT_IOS_SDK_VERSION, "iphone"); + } + + @Test + public void testRegistersStoryboardCompileActions() throws Exception { + checkRegistersStoryboardCompileActions(RULE_TYPE_PAIR, DEFAULT_IOS_SDK_VERSION, "iphone"); + } + + @Test + public void testMultiCpuCompiledResourcesFromGenrule() throws Exception { + checkMultiCpuCompiledResourcesFromGenrule(RULE_TYPE_PAIR); + } + + @Test + public void testMultiCpuGeneratedResourcesFromGenrule() throws Exception { + checkMultiCpuGeneratedResourcesFromGenrule(RULE_TYPE_PAIR); + } + + @Test + public void testTwoStringsOneBundlePath() throws Exception { + //TODO(bazel-team): This error should be on //x:x but shows up on :bin right now until that + // doesn't support bundling anymore. + checkTwoStringsOneBundlePath(RULE_TYPE_PAIR, "bin"); + } + + @Test + public void testTwoResourcesOneBundlePath() throws Exception { + //TODO(bazel-team): This error should be on //x:x but shows up on :bin right now until that + // doesn't support bundling anymore. + checkTwoResourcesOneBundlePath(RULE_TYPE_PAIR, "bin"); + } + + @Test + public void testSameStringsTwice() throws Exception { + //TODO(bazel-team): This error should be on //x:x but shows up on :bin right now until that + // doesn't support bundling anymore. + checkSameStringsTwice(RULE_TYPE_PAIR, "bin"); + } + + @Test + public void testGenruleWithoutJavaCcDeps() throws Exception { + checkGenruleWithoutJavaCcDependency(RULE_TYPE_PAIR); + } + + @Test + public void testCcDependencyWithProtoDependencyMultiArch() throws Exception { + checkCcDependencyWithProtoDependencyMultiArch( + RULE_TYPE_PAIR, ConfigurationDistinguisher.IOS_APPLICATION); + } + + @Test + public void testAppleSdkVersionEnv() throws Exception { + RULE_TYPE_PAIR.scratchTargets(scratch); + + useConfiguration("--ios_multi_cpus=x86_64,i386"); + SpawnAction action = (SpawnAction) getGeneratingAction( + getBinArtifact("x_lipobin", getConfiguredTarget("//x:x"))); + + assertAppleSdkVersionEnv(action); + } + + @Test + public void testNonDefaultAppleSdkVersionEnv() throws Exception { + RULE_TYPE_PAIR.scratchTargets(scratch); + + useConfiguration("--ios_sdk_version=8.1", "--ios_multi_cpus=x86_64,i386"); + SpawnAction action = (SpawnAction) getGeneratingAction( + getBinArtifact("x_lipobin", getConfiguredTarget("//x:x"))); + + assertAppleSdkVersionEnv(action, "8.1"); + } + + @Test + public void testAppleSdkDefaultPlatformEnv() throws Exception { + RULE_TYPE_PAIR.scratchTargets(scratch); + + useConfiguration("--ios_multi_cpus=x86_64,i386"); + SpawnAction action = (SpawnAction) getGeneratingAction( + getBinArtifact("x_lipobin", getConfiguredTarget("//x:x"))); + + assertAppleSdkPlatformEnv(action, "iPhoneSimulator"); + } + + @Test + public void testAppleSdkDevicePlatformEnv() throws Exception { + RULE_TYPE_PAIR.scratchTargets(scratch); + + useConfiguration("--ios_multi_cpus=arm64,armv7"); + SpawnAction action = (SpawnAction) getGeneratingAction( + getBinArtifact("x_lipobin", getConfiguredTarget("//x:x"))); + + assertAppleSdkPlatformEnv(action, "iPhoneOS"); + } + + @Test + public void testXcodeVersionEnv() throws Exception { + RULE_TYPE_PAIR.scratchTargets(scratch); + + useConfiguration("--xcode_version=5.8", "--ios_multi_cpus=x86_64,i386"); + SpawnAction action = (SpawnAction) getGeneratingAction( + getBinArtifact("x_lipobin", getConfiguredTarget("//x:x"))); + + assertXcodeVersionEnv(action, "5.8"); + } + + @Test + public void testLaunchStoryboardIncluded() throws Exception { + checkLaunchStoryboardIncluded(RULE_TYPE_PAIR); + } + + @Test + public void testLaunchStoryboardXibIncluded() throws Exception { + checkLaunchStoryboardXib(RULE_TYPE_PAIR); + } + + @Test + public void testLaunchStoryboardLproj() throws Exception { + checkLaunchStoryboardLproj(RULE_TYPE_PAIR); + } + + @Test + public void testAutomaticPlistEntries() throws Exception { + checkAutomaticPlistEntries(RULE_TYPE); + } + + @Test + public void testBundleMergeInputContainsPlMergeOutput() throws Exception { + checkBundleMergeInputContainsPlMergeOutput(RULE_TYPE); + } + + @Test + public void testMultipleInfoPlists() throws Exception { + checkMultipleInfoPlists(RULE_TYPE); + } + + @Test + public void testInfoplistAndInfoplistsTogether() throws Exception { + checkInfoplistAndInfoplistsTogether(RULE_TYPE); + } + + @Test + public void testLateLoadedObjcFrameworkInFinalBundle() throws Exception { + scratch.file("x/Foo.framework/Foo"); + scratch.file("x/Foo.framework/Info.plist"); + scratch.file("x/Foo.framework/Headers/Foo.h"); + scratch.file("x/Foo.framework/Resources/bar.png"); + scratch.file( + "x/BUILD", + "objc_framework(", + " name = 'foo_framework',", + " framework_imports = glob(['Foo.framework/**']),", + " is_dynamic = 1,", + ")", + "", + "objc_binary(", + " name = 'bin',", + " srcs = [ 'a.m' ],", + " runtime_deps = [ ':foo_framework' ],", + ")", + "", + "ios_application(", + " name = 'x',", + " binary = ':bin',", + ")"); + + BundleMergeProtos.Control mergeControl = bundleMergeControl("//x:x"); + + assertThat(mergeControl.getBundleFileList()) + .containsAllOf( + BundleFile.newBuilder() + .setBundlePath("Frameworks/Foo.framework/Foo") + .setSourceFile(getSourceArtifact("x/Foo.framework/Foo").getExecPathString()) + .setExternalFileAttribute(BundleableFile.EXECUTABLE_EXTERNAL_FILE_ATTRIBUTE) + .build(), + BundleFile.newBuilder() + .setBundlePath("Frameworks/Foo.framework/Info.plist") + .setSourceFile(getSourceArtifact("x/Foo.framework/Info.plist").getExecPathString()) + .setExternalFileAttribute(BundleableFile.EXECUTABLE_EXTERNAL_FILE_ATTRIBUTE) + .build(), + BundleFile.newBuilder() + .setBundlePath("Frameworks/Foo.framework/Resources/bar.png") + .setSourceFile( + getSourceArtifact("x/Foo.framework/Resources/bar.png").getExecPathString()) + .setExternalFileAttribute(BundleableFile.DEFAULT_EXTERNAL_FILE_ATTRIBUTE) + .build()); + + assertThat(mergeControl.getBundleFileList()) + .doesNotContain( + BundleFile.newBuilder() + .setBundlePath("Frameworks/Foo.framework/Headers/Foo.h") + .setSourceFile( + getSourceArtifact("x/Foo.framework/Headers/Foo.h").getExecPathString()) + .setExternalFileAttribute(BundleableFile.DEFAULT_EXTERNAL_FILE_ATTRIBUTE) + .build()); + } + + @Test + public void testLateloadedObjcFrameworkSigned() throws Exception { + useConfiguration("--cpu=ios_arm64"); + + scratch.file("x/Foo.framework/Foo"); + scratch.file("x/Foo.framework/Info.plist"); + scratch.file("x/Foo.framework/Headers/Foo.h"); + scratch.file("x/Foo.framework/Resources/bar.png"); + scratch.file( + "x/BUILD", + "objc_framework(", + " name = 'foo_framework',", + " framework_imports = glob(['Foo.framework/**']),", + " is_dynamic = 1,", + ")", + "", + "objc_binary(", + " name = 'bin',", + " srcs = [ 'a.m' ],", + " runtime_deps = [ ':foo_framework' ],", + ")", + "", + "ios_application(", + " name = 'x',", + " binary = ':bin',", + ")"); + + SpawnAction signingAction = (SpawnAction) ipaGeneratingAction(); + + assertThat(normalizeBashArgs(signingAction.getArguments())) + .containsAllOf("--sign", "${t}/Payload/x.app/Frameworks/*", "--sign", "${t}/Payload/x.app") + .inOrder(); + } + + @Test + public void aspectOnSplitAttributeRegressionTest() throws Exception { + useConfiguration("--ios_multi_cpus=armv7,arm64"); + scratch.file("x/a.m"); + scratch.file("x/x-Info.plist"); + scratch.file( + "x/extension.bzl", + "def _my_aspect_impl(target, ctx):", + " if type(ctx.rule.attr.binary) != 'list':", + " fail('Expected a list for split')", + " if len(ctx.rule.attr.binary) != 2:", + " fail('Expected 2 items in split')", + " return struct()", + "my_aspect = aspect(_my_aspect_impl)", + "def _my_rule_impl(ctx):", + " pass", + "my_rule = rule(_my_rule_impl, attrs = { 'deps' : attr.label_list(aspects = [my_aspect]) })" + ); + scratch.file("x/BUILD", + "load(':extension.bzl', 'my_rule')", + "objc_binary(name = 'bin', srcs = ['a.m'], )", + "ios_application(name = 'x', binary = ':bin',)", + "my_rule(name = 'y', deps = [ ':x' ])" + ); + getConfiguredTarget("//x:y"); + } + + @Test + public void aspectOnSplitAttributeNoSplitRegressionTest() throws Exception { + useConfiguration("--ios_multi_cpus=arm64"); + scratch.file("x/a.m"); + scratch.file("x/x-Info.plist"); + scratch.file( + "x/extension.bzl", + "def _my_aspect_impl(target, ctx):", + " if type(ctx.rule.attr.binary) != 'list':", + " fail('Expected a list for split')", + " if len(ctx.rule.attr.binary) != 1:", + " fail('Expected 1 items in split')", + " return struct()", + "my_aspect = aspect(_my_aspect_impl)", + "def _my_rule_impl(ctx):", + " pass", + "my_rule = rule(_my_rule_impl, attrs = { 'deps' : attr.label_list(aspects = [my_aspect]) })" + ); + scratch.file("x/BUILD", + "load(':extension.bzl', 'my_rule')", + "objc_binary(name = 'bin', srcs = ['a.m'], )", + "ios_application(name = 'x', binary = ':bin',)", + "my_rule(name = 'y', deps = [ ':x' ])" + ); + getConfiguredTarget("//x:y"); + } + + @Test + public void testMergeBundleActionsWithNestedBundle() throws Exception { + checkMergeBundleActionsWithNestedBundle(RULE_TYPE_PAIR, targetConfig); + } + + @Test + public void testIncludesStoryboardOutputZipsAsMergeZips() throws Exception { + checkIncludesStoryboardOutputZipsAsMergeZips(RULE_TYPE_PAIR, targetConfig); + } + + @Test + public void testCcDependency() throws Exception { + checkCcDependency(RULE_TYPE_PAIR, ConfigurationDistinguisher.IOS_APPLICATION); + } + + @Test + public void testCcDependencyMultiArch() throws Exception { + checkCcDependencyMultiArch(RULE_TYPE_PAIR, ConfigurationDistinguisher.IOS_APPLICATION); + } + + @Test + public void testCCDependencyWithProtoDependency() throws Exception { + checkCcDependencyWithProtoDependency( + RULE_TYPE_PAIR, ConfigurationDistinguisher.IOS_APPLICATION); + } + + @Test + public void testCcDependencyAndJ2objcDependency() throws Exception { + checkCcDependencyAndJ2objcDependency( + RULE_TYPE_PAIR, ConfigurationDistinguisher.IOS_APPLICATION); + } + + @Test + public void testApplicationExtension() throws Exception { + // Including minimum OS version to trigger a special code path in extension split transitions + // which have a higher chance of conflicting with application transitions. See flag + // --DO_NOT_USE_configuration_distinguisher for details. + useConfiguration("--ios_multi_cpus=i386,x86_64", "--ios_minimum_os=8.1"); + DottedVersion minOsString = DottedVersion.fromString("8.1"); + scratch.file( + "x/BUILD", + "ios_extension_binary(", + " name = 'ext_bin',", + " srcs = ['ebin.m'],", + ")", + "", + "ios_extension(", + " name = 'ext',", + " binary = ':ext_bin',", + ")", + "", + "objc_binary(", + " name = 'bin',", + " srcs = ['bin.m'],", + ")", + "", + "ios_application(", + " name = 'app',", + " binary = ':bin',", + " extensions = [':ext'],", + ")"); + + SpawnAction appLipoAction = + (SpawnAction) + getGeneratingAction( + getBinArtifact( + "app_lipobin", getConfiguredTarget("//x:app", getTargetConfiguration()))); + + assertThat(Artifact.toExecPaths(appLipoAction.getInputs())) + .containsExactly( + configurationBin("i386", ConfigurationDistinguisher.IOS_APPLICATION, minOsString) + + "x/bin_bin", + configurationBin("x86_64", ConfigurationDistinguisher.IOS_APPLICATION, minOsString) + + "x/bin_bin", + MOCK_XCRUNWRAPPER_PATH); + + SpawnAction extLipoAction = + (SpawnAction) + getGeneratingAction( + getBinArtifact( + "ext_lipobin", getConfiguredTarget("//x:ext", getTargetConfiguration()))); + + assertThat(Artifact.toExecPaths(extLipoAction.getInputs())) + .containsExactly( + configurationBin("i386", ConfigurationDistinguisher.IOS_EXTENSION, minOsString) + + "x/ext_bin_bin", + configurationBin("x86_64", ConfigurationDistinguisher.IOS_EXTENSION, minOsString) + + "x/ext_bin_bin", MOCK_XCRUNWRAPPER_PATH); + } + + @Test + public void testGenruleDependencyMultiArch() throws Exception { + checkGenruleDependencyMultiArch(RULE_TYPE_PAIR, ConfigurationDistinguisher.IOS_APPLICATION); + } + + @Test + public void testTargetHasCpuSpecificDsymFiles() throws Exception { + checkTargetHasCpuSpecificDsymFiles(RULE_TYPE); + } + + @Test + public void testTargetHasDsymPlist() throws Exception { + checkTargetHasDsymPlist(RULE_TYPE); + } + + @Test + public void testPropagatesDebugSymbolsFromExtensions() throws Exception { + useConfiguration("--ios_multi_cpus=i386,x86_64", "--apple_generate_dsym"); + scratch.file( + "x/BUILD", + "ios_extension_binary(", + " name = 'ext2_bin',", + " srcs = ['ebin.m'],", + ")", + "", + "ios_extension(", + " name = 'ext2',", + " binary = ':ext2_bin',", + ")", + "", + "ios_extension_binary(", + " name = 'ext_bin',", + " srcs = ['ebin.m'],", + ")", + "", + "ios_extension(", + " name = 'ext',", + " binary = ':ext_bin',", + ")", + "", + "apple_watch_extension_binary(", + " name = 'watch_bin',", + " srcs = ['a.m'],", + ")", + "", + "apple_watch1_extension(", + " name = 'watch_ext',", + " app_name = 'y',", + " binary = ':watch_bin',", + ")", + "", + "objc_binary(", + " name = 'bin',", + " srcs = ['bin.m'],", + ")", + "", + "ios_application(", + " name = 'app',", + " binary = ':bin',", + " extensions = [':ext', ':ext2', ':watch_ext'],", + ")"); + + Iterable<Artifact> filesToBuild = + getConfiguredTarget("//x:app").getProvider(FileProvider.class).getFilesToBuild(); + assertThat(filesToBuild) + .containsAllOf( + getBinArtifact("app.app.dSYM/Contents/Resources/DWARF/app_i386", "//x:app"), + getBinArtifact("app.app.dSYM/Contents/Resources/DWARF/app_x86_64", "//x:app"), + getBinArtifact("app.app.dSYM/Contents/Info.plist", "//x:app"), + getBinArtifact("ext.app.dSYM/Contents/Resources/DWARF/ext_i386", "//x:app"), + getBinArtifact("ext.app.dSYM/Contents/Resources/DWARF/ext_x86_64", "//x:app"), + getBinArtifact("ext.app.dSYM/Contents/Info.plist", "//x:app"), + getBinArtifact("ext2.app.dSYM/Contents/Resources/DWARF/ext2_i386", "//x:app"), + getBinArtifact("ext2.app.dSYM/Contents/Resources/DWARF/ext2_x86_64", "//x:app"), + getBinArtifact("ext2.app.dSYM/Contents/Info.plist", "//x:app"), + getBinArtifact("watch_ext.app.dSYM/Contents/Resources/DWARF/watch_ext_i386", "//x:app"), + getBinArtifact( + "watch_ext.app.dSYM/Contents/Resources/DWARF/watch_ext_x86_64", "//x:app"), + getBinArtifact("watch_ext.app.dSYM/Contents/Info.plist", "//x:app")); + } + + @Test + public void testMultiArchitectureFanOut() throws Exception { + checkBinaryLipoActionMultiCpu(RULE_TYPE_PAIR, ConfigurationDistinguisher.IOS_APPLICATION); + } + + @Test + public void testMultiArchitectureWithConfigurableAttribute() throws Exception { + useConfiguration("--ios_multi_cpus=armv7,arm64", "--cpu=ios_i386"); + scratch.file( + "x/BUILD", + "config_setting(", + " name = 'i386',", + " values = {'cpu': 'ios_i386'},", + ")", + "", + "config_setting(", + " name = 'armv7',", + " values = {'cpu': 'ios_armv7'},", + ")", + "", + "objc_library(", + " name = 'libi386',", + " srcs = ['i386.m'],", + ")", + "", + "objc_library(", + " name = 'libarmv7',", + " srcs = ['armv7.m'],", + ")", + "", + "objc_library(", + " name = 'libdefault',", + " srcs = ['default.m'],", + ")", + "", + "objc_binary(", + " name = 'bin',", + " srcs = ['bin.m'],", + " deps = select({", + " ':i386': [':libi386'],", + " ':armv7': [':libarmv7'],", + " '//conditions:default': [':libdefault'],", + " }),", + ")", + "", + "ios_application(", + " name = 'app',", + " binary = ':bin',", + ")"); + + CommandAction appLipoAction = + (CommandAction) + getGeneratingAction( + getBinArtifact( + "app_lipobin", getConfiguredTarget("//x:app", getTargetConfiguration()))); + + assertThat(Artifact.toExecPaths(appLipoAction.getInputs())) + .containsExactly( + configurationBin("armv7", ConfigurationDistinguisher.IOS_APPLICATION) + "x/bin_bin", + configurationBin("arm64", ConfigurationDistinguisher.IOS_APPLICATION) + "x/bin_bin", + MOCK_XCRUNWRAPPER_PATH); + + ImmutableSet.Builder<Artifact> binInputs = ImmutableSet.builder(); + for (Artifact bin : appLipoAction.getInputs()) { + CommandAction binAction = (CommandAction) getGeneratingAction(bin); + if (binAction != null) { + binInputs.addAll(binAction.getInputs()); + } + } + + assertThat(Artifact.toExecPaths(binInputs.build())) + .containsAllOf( + configurationBin("armv7", ConfigurationDistinguisher.IOS_APPLICATION) + + "x/liblibarmv7.a", + configurationBin("arm64", ConfigurationDistinguisher.IOS_APPLICATION) + + "x/liblibdefault.a"); + + assertThat(Artifact.toExecPaths(binInputs.build())) + .doesNotContain( + configurationBin("i386", ConfigurationDistinguisher.IOS_APPLICATION) + + "x/liblibi386.a"); + } +} |