• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 the cc_args rule."""
15
16load("//cc:cc_toolchain_config_lib.bzl", "flag_group", "variable_with_value")
17load("//cc/toolchains:cc_toolchain_info.bzl", "VariableInfo")
18load("//cc/toolchains:format.bzl", "format_arg")
19load(
20    "//cc/toolchains/impl:nested_args.bzl",
21    "FORMAT_ARGS_ERR",
22    "REQUIRES_EQUAL_ERR",
23    "REQUIRES_MUTUALLY_EXCLUSIVE_ERR",
24    "REQUIRES_NONE_ERR",
25    "format_string_indexes",
26    "format_variable",
27    "nested_args_provider",
28    "raw_string",
29)
30load("//tests/rule_based_toolchain:subjects.bzl", "result_fn_wrapper", "subjects")
31
32visibility("private")
33
34def _expect_that_nested(env, expr = None, **kwargs):
35    return env.expect.that_value(
36        expr = expr,
37        value = result_fn_wrapper(nested_args_provider)(
38            label = Label("//:args"),
39            **kwargs
40        ),
41        factory = subjects.result(subjects.NestedArgsInfo),
42    )
43
44def _expect_that_formatted(env, var, iterate_over = None, expr = None):
45    return env.expect.that_value(
46        result_fn_wrapper(format_variable)(var, iterate_over),
47        factory = subjects.result(subjects.str),
48        expr = expr or "format_variable(var=%r, iterate_over=%r" % (var, iterate_over),
49    )
50
51def _expect_that_format_string_indexes(env, var, expr = None):
52    return env.expect.that_value(
53        result_fn_wrapper(format_string_indexes)(var),
54        factory = subjects.result(subjects.collection),
55        expr = expr or "format_string_indexes(%r)" % var,
56    )
57
58def _format_string_indexes_test(env, _):
59    _expect_that_format_string_indexes(env, "foo").ok().contains_exactly([])
60    _expect_that_format_string_indexes(env, "%%").ok().contains_exactly([])
61    _expect_that_format_string_indexes(env, "%").err().equals(
62        '% should always either of the form %s, or escaped with %%. Instead, got "%"',
63    )
64    _expect_that_format_string_indexes(env, "%a").err().equals(
65        '% should always either of the form %s, or escaped with %%. Instead, got "%a"',
66    )
67    _expect_that_format_string_indexes(env, "%s").ok().contains_exactly([0])
68    _expect_that_format_string_indexes(env, "%%%s%s").ok().contains_exactly([2, 4])
69    _expect_that_format_string_indexes(env, "%%{").ok().contains_exactly([])
70    _expect_that_format_string_indexes(env, "%%s").ok().contains_exactly([])
71    _expect_that_format_string_indexes(env, "%{foo}").err().equals(
72        'Using the old mechanism for variables, %{variable}, but we instead use format_arg("--foo=%s", "//cc/toolchains/variables:<variable>"). Got "%{foo}"',
73    )
74
75def _formats_raw_strings_test(env, _):
76    _expect_that_formatted(
77        env,
78        raw_string("foo"),
79    ).ok().equals("foo")
80    _expect_that_formatted(
81        env,
82        raw_string("%s"),
83    ).err().contains("Can't use %s with a raw string. Either escape it with %%s or use format_arg")
84
85def _formats_variables_test(env, targets):
86    _expect_that_formatted(
87        env,
88        format_arg("ab %s cd", targets.foo[VariableInfo]),
89    ).ok().equals("ab %{foo} cd")
90
91    _expect_that_formatted(
92        env,
93        format_arg("foo", targets.foo[VariableInfo]),
94    ).err().equals('format_arg requires a "%s" in the format string, but got "foo"')
95    _expect_that_formatted(
96        env,
97        format_arg("%s%s", targets.foo[VariableInfo]),
98    ).err().equals('Only one %s can be used in a format string, but got "%s%s"')
99
100    _expect_that_formatted(
101        env,
102        format_arg("%s"),
103        iterate_over = "foo",
104    ).ok().equals("%{foo}")
105    _expect_that_formatted(
106        env,
107        format_arg("%s"),
108    ).err().contains("format_arg requires either a variable to format, or iterate_over must be provided")
109
110def _iterate_over_test(env, _):
111    inner = _expect_that_nested(
112        env,
113        args = [raw_string("--foo")],
114    ).ok().actual
115    env.expect.that_str(inner.legacy_flag_group).equals(flag_group(flags = ["--foo"]))
116
117    nested = _expect_that_nested(
118        env,
119        nested = [inner],
120        iterate_over = "my_list",
121    ).ok()
122    nested.iterate_over().some().equals("my_list")
123    nested.legacy_flag_group().equals(flag_group(
124        iterate_over = "my_list",
125        flag_groups = [inner.legacy_flag_group],
126    ))
127    nested.requires_types().contains_exactly({})
128
129def _requires_types_test(env, targets):
130    _expect_that_nested(
131        env,
132        requires_not_none = "abc",
133        requires_none = "def",
134        args = [raw_string("--foo")],
135        expr = "mutually_exclusive",
136    ).err().equals(REQUIRES_MUTUALLY_EXCLUSIVE_ERR)
137
138    _expect_that_nested(
139        env,
140        requires_none = "var",
141        args = [raw_string("--foo")],
142        expr = "requires_none",
143    ).ok().requires_types().contains_exactly(
144        {"var": [struct(
145            msg = REQUIRES_NONE_ERR,
146            valid_types = ["option"],
147            after_option_unwrap = False,
148        )]},
149    )
150
151    _expect_that_nested(
152        env,
153        args = [raw_string("foo %s baz")],
154        expr = "no_variable",
155    ).err().contains("Can't use %s with a raw string")
156
157    _expect_that_nested(
158        env,
159        args = [format_arg("foo %s baz", targets.foo[VariableInfo])],
160        expr = "type_validation",
161    ).ok().requires_types().contains_exactly(
162        {"foo": [struct(
163            msg = FORMAT_ARGS_ERR,
164            valid_types = ["string", "file", "directory"],
165            after_option_unwrap = True,
166        )]},
167    )
168
169    nested = _expect_that_nested(
170        env,
171        requires_equal = "foo",
172        requires_equal_value = "value",
173        args = [format_arg("--foo=%s", targets.foo[VariableInfo])],
174        expr = "type_and_requires_equal_validation",
175    ).ok()
176    nested.requires_types().contains_exactly(
177        {"foo": [
178            struct(
179                msg = REQUIRES_EQUAL_ERR,
180                valid_types = ["string"],
181                after_option_unwrap = True,
182            ),
183            struct(
184                msg = FORMAT_ARGS_ERR,
185                valid_types = ["string", "file", "directory"],
186                after_option_unwrap = True,
187            ),
188        ]},
189    )
190    nested.legacy_flag_group().equals(flag_group(
191        expand_if_equal = variable_with_value(name = "foo", value = "value"),
192        flags = ["--foo=%{foo}"],
193    ))
194
195TARGETS = [
196    ":foo",
197]
198
199TESTS = {
200    "format_string_indexes_test": _format_string_indexes_test,
201    "formats_raw_strings_test": _formats_raw_strings_test,
202    "formats_variables_test": _formats_variables_test,
203    "iterate_over_test": _iterate_over_test,
204    "requires_types_test": _requires_types_test,
205}
206