blob: 1fdb42816d8466944a550f2f7d32ebc457052722 [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 #
23 # If set, the pw_test() template creates an action that invokes the test runner
24 # on each test executable. If unset, the pw_test() template only creates a test
25 # executable target.
26 #
27 # This should only be enabled for targets which support parallelized running of
28 # unit tests, such as desktops with multiple cores.
29 pw_unit_test_AUTOMATIC_RUNNER = ""
30
Alexei Frolovfbe68ff2020-11-16 13:44:52 -080031 # Additional dependencies required by all unit test targets. (For example, if
32 # using a different test library like Googletest.)
33 pw_unit_test_PUBLIC_DEPS = []
34
Alexei Frolov4c0428a2020-06-10 10:46:04 -070035 # Implementation of a main function for "pw_test" unit test binaries.
36 pw_unit_test_MAIN = "$dir_pw_unit_test:simple_printing_main"
37}
Alexei Frolov925fb8f2019-11-05 16:32:30 -080038
Wyatt Heplerdfe3c612020-04-23 13:13:45 -070039# Defines a target if enable_if is true. Otherwise, it defines that target as
Alexei Frolov69dccfd2020-11-13 12:10:24 -080040# <target_name>.DISABLED and creates an empty <target_name> group. This can be
Wyatt Heplerdfe3c612020-04-23 13:13:45 -070041# used to conditionally create targets without having to conditionally add them
42# to groups. This results in simpler BUILD.gn files.
43template("_pw_disableable_target") {
44 assert(defined(invoker.enable_if),
45 "`enable_if` is required for _pw_disableable_target")
46 assert(defined(invoker.target_type),
47 "`target_type` is required for _pw_disableable_target")
48
49 if (invoker.enable_if) {
50 _actual_target_name = target_name
51 } else {
Alexei Frolov69dccfd2020-11-13 12:10:24 -080052 _actual_target_name = target_name + ".DISABLED"
Wyatt Heplerdfe3c612020-04-23 13:13:45 -070053
Wyatt Hepler4e6a4722020-07-09 17:34:48 -070054 # If the target is disabled, create an empty target in its place. Use an
55 # action with the original target's sources as inputs to ensure that
56 # the source files exist (even if they don't compile).
Wyatt Heplerc8e05a42020-10-19 14:49:39 -070057 pw_python_action(target_name) {
Wyatt Hepler27f69f02020-07-27 09:06:21 -070058 script = "$dir_pw_build/py/pw_build/nop.py"
Wyatt Hepler4e6a4722020-07-09 17:34:48 -070059 stamp = true
60
61 inputs = []
62 if (defined(invoker.sources)) {
63 inputs += invoker.sources
64 }
65 if (defined(invoker.public)) {
66 inputs += invoker.public
67 }
Wyatt Heplerdfe3c612020-04-23 13:13:45 -070068 }
69 }
70
71 target(invoker.target_type, _actual_target_name) {
72 forward_variables_from(invoker,
73 "*",
74 [
75 "enable_if",
76 "target_type",
77 ])
Wyatt Hepler68fde052020-05-13 14:43:03 -070078
79 # Remove "" from dependencies. This allows disabling targets if a variable
80 # (e.g. a backend) is empty.
81 if (defined(public_deps)) {
82 public_deps += [ "" ]
83 public_deps -= [ "" ]
84 }
85 if (defined(deps)) {
86 deps += [ "" ]
87 deps -= [ "" ]
88 }
Wyatt Heplerdfe3c612020-04-23 13:13:45 -070089 }
90}
91
Alexei Frolov69dccfd2020-11-13 12:10:24 -080092# Creates a library and an executable target for a unit test.
93#
94# <target_name>.lib contains the provided test sources as a library, which can
95# then be linked into a test executable.
96# <target_name> is a standalone executable which contains only the test sources
97# specified in the pw_unit_test_template.
Alexei Frolova454c682019-11-19 10:55:07 -080098#
Alexei Frolov4c0428a2020-06-10 10:46:04 -070099# If the pw_unit_test_AUTOMATIC_RUNNER variable is set, this template also creates a
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800100# "${test_name}.run" target which runs the unit test executable after building
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800101# it.
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800102#
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700103# Args:
104# - enable_if: (optional) Conditionally enables or disables this test. The test
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800105# target and *.run target do nothing when the test is disabled. The
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700106# disabled test can still be built and run with the
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800107# <target_name>.DISABLED and <target_name>.DISABLED.run targets.
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700108# Defaults to true (enable_if).
109# - All of the regular "executable" target args are accepted.
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800110template("pw_test") {
111 # This is required in order to reference the pw_test template's target name
112 # within the test_metadata of the metadata group below. The group() definition
113 # creates a new scope where the "target_name" variable is set to its target,
114 # shadowing the one in this scope.
Alexei Frolovd1f98fa2019-11-08 15:41:37 -0800115 _test_target_name = target_name
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800116
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700117 _test_is_enabled = !defined(invoker.enable_if) || invoker.enable_if
118
Michael Spang524ead42020-06-12 14:23:40 -0400119 # Always set the output_dir as pigweed is not compatible with shared
120 # bin directories for tests.
Michael Spangcdba5162020-06-12 14:45:07 -0400121 _test_output_dir = "${target_out_dir}/test"
Michael Spang524ead42020-06-12 14:23:40 -0400122 if (defined(invoker.output_dir)) {
123 _test_output_dir = invoker.output_dir
124 }
125
Michael Spang6aa8eb02020-06-11 20:19:05 -0400126 _test_main = pw_unit_test_MAIN
127 if (defined(invoker.test_main)) {
128 _test_main = invoker.test_main
129 }
130
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800131 # The unit test code as a source_set.
132 _pw_disableable_target("$target_name.lib") {
133 target_type = "pw_source_set"
134 enable_if = _test_is_enabled
135 forward_variables_from(invoker, "*", [ "metadata" ])
136
137 if (!defined(public_deps)) {
138 public_deps = []
139 }
Alexei Frolovfbe68ff2020-11-16 13:44:52 -0800140 public_deps += pw_unit_test_PUBLIC_DEPS + [ dir_pw_unit_test ]
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800141 }
142
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700143 _pw_disableable_target(_test_target_name) {
144 target_type = "pw_executable"
145 enable_if = _test_is_enabled
146
Alexei Frolova454c682019-11-19 10:55:07 -0800147 # Metadata for this test when used as part of a pw_test_group target.
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800148 metadata = {
Alexei Frolova454c682019-11-19 10:55:07 -0800149 tests = [
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800150 {
Alexei Frolova454c682019-11-19 10:55:07 -0800151 type = "test"
Alexei Frolovd1f98fa2019-11-08 15:41:37 -0800152 test_name = _test_target_name
Michael Spang524ead42020-06-12 14:23:40 -0400153 test_directory = rebase_path(_test_output_dir, root_build_dir)
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800154 },
155 ]
156 }
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800157
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800158 deps = [ ":$_test_target_name.lib" ]
Michael Spang6aa8eb02020-06-11 20:19:05 -0400159 if (_test_main != "") {
160 deps += [ _test_main ]
161 }
Michael Spang524ead42020-06-12 14:23:40 -0400162
163 output_dir = _test_output_dir
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800164 }
165
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700166 if (pw_unit_test_AUTOMATIC_RUNNER != "") {
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800167 # When the automatic runner is set, create an action which runs the unit
168 # test executable using the test runner script.
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700169 if (_test_is_enabled) {
170 _test_to_run = _test_target_name
171 } else {
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800172 # Create a run target for the .DISABLED version of the test.
173 _test_to_run = _test_target_name + ".DISABLED"
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800174
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700175 # Create a dummy _run target for the regular version of the test.
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800176 group(_test_target_name + ".run") {
Wyatt Heplerdfe3c612020-04-23 13:13:45 -0700177 deps = [ ":$_test_target_name" ]
178 }
179 }
180
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800181 pw_python_action(_test_to_run + ".run") {
Rob Mohra0ba54f2020-02-27 11:43:49 -0800182 deps = [ ":$_test_target_name" ]
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700183 inputs = [ pw_unit_test_AUTOMATIC_RUNNER ]
Alexei Frolov3dbfcf02019-11-22 16:38:02 -0800184 script = "$dir_pw_unit_test/py/pw_unit_test/test_runner.py"
Wyatt Hepler438caa02021-01-15 17:13:11 -0800185 python_deps = [ "$dir_pw_cli/py" ]
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800186 args = [
187 "--runner",
Wyatt Hepler8224a642020-07-29 08:55:56 -0700188 rebase_path(pw_unit_test_AUTOMATIC_RUNNER),
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800189 "--test",
Wyatt Hepler8224a642020-07-29 08:55:56 -0700190 "<TARGET_FILE(:$_test_to_run)>",
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800191 ]
Alexei Frolov917756d2019-11-12 14:34:34 -0800192 stamp = true
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800193 }
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800194
195 # TODO(frolv): Alias for the deprecated _run target. Remove when projects
196 # are migrated.
197 group(_test_to_run + "_run") {
198 public_deps = [ ":$_test_to_run.run" ]
199 }
200 } else {
201 group(_test_target_name + ".run") {
202 }
Alexei Frolov925fb8f2019-11-05 16:32:30 -0800203 }
204}
Alexei Frolova454c682019-11-19 10:55:07 -0800205
206# Defines a related collection of unit tests.
207#
208# pw_test_group targets output a JSON metadata file for the Pigweed test runner.
209#
210# Args:
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700211# - tests: List of pw_test targets for each of the tests in the group.
212# - group_deps: (optional) pw_test_group targets on which this group depends.
213# - enable_if: (optional) Conditionally enables or disables this test group.
214# If false, an empty group is created. Defaults to true.
Alexei Frolova454c682019-11-19 10:55:07 -0800215template("pw_test_group") {
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800216 _group_target = target_name
217 _group_deps_metadata = []
Wyatt Hepleredf6f292019-11-25 18:52:21 -0800218 if (defined(invoker.tests)) {
219 _deps = invoker.tests
220 } else {
221 _deps = []
222 }
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800223
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700224 _group_is_enabled = !defined(invoker.enable_if) || invoker.enable_if
225
226 if (_group_is_enabled) {
227 if (defined(invoker.group_deps)) {
228 # If the group specified any other group dependencies, create a metadata
229 # entry for each of them indicating that they are another group and a
230 # group target to collect that metadata.
231 foreach(dep, invoker.group_deps) {
232 _group_deps_metadata += [
233 {
234 type = "dep"
Wyatt Heplerea02de82020-11-08 00:22:03 -0800235 group = get_label_info(dep, "label_no_toolchain")
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700236 },
237 ]
238 }
239
240 _deps += invoker.group_deps
Alexei Frolova454c682019-11-19 10:55:07 -0800241 }
242
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800243 group(_group_target + ".lib") {
244 deps = []
245 foreach(_target, _deps) {
246 _dep_target = get_label_info(_target, "label_no_toolchain")
247 _dep_toolchain = get_label_info(_target, "toolchain")
248 deps += [ "$_dep_target.lib($_dep_toolchain)" ]
249 }
250 }
251
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700252 _metadata_group_target = "${target_name}_pw_test_group_metadata"
253 group(_metadata_group_target) {
254 metadata = {
255 group_deps = _group_deps_metadata
256 self = [
257 {
258 type = "self"
Wyatt Heplerea02de82020-11-08 00:22:03 -0800259 name = get_label_info(":$_group_target", "label_no_toolchain")
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700260 },
261 ]
Alexei Frolova454c682019-11-19 10:55:07 -0800262
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700263 # Metadata from the group's own unit test targets is forwarded through
264 # the group dependencies group. This entry is listed as a "walk_key" in
265 # the generated file so that only test targets' metadata (not group
266 # targets) appear in the output.
267 if (defined(invoker.tests)) {
268 propagate_metadata_from = invoker.tests
269 }
270 }
271 deps = _deps
272 }
273
274 _test_group_deps = [ ":$_metadata_group_target" ]
275
276 generated_file(_group_target) {
277 outputs = [ "$target_out_dir/$target_name.testinfo.json" ]
278 data_keys = [
279 "group_deps",
280 "self",
281 "tests",
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800282 ]
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700283 walk_keys = [ "propagate_metadata_from" ]
284 output_conversion = "json"
285 deps = _test_group_deps
286 }
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800287
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800288 # If automatic test running is enabled, create a *.run group that collects
289 # all of the individual *.run targets and groups.
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700290 if (pw_unit_test_AUTOMATIC_RUNNER != "") {
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800291 group(_group_target + ".run") {
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700292 deps = [ ":$_group_target" ]
293 foreach(_target, _deps) {
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800294 _dep_target = get_label_info(_target, "label_no_toolchain")
295 _dep_toolchain = get_label_info(_target, "toolchain")
296 deps += [ "$_dep_target.run($_dep_toolchain)" ]
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700297 }
Wyatt Hepleredf6f292019-11-25 18:52:21 -0800298 }
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800299
300 # TODO(frolv): Remove this deprecated alias.
301 group(_group_target + "_run") {
302 deps = [ ":$_group_target.run" ]
303 }
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800304 }
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700305 } else { # _group_is_enabled
306 # Create empty groups for the tests to avoid pulling in any dependencies.
307 group(_group_target) {
308 }
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800309 group(_group_target + ".lib") {
310 }
Alexei Frolov8403f0a2019-11-20 13:57:54 -0800311
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700312 if (pw_unit_test_AUTOMATIC_RUNNER != "") {
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800313 group(_group_target + ".run") {
314 }
315
316 # TODO(frolv): Remove this deprecated alias.
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700317 group(_group_target + "_run") {
Wyatt Hepleredf6f292019-11-25 18:52:21 -0800318 }
319 }
Alexei Frolovbcac2c92020-05-19 10:24:20 -0700320
321 not_needed("*")
322 not_needed(invoker, "*")
Wyatt Hepleredf6f292019-11-25 18:52:21 -0800323 }
Alexei Frolov69dccfd2020-11-13 12:10:24 -0800324
325 # All of the tests in this group and its dependencies bundled into a single
326 # test binary.
327 pw_test(_group_target + ".bundle") {
328 deps = [ ":$_group_target.lib" ]
329 enable_if = _group_is_enabled
330 }
Alexei Frolova454c682019-11-19 10:55:07 -0800331}