1# Copyright 2024 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"""Tests for variables rule.""" 15 16load("//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeInfo", "BuiltinVariablesInfo", "NestedArgsInfo", "VariableInfo") 17load("//cc/toolchains/impl:args_utils.bzl", _validate_nested_args = "validate_nested_args") 18load( 19 "//cc/toolchains/impl:nested_args.bzl", 20 "FORMAT_ARGS_ERR", 21 "REQUIRES_TRUE_ERR", 22) 23load("//cc/toolchains/impl:variables.bzl", "types", _get_type = "get_type") 24load("//tests/rule_based_toolchain:subjects.bzl", "result_fn_wrapper", "subjects") 25 26visibility("private") 27 28get_type = result_fn_wrapper(_get_type) 29validate_nested_args = result_fn_wrapper(_validate_nested_args) 30 31_ARGS_LABEL = Label("//:args") 32_NESTED_LABEL = Label("//:nested_vars") 33 34def _type(target): 35 return target[VariableInfo].type 36 37def _types_represent_correctly_test(env, targets): 38 env.expect.that_str(_type(targets.str_list)["repr"]).equals("List[string]") 39 env.expect.that_str(_type(targets.str_option)["repr"]).equals("Option[string]") 40 env.expect.that_str(_type(targets.struct)["repr"]).equals("struct(nested_str=string, nested_str_list=List[string])") 41 env.expect.that_str(_type(targets.struct_list)["repr"]).equals("List[struct(nested_str=string, nested_str_list=List[string])]") 42 43def _get_types_test(env, targets): 44 c_compile = targets.c_compile[ActionTypeInfo] 45 cpp_compile = targets.cpp_compile[ActionTypeInfo] 46 variables = targets.variables[BuiltinVariablesInfo].variables 47 48 def expect_type(key, overrides = {}, expr = None, actions = []): 49 return env.expect.that_value( 50 get_type( 51 variables = variables, 52 overrides = overrides, 53 args_label = _ARGS_LABEL, 54 nested_label = _NESTED_LABEL, 55 actions = actions, 56 name = key, 57 ), 58 # It's not a string, it's a complex recursive type, but string 59 # supports .equals, which is all we care about. 60 factory = subjects.result(subjects.str), 61 expr = expr or key, 62 ) 63 64 expect_type("unknown").err().contains( 65 """The variable unknown does not exist. Did you mean one of the following? 66optional_list 67str 68str_list 69""", 70 ) 71 72 expect_type("str").ok().equals(types.string) 73 expect_type("str.invalid").err().equals("""Attempted to access "str.invalid", but "str" was not a struct - it had type string.""") 74 75 expect_type("str_option").ok().equals(types.option(types.string)) 76 77 expect_type("str_list").ok().equals(types.list(types.string)) 78 79 expect_type("str_list.invalid").err().equals("""Attempted to access "str_list.invalid", but "str_list" was not a struct - it had type List[string].""") 80 81 expect_type("struct").ok().equals(_type(targets.struct)) 82 83 expect_type("struct.nested_str_list").ok().equals(types.list(types.string)) 84 85 expect_type("struct_list").ok().equals(_type(targets.struct_list)) 86 87 expect_type("struct_list.nested_str_list").err().equals("""Attempted to access "struct_list.nested_str_list", but "struct_list" was not a struct - it had type List[struct(nested_str=string, nested_str_list=List[string])]. Maybe you meant to use iterate_over.""") 88 89 expect_type("struct.unknown").err().equals("""Unable to find "unknown" in "struct", which had the following attributes: 90nested_str: string 91nested_str_list: List[string]""") 92 93 expect_type("struct", actions = [c_compile]).ok() 94 expect_type("struct", actions = [c_compile, cpp_compile]).err().equals( 95 "The variable %s is inaccessible from the action %s. This is required because it is referenced in %s, which is included by %s, which references that action" % (targets.struct.label, cpp_compile.label, _NESTED_LABEL, _ARGS_LABEL), 96 ) 97 98 expect_type("struct.nested_str_list", actions = [c_compile]).ok() 99 expect_type("struct.nested_str_list", actions = [c_compile, cpp_compile]).err() 100 101 # Simulate someone doing iterate_over = struct_list. 102 expect_type( 103 "struct_list", 104 overrides = {"struct_list": _type(targets.struct)}, 105 expr = "struct_list_override", 106 ).ok().equals(_type(targets.struct)) 107 108 expect_type( 109 "struct_list.nested_str_list", 110 overrides = {"struct_list": _type(targets.struct)}, 111 ).ok().equals(types.list(types.string)) 112 113 expect_type( 114 "struct_list.nested_str_list", 115 overrides = { 116 "struct_list": _type(targets.struct), 117 "struct_list.nested_str_list": types.string, 118 }, 119 ).ok().equals(types.string) 120 121def _variable_validation_test(env, targets): 122 c_compile = targets.c_compile[ActionTypeInfo] 123 cpp_compile = targets.cpp_compile[ActionTypeInfo] 124 variables = targets.variables[BuiltinVariablesInfo].variables 125 126 def _expect_validated(target, expr = None, actions = []): 127 return env.expect.that_value( 128 validate_nested_args( 129 nested_args = target[NestedArgsInfo], 130 variables = variables, 131 actions = actions, 132 label = _ARGS_LABEL, 133 ), 134 expr = expr, 135 # Type is Result[None] 136 factory = subjects.result(subjects.unknown), 137 ) 138 139 _expect_validated(targets.simple_str, expr = "simple_str").ok() 140 _expect_validated(targets.list_not_allowed).err().equals( 141 FORMAT_ARGS_ERR + ", but str_list has type List[string]", 142 ) 143 _expect_validated(targets.iterate_over_list, expr = "iterate_over_list").ok() 144 _expect_validated(targets.iterate_over_non_list, expr = "iterate_over_non_list").err().equals( 145 "Attempting to iterate over str, but it was not a list - it was a string", 146 ) 147 _expect_validated(targets.str_not_a_bool, expr = "str_not_a_bool").err().equals( 148 REQUIRES_TRUE_ERR + ", but str has type string", 149 ) 150 _expect_validated(targets.str_equal, expr = "str_equal").ok() 151 _expect_validated(targets.inner_iter, expr = "inner_iter_standalone").err().equals( 152 'Attempted to access "struct_list.nested_str_list", but "struct_list" was not a struct - it had type List[struct(nested_str=string, nested_str_list=List[string])]. Maybe you meant to use iterate_over.', 153 ) 154 155 _expect_validated(targets.outer_iter, actions = [c_compile], expr = "outer_iter_valid_action").ok() 156 _expect_validated(targets.outer_iter, actions = [c_compile, cpp_compile], expr = "outer_iter_missing_action").err().equals( 157 "The variable %s is inaccessible from the action %s. This is required because it is referenced in %s, which is included by %s, which references that action" % (targets.struct_list.label, cpp_compile.label, targets.outer_iter.label, _ARGS_LABEL), 158 ) 159 160 _expect_validated(targets.bad_outer_iter, expr = "bad_outer_iter").err().equals( 161 FORMAT_ARGS_ERR + ", but struct_list.nested_str_list has type List[string]", 162 ) 163 164 _expect_validated(targets.optional_list_iter, expr = "optional_list_iter").ok() 165 166 _expect_validated(targets.bad_nested_optional, expr = "bad_nested_optional").err().equals( 167 FORMAT_ARGS_ERR + ", but str_option has type Option[string]", 168 ) 169 _expect_validated(targets.good_nested_optional, expr = "good_nested_optional").ok() 170 171TARGETS = [ 172 "//tests/rule_based_toolchain/actions:c_compile", 173 "//tests/rule_based_toolchain/actions:cpp_compile", 174 ":bad_nested_optional", 175 ":bad_outer_iter", 176 ":good_nested_optional", 177 ":inner_iter", 178 ":iterate_over_list", 179 ":iterate_over_non_list", 180 ":list_not_allowed", 181 ":nested_str_list", 182 ":optional_list_iter", 183 ":outer_iter", 184 ":simple_str", 185 ":str", 186 ":str_equal", 187 ":str_list", 188 ":str_not_a_bool", 189 ":str_option", 190 ":struct", 191 ":struct_list", 192 ":variables", 193] 194 195# @unsorted-dict-items 196TESTS = { 197 "types_represent_correctly_test": _types_represent_correctly_test, 198 "get_types_test": _get_types_test, 199 "variable_validation_test": _variable_validation_test, 200} 201