/* * 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 org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.matchesPattern; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; 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.testutil.integration.ProjectWorkspace; import com.facebook.buck.testutil.integration.TemporaryPaths; import com.facebook.buck.testutil.integration.TestDataHelper; import com.facebook.buck.util.ProcessExecutor; import com.facebook.buck.util.environment.Platform; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.regex.Pattern; import org.junit.Rule; import org.junit.Test; public class PrebuiltAppleFrameworkIntegrationTest { @Rule public TemporaryPaths tmp = new TemporaryPaths(); @Test public void testPrebuiltAppleFrameworkBuildsSomething() throws InterruptedException, IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "prebuilt_apple_framework_builds", tmp); workspace.setUp(); ProjectFilesystem filesystem = new ProjectFilesystem(workspace.getDestPath()); BuildTarget target = BuildTargetFactory.newInstance("//prebuilt:BuckTest"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", target.getFullyQualifiedName()); result.assertSuccess(); assertTrue(Files.exists(workspace.getPath(BuildTargets.getGenPath(filesystem, target, "%s")))); } @Test public void testPrebuiltAppleFrameworkLinks() throws IOException, InterruptedException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "prebuilt_apple_framework_links", tmp); workspace.setUp(); ProjectFilesystem filesystem = new ProjectFilesystem(workspace.getDestPath()); BuildTarget target = BuildTargetFactory.newInstance("//app:TestApp"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", target.getFullyQualifiedName()); result.assertSuccess(); Path testBinaryPath = workspace.getPath(BuildTargets.getGenPath(filesystem, target, "%s")); assertTrue(Files.exists(testBinaryPath)); ProcessExecutor.Result otoolResult = workspace.runCommand("otool", "-L", testBinaryPath.toString()); assertEquals(0, otoolResult.getExitCode()); assertThat( otoolResult.getStdout().orElse(""), containsString("@rpath/BuckTest.framework/BuckTest")); assertThat(otoolResult.getStdout().orElse(""), not(containsString("BuckTest.dylib"))); } @Test public void testPrebuiltAppleFrameworkCopiedToBundle() throws IOException, InterruptedException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "prebuilt_apple_framework_links", tmp); workspace.setUp(); ProjectFilesystem filesystem = new ProjectFilesystem(workspace.getDestPath()); BuildTarget target = BuildTargetFactory.newInstance("//app:TestAppBundle#dwarf-and-dsym,include-frameworks"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", target.getFullyQualifiedName()); result.assertSuccess(); Path includedFramework = workspace .getPath(BuildTargets.getGenPath(filesystem, target, "%s")) .resolve("TestAppBundle.app") .resolve("Frameworks") .resolve("BuckTest.framework"); assertTrue(Files.isDirectory(includedFramework)); } @Test public void testStaticWithDependencies() throws IOException, InterruptedException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "prebuilt_apple_framework_static", tmp); workspace.setUp(); ProjectFilesystem filesystem = new ProjectFilesystem(workspace.getDestPath()); BuildTarget target = BuildTargetFactory.newInstance("//app:TestApp#static,macosx-x86_64"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", target.getFullyQualifiedName()); result.assertSuccess(); Path testBinaryPath = workspace.getPath(BuildTargets.getGenPath(filesystem, target, "%s")); ProcessExecutor.Result otoolResult = workspace.runCommand("otool", "-L", testBinaryPath.toString()); assertEquals(0, otoolResult.getExitCode()); assertThat(otoolResult.getStdout().orElse(""), containsString("Foundation.framework")); assertThat( otoolResult.getStdout().orElse(""), not(containsString("@rpath/BuckTest.framework/BuckTest"))); ProcessExecutor.Result nmResult = workspace.runCommand("nm", testBinaryPath.toString()); assertEquals(0, nmResult.getExitCode()); assertThat(nmResult.getStdout().orElse(""), containsString("S _OBJC_CLASS_$_Hello")); assertThat(nmResult.getStdout().orElse(""), not(containsString("U _OBJC_CLASS_$_Hello"))); assertThat(nmResult.getStdout().orElse(""), containsString("S _OBJC_CLASS_$_Strings")); assertThat(nmResult.getStdout().orElse(""), not(containsString("U _OBJC_CLASS_$_Strings"))); } @Test public void headerUsesShouldMapBackToTestApp() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "prebuilt_apple_framework_links", tmp); workspace.setUp(); workspace .runBuckBuild( "//app:TestApp#iphonesimulator-x86_64", "--config", "cxx.untracked_headers=error") .assertSuccess(); } @Test public void ruleKeyChangesWhenFrameworkIsModified() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "prebuilt_apple_framework_links", tmp); workspace.setUp(); String resultBefore; { ProjectWorkspace.ProcessResult result = workspace.runBuckCommand( "targets", "--show-rulekey", "//app:TestApp#iphonesimulator-x86_64"); resultBefore = result.assertSuccess().getStdout(); } workspace.writeContentsToPath("", "prebuilt/BuckTest.framework/Headers/Hello.h"); String resultAfter; { ProjectWorkspace.ProcessResult result = workspace.runBuckCommand( "targets", "--show-rulekey", "//app:TestApp#iphonesimulator-x86_64"); resultAfter = result.assertSuccess().getStdout(); } assertNotEquals( "Rule Key before and after header change should be different", resultBefore, resultAfter); } @Test public void testProjectGeneratorGeneratesWorkingProject() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "prebuilt_apple_framework_links", tmp); workspace.setUp(); workspace.runBuckCommand("project", "//app:workspace").assertSuccess(); { ProcessExecutor.Result result = workspace.runCommand( "xcodebuild", // "json" output. "-json", // Make sure the output stays in the temp folder. "-derivedDataPath", "xcode-out/", // Build the project that we just generated "-workspace", "app/TestAppBundle.xcworkspace", "-scheme", "TestAppBundle", // Build for iphonesimulator "-arch", "x86_64", "-sdk", "iphonesimulator"); result.getStderr().ifPresent(System.err::print); assertEquals("xcodebuild should succeed", 0, result.getExitCode()); } Path appBundlePath = tmp.getRoot().resolve("xcode-out/Build/Products/Debug-iphonesimulator/TestAppBundle.app"); assertTrue( "Framework is copied into bundle.", Files.isRegularFile(appBundlePath.resolve("Frameworks/BuckTest.framework/BuckTest"))); { ProcessExecutor.Result result = workspace.runCommand("otool", "-l", appBundlePath.resolve("TestAppBundle").toString()); assertThat( "App binary adds Framework dir to rpath.", result.getStdout().get(), matchesPattern( Pattern.compile( ".*\\s+cmd LC_RPATH.*\\s+path @executable_path/Frameworks\\b.*", Pattern.DOTALL))); assertThat( "App binary has load instruction for framework", result.getStdout().get(), matchesPattern( Pattern.compile( ".*\\s+cmd LC_LOAD_DYLIB.*\\s+name @rpath/BuckTest.framework/BuckTest\\b.*", Pattern.DOTALL))); } } }