blob: 00729bc273f3a014e69f3cd7b2fc30f3155b1084 [file] [log] [blame]
Ryan Prichard7aea7e92022-01-13 17:30:17 -08001# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4#[=======================================================================[.rst:
5FindXCTest
6----------
7
8.. versionadded:: 3.3
9
10Functions to help creating and executing XCTest bundles.
11
12An XCTest bundle is a CFBundle with a special product-type
13and bundle extension. The Mac Developer Library provides more
14information in the `Testing with Xcode`_ document.
15
16.. _Testing with Xcode: http://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/testing_with_xcode/
17
18Module Functions
19^^^^^^^^^^^^^^^^
20
21.. command:: xctest_add_bundle
22
23 The ``xctest_add_bundle`` function creates a XCTest bundle named
24 <target> which will test the target <testee>. Supported target types
25 for testee are Frameworks and App Bundles::
26
27 xctest_add_bundle(
28 <target> # Name of the XCTest bundle
29 <testee> # Target name of the testee
30 )
31
32.. command:: xctest_add_test
33
34 The ``xctest_add_test`` function adds an XCTest bundle to the
35 project to be run by :manual:`ctest(1)`. The test will be named
36 <name> and tests <bundle>::
37
38 xctest_add_test(
39 <name> # Test name
40 <bundle> # Target name of XCTest bundle
41 )
42
43Module Variables
44^^^^^^^^^^^^^^^^
45
46The following variables are set by including this module:
47
48.. variable:: XCTest_FOUND
49
50 True if the XCTest Framework and executable were found.
51
52.. variable:: XCTest_EXECUTABLE
53
54 The path to the xctest command line tool used to execute XCTest bundles.
55
56.. variable:: XCTest_INCLUDE_DIRS
57
58 The directory containing the XCTest Framework headers.
59
60.. variable:: XCTest_LIBRARIES
61
62 The location of the XCTest Framework.
63
64#]=======================================================================]
65
66set(_PRESERVED_CMAKE_FIND_ROOT_PATH "${CMAKE_FIND_ROOT_PATH}")
67
68if(CMAKE_EFFECTIVE_SYSTEM_NAME STREQUAL "Apple"
69 AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
70 # Non-macos systems set the CMAKE_FIND_ROOT_PATH_MODE to "ONLY" which
71 # restricts the search paths too much to find XCTest.framework. In
72 # contrast to the regular system frameworks which reside within the
73 # SDK direectory the XCTest framework is located in the respective
74 # platform directory which is not added to the CMAKE_FIND_ROOT_PATH
75 # (only to CMAKE_SYSTEM_FRAMEWORK_PATH) and therefore not searched.
76 #
77 # Until this is properly addressed, temporaily add the platform
78 # directory to CMAKE_FIND_ROOT_PATH.
79 list(APPEND CMAKE_FIND_ROOT_PATH "${_CMAKE_OSX_SYSROOT_PATH}/../..")
80endif()
81
82find_path(XCTest_INCLUDE_DIR
83 NAMES "XCTest/XCTest.h"
84 DOC "XCTest include directory")
85mark_as_advanced(XCTest_INCLUDE_DIR)
86
87find_library(XCTest_LIBRARY
88 NAMES XCTest
89 DOC "XCTest Framework library")
90mark_as_advanced(XCTest_LIBRARY)
91
92set(CMAKE_FIND_ROOT_PATH "${_PRESERVED_CMAKE_FIND_ROOT_PATH}")
93unset(_PRESERVED_CMAKE_FIND_ROOT_PATH)
94
95execute_process(
96 COMMAND xcrun --find xctest
97 OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE
98 ERROR_VARIABLE _xcrun_err)
99if(_xcrun_out)
100 set(XCTest_EXECUTABLE "${_xcrun_out}" CACHE FILEPATH "XCTest executable")
101 mark_as_advanced(XCTest_EXECUTABLE)
102endif()
103
104include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
105find_package_handle_standard_args(XCTest
106 FOUND_VAR XCTest_FOUND
107 REQUIRED_VARS XCTest_LIBRARY XCTest_INCLUDE_DIR XCTest_EXECUTABLE)
108
109if(XCTest_FOUND)
110 set(XCTest_INCLUDE_DIRS "${XCTest_INCLUDE_DIR}")
111 set(XCTest_LIBRARIES "${XCTest_LIBRARY}")
112endif(XCTest_FOUND)
113
114
115function(xctest_add_bundle target testee)
116 if(NOT XCTest_FOUND)
117 message(FATAL_ERROR "XCTest is required to create a XCTest Bundle.")
118 endif(NOT XCTest_FOUND)
119
120 if(NOT CMAKE_OSX_SYSROOT)
121 message(FATAL_ERROR "Adding XCTest bundles requires CMAKE_OSX_SYSROOT to be set.")
122 endif()
123
124 add_library(${target} MODULE ${ARGN})
125
126 set_target_properties(${target} PROPERTIES
127 BUNDLE TRUE
128 XCTEST TRUE
129 XCTEST_TESTEE ${testee})
130
131 target_link_libraries(${target} PRIVATE "-framework Foundation")
132 target_link_libraries(${target} PRIVATE ${XCTest_LIBRARIES})
133 target_include_directories(${target} PRIVATE ${XCTest_INCLUDE_DIRS})
134
135 # retrieve testee target type
136 if(NOT TARGET ${testee})
137 message(FATAL_ERROR "${testee} is not a target.")
138 endif()
139 get_property(_testee_type TARGET ${testee} PROPERTY TYPE)
140 get_property(_testee_framework TARGET ${testee} PROPERTY FRAMEWORK)
141 get_property(_testee_macosx_bundle TARGET ${testee} PROPERTY MACOSX_BUNDLE)
142
143 if(_testee_type STREQUAL "SHARED_LIBRARY" AND _testee_framework)
144 # testee is a Framework
145 target_link_libraries(${target} PRIVATE ${testee})
146
147 elseif(_testee_type STREQUAL "STATIC_LIBRARY")
148 # testee is a static library
149 target_link_libraries(${target} PRIVATE ${testee})
150
151 elseif(_testee_type STREQUAL "EXECUTABLE" AND _testee_macosx_bundle)
152 # testee is an App Bundle
153 add_dependencies(${target} ${testee})
154 if(XCODE)
155 set_target_properties(${target} PROPERTIES
156 XCODE_ATTRIBUTE_BUNDLE_LOADER "$(TEST_HOST)"
157 XCODE_ATTRIBUTE_TEST_HOST "$<TARGET_FILE:${testee}>")
158 if(XCODE_VERSION VERSION_GREATER_EQUAL 7.3)
159 # The Xcode "new build system" used a different path until Xcode 12.5.
160 if(CMAKE_XCODE_BUILD_SYSTEM EQUAL 12 AND
161 XCODE_VERSION VERSION_LESS 12.5 AND
162 NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
163 set(_output_directory "$<TARGET_BUNDLE_CONTENT_DIR:${testee}>")
164 else()
165 set(_output_directory "$<TARGET_BUNDLE_CONTENT_DIR:${testee}>/PlugIns")
166 endif()
167 set_target_properties(${target} PROPERTIES
168 LIBRARY_OUTPUT_DIRECTORY "${_output_directory}")
169 endif()
170 else(XCODE)
171 target_link_libraries(${target}
172 PRIVATE -bundle_loader $<TARGET_FILE:${testee}>)
173 endif(XCODE)
174
175 else()
176 message(FATAL_ERROR "Testee ${testee} is of unsupported type.")
177 endif()
178endfunction(xctest_add_bundle)
179
180
181function(xctest_add_test name bundle)
182 if(NOT XCTest_EXECUTABLE)
183 message(FATAL_ERROR "XCTest executable is required to register a test.")
184 endif()
185
186 # check that bundle is a XCTest Bundle
187
188 if(NOT TARGET ${bundle})
189 message(FATAL_ERROR "${bundle} is not a target.")
190 endif(NOT TARGET ${bundle})
191
192 get_property(_test_type TARGET ${bundle} PROPERTY TYPE)
193 get_property(_test_bundle TARGET ${bundle} PROPERTY BUNDLE)
194 get_property(_test_xctest TARGET ${bundle} PROPERTY XCTEST)
195
196 if(NOT _test_type STREQUAL "MODULE_LIBRARY"
197 OR NOT _test_xctest OR NOT _test_bundle)
198 message(FATAL_ERROR "Test ${bundle} is not an XCTest Bundle")
199 endif()
200
201 # get and check testee properties
202
203 get_property(_testee TARGET ${bundle} PROPERTY XCTEST_TESTEE)
204 if(NOT TARGET ${_testee})
205 message(FATAL_ERROR "${_testee} is not a target.")
206 endif()
207
208 get_property(_testee_type TARGET ${_testee} PROPERTY TYPE)
209 get_property(_testee_framework TARGET ${_testee} PROPERTY FRAMEWORK)
210
211 # register test
212
213 add_test(
214 NAME ${name}
215 COMMAND ${XCTest_EXECUTABLE} $<TARGET_BUNDLE_DIR:${bundle}>)
216
217 # point loader to testee in case rpath is disabled
218
219 if(_testee_type STREQUAL "SHARED_LIBRARY" AND _testee_framework)
220 set_property(TEST ${name} APPEND PROPERTY
221 ENVIRONMENT DYLD_FRAMEWORK_PATH=$<TARGET_LINKER_FILE_DIR:${_testee}>/..)
222 endif()
223endfunction(xctest_add_test)