1# Copyright 2023 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 15import("//build_overrides/pigweed.gni") 16 17import("$dir_pw_build/python.gni") 18import("$dir_pw_build/test_info.gni") 19 20# Creates a Python action to use as a test and associated metadata. 21# 22# This template derives several additional targets: 23# - <target_name>.metadata produces the test metadata when included in a 24# `pw_test_group`. This metadata includes the Ninja target that runs the 25# test. 26# - <target_name>.script creates a `pw_python_action` to run the test and 27# wraps it as a standalone `pw_python_package`. 28# - <target_name>.group creates a `pw_python_group` in order to apply tools, 29# e.g. linters, to the standalone package. 30# - <target_name>.lib is an empty group for compatibility with 31# `pw_test_group`. 32# - <target_name>.run invokes the test. 33# 34# Targets defined using this template will produce test metadata with a 35# `test_type` of "action_test" and a `ninja_target` value that will invoke the 36# test when passed to Ninja, i.e. `ninja -C out <ninja_target>`. 37# 38# Args: 39# - The following args have the same meaning as for `pw_test`: 40# enable_if 41# envvars (may also use `environment`) 42# tags 43# extra_metadata 44# source_gen_deps 45# 46# - The following args have the same meaning as for `pw_python_action`: 47# script (may be omitted if `sources` has length=1) 48# args 49# deps 50# environment (may also use `envvars`) 51# working_directory 52# command_launcher 53# venv 54# 55# - The following args have the same meaning as for `pw_python_package`: 56# sources 57# python_deps 58# other_deps 59# inputs 60# static_analysis 61# pylintrc 62# mypy_ini 63# ruff_toml 64# 65# - action: Optional string or scope. If a string, this should be a label to 66# a `pw_python_action` target that performs the test. If a scope, this 67# has the same meaning as for `pw_python_script`. 68template("pw_python_action_test") { 69 _test_target_name = target_name 70 _deps = [] 71 _run_deps = [] 72 _metadata = { 73 } 74 75 _test_is_enabled = !defined(invoker.enable_if) || invoker.enable_if 76 if (_test_is_enabled) { 77 # Metadata for this test when used as part of a pw_test_group target. 78 _test_metadata = "${target_name}.metadata" 79 _ninja_target = "$target_out_dir/$target_name.run.stamp" 80 _extra_metadata = { 81 forward_variables_from(invoker, [ "extra_metadata" ]) 82 ninja_target = rebase_path(_ninja_target, root_build_dir) 83 } 84 pw_test_info(_test_metadata) { 85 test_type = "action_test" 86 test_name = _test_target_name 87 forward_variables_from(invoker, [ "tags" ]) 88 extra_metadata = _extra_metadata 89 } 90 _deps += [ ":$_test_metadata" ] 91 _metadata = { 92 test_barrier = [ ":$_test_metadata" ] 93 } 94 95 if (defined(invoker.action) && invoker.action == "${invoker.action}") { 96 # `action` is a label to an existing Python action. 97 _run_deps = [ invoker.action ] 98 if (defined(invoker.deps)) { 99 _deps += invoker.deps 100 } 101 } else { 102 # Wrap the action in a Python script target for additional flexibility. 103 _test_script_name = _test_target_name + ".script" 104 105 _sources = [] 106 if (defined(invoker.script)) { 107 _sources += [ invoker.script ] 108 } 109 if (defined(invoker.sources)) { 110 _sources += invoker.sources 111 } 112 113 pw_python_script(_test_script_name) { 114 other_deps = [] 115 forward_variables_from(invoker, 116 [ 117 "action", 118 "python_deps", 119 "other_deps", 120 "inputs", 121 "static_analysis", 122 "testonly", 123 "pylintrc", 124 "mypy_ini", 125 "ruff_toml", 126 ]) 127 sources = _sources 128 if (defined(invoker.source_gen_deps)) { 129 other_deps += invoker.source_gen_deps 130 } 131 if (!defined(pylintrc)) { 132 pylintrc = "$dir_pigweed/.pylintrc" 133 } 134 if (!defined(mypy_ini)) { 135 mypy_ini = "$dir_pigweed/.mypy.ini" 136 } 137 if (!defined(ruff_toml)) { 138 ruff_toml = "$dir_pigweed/.ruff.toml" 139 } 140 if (!defined(action)) { 141 action = { 142 environment = [] 143 forward_variables_from(invoker, 144 [ 145 "script", 146 "args", 147 "deps", 148 "environment", 149 "working_directory", 150 "command_launcher", 151 "venv", 152 ]) 153 if (defined(invoker.envvars)) { 154 environment += invoker.envvars 155 } 156 stamp = true 157 } 158 } 159 } 160 _deps += [ ":$_test_script_name" ] 161 _run_deps = [ ":$_test_script_name.action" ] 162 163 # Create a Python group in order to ensure the package is linted. 164 _test_python_group = _test_target_name + ".group" 165 pw_python_group(_test_python_group) { 166 python_deps = [ ":$_test_script_name" ] 167 } 168 _deps += [ ":$_test_python_group" ] 169 } 170 } else { 171 if (defined(invoker.source_gen_deps)) { 172 _deps += invoker.source_gen_deps 173 } 174 } 175 176 # For compatibility with `pw_test_group`. 177 group(_test_target_name + ".lib") { 178 forward_variables_from(invoker, [ "testonly" ]) 179 } 180 181 # For compatibility with `pw_test_group`. 182 group(_test_target_name + ".run") { 183 forward_variables_from(invoker, [ "testonly" ]) 184 deps = _run_deps 185 } 186 187 group(_test_target_name) { 188 forward_variables_from(invoker, [ "testonly" ]) 189 deps = _deps 190 metadata = _metadata 191 } 192} 193