/* * Copyright 2015-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 org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.matchesPattern; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import com.facebook.buck.cxx.CxxDescriptionEnhancer; import com.facebook.buck.cxx.LinkerMapMode; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.BuildTargetFactory; import com.facebook.buck.model.BuildTargets; import com.facebook.buck.model.InternalFlavor; import com.facebook.buck.testutil.integration.ProjectWorkspace; import com.facebook.buck.testutil.integration.TemporaryPaths; import com.facebook.buck.testutil.integration.TestDataHelper; import com.facebook.buck.util.HumanReadableException; import com.facebook.buck.util.ProcessExecutor; import com.facebook.buck.util.environment.Platform; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; public class AppleTestIntegrationTest { @Rule public TemporaryPaths tmp = new TemporaryPaths(); @Rule public ExpectedException thrown = ExpectedException.none(); private ProjectFilesystem filesystem; @Before public void setUp() throws InterruptedException { filesystem = new ProjectFilesystem(tmp.getRoot()); } @Test public void testAppleTestHeaderSymlinkTree() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "apple_test_header_symlink_tree", tmp); workspace.setUp(); BuildTarget buildTarget = BuildTargetFactory.newInstance( "//Libraries/TestLibrary:Test#iphonesimulator-x86_64,private-headers"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", buildTarget.getFullyQualifiedName()); result.assertSuccess(); Path projectRoot = tmp.getRoot().toRealPath(); Path inputPath = projectRoot.resolve(buildTarget.getBasePath()); Path outputPath = projectRoot.resolve(BuildTargets.getGenPath(filesystem, buildTarget, "%s")); assertIsSymbolicLink(outputPath.resolve("Header.h"), inputPath.resolve("Header.h")); assertIsSymbolicLink(outputPath.resolve("Test/Header.h"), inputPath.resolve("Header.h")); } @Test public void testInfoPlistFromExportRule() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "apple_test_info_plist_export_file", tmp); workspace.setUp(); BuildTarget buildTarget = BuildTargetFactory.newInstance("//:foo#iphonesimulator-x86_64"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", buildTarget.getFullyQualifiedName()); result.assertSuccess(); Path projectRoot = Paths.get(tmp.getRoot().toFile().getCanonicalPath()); BuildTarget appleTestBundleFlavoredBuildTarget = buildTarget.withFlavors( InternalFlavor.of("iphonesimulator-x86_64"), InternalFlavor.of("apple-test-bundle"), AppleDebugFormat.DWARF.getFlavor(), LinkerMapMode.NO_LINKER_MAP.getFlavor(), AppleDescriptions.NO_INCLUDE_FRAMEWORKS_FLAVOR); Path outputPath = projectRoot.resolve( BuildTargets.getGenPath(filesystem, appleTestBundleFlavoredBuildTarget, "%s")); Path bundlePath = outputPath.resolve("foo.xctest"); Path infoPlistPath = bundlePath.resolve("Info.plist"); assertTrue(Files.isDirectory(bundlePath)); assertTrue(Files.isRegularFile(infoPlistPath)); } @Test public void testSetsFrameworkSearchPathAndLinksCorrectly() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "apple_test_framework_search_path", tmp); workspace.setUp(); BuildTarget buildTarget = BuildTargetFactory.newInstance("//:foo#iphonesimulator-x86_64"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", buildTarget.getFullyQualifiedName()); result.assertSuccess(); Path projectRoot = Paths.get(tmp.getRoot().toFile().getCanonicalPath()); BuildTarget appleTestBundleFlavoredBuildTarget = buildTarget.withFlavors( InternalFlavor.of("iphonesimulator-x86_64"), InternalFlavor.of("apple-test-bundle"), AppleDebugFormat.DWARF.getFlavor(), LinkerMapMode.NO_LINKER_MAP.getFlavor(), AppleDescriptions.NO_INCLUDE_FRAMEWORKS_FLAVOR); Path outputPath = projectRoot.resolve( BuildTargets.getGenPath(filesystem, appleTestBundleFlavoredBuildTarget, "%s")); Path bundlePath = outputPath.resolve("foo.xctest"); Path testBinaryPath = bundlePath.resolve("foo"); assertTrue(Files.isDirectory(bundlePath)); assertTrue(Files.isRegularFile(testBinaryPath)); } @Test public void testInfoPlistVariableSubstitutionWorksCorrectly() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "apple_test_info_plist_substitution", tmp); workspace.setUp(); BuildTarget target = workspace.newBuildTarget("//:foo#iphonesimulator-x86_64"); workspace.runBuckCommand("build", target.getFullyQualifiedName()).assertSuccess(); workspace.verify( Paths.get("foo_output.expected"), BuildTargets.getGenPath( filesystem, BuildTarget.builder(target) .addFlavors(AppleDebugFormat.DWARF.getFlavor()) .addFlavors(AppleTestDescription.BUNDLE_FLAVOR) .addFlavors(LinkerMapMode.NO_LINKER_MAP.getFlavor()) .addFlavors(AppleDescriptions.NO_INCLUDE_FRAMEWORKS_FLAVOR) .build(), "%s")); } @Test public void testDefaultPlatformBuilds() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_default_platform", tmp); workspace.setUp(); BuildTarget target = workspace.newBuildTarget("//:foo"); workspace.runBuckCommand("build", target.getFullyQualifiedName()).assertSuccess(); workspace.verify( Paths.get("foo_output.expected"), BuildTargets.getGenPath( filesystem, BuildTarget.builder(target) .addFlavors(AppleTestDescription.BUNDLE_FLAVOR) .addFlavors(AppleDebugFormat.DWARF.getFlavor()) .addFlavors(LinkerMapMode.NO_LINKER_MAP.getFlavor()) .addFlavors(AppleDescriptions.NO_INCLUDE_FRAMEWORKS_FLAVOR) .build(), "%s")); } @Test public void testLinkedAsMachOBundleWithNoDylibDeps() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_with_deps", tmp); workspace.setUp(); BuildTarget buildTarget = workspace.newBuildTarget("//:foo"); workspace.runBuckCommand("build", buildTarget.getFullyQualifiedName()).assertSuccess(); workspace.verify( Paths.get("foo_output.expected"), BuildTargets.getGenPath( filesystem, BuildTarget.builder(buildTarget) .addFlavors(AppleDebugFormat.DWARF.getFlavor()) .addFlavors(AppleTestDescription.BUNDLE_FLAVOR) .addFlavors(LinkerMapMode.NO_LINKER_MAP.getFlavor()) .addFlavors(AppleDescriptions.NO_INCLUDE_FRAMEWORKS_FLAVOR) .build(), "%s")); Path projectRoot = Paths.get(tmp.getRoot().toFile().getCanonicalPath()); BuildTarget appleTestBundleFlavoredBuildTarget = buildTarget.withFlavors( InternalFlavor.of("apple-test-bundle"), AppleDebugFormat.DWARF.getFlavor(), LinkerMapMode.NO_LINKER_MAP.getFlavor(), AppleDescriptions.NO_INCLUDE_FRAMEWORKS_FLAVOR); Path outputPath = projectRoot.resolve( BuildTargets.getGenPath(filesystem, appleTestBundleFlavoredBuildTarget, "%s")); Path bundlePath = outputPath.resolve("foo.xctest"); Path testBinaryPath = bundlePath.resolve("foo"); ProcessExecutor.Result binaryFileTypeResult = workspace.runCommand("file", "-b", testBinaryPath.toString()); assertEquals(0, binaryFileTypeResult.getExitCode()); assertThat( binaryFileTypeResult.getStdout().orElse(""), containsString("Mach-O 64-bit bundle x86_64")); ProcessExecutor.Result otoolResult = workspace.runCommand("otool", "-L", testBinaryPath.toString()); assertEquals(0, otoolResult.getExitCode()); assertThat(otoolResult.getStdout().orElse(""), containsString("foo")); assertThat(otoolResult.getStdout().orElse(""), not(containsString("bar.dylib"))); ProcessExecutor.Result nmResult = workspace.runCommand("nm", "-j", testBinaryPath.toString()); assertEquals(0, nmResult.getExitCode()); assertThat(nmResult.getStdout().orElse(""), containsString("_OBJC_CLASS_$_Foo")); assertThat(nmResult.getStdout().orElse(""), containsString("_OBJC_CLASS_$_Bar")); } @Test public void testWithResourcesCopiesResourceFilesAndDirs() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_with_resources", tmp); workspace.setUp(); BuildTarget target = workspace.newBuildTarget("//:foo#iphonesimulator-x86_64"); workspace.runBuckCommand("build", target.getFullyQualifiedName()).assertSuccess(); workspace.verify( Paths.get("foo_output.expected"), BuildTargets.getGenPath( filesystem, BuildTarget.builder(target) .addFlavors(AppleDebugFormat.DWARF.getFlavor()) .addFlavors(AppleTestDescription.BUNDLE_FLAVOR) .addFlavors(LinkerMapMode.NO_LINKER_MAP.getFlavor()) .addFlavors(AppleDescriptions.NO_INCLUDE_FRAMEWORKS_FLAVOR) .build(), "%s")); } @Test public void shouldRefuseToRunAppleTestIfXctestNotPresent() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_xctest", tmp); workspace.setUp(); thrown.expect(HumanReadableException.class); thrown.expectMessage( containsString( "Set xctool_path = /path/to/xctool or xctool_zip_target = //path/to:xctool-zip in the " + "[apple] section of .buckconfig to run this test")); workspace.runBuckCommand("test", "//:foo"); } @Test public void successOnTestPassing() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_xctest", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); workspace.addBuckConfigLocalOption("apple", "xctool_path", "fbxctest/bin/fbxctest"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("test", "//:foo"); result.assertSuccess(); assertThat(result.getStderr(), containsString("1 Passed 0 Skipped 0 Failed FooXCTest")); } @Test public void skipsXCUITests() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_xcuitest", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); workspace.addBuckConfigLocalOption("apple", "xctool_path", "fbxctest/bin/fbxctest"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("test", "//:foo", "//:bar"); result.assertSuccess(); assertThat(result.getStderr(), containsString("1 Passed 0 Skipped 0 Failed FooXCTest")); } @Test public void slowTestShouldFailWithTimeout() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "slow_xc_tests_per_rule_timeout", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); workspace.addBuckConfigLocalOption("apple", "xctool_path", "fbxctest/bin/fbxctest"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("test", "//:spinning"); result.assertSpecialExitCode("test should fail", 42); assertThat(result.getStderr(), containsString("Timed out after 100 ms running test command")); } @Test public void exitCodeIsCorrectOnTestFailure() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_xctest_failure", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); workspace.addBuckConfigLocalOption("apple", "xctool_path", "fbxctest/bin/fbxctest"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("test", "//:foo"); result.assertSpecialExitCode("test should fail", 42); assertThat(result.getStderr(), containsString("0 Passed 0 Skipped 1 Failed FooXCTest")); assertThat( result.getStderr(), matchesPattern( "(?s).*FAILURE FooXCTest -\\[FooXCTest testTwoPlusTwoEqualsFive\\]:.*FooXCTest.m:9.*")); } @Test(timeout = 180000) public void successOnAppTestPassing() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_with_host_app", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); workspace.addBuckConfigLocalOption("apple", "xctool_path", "fbxctest/bin/fbxctest"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("test", "//:AppTest"); result.assertSuccess(); assertThat(result.getStderr(), containsString("1 Passed 0 Skipped 0 Failed AppTest")); } @Test(timeout = 180000) public void testWithHostAppWithDsym() throws IOException, InterruptedException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_with_host_app", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); workspace.addBuckConfigLocalOption("apple", "xctool_path", "fbxctest/bin/fbxctest"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand( "test", "//:AppTest", "--config", "cxx.cflags=-g", "--config", "apple.default_debug_info_format_for_binaries=DWARF_AND_DSYM", "--config", "apple.default_debug_info_format_for_libraries=DWARF_AND_DSYM", "--config", "apple.default_debug_info_format_for_tests=DWARF_AND_DSYM"); result.assertSuccess(); assertThat(result.getStderr(), containsString("1 Passed 0 Skipped 0 Failed AppTest")); Path appTestDsym = tmp.getRoot() .resolve(filesystem.getBuckPaths().getGenDir()) .resolve("AppTest#apple-test-bundle,dwarf-and-dsym,no-include-frameworks,no-linkermap") .resolve("AppTest.xctest.dSYM"); AppleDsymTestUtil.checkDsymFileHasDebugSymbol( "-[AppTest testMagicValue]", workspace, appTestDsym); Path hostAppDsym = tmp.getRoot() .resolve(filesystem.getBuckPaths().getGenDir()) .resolve("TestHostApp#dwarf-and-dsym,no-include-frameworks") .resolve("TestHostApp.app.dSYM"); AppleDsymTestUtil.checkDsymFileHasDebugSymbol( "-[TestHostApp magicValue]", workspace, hostAppDsym); } @Test(timeout = 180000) public void exitCodeIsCorrectOnAppTestFailure() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "apple_test_with_host_app_failure", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); workspace.addBuckConfigLocalOption("apple", "xctool_path", "fbxctest/bin/fbxctest"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand( "test", "--config", "apple.xctool_path=fbxctest/bin/fbxctest", "//:AppTest"); result.assertSpecialExitCode("test should fail", 42); assertThat(result.getStderr(), containsString("0 Passed 0 Skipped 1 Failed AppTest")); assertThat( result.getStderr(), matchesPattern( "(?s).*FAILURE AppTest -\\[AppTest testMagicValueShouldFail\\]:.*AppTest\\.m:13.*")); } @Test public void successOnOsxLogicTestPassing() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_osx_logic_test", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand( "test", "--config", "apple.xctool_path=fbxctest/bin/fbxctest", "//:LibTest"); result.assertSuccess(); assertThat(result.getStderr(), containsString("1 Passed 0 Skipped 0 Failed LibTest")); } @Test public void buckTestOnLibTargetRunsTestTarget() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_osx_logic_test", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand( "test", "--config", "apple.xctool_path=fbxctest/bin/fbxctest", "//:Lib"); result.assertSuccess(); assertThat(result.getStderr(), containsString("1 Passed 0 Skipped 0 Failed LibTest")); } @Test(timeout = 180000) public void successForAppTestWithXib() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "app_bundle_with_compiled_resources", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); workspace.addBuckConfigLocalOption("apple", "xctool_path", "fbxctest/bin/fbxctest"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("test", "//:AppTest"); result.assertSuccess(); assertThat(result.getStderr(), containsString("1 Passed 0 Skipped 0 Failed AppTest")); } @Test public void successOnTestPassingWithFbXcTestZipTarget() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "apple_test_fbxctest_zip_target", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand( "test", "--config", "apple.xctool_path=fbxctest/bin/fbxctest", "//:foo"); result.assertSuccess(); assertThat(result.getStderr(), containsString("1 Passed 0 Skipped 0 Failed FooXCTest")); } // This test is disabled since the movement from xctool to fbxctest @Test public void testDependenciesLinking() throws IOException, InterruptedException { assumeTrue(false); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_dependencies_test", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand( "test", "--config", "apple.xctool_path=fbxctest/bin/fbxctest", "//:App"); result.assertSuccess(); ProcessExecutor.Result hasSymbol = workspace.runCommand( "nm", workspace .getPath( BuildTargets.getGenPath( filesystem, workspace.newBuildTarget("#AppBinary#binary,iphonesimulator-x86_64"), "AppBinary#apple-dsym,iphonesimulator-x86_64.dSYM")) .toString()); assertThat(hasSymbol.getExitCode(), equalTo(0)); assertThat(hasSymbol.getStdout().get(), containsString("U _OBJC_CLASS_$_Library")); } @Test public void environmentOverrideAffectsXctoolTest() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); // Our version of xctool doesn't pass through any environment variables, so just see if xctool // itself crashes. ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_xctest", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); workspace .runBuckCommand("test", "--config", "apple.xctool_path=fbxctest/bin/fbxctest", "//:foo") .assertSuccess("normally the test should succeed"); workspace.resetBuildLogFile(); workspace .runBuckCommand( "test", "--config", "apple.xctool_path=fbxctest/bin/fbxctest", "--test-runner-env", "DYLD_INSERT_LIBRARIES=/non_existent_library_omg.dylib", "//:foo") .assertTestFailure("test should fail if i set incorrect dyld environment"); } @Test public void environmentOverrideAffectsXctestTest() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_env", tmp); workspace.setUp(); ProjectWorkspace.ProcessResult result; result = workspace.runBuckCommand( "test", "--config", "apple.xctest_platforms=macosx", "//:foo#macosx-x86_64"); result.assertTestFailure("normally the test should fail"); workspace.resetBuildLogFile(); result = workspace.runBuckCommand( "test", "--config", "apple.xctest_platforms=macosx", "--test-runner-env", "FOO=bar", "//:foo#macosx-x86_64"); result.assertSuccess("should pass when I pass correct environment"); } @Test public void appleTestWithoutTestHostShouldSupportMultiarch() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_xctest", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); BuildTarget target = BuildTargetFactory.newInstance("//:foo#iphonesimulator-i386,iphonesimulator-x86_64"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand( "test", "--config", "apple.xctool_path=fbxctest/bin/fbxctest", target.getFullyQualifiedName()); result.assertSuccess(); assertThat(result.getStderr(), containsString("1 Passed 0 Skipped 0 Failed FooXCTest")); result = workspace.runBuckCommand("targets", "--show-output", target.getFullyQualifiedName()); result.assertSuccess(); Path output = workspace .getDestPath() .resolve(Iterables.getLast(Splitter.on(' ').limit(2).split(result.getStdout().trim()))); // check result is actually multiarch. ProcessExecutor.Result lipoVerifyResult = workspace.runCommand( "lipo", output.resolve("foo").toString(), "-verify_arch", "i386", "x86_64"); assertEquals(lipoVerifyResult.getStderr().orElse(""), 0, lipoVerifyResult.getExitCode()); } @Test public void appleTestWithoutTestHostMultiarchShouldHaveMultiarchDsym() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_xctest", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); BuildTarget target = BuildTargetFactory.newInstance("//:foo#iphonesimulator-i386,iphonesimulator-x86_64"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand( "build", "--config", "cxx.cflags=-g", "--config", "apple.xctool_path=fbxctest/bin/fbxctest", "--config", "apple.default_debug_info_format_for_binaries=DWARF_AND_DSYM", "--config", "apple.default_debug_info_format_for_libraries=DWARF_AND_DSYM", "--config", "apple.default_debug_info_format_for_tests=DWARF_AND_DSYM", target.getFullyQualifiedName()); result.assertSuccess(); BuildTarget libraryTarget = target.withAppendedFlavors( AppleTestDescription.LIBRARY_FLAVOR, CxxDescriptionEnhancer.MACH_O_BUNDLE_FLAVOR); Path output = workspace .getDestPath() .resolve( BuildTargets.getGenPath( filesystem, libraryTarget.withAppendedFlavors(AppleDsym.RULE_FLAVOR), "%s.dSYM")) .resolve("Contents/Resources/DWARF/" + libraryTarget.getShortName()); ProcessExecutor.Result lipoVerifyResult = workspace.runCommand("lipo", output.toString(), "-verify_arch", "i386", "x86_64"); assertEquals(lipoVerifyResult.getStderr().orElse(""), 0, lipoVerifyResult.getExitCode()); AppleDsymTestUtil.checkDsymFileHasDebugSymbolForConcreteArchitectures( "-[FooXCTest testTwoPlusTwoEqualsFour]", workspace, output, Optional.of(ImmutableList.of("i386", "x86_64"))); } @Test(timeout = 180000) public void appleTestWithTestHostShouldSupportMultiarch() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "apple_test_with_host_app", tmp); workspace.setUp(); workspace.copyRecursively( TestDataHelper.getTestDataDirectory(this).resolve("fbxctest"), Paths.get("fbxctest")); BuildTarget target = BuildTargetFactory.newInstance("//:AppTest#iphonesimulator-i386,iphonesimulator-x86_64"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand( "test", "--config", "apple.xctool_path=fbxctest/bin/fbxctest", target.getFullyQualifiedName()); result.assertSuccess(); assertThat(result.getStderr(), containsString("1 Passed 0 Skipped 0 Failed AppTest")); result = workspace.runBuckCommand("targets", "--show-output", target.getFullyQualifiedName()); result.assertSuccess(); Path output = workspace .getDestPath() .resolve(Iterables.getLast(Splitter.on(' ').limit(2).split(result.getStdout().trim()))); // check result is actually multiarch. ProcessExecutor.Result lipoVerifyResult = workspace.runCommand( "lipo", output.resolve("AppTest").toString(), "-verify_arch", "i386", "x86_64"); assertEquals(lipoVerifyResult.getStderr().orElse(""), 0, lipoVerifyResult.getExitCode()); } private static void assertIsSymbolicLink(Path link, Path target) throws IOException { assertTrue(Files.isSymbolicLink(link)); assertTrue(Files.isSameFile(target, Files.readSymbolicLink(link))); } }