blob: 016919414985f0dc01777fd0d8379ca4cd676666 [file] [log] [blame]
Alexei Frolov925fb8f2019-11-05 16:32:30 -08001# Copyright 2019 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7# https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14
Armando Montanezfb3d3fb2020-06-09 18:12:12 -070015import("//build_overrides/pigweed.gni")
16
Wyatt Hepler51ded742020-10-19 14:45:27 -070017import("$dir_pw_build/python_action.gni")
Alexei Frolovedd2f142020-06-09 19:11:27 -070018import("$dir_pw_build/target_types.gni")
Wyatt Heplerd49f8fe2020-10-15 10:13:47 -070019
Alexei Frolov4c0428a2020-06-10 10:46:04 -070020declare_args() {
21 # Path to a test runner to automatically run unit tests after they are built.
22 #
Armando Montanez4ddaa9e2021-12-07 15:40:51 -080023 # If set, a ``pw_test`` target's ``<target_name>.run`` action will invoke the
24 # test runner specified by this argument, passing the path to the unit test to
25 # run. If this is unset, the ``pw_test`` target's ``<target_name>.run`` step
26 # will do nothing.
Alexei Frolov4c0428a2020-06-10 10:46:04 -070027 #
Armando Montanez4ddaa9e2021-12-07 15:40:51 -080028 # Targets that don't support parallelized execution of tests (e.g. a on-device
29 # test runner that must flash a device and run the test in serial) should
30 # set pw_unit_test_POOL_DEPTH to 1.
31 #
32 # Type: string (name of an executable on the PATH, or path to an executable)
33 # Usage: toolchain-controlled only
Alexei Frolov4c0428a2020-06-10 10:46:04 -070034 pw_unit_test_AUTOMATIC_RUNNER = ""
35
Edwin Vane81f8aa62021-12-07 21:46:37 -050036 # Optional list of arguments to forward to the automatic runner.
37 #
38 # Type: list of strings (args to pass to pw_unit_test_AUTOMATIC_RUNNER)
39 # Usage: toolchain-controlled only
40 pw_unit_test_AUTOMATIC_RUNNER_ARGS = []
41
Austin Foxleybad57472022-02-03 23:45:05 +000042 # Optional timeout to apply when running tests via the automatic runner.
43 # Timeout is in seconds. Defaults to empty which means no timeout.
44 pw_unit_test_AUTOMATIC_RUNNER_TIMEOUT = ""
45
Alexei Frolovfbe68ff2020-11-16 13:44:52 -080046 # Additional dependencies required by all unit test targets. (For example, if
47 # using a different test library like Googletest.)
Armando Montanez4ddaa9e2021-12-07 15:40:51 -080048 #
49 # Type: list of strings (list of dependencies as GN paths)
50 # Usage: toolchain-controlled only
Alexei Frolovfbe68ff2020-11-16 13:44:52 -080051 pw_unit_test_PUBLIC_DEPS = []
52
Armando Montanez4ddaa9e2021-12-07 15:40:51 -080053 # Implementation of a main function for ``pw_test`` unit test binaries.
54 #
55 # Type: string (GN path to a source set)
56 # Usage: toolchain-controlled only
Alexei Frolov4c0428a2020-06-10 10:46:04 -070057 pw_unit_test_MAIN = "$dir_pw_unit_test:simple_printing_main"
Armando Montanez4ddaa9e2021-12-07 15:40:51 -080058
59 # The maximum number of unit tests that may be run concurrently for the
60 # current toolchain. Setting this to 0 disables usage of a pool, allowing
61 # unlimited parallelization.
62 #
63 # Note: A single target with two toolchain configurations (e.g. release/debug)
64 # will use two separate test runner pools by default. Set
65 # pw_unit_test_POOL_TOOLCHAIN to the same toolchain for both targets to
66 # merge the pools and force serialization.
67 #
68 # Type: integer
69 # Usage: toolchain-controlled only
70 pw_unit_test_POOL_DEPTH = 0
71
72 # The toolchain to use when referring to the pw_unit_test runner pool. When
73 # this is disabled, the current toolchain is used. This means that every
74 # toolchain will use its own pool definition. If two toolchains should share
75 # the same pool, this argument should be by one of the toolchains to the GN
76 # path of the other toolchain.
77 #
78 # Type: string (GN path to a toolchain)
79 # Usage: toolchain-controlled only
80 pw_unit_test_POOL_TOOLCHAIN = ""
Alexei Frolov4c0428a2020-06-10 10:46:04 -070081}
Alexei Frolov925fb8f2019-11-05 16:32:30 -080082
Wyatt Heplerdfe3c612020-04-23 13:13:45 -070083# Defines a target if enable_if is true. Otherwise, it defines that target as
Alexei Frolov69dccfd2020-11-13 12:10:24 -080084# <target_name>.DISABLED and creates an empty <target_name> group. This can be
Wyatt Heplerdfe3c612020-04-23 13:13:45 -070085# used to conditionally create targets without having to conditionally add them
86# to groups. This results in simpler BUILD.gn files.
87template("_pw_disableable_target") {
88 assert(defined(invoker.enable_if),
89 "`enable_if` is required for _pw_disableable_target")
90 assert(defined(invoker.target_type),
91 "`target_type` is required for _pw_disableable_target")
92
93 if (invoker.enable_if) {
94 _actual_target_name = target_name
95 } else {
Alexei Frolov69dccfd2020-11-13 12:10:24 -080096 _actual_target_name = target_name + ".DISABLED"
Wyatt Heplerdfe3c612020-04-23 13:13:45 -070097
Wyatt Hepler4e6a4722020-07-09 17:34:48 -070098 # If the target is disabled, create an empty target in its place. Use an
99 # action with the original target's sources as inputs to ensure that
100 # the source files exist (even if they don't compile).
Wyatt Heplerc8e05a42020-10-19 14:49:39 -0700101 pw_python_action(target_name) {
Wyatt Hepler27f69f02020-07-27 09:06:21 -0700102 script = "$dir_pw_build/py/pw_build/nop.py"
Wyatt Hepler4e6a4722020-07-09 17:34:48 -0700103 stamp = true
104
105 inputs = []
106 if (defined(invoker.sources)) {
107 inputs += invoker.sources
108 }
109 if (defined(invoker.public)) {
110 inputs += invoker.public
111 }
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700112 }
113 }
114
115 target(invoker.target_type, _actual_target_name) {
116 forward_variables_from(invoker,
117 "*",
118 [
119 "enable_if",
120 "target_type",
121 ])
Wyatt Hepler68fde052020-05-13 14:43:03 -0700122
123 # Remove "" from dependencies. This allows disabling targets if a variable
124 # (e.g. a backend) is empty.
125 if (defined(public_deps)) {
126 public_deps += [ "" ]
127 public_deps -= [ "" ]
128 }
129 if (defined(deps)) {
130 deps += [ "" ]
131 deps -= [ "" ]
132 }
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700133 }
134}
135
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800136# Creates a library and an executable target for a unit test.
137#
138# <target_name>.lib contains the provided test sources as a library, which can
139# then be linked into a test executable.
140# <target_name> is a standalone executable which contains only the test sources
141# specified in the pw_unit_test_template.
Alexei Frolova454c682019-11-19 10:55:07 -0800142#
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700143# If the pw_unit_test_AUTOMATIC_RUNNER variable is set, this template also creates a
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800144# "${test_name}.run" target which runs the unit test executable after building
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800145# it.
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800146#
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700147# Args:
148# - enable_if: (optional) Conditionally enables or disables this test. The test
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800149# target and *.run target do nothing when the test is disabled. The
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700150# disabled test can still be built and run with the
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800151# <target_name>.DISABLED and <target_name>.DISABLED.run targets.
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700152# Defaults to true (enable_if).
153# - All of the regular "executable" target args are accepted.
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800154template("pw_test") {
155 # This is required in order to reference the pw_test template's target name
156 # within the test_metadata of the metadata group below. The group() definition
157 # creates a new scope where the "target_name" variable is set to its target,
158 # shadowing the one in this scope.
Alexei Frolovd1f98fa2019-11-08 15:41:37 -0800159 _test_target_name = target_name
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800160
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700161 _test_is_enabled = !defined(invoker.enable_if) || invoker.enable_if
162
Michael Spang524ead42020-06-12 14:23:40 -0400163 # Always set the output_dir as pigweed is not compatible with shared
164 # bin directories for tests.
Michael Spangcdba5162020-06-12 14:45:07 -0400165 _test_output_dir = "${target_out_dir}/test"
Michael Spang524ead42020-06-12 14:23:40 -0400166 if (defined(invoker.output_dir)) {
167 _test_output_dir = invoker.output_dir
168 }
169
Michael Spang6aa8eb02020-06-11 20:19:05 -0400170 _test_main = pw_unit_test_MAIN
171 if (defined(invoker.test_main)) {
172 _test_main = invoker.test_main
173 }
174
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800175 # The unit test code as a source_set.
176 _pw_disableable_target("$target_name.lib") {
177 target_type = "pw_source_set"
178 enable_if = _test_is_enabled
179 forward_variables_from(invoker, "*", [ "metadata" ])
180
181 if (!defined(public_deps)) {
182 public_deps = []
183 }
Alexei Frolovfbe68ff2020-11-16 13:44:52 -0800184 public_deps += pw_unit_test_PUBLIC_DEPS + [ dir_pw_unit_test ]
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800185 }
186
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700187 _pw_disableable_target(_test_target_name) {
188 target_type = "pw_executable"
189 enable_if = _test_is_enabled
190
Alexei Frolova454c682019-11-19 10:55:07 -0800191 # Metadata for this test when used as part of a pw_test_group target.
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800192 metadata = {
Alexei Frolova454c682019-11-19 10:55:07 -0800193 tests = [
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800194 {
Alexei Frolova454c682019-11-19 10:55:07 -0800195 type = "test"
Alexei Frolovd1f98fa2019-11-08 15:41:37 -0800196 test_name = _test_target_name
Michael Spang524ead42020-06-12 14:23:40 -0400197 test_directory = rebase_path(_test_output_dir, root_build_dir)
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800198 },
199 ]
200 }
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800201
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800202 deps = [ ":$_test_target_name.lib" ]
Michael Spang6aa8eb02020-06-11 20:19:05 -0400203 if (_test_main != "") {
204 deps += [ _test_main ]
205 }
Michael Spang524ead42020-06-12 14:23:40 -0400206
207 output_dir = _test_output_dir
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800208 }
209
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700210 if (pw_unit_test_AUTOMATIC_RUNNER != "") {
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800211 # When the automatic runner is set, create an action which runs the unit
212 # test executable using the test runner script.
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700213 if (_test_is_enabled) {
214 _test_to_run = _test_target_name
215 } else {
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800216 # Create a run target for the .DISABLED version of the test.
217 _test_to_run = _test_target_name + ".DISABLED"
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800218
Rob Mohr2f6662c2021-05-21 15:50:11 -0700219 # Create a placeholder _run target for the regular version of the test.
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800220 group(_test_target_name + ".run") {
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700221 deps = [ ":$_test_target_name" ]
222 }
223 }
224
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800225 pw_python_action(_test_to_run + ".run") {
Armando Montanez4ddaa9e2021-12-07 15:40:51 -0800226 # Optionally limit max test runner concurrency.
227 if (pw_unit_test_POOL_DEPTH != 0) {
228 _pool_toolchain = current_toolchain
229 if (pw_unit_test_POOL_TOOLCHAIN != "") {
230 _pool_toolchain = pw_unit_test_POOL_TOOLCHAIN
231 }
232 pool = "$dir_pw_unit_test:unit_test_pool($_pool_toolchain)"
233 }
234
Rob Mohra0ba54f2020-02-27 11:43:49 -0800235 deps = [ ":$_test_target_name" ]
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700236 inputs = [ pw_unit_test_AUTOMATIC_RUNNER ]
Armando Montanez2a0d4d52022-01-06 16:34:02 -0800237 module = "pw_unit_test.test_runner"
238 python_deps = [ "$dir_pw_unit_test/py" ]
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800239 args = [
240 "--runner",
Michael Spangc8b93902021-05-30 15:53:56 -0400241 rebase_path(pw_unit_test_AUTOMATIC_RUNNER, root_build_dir),
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800242 "--test",
Wyatt Hepler8224a642020-07-29 08:55:56 -0700243 "<TARGET_FILE(:$_test_to_run)>",
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800244 ]
Austin Foxleybad57472022-02-03 23:45:05 +0000245 if (pw_unit_test_AUTOMATIC_RUNNER_TIMEOUT != "") {
246 args += [
247 "--timeout",
248 pw_unit_test_AUTOMATIC_RUNNER_TIMEOUT,
249 ]
250 }
Edwin Vane81f8aa62021-12-07 21:46:37 -0500251 if (pw_unit_test_AUTOMATIC_RUNNER_ARGS != []) {
252 args += [ "--" ] + pw_unit_test_AUTOMATIC_RUNNER_ARGS
253 }
Alexei Frolov917756d2019-11-12 14:34:34 -0800254 stamp = true
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800255 }
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800256
257 # TODO(frolv): Alias for the deprecated _run target. Remove when projects
258 # are migrated.
259 group(_test_to_run + "_run") {
260 public_deps = [ ":$_test_to_run.run" ]
261 }
262 } else {
263 group(_test_target_name + ".run") {
264 }
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800265 }
266}
Alexei Frolova454c682019-11-19 10:55:07 -0800267
268# Defines a related collection of unit tests.
269#
270# pw_test_group targets output a JSON metadata file for the Pigweed test runner.
271#
272# Args:
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700273# - tests: List of pw_test targets for each of the tests in the group.
274# - group_deps: (optional) pw_test_group targets on which this group depends.
275# - enable_if: (optional) Conditionally enables or disables this test group.
276# If false, an empty group is created. Defaults to true.
Alexei Frolova454c682019-11-19 10:55:07 -0800277template("pw_test_group") {
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800278 _group_target = target_name
279 _group_deps_metadata = []
Wyatt Hepleredf6f292019-11-25 18:52:21 -0800280 if (defined(invoker.tests)) {
281 _deps = invoker.tests
282 } else {
283 _deps = []
284 }
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800285
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700286 _group_is_enabled = !defined(invoker.enable_if) || invoker.enable_if
287
288 if (_group_is_enabled) {
289 if (defined(invoker.group_deps)) {
290 # If the group specified any other group dependencies, create a metadata
291 # entry for each of them indicating that they are another group and a
292 # group target to collect that metadata.
293 foreach(dep, invoker.group_deps) {
294 _group_deps_metadata += [
295 {
296 type = "dep"
Wyatt Heplerea02de82020-11-08 00:22:03 -0800297 group = get_label_info(dep, "label_no_toolchain")
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700298 },
299 ]
300 }
301
302 _deps += invoker.group_deps
Alexei Frolova454c682019-11-19 10:55:07 -0800303 }
304
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800305 group(_group_target + ".lib") {
306 deps = []
307 foreach(_target, _deps) {
308 _dep_target = get_label_info(_target, "label_no_toolchain")
309 _dep_toolchain = get_label_info(_target, "toolchain")
310 deps += [ "$_dep_target.lib($_dep_toolchain)" ]
311 }
312 }
313
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700314 _metadata_group_target = "${target_name}_pw_test_group_metadata"
315 group(_metadata_group_target) {
316 metadata = {
317 group_deps = _group_deps_metadata
318 self = [
319 {
320 type = "self"
Wyatt Heplerea02de82020-11-08 00:22:03 -0800321 name = get_label_info(":$_group_target", "label_no_toolchain")
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700322 },
323 ]
Alexei Frolova454c682019-11-19 10:55:07 -0800324
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700325 # Metadata from the group's own unit test targets is forwarded through
326 # the group dependencies group. This entry is listed as a "walk_key" in
327 # the generated file so that only test targets' metadata (not group
328 # targets) appear in the output.
329 if (defined(invoker.tests)) {
330 propagate_metadata_from = invoker.tests
331 }
332 }
333 deps = _deps
334 }
335
336 _test_group_deps = [ ":$_metadata_group_target" ]
337
338 generated_file(_group_target) {
339 outputs = [ "$target_out_dir/$target_name.testinfo.json" ]
340 data_keys = [
341 "group_deps",
342 "self",
343 "tests",
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800344 ]
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700345 walk_keys = [ "propagate_metadata_from" ]
346 output_conversion = "json"
347 deps = _test_group_deps
348 }
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800349
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800350 # If automatic test running is enabled, create a *.run group that collects
351 # all of the individual *.run targets and groups.
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700352 if (pw_unit_test_AUTOMATIC_RUNNER != "") {
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800353 group(_group_target + ".run") {
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700354 deps = [ ":$_group_target" ]
355 foreach(_target, _deps) {
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800356 _dep_target = get_label_info(_target, "label_no_toolchain")
357 _dep_toolchain = get_label_info(_target, "toolchain")
358 deps += [ "$_dep_target.run($_dep_toolchain)" ]
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700359 }
Wyatt Hepleredf6f292019-11-25 18:52:21 -0800360 }
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800361
362 # TODO(frolv): Remove this deprecated alias.
363 group(_group_target + "_run") {
364 deps = [ ":$_group_target.run" ]
365 }
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800366 }
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700367 } else { # _group_is_enabled
368 # Create empty groups for the tests to avoid pulling in any dependencies.
369 group(_group_target) {
370 }
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800371 group(_group_target + ".lib") {
372 }
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800373
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700374 if (pw_unit_test_AUTOMATIC_RUNNER != "") {
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800375 group(_group_target + ".run") {
376 }
377
378 # TODO(frolv): Remove this deprecated alias.
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700379 group(_group_target + "_run") {
Wyatt Hepleredf6f292019-11-25 18:52:21 -0800380 }
381 }
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700382
383 not_needed("*")
384 not_needed(invoker, "*")
Wyatt Hepleredf6f292019-11-25 18:52:21 -0800385 }
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800386
387 # All of the tests in this group and its dependencies bundled into a single
388 # test binary.
389 pw_test(_group_target + ".bundle") {
390 deps = [ ":$_group_target.lib" ]
391 enable_if = _group_is_enabled
392 }
Alexei Frolova454c682019-11-19 10:55:07 -0800393}