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("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo") 17load("//cc:cc_toolchain_config_lib.bzl", "flag_group", "variable_with_value") 18load( 19 "//cc/toolchains/impl:nested_args.bzl", 20 "FORMAT_ARGS_ERR", 21 "REQUIRES_EQUAL_ERR", 22 "REQUIRES_MUTUALLY_EXCLUSIVE_ERR", 23 "REQUIRES_NONE_ERR", 24 "format_args", 25 "nested_args_provider", 26) 27load("//tests/rule_based_toolchain:subjects.bzl", "result_fn_wrapper", "subjects") 28 29visibility("private") 30 31def _expect_that_nested(env, expr = None, **kwargs): 32 return env.expect.that_value( 33 expr = expr, 34 value = result_fn_wrapper(nested_args_provider)( 35 label = Label("//:args"), 36 **kwargs 37 ), 38 factory = subjects.result(subjects.NestedArgsInfo), 39 ) 40 41def _expect_that_formatted(env, args, format, must_use = [], expr = None): 42 return env.expect.that_value( 43 result_fn_wrapper(format_args)(args, format, must_use = must_use), 44 factory = subjects.result(subjects.collection), 45 expr = expr or "format_args(%r, %r)" % (args, format), 46 ) 47 48def _format_args_test(env, targets): 49 _expect_that_formatted( 50 env, 51 [ 52 "a % b", 53 "a {{", 54 "}} b", 55 "a {{ b }}", 56 ], 57 {}, 58 ).ok().contains_exactly([ 59 "a %% b", 60 "a {", 61 "} b", 62 "a { b }", 63 ]).in_order() 64 65 _expect_that_formatted( 66 env, 67 ["{foo"], 68 {}, 69 ).err().equals('Unmatched { in "{foo"') 70 71 _expect_that_formatted( 72 env, 73 ["foo}"], 74 {}, 75 ).err().equals('Unexpected } in "foo}"') 76 _expect_that_formatted( 77 env, 78 ["{foo}"], 79 {}, 80 ).err().contains('Unknown variable "foo" in format string "{foo}"') 81 82 _expect_that_formatted( 83 env, 84 [ 85 "a {var}", 86 "b {directory}", 87 "c {file}", 88 ], 89 { 90 "directory": targets.directory, 91 "file": targets.bin_wrapper, 92 "var": targets.foo, 93 }, 94 ).ok().contains_exactly([ 95 "a %{foo}", 96 "b " + targets.directory[DirectoryInfo].path, 97 "c " + targets.bin_wrapper[DefaultInfo].files.to_list()[0].path, 98 ]).in_order() 99 100 _expect_that_formatted( 101 env, 102 ["{var}", "{var}"], 103 {"var": targets.foo}, 104 ).ok().contains_exactly(["%{foo}", "%{foo}"]) 105 106 _expect_that_formatted( 107 env, 108 [], 109 {"var": targets.foo}, 110 must_use = ["var"], 111 ).err().contains('"var" was not used') 112 113 _expect_that_formatted( 114 env, 115 ["{var} {var}"], 116 {"var": targets.foo}, 117 ).err().contains('"{var} {var}" contained multiple variables') 118 119 _expect_that_formatted( 120 env, 121 ["{foo} {bar}"], 122 {"bar": targets.foo, "foo": targets.foo}, 123 ).err().contains('"{foo} {bar}" contained multiple variables') 124 125def _iterate_over_test(env, targets): 126 inner = _expect_that_nested( 127 env, 128 args = ["--foo"], 129 ).ok().actual 130 env.expect.that_str(inner.legacy_flag_group).equals(flag_group(flags = ["--foo"])) 131 132 nested = _expect_that_nested( 133 env, 134 nested = [inner], 135 iterate_over = targets.my_list, 136 ).ok() 137 nested.iterate_over().some().equals("my_list") 138 nested.legacy_flag_group().equals(flag_group( 139 iterate_over = "my_list", 140 flag_groups = [inner.legacy_flag_group], 141 )) 142 nested.requires_types().contains_exactly({}) 143 144def _requires_types_test(env, targets): 145 _expect_that_nested( 146 env, 147 requires_not_none = "abc", 148 requires_none = "def", 149 args = ["--foo"], 150 expr = "mutually_exclusive", 151 ).err().equals(REQUIRES_MUTUALLY_EXCLUSIVE_ERR) 152 153 _expect_that_nested( 154 env, 155 requires_none = "var", 156 args = ["--foo"], 157 expr = "requires_none", 158 ).ok().requires_types().contains_exactly( 159 {"var": [struct( 160 msg = REQUIRES_NONE_ERR, 161 valid_types = ["option"], 162 after_option_unwrap = False, 163 )]}, 164 ) 165 166 _expect_that_nested( 167 env, 168 args = ["foo {foo} baz"], 169 format = {targets.foo: "foo"}, 170 expr = "type_validation", 171 ).ok().requires_types().contains_exactly( 172 {"foo": [struct( 173 msg = FORMAT_ARGS_ERR, 174 valid_types = ["string", "file", "directory"], 175 after_option_unwrap = True, 176 )]}, 177 ) 178 179 nested = _expect_that_nested( 180 env, 181 requires_equal = "foo", 182 requires_equal_value = "value", 183 args = ["--foo={foo}"], 184 format = {targets.foo: "foo"}, 185 expr = "type_and_requires_equal_validation", 186 ).ok() 187 nested.requires_types().contains_exactly( 188 {"foo": [ 189 struct( 190 msg = REQUIRES_EQUAL_ERR, 191 valid_types = ["string"], 192 after_option_unwrap = True, 193 ), 194 struct( 195 msg = FORMAT_ARGS_ERR, 196 valid_types = ["string", "file", "directory"], 197 after_option_unwrap = True, 198 ), 199 ]}, 200 ) 201 nested.legacy_flag_group().equals(flag_group( 202 expand_if_equal = variable_with_value(name = "foo", value = "value"), 203 flags = ["--foo=%{foo}"], 204 )) 205 206TARGETS = [ 207 ":foo", 208 ":my_list", 209 "//tests/rule_based_toolchain/testdata:directory", 210 "//tests/rule_based_toolchain/testdata:bin_wrapper", 211] 212 213TESTS = { 214 "format_args_test": _format_args_test, 215 "iterate_over_test": _iterate_over_test, 216 "requires_types_test": _requires_types_test, 217} 218