1# Copyright 2022 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 analysis_test.bzl.""" 16 17load("//lib:analysis_test.bzl", "analysis_test", "test_suite") 18load("//lib:truth.bzl", "matching") 19load("//lib:util.bzl", "TestingAspectInfo") 20 21################################### 22####### change_setting_test ####### 23################################### 24 25_ChangeSettingInfo = provider( 26 doc = "min_os_version for change_setting_test", 27 fields = ["min_os_version"], 28) 29 30def _change_setting_fake_rule(ctx): 31 return [_ChangeSettingInfo(min_os_version = ctx.fragments.cpp.minimum_os_version())] 32 33change_setting_fake_rule = rule( 34 implementation = _change_setting_fake_rule, 35 fragments = ["cpp"], 36) 37 38def test_change_setting(name): 39 """Test to verify that an analysis test may change configuration.""" 40 change_setting_fake_rule(name = name + "_fake_target", tags = ["manual"]) 41 42 analysis_test( 43 name = name, 44 target = name + "_fake_target", 45 impl = _test_change_setting, 46 config_settings = { 47 "//command_line_option:minimum_os_version": "1234.5678", 48 }, 49 ) 50 51def _test_change_setting(env, target): 52 dep_min_os_version = target[_ChangeSettingInfo].min_os_version 53 env.expect.that_str(dep_min_os_version).equals("1234.5678") 54 55#################################### 56####### failure_testing_test ####### 57#################################### 58 59def _failure_testing_fake_rule(_ctx): 60 fail("This rule should never work") 61 62failure_testing_fake_rule = rule( 63 implementation = _failure_testing_fake_rule, 64) 65 66def test_failure_testing(name): 67 """Test to verify that an analysis test may verify a rule fails with fail().""" 68 failure_testing_fake_rule(name = name + "_fake_target", tags = ["manual"]) 69 70 analysis_test( 71 name = name, 72 target = name + "_fake_target", 73 impl = _test_failure_testing, 74 expect_failure = True, 75 ) 76 77def _test_failure_testing(env, target): 78 env.expect.that_target(target).failures().contains_predicate(matching.contains("This rule should never work")) 79 80############################################ 81####### fail_unexpected_passing_test ####### 82############################################ 83 84def _fail_unexpected_passing_fake_rule(_ctx): 85 return [] 86 87fail_unexpected_passing_fake_rule = rule( 88 implementation = _fail_unexpected_passing_fake_rule, 89) 90 91# @unused # TODO(ilist): add a shell test checking it fails 92def test_fail_unexpected_passing(name): 93 """Test that fails by expecting an error that never occurs.""" 94 fail_unexpected_passing_fake_rule(name = name + "_fake_target", tags = ["manual"]) 95 96 analysis_test( 97 name = name, 98 target = name + "_fake_target", 99 impl = _test_fail_unexpected_passing, 100 expect_failure = True, 101 ) 102 103def _test_fail_unexpected_passing(env, target): 104 env.expect.that_target(target).failures().contains_predicate(matching.contains("Oh no, going to fail")) 105 106################################################ 107####### change_setting_with_failure_test ####### 108################################################ 109def _change_setting_with_failure_fake_rule(ctx): 110 if ctx.fragments.cpp.minimum_os_version() == "error_error": 111 fail("unexpected minimum_os_version!!!") 112 return [] 113 114change_setting_with_failure_fake_rule = rule( 115 implementation = _change_setting_with_failure_fake_rule, 116 fragments = ["cpp"], 117) 118 119def test_change_setting_with_failure(name): 120 change_setting_with_failure_fake_rule(name = name + "_fake_target", tags = ["manual"]) 121 122 analysis_test( 123 name = name, 124 target = name + "_fake_target", 125 impl = _test_change_setting_with_failure, 126 expect_failure = True, 127 config_settings = { 128 "//command_line_option:minimum_os_version": "error_error", 129 }, 130 ) 131 132def _test_change_setting_with_failure(env, target): 133 """Test verifying failure while changing configuration.""" 134 env.expect.that_target(target).failures().contains_predicate( 135 matching.contains("unexpected minimum_os_version!!!"), 136 ) 137 138#################################### 139####### inspect_actions_test ####### 140#################################### 141def _inspect_actions_fake_rule(ctx): 142 out_file = ctx.actions.declare_file("out.txt") 143 ctx.actions.run_shell( 144 command = "echo 'hello' > %s" % out_file.basename, 145 outputs = [out_file], 146 ) 147 return [DefaultInfo(files = depset([out_file]))] 148 149inspect_actions_fake_rule = rule(implementation = _inspect_actions_fake_rule) 150 151def test_inspect_actions(name): 152 """Test verifying actions registered by a target.""" 153 inspect_actions_fake_rule(name = name + "_fake_target", tags = ["manual"]) 154 155 analysis_test(name = name, target = name + "_fake_target", impl = _test_inspect_actions) 156 157def _test_inspect_actions(env, target): 158 env.expect.that_int(len(target[TestingAspectInfo].actions)).equals(1) 159 action_output = target[TestingAspectInfo].actions[0].outputs.to_list()[0] 160 env.expect.that_str(action_output.basename).equals("out.txt") 161 162#################################### 163####### inspect_aspect_test ####### 164#################################### 165_AddedByAspectInfo = provider( 166 doc = "Example provider added by example aspect", 167 fields = {"value": "(str)"}, 168) 169 170def _example_aspect_impl(_target, _ctx): 171 return [_AddedByAspectInfo(value = "attached by aspect")] 172 173example_aspect = aspect(implementation = _example_aspect_impl) 174 175def _inspect_aspect_fake_rule(ctx): 176 out_file = ctx.actions.declare_file("out.txt") 177 ctx.actions.run_shell( 178 command = "echo 'hello' > %s" % out_file.basename, 179 outputs = [out_file], 180 ) 181 return [DefaultInfo(files = depset([out_file]))] 182 183inspect_aspect_fake_rule = rule(implementation = _inspect_aspect_fake_rule) 184 185def test_inspect_aspect(name): 186 """Test verifying aspect run on a target.""" 187 inspect_aspect_fake_rule(name = name + "_fake_target", tags = ["manual"]) 188 189 analysis_test( 190 name = name, 191 target = name + "_fake_target", 192 impl = _test_inspect_aspect, 193 extra_target_under_test_aspects = [example_aspect], 194 ) 195 196def _test_inspect_aspect(env, target): 197 env.expect.that_str(target[_AddedByAspectInfo].value).equals("attached by aspect") 198 199######################################## 200####### inspect_output_dirs_test ####### 201######################################## 202_OutputDirInfo = provider( 203 doc = "bin_path for inspect_output_dirs_test", 204 fields = ["bin_path"], 205) 206 207def _inspect_output_dirs_fake_rule(ctx): 208 return [_OutputDirInfo(bin_path = ctx.bin_dir.path)] 209 210inspect_output_dirs_fake_rule = rule(implementation = _inspect_output_dirs_fake_rule) 211 212######################################## 213####### common_attributes_test ####### 214######################################## 215 216def _test_common_attributes(name): 217 native.filegroup(name = name + "_subject") 218 _toolchain_template_vars(name = name + "_toolchain_template_vars") 219 analysis_test( 220 name = name, 221 impl = _test_common_attributes_impl, 222 target = name + "_subject", 223 attr_values = dict( 224 features = ["some-feature"], 225 tags = ["taga", "tagb"], 226 visibility = ["//visibility:private"], 227 toolchains = [name + "_toolchain_template_vars"], 228 # An empty list means "compatible with everything" 229 target_compatible_with = [], 230 ), 231 ) 232 233def _test_common_attributes_impl(env, target): 234 _ = target # @unused 235 ctx = env.ctx 236 expect = env.expect 237 238 expect.that_collection(ctx.attr.tags).contains_at_least(["taga", "tagb"]) 239 240 expect.that_collection(ctx.attr.features).contains_exactly(["some-feature"]) 241 242 expect.that_collection(ctx.attr.visibility).contains_exactly([ 243 Label("//visibility:private"), 244 ]) 245 246 expect.that_collection(ctx.attr.target_compatible_with).contains_exactly([]) 247 248 expanded = ctx.expand_make_variables("cmd", "$(key)", {}) 249 expect.that_str(expanded).equals("value") 250 251def _toolchain_template_vars_impl(ctx): 252 _ = ctx # @unused 253 return [platform_common.TemplateVariableInfo({"key": "value"})] 254 255_toolchain_template_vars = rule(implementation = _toolchain_template_vars_impl) 256 257def analysis_test_test_suite(name): 258 test_suite( 259 name = name, 260 tests = [ 261 test_change_setting, 262 _test_common_attributes, 263 test_failure_testing, 264 test_change_setting_with_failure, 265 test_inspect_actions, 266 test_inspect_aspect, 267 ], 268 ) 269