Francois-Rene Rideau | 608b4cd | 2015-07-29 15:40:46 +0000 | [diff] [blame] | 1 | """Utilities for testing bazel.""" |
| 2 | # |
Damien Martin-Guillerez | f88f4d8 | 2015-09-25 13:56:55 +0000 | [diff] [blame] | 3 | # Copyright 2015 The Bazel Authors. All rights reserved. |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 16 | |
Googler | b89ec43 | 2024-10-07 10:05:35 -0700 | [diff] [blame] | 17 | load("@rules_shell//shell:sh_test.bzl", "sh_test") |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 18 | load(":test_rules_private.bzl", "BASH_RUNFILES_DEP", "INIT_BASH_RUNFILES") |
| 19 | |
| 20 | _SH_STUB = "\n".join(["#!/bin/bash"] + INIT_BASH_RUNFILES + [ |
| 21 | "function add_ws_name() {", |
| 22 | ' [[ "$1" =~ external/* ]] && echo "${1#external/}" || echo "$TEST_WORKSPACE/$1"', |
| 23 | "}", |
| 24 | "", |
| 25 | ]) |
| 26 | |
| 27 | def _bash_rlocation(f): |
| 28 | return '"$(rlocation "$(add_ws_name "%s")")"' % f.short_path |
| 29 | |
| 30 | def _make_sh_test(name, **kwargs): |
Googler | b89ec43 | 2024-10-07 10:05:35 -0700 | [diff] [blame] | 31 | sh_test( |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 32 | name = name, |
| 33 | srcs = [name + "_impl"], |
| 34 | data = [name + "_impl"], |
| 35 | deps = [BASH_RUNFILES_DEP], |
| 36 | **kwargs |
| 37 | ) |
| 38 | |
Laszlo Csomor | 6d0b14b | 2019-07-04 01:20:48 -0700 | [diff] [blame] | 39 | _TEST_ATTRS = { |
| 40 | "args": None, |
| 41 | "size": None, |
| 42 | "timeout": None, |
| 43 | "flaky": None, |
| 44 | "local": None, |
| 45 | "shard_count": None, |
| 46 | } |
| 47 | |
| 48 | def _helper_rule_attrs(test_attrs, own_attrs): |
| 49 | r = {} |
| 50 | r.update({k: v for k, v in test_attrs.items() if k not in _TEST_ATTRS}) |
| 51 | r.update(own_attrs) |
| 52 | r.update( |
| 53 | dict( |
| 54 | testonly = 1, |
| 55 | visibility = ["//visibility:private"], |
| 56 | ), |
| 57 | ) |
| 58 | return r |
| 59 | |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 60 | ### First, trivial tests that either always pass, always fail, |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 61 | ### or sometimes pass depending on a trivial computation. |
| 62 | |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 63 | def success_target(ctx, msg, exe = None): |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 64 | """Return a success for an analysis test. |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 65 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 66 | The test rule must have an executable output. |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 67 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 68 | Args: |
| 69 | ctx: the Bazel rule context |
| 70 | msg: an informative message to display |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 71 | exe: the output artifact (must have been created with |
| 72 | ctx.actions.declare_file or declared in ctx.output), or None meaning |
| 73 | ctx.outputs.executable |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 74 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 75 | Returns: |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 76 | DefaultInfo that can be added to a sh_test's srcs AND data. The test will |
| 77 | always pass. |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 78 | """ |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 79 | exe = exe or ctx.outputs.executable |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 80 | ctx.actions.write( |
| 81 | output = exe, |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 82 | content = "#!/bin/bash\ncat <<'__eof__'\n" + msg + "\n__eof__\necho", |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 83 | is_executable = True, |
| 84 | ) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 85 | return [DefaultInfo(files = depset([exe]))] |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 86 | |
| 87 | def _successful_test_impl(ctx): |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 88 | return success_target(ctx, ctx.attr.msg, exe = ctx.outputs.out) |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 89 | |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 90 | _successful_rule = rule( |
| 91 | attrs = { |
| 92 | "msg": attr.string(mandatory = True), |
| 93 | "out": attr.output(), |
| 94 | }, |
Googler | 9c2989d | 2015-08-25 17:57:13 +0000 | [diff] [blame] | 95 | implementation = _successful_test_impl, |
| 96 | ) |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 97 | |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 98 | def successful_test(name, msg, **kwargs): |
| 99 | _successful_rule( |
Laszlo Csomor | 6d0b14b | 2019-07-04 01:20:48 -0700 | [diff] [blame] | 100 | **_helper_rule_attrs( |
| 101 | kwargs, |
| 102 | dict( |
| 103 | name = name + "_impl", |
| 104 | msg = msg, |
| 105 | out = name + "_impl.sh", |
| 106 | ), |
| 107 | ) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 108 | ) |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 109 | |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 110 | _make_sh_test(name, **kwargs) |
| 111 | |
| 112 | def failure_target(ctx, msg, exe = None): |
| 113 | """Return a failure for an analysis test. |
laszlocsomor | 28f8af7c | 2019-05-17 01:48:56 -0700 | [diff] [blame] | 114 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 115 | Args: |
| 116 | ctx: the Bazel rule context |
| 117 | msg: an informative message to display |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 118 | exe: the output artifact (must have been created with |
| 119 | ctx.actions.declare_file or declared in ctx.output), or None meaning |
| 120 | ctx.outputs.executable |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 121 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 122 | Returns: |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 123 | DefaultInfo that can be added to a sh_test's srcs AND data. The test will |
| 124 | always fail. |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 125 | """ |
| 126 | |
| 127 | ### fail(msg) ### <--- This would fail at analysis time. |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 128 | exe = exe or ctx.outputs.executable |
laurentlb | f09429c | 2018-11-14 06:07:43 -0800 | [diff] [blame] | 129 | ctx.actions.write( |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 130 | output = exe, |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 131 | content = "#!/bin/bash\ncat >&2 <<'__eof__'\n" + msg + "\n__eof__\nexit 1", |
laurentlb | fe2791b | 2018-11-14 08:54:01 -0800 | [diff] [blame] | 132 | is_executable = True, |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 133 | ) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 134 | return [DefaultInfo(files = depset([exe]))] |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 135 | |
| 136 | def _failed_test_impl(ctx): |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 137 | return failure_target(ctx, ctx.attr.msg, exe = ctx.outputs.out) |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 138 | |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 139 | _failed_rule = rule( |
| 140 | attrs = { |
| 141 | "msg": attr.string(mandatory = True), |
| 142 | "out": attr.output(), |
| 143 | }, |
Googler | 9c2989d | 2015-08-25 17:57:13 +0000 | [diff] [blame] | 144 | implementation = _failed_test_impl, |
| 145 | ) |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 146 | |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 147 | def failed_test(name, msg, **kwargs): |
| 148 | _failed_rule( |
Laszlo Csomor | 6d0b14b | 2019-07-04 01:20:48 -0700 | [diff] [blame] | 149 | **_helper_rule_attrs( |
| 150 | kwargs, |
| 151 | dict( |
| 152 | name = name + "_impl", |
| 153 | msg = msg, |
| 154 | out = name + "_impl.sh", |
| 155 | ), |
| 156 | ) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 157 | ) |
| 158 | |
| 159 | _make_sh_test(name, **kwargs) |
| 160 | |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 161 | ### Second, general purpose utilities |
| 162 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 163 | def assert_(condition, string = "assertion failed", *args): |
| 164 | """Trivial assertion mechanism. |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 165 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 166 | Args: |
| 167 | condition: a generalized boolean expected to be true |
| 168 | string: a format string for the error message should the assertion fail |
| 169 | *args: format arguments for the error message should the assertion fail |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 170 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 171 | Returns: |
| 172 | None. |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 173 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 174 | Raises: |
| 175 | an error if the condition isn't true. |
| 176 | """ |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 177 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 178 | if not condition: |
| 179 | fail(string % args) |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 180 | |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 181 | def strip_prefix(prefix, string): |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 182 | assert_( |
| 183 | string.startswith(prefix), |
| 184 | "%s does not start with %s", |
| 185 | string, |
| 186 | prefix, |
| 187 | ) |
| 188 | return string[len(prefix):len(string)] |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 189 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 190 | def expectation_description(expect = None, expect_failure = None): |
| 191 | """Turn expectation of result or error into a string.""" |
| 192 | if expect_failure: |
| 193 | return "failure " + str(expect_failure) |
| 194 | else: |
| 195 | return "result " + repr(expect) |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 196 | |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 197 | def check_results(result, failure, expect, expect_failure): |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 198 | """See if actual computation results match expectations. |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 199 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 200 | Args: |
| 201 | result: the result returned by the test if it ran to completion |
| 202 | failure: the failure message caught while testing, if any |
| 203 | expect: the expected result for a successful test, if no failure expected |
| 204 | expect_failure: the expected failure message for the test, if any |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 205 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 206 | Returns: |
| 207 | a pair (tuple) of a boolean (true if success) and a message (string). |
| 208 | """ |
| 209 | wanted = expectation_description(expect, expect_failure) |
| 210 | found = expectation_description(result, failure) |
| 211 | if wanted == found: |
| 212 | return (True, "successfully computed " + wanted) |
| 213 | else: |
| 214 | return (False, "expect " + wanted + " but found " + found) |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 215 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 216 | def load_results( |
| 217 | name, |
| 218 | result = None, |
| 219 | failure = None, |
| 220 | expect = None, |
| 221 | expect_failure = None): |
| 222 | """issue load-time results of a test. |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 223 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 224 | Args: |
| 225 | name: the name of the Bazel rule at load time. |
| 226 | result: the result returned by the test if it ran to completion |
| 227 | failure: the failure message caught while testing, if any |
| 228 | expect: the expected result for a successful test, if no failure expected |
| 229 | expect_failure: the expected failure message for the test, if any |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 230 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 231 | Returns: |
| 232 | None, after issuing a rule that will succeed at execution time if |
| 233 | expectations were met. |
| 234 | """ |
| 235 | (is_success, msg) = check_results(result, failure, expect, expect_failure) |
| 236 | this_test = successful_test if is_success else failed_test |
| 237 | return this_test(name = name, msg = msg) |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 238 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 239 | def analysis_results( |
| 240 | ctx, |
| 241 | result = None, |
| 242 | failure = None, |
| 243 | expect = None, |
| 244 | expect_failure = None): |
| 245 | """issue analysis-time results of a test. |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 246 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 247 | Args: |
| 248 | ctx: the Bazel rule context |
| 249 | result: the result returned by the test if it ran to completion |
| 250 | failure: the failure message caught while testing, if any |
| 251 | expect: the expected result for a successful test, if no failure expected |
| 252 | expect_failure: the expected failure message for the test, if any |
Francois-Rene Rideau | 73893cc | 2015-07-20 23:40:48 +0000 | [diff] [blame] | 253 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 254 | Returns: |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 255 | DefaultInfo that can be added to a sh_test's srcs AND data. The test will |
| 256 | always succeed at execution time if expectation were met, |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 257 | or fail at execution time if they didn't. |
| 258 | """ |
| 259 | (is_success, msg) = check_results(result, failure, expect, expect_failure) |
| 260 | this_test = success_target if is_success else failure_target |
| 261 | return this_test(ctx, msg) |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 262 | |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 263 | ### Simple tests |
| 264 | |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 265 | def _rule_test_rule_impl(ctx): |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 266 | """check that a rule generates the desired outputs and providers.""" |
| 267 | rule_ = ctx.attr.rule |
| 268 | rule_name = str(rule_.label) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 269 | exe = ctx.outputs.out |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 270 | if ctx.attr.generates: |
| 271 | # Generate the proper prefix to remove from generated files. |
| 272 | prefix_parts = [] |
John Cater | b89f30e | 2016-11-30 19:01:23 +0000 | [diff] [blame] | 273 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 274 | if rule_.label.workspace_root: |
| 275 | # Create a prefix that is correctly relative to the output of this rule. |
| 276 | prefix_parts = ["..", strip_prefix("external/", rule_.label.workspace_root)] |
John Cater | b89f30e | 2016-11-30 19:01:23 +0000 | [diff] [blame] | 277 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 278 | if rule_.label.package: |
| 279 | prefix_parts.append(rule_.label.package) |
John Cater | b89f30e | 2016-11-30 19:01:23 +0000 | [diff] [blame] | 280 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 281 | prefix = "/".join(prefix_parts) |
John Cater | b89f30e | 2016-11-30 19:01:23 +0000 | [diff] [blame] | 282 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 283 | if prefix: |
| 284 | # If the prefix isn't empty, it needs a trailing slash. |
| 285 | prefix = prefix + "/" |
John Cater | b89f30e | 2016-11-30 19:01:23 +0000 | [diff] [blame] | 286 | |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 287 | # TODO(bazel-team): Use set() instead of sorted() once |
| 288 | # set comparison is implemented. |
| 289 | # TODO(bazel-team): Use a better way to determine if two paths refer to |
| 290 | # the same file. |
| 291 | generates = sorted(ctx.attr.generates) |
| 292 | generated = sorted([ |
| 293 | strip_prefix(prefix, f.short_path) |
| 294 | for f in rule_.files.to_list() |
| 295 | ]) |
| 296 | if generates != generated: |
| 297 | fail("rule %s generates %s not %s" % |
| 298 | (rule_name, repr(generated), repr(generates))) |
| 299 | provides = ctx.attr.provides |
| 300 | if provides: |
| 301 | files = [] |
| 302 | commands = [] |
| 303 | for k in provides.keys(): |
| 304 | if hasattr(rule_, k): |
| 305 | v = repr(getattr(rule_, k)) |
| 306 | else: |
| 307 | fail(("rule %s doesn't provide attribute %s. " + |
| 308 | "Its list of attributes is: %s") % |
| 309 | (rule_name, k, dir(rule_))) |
laurentlb | f09429c | 2018-11-14 06:07:43 -0800 | [diff] [blame] | 310 | file_ = ctx.actions.declare_file(exe.basename + "." + k) |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 311 | files += [file_] |
| 312 | regexp = provides[k] |
| 313 | commands += [ |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 314 | "file_=%s" % _bash_rlocation(file_), |
| 315 | "if ! grep %s \"$file_\" ; then echo 'bad %s:' ; cat \"$file_\" ; echo ; exit 1 ; fi" % |
| 316 | (repr(regexp), k), |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 317 | ] |
laurentlb | f09429c | 2018-11-14 06:07:43 -0800 | [diff] [blame] | 318 | ctx.actions.write(output = file_, content = v) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 319 | script = _SH_STUB + "\n".join(commands) |
laurentlb | fe2791b | 2018-11-14 08:54:01 -0800 | [diff] [blame] | 320 | ctx.actions.write(output = exe, content = script, is_executable = True) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 321 | return [DefaultInfo(files = depset([exe]), runfiles = ctx.runfiles([exe] + files))] |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 322 | else: |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 323 | return success_target(ctx, "success", exe = exe) |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 324 | |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 325 | _rule_test_rule = rule( |
Googler | 9c2989d | 2015-08-25 17:57:13 +0000 | [diff] [blame] | 326 | attrs = { |
| 327 | "rule": attr.label(mandatory = True), |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 328 | "generates": attr.string_list(), |
Googler | 9c2989d | 2015-08-25 17:57:13 +0000 | [diff] [blame] | 329 | "provides": attr.string_dict(), |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 330 | "out": attr.output(), |
Googler | 9c2989d | 2015-08-25 17:57:13 +0000 | [diff] [blame] | 331 | }, |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 332 | implementation = _rule_test_rule_impl, |
Googler | 9c2989d | 2015-08-25 17:57:13 +0000 | [diff] [blame] | 333 | ) |
Francois-Rene Rideau | b29ebdc | 2015-06-19 15:10:47 +0000 | [diff] [blame] | 334 | |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 335 | def rule_test(name, rule, generates = None, provides = None, **kwargs): |
| 336 | _rule_test_rule( |
Laszlo Csomor | 6d0b14b | 2019-07-04 01:20:48 -0700 | [diff] [blame] | 337 | **_helper_rule_attrs( |
| 338 | kwargs, |
| 339 | dict( |
| 340 | name = name + "_impl", |
| 341 | rule = rule, |
| 342 | generates = generates, |
| 343 | provides = provides, |
| 344 | out = name + ".sh", |
| 345 | ), |
| 346 | ) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 347 | ) |
| 348 | |
| 349 | _make_sh_test(name, **kwargs) |
| 350 | |
| 351 | def _file_test_rule_impl(ctx): |
vladmos | 20a042f | 2018-06-01 04:51:21 -0700 | [diff] [blame] | 352 | """check that a file has a given content.""" |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 353 | exe = ctx.outputs.out |
Googler | a780be3 | 2018-10-16 13:29:06 -0700 | [diff] [blame] | 354 | file_ = ctx.file.file |
| 355 | content = ctx.attr.content |
| 356 | regexp = ctx.attr.regexp |
| 357 | matches = ctx.attr.matches |
| 358 | if bool(content) == bool(regexp): |
| 359 | fail("Must specify one and only one of content or regexp") |
| 360 | if content and matches != -1: |
| 361 | fail("matches only makes sense with regexp") |
| 362 | if content: |
laurentlb | f09429c | 2018-11-14 06:07:43 -0800 | [diff] [blame] | 363 | dat = ctx.actions.declare_file(exe.basename + ".dat") |
| 364 | ctx.actions.write( |
Googler | a780be3 | 2018-10-16 13:29:06 -0700 | [diff] [blame] | 365 | output = dat, |
| 366 | content = content, |
| 367 | ) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 368 | script = "diff -u %s %s" % (_bash_rlocation(dat), _bash_rlocation(file_)) |
laurentlb | f09429c | 2018-11-14 06:07:43 -0800 | [diff] [blame] | 369 | ctx.actions.write( |
Googler | a780be3 | 2018-10-16 13:29:06 -0700 | [diff] [blame] | 370 | output = exe, |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 371 | content = _SH_STUB + script, |
laurentlb | f09429c | 2018-11-14 06:07:43 -0800 | [diff] [blame] | 372 | is_executable = True, |
Googler | a780be3 | 2018-10-16 13:29:06 -0700 | [diff] [blame] | 373 | ) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 374 | return [DefaultInfo(files = depset([exe]), runfiles = ctx.runfiles([exe, dat, file_]))] |
Googler | a780be3 | 2018-10-16 13:29:06 -0700 | [diff] [blame] | 375 | if matches != -1: |
| 376 | script = "[ %s == $(grep -c %s %s) ]" % ( |
| 377 | matches, |
| 378 | repr(regexp), |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 379 | _bash_rlocation(file_), |
Googler | a780be3 | 2018-10-16 13:29:06 -0700 | [diff] [blame] | 380 | ) |
| 381 | else: |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 382 | script = "grep %s %s" % (repr(regexp), _bash_rlocation(file_)) |
laurentlb | f09429c | 2018-11-14 06:07:43 -0800 | [diff] [blame] | 383 | ctx.actions.write( |
Googler | a780be3 | 2018-10-16 13:29:06 -0700 | [diff] [blame] | 384 | output = exe, |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 385 | content = _SH_STUB + script, |
laurentlb | f09429c | 2018-11-14 06:07:43 -0800 | [diff] [blame] | 386 | is_executable = True, |
Laszlo Csomor | d550145 | 2018-10-16 08:28:21 -0700 | [diff] [blame] | 387 | ) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 388 | return [DefaultInfo(files = depset([exe]), runfiles = ctx.runfiles([exe, file_]))] |
Laszlo Csomor | d550145 | 2018-10-16 08:28:21 -0700 | [diff] [blame] | 389 | |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 390 | _file_test_rule = rule( |
Googler | 9c2989d | 2015-08-25 17:57:13 +0000 | [diff] [blame] | 391 | attrs = { |
Googler | a780be3 | 2018-10-16 13:29:06 -0700 | [diff] [blame] | 392 | "file": attr.label( |
Googler | 9c2989d | 2015-08-25 17:57:13 +0000 | [diff] [blame] | 393 | mandatory = True, |
laurentlb | f09429c | 2018-11-14 06:07:43 -0800 | [diff] [blame] | 394 | allow_single_file = True, |
Googler | 9c2989d | 2015-08-25 17:57:13 +0000 | [diff] [blame] | 395 | ), |
| 396 | "content": attr.string(default = ""), |
| 397 | "regexp": attr.string(default = ""), |
| 398 | "matches": attr.int(default = -1), |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 399 | "out": attr.output(), |
Googler | 9c2989d | 2015-08-25 17:57:13 +0000 | [diff] [blame] | 400 | }, |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 401 | implementation = _file_test_rule_impl, |
Googler | 9c2989d | 2015-08-25 17:57:13 +0000 | [diff] [blame] | 402 | ) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 403 | |
| 404 | def file_test(name, file, content = None, regexp = None, matches = None, **kwargs): |
| 405 | _file_test_rule( |
Laszlo Csomor | 6d0b14b | 2019-07-04 01:20:48 -0700 | [diff] [blame] | 406 | **_helper_rule_attrs( |
| 407 | kwargs, |
| 408 | dict( |
| 409 | name = name + "_impl", |
| 410 | file = file, |
| 411 | content = content or "", |
| 412 | regexp = regexp or "", |
| 413 | matches = matches if (matches != None) else -1, |
| 414 | out = name + "_impl.sh", |
| 415 | ), |
| 416 | ) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 417 | ) |
Laszlo Csomor | 77b9875 | 2019-05-17 03:15:22 -0700 | [diff] [blame] | 418 | _make_sh_test(name, **kwargs) |