xref: /aosp_15_r20/external/bazelbuild-rules_cc/tests/rule_based_toolchain/variables/variables_test.bzl (revision eed53cd41c5909d05eedc7ad9720bb158fd93452)
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