1# Copyright 2019 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://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, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Unit tests for unittest.bzl.""" 16 17load("//lib:partial.bzl", "partial") 18load("//lib:unittest.bzl", "analysistest", "asserts", "loadingtest", "unittest") 19 20################################### 21####### basic_failing_test ######## 22################################### 23 24def _basic_failing_test(ctx): 25 """Unit tests for a basic library verification test that fails.""" 26 env = unittest.begin(ctx) 27 28 asserts.equals(env, 1, 2) 29 30 return unittest.end(env) 31 32basic_failing_test = unittest.make(_basic_failing_test) 33 34################################### 35####### failure_message_test ###### 36################################### 37 38def _failure_message_test(ctx): 39 """Failing unit test with arbitrary content in the message.""" 40 env = unittest.begin(ctx) 41 42 if not ctx.attr.message: 43 unittest.fail(env, "Message must be non-empty.") 44 asserts.equals(env, "", ctx.attr.message) 45 46 return unittest.end(env) 47 48failure_message_test = unittest.make( 49 _failure_message_test, 50 attrs = { 51 "message": attr.string(), 52 }, 53) 54 55################################### 56####### basic_passing_test ######## 57################################### 58def _basic_passing_test(ctx): 59 """Unit tests for a basic library verification test.""" 60 env = unittest.begin(ctx) 61 62 asserts.equals(env, 1, 1) 63 64 return unittest.end(env) 65 66basic_passing_test = unittest.make(_basic_passing_test) 67 68################################################# 69####### basic_passing_short_timeout_test ######## 70################################################# 71def _basic_passing_short_timeout_test(ctx): 72 """Unit tests for a basic library verification test.""" 73 env = unittest.begin(ctx) 74 75 asserts.equals(env, ctx.attr.timeout, "short") 76 77 return unittest.end(env) 78 79basic_passing_short_timeout_test = unittest.make(_basic_passing_short_timeout_test) 80 81################################### 82####### change_setting_test ####### 83################################### 84def _change_setting_test(ctx): 85 """Test to verify that an analysis test may change configuration.""" 86 env = analysistest.begin(ctx) 87 88 dep_min_os_version = analysistest.target_under_test(env)[_ChangeSettingInfo].min_os_version 89 asserts.equals(env, "1234.5678", dep_min_os_version) 90 91 return analysistest.end(env) 92 93_ChangeSettingInfo = provider( 94 doc = "min_os_version for change_setting_test", 95 fields = ["min_os_version"], 96) 97 98def _change_setting_fake_rule(ctx): 99 return [_ChangeSettingInfo(min_os_version = ctx.fragments.cpp.minimum_os_version())] 100 101change_setting_fake_rule = rule( 102 implementation = _change_setting_fake_rule, 103 fragments = ["cpp"], 104) 105 106change_setting_test = analysistest.make( 107 _change_setting_test, 108 config_settings = { 109 "//command_line_option:minimum_os_version": "1234.5678", 110 }, 111) 112 113#################################### 114####### failure_testing_test ####### 115#################################### 116def _failure_testing_test(ctx): 117 """Test to verify that an analysis test may verify a rule fails with fail().""" 118 env = analysistest.begin(ctx) 119 120 asserts.expect_failure(env, "This rule should never work") 121 122 return analysistest.end(env) 123 124def _failure_testing_fake_rule(ctx): 125 _ignore = [ctx] # @unused 126 fail("This rule should never work") 127 128failure_testing_fake_rule = rule( 129 implementation = _failure_testing_fake_rule, 130) 131 132failure_testing_test = analysistest.make( 133 _failure_testing_test, 134 expect_failure = True, 135) 136 137############################################ 138####### fail_unexpected_passing_test ####### 139############################################ 140def _fail_unexpected_passing_test(ctx): 141 """Test that fails by expecting an error that never occurs.""" 142 env = analysistest.begin(ctx) 143 144 asserts.expect_failure(env, "Oh no, going to fail") 145 146 return analysistest.end(env) 147 148def _fail_unexpected_passing_fake_rule(ctx): 149 _ignore = [ctx] # @unused 150 return [] 151 152fail_unexpected_passing_fake_rule = rule( 153 implementation = _fail_unexpected_passing_fake_rule, 154) 155 156fail_unexpected_passing_test = analysistest.make( 157 _fail_unexpected_passing_test, 158 expect_failure = True, 159) 160 161################################################ 162####### change_setting_with_failure_test ####### 163################################################ 164def _change_setting_with_failure_test(ctx): 165 """Test verifying failure while changing configuration.""" 166 env = analysistest.begin(ctx) 167 168 asserts.expect_failure(env, "unexpected minimum_os_version!!!") 169 170 return analysistest.end(env) 171 172def _change_setting_with_failure_fake_rule(ctx): 173 if ctx.fragments.cpp.minimum_os_version() == "error_error": 174 fail("unexpected minimum_os_version!!!") 175 return [] 176 177change_setting_with_failure_fake_rule = rule( 178 implementation = _change_setting_with_failure_fake_rule, 179 fragments = ["cpp"], 180) 181 182change_setting_with_failure_test = analysistest.make( 183 _change_setting_with_failure_test, 184 expect_failure = True, 185 config_settings = { 186 "//command_line_option:minimum_os_version": "error_error", 187 }, 188) 189 190#################################### 191####### inspect_actions_test ####### 192#################################### 193def _inspect_actions_test(ctx): 194 """Test verifying actions registered by a target.""" 195 env = analysistest.begin(ctx) 196 197 actions = analysistest.target_actions(env) 198 asserts.equals(env, 1, len(actions)) 199 action_output = actions[0].outputs.to_list()[0] 200 asserts.equals(env, "out.txt", action_output.basename) 201 return analysistest.end(env) 202 203def _inspect_actions_fake_rule(ctx): 204 out_file = ctx.actions.declare_file("out.txt") 205 ctx.actions.run_shell( 206 command = "echo 'hello' > %s" % out_file.basename, 207 outputs = [out_file], 208 ) 209 return [DefaultInfo(files = depset([out_file]))] 210 211inspect_actions_fake_rule = rule( 212 implementation = _inspect_actions_fake_rule, 213) 214 215inspect_actions_test = analysistest.make( 216 _inspect_actions_test, 217) 218 219#################################### 220####### inspect_aspect_test ####### 221#################################### 222_AddedByAspectInfo = provider( 223 doc = "Example provider added by example aspect", 224 fields = { 225 "value": "(str)", 226 }, 227) 228 229def _example_aspect_impl(target, ctx): 230 _ignore = [target, ctx] # @unused 231 return [ 232 _AddedByAspectInfo(value = "attached by aspect"), 233 ] 234 235example_aspect = aspect( 236 implementation = _example_aspect_impl, 237) 238 239def _inspect_aspect_test(ctx): 240 """Test verifying aspect run on a target.""" 241 env = analysistest.begin(ctx) 242 243 tut = env.ctx.attr.target_under_test 244 asserts.equals(env, "attached by aspect", tut[_AddedByAspectInfo].value) 245 return analysistest.end(env) 246 247def _inspect_aspect_fake_rule(ctx): 248 out_file = ctx.actions.declare_file("out.txt") 249 ctx.actions.run_shell( 250 command = "echo 'hello' > %s" % out_file.basename, 251 outputs = [out_file], 252 ) 253 return [DefaultInfo(files = depset([out_file]))] 254 255inspect_aspect_fake_rule = rule( 256 implementation = _inspect_aspect_fake_rule, 257) 258 259inspect_aspect_test = analysistest.make( 260 _inspect_aspect_test, 261 extra_target_under_test_aspects = [example_aspect], 262) 263 264######################################## 265####### inspect_output_dirs_test ####### 266######################################## 267_OutputDirInfo = provider( 268 doc = "bin_path for inspect_output_dirs_test", 269 fields = ["bin_path"], 270) 271 272def _inspect_output_dirs_test(ctx): 273 """Test verifying output directories used by a test.""" 274 env = analysistest.begin(ctx) 275 276 # Assert that the output bin dir observed by the aspect added by analysistest 277 # is the same as those observed by the rule directly, even when that's 278 # under a config transition and therefore not the same as the bin dir 279 # used by the test rule. 280 bin_path = analysistest.target_bin_dir_path(env) 281 target_under_test = analysistest.target_under_test(env) 282 asserts.false(env, not bin_path, "bin dir path not found.") 283 asserts.false( 284 env, 285 bin_path == ctx.bin_dir.path, 286 "test bin dir (%s) expected to differ with target_under_test bin dir (%s)." % (bin_path, ctx.bin_dir.path), 287 ) 288 asserts.equals(env, bin_path, target_under_test[_OutputDirInfo].bin_path) 289 return analysistest.end(env) 290 291def _inspect_output_dirs_fake_rule(ctx): 292 return [ 293 _OutputDirInfo( 294 bin_path = ctx.bin_dir.path, 295 ), 296 ] 297 298inspect_output_dirs_fake_rule = rule( 299 implementation = _inspect_output_dirs_fake_rule, 300) 301 302inspect_output_dirs_test = analysistest.make( 303 _inspect_output_dirs_test, 304 # The output directories differ between the test and target under test when 305 # the target under test is under a config transition. 306 config_settings = { 307 "//command_line_option:minimum_os_version": "1234.5678", 308 }, 309) 310 311def _loading_phase_test(env): 312 loadingtest.equals(env, "self_glob", ["unittest_tests.bzl"], native.glob(["unittest_tests.bzl"])) 313 314 # now use our own calls to assert we created a test case rule and test_suite for it. 315 loadingtest.equals(env, "test_exists", True, native.existing_rule(env.name + "_self_glob") != None) 316 loadingtest.equals(env, "suite_exists", True, native.existing_rule(env.name + "_tests") != None) 317 318######################################### 319 320# buildifier: disable=unnamed-macro 321def unittest_passing_tests_suite(): 322 """Creates the test targets and test suite for passing unittest.bzl tests. 323 324 Not all tests are included. Some unittest.bzl tests verify a test fails 325 when assertions are not met. Such tests must be run in an e2e shell test. 326 This suite only includes tests which verify success tests. 327 """ 328 unittest.suite( 329 "unittest_tests", 330 basic_passing_test, 331 partial.make(basic_passing_short_timeout_test, timeout = "short"), 332 ) 333 334 change_setting_test( 335 name = "change_setting_test", 336 target_under_test = ":change_setting_fake_target", 337 ) 338 change_setting_fake_rule( 339 name = "change_setting_fake_target", 340 tags = ["manual"], 341 ) 342 343 failure_testing_test( 344 name = "failure_testing_test", 345 target_under_test = ":failure_testing_fake_target", 346 ) 347 failure_testing_fake_rule( 348 name = "failure_testing_fake_target", 349 tags = ["manual"], 350 ) 351 352 change_setting_with_failure_test( 353 name = "change_setting_with_failure_test", 354 target_under_test = ":change_setting_with_failure_fake_target", 355 ) 356 change_setting_with_failure_fake_rule( 357 name = "change_setting_with_failure_fake_target", 358 tags = ["manual"], 359 ) 360 361 inspect_actions_test( 362 name = "inspect_actions_test", 363 target_under_test = ":inspect_actions_fake_target", 364 ) 365 inspect_actions_fake_rule( 366 name = "inspect_actions_fake_target", 367 tags = ["manual"], 368 ) 369 370 inspect_aspect_test( 371 name = "inspect_aspect_test", 372 target_under_test = ":inspect_aspect_fake_target", 373 ) 374 inspect_aspect_fake_rule( 375 name = "inspect_aspect_fake_target", 376 tags = ["manual"], 377 ) 378 379 inspect_output_dirs_test( 380 name = "inspect_output_dirs_test", 381 target_under_test = ":inspect_output_dirs_fake_target", 382 ) 383 inspect_output_dirs_fake_rule( 384 name = "inspect_output_dirs_fake_target", 385 tags = ["manual"], 386 ) 387 388 loading_env = loadingtest.make("selftest") 389 _loading_phase_test(loading_env) 390