# Copyright 2024 The Bazel Authors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Tests for the cc_args rule.""" load("//cc:cc_toolchain_config_lib.bzl", "flag_group", "variable_with_value") load("//cc/toolchains:cc_toolchain_info.bzl", "VariableInfo") load("//cc/toolchains:format.bzl", "format_arg") load( "//cc/toolchains/impl:nested_args.bzl", "FORMAT_ARGS_ERR", "REQUIRES_EQUAL_ERR", "REQUIRES_MUTUALLY_EXCLUSIVE_ERR", "REQUIRES_NONE_ERR", "format_string_indexes", "format_variable", "nested_args_provider", "raw_string", ) load("//tests/rule_based_toolchain:subjects.bzl", "result_fn_wrapper", "subjects") visibility("private") def _expect_that_nested(env, expr = None, **kwargs): return env.expect.that_value( expr = expr, value = result_fn_wrapper(nested_args_provider)( label = Label("//:args"), **kwargs ), factory = subjects.result(subjects.NestedArgsInfo), ) def _expect_that_formatted(env, var, iterate_over = None, expr = None): return env.expect.that_value( result_fn_wrapper(format_variable)(var, iterate_over), factory = subjects.result(subjects.str), expr = expr or "format_variable(var=%r, iterate_over=%r" % (var, iterate_over), ) def _expect_that_format_string_indexes(env, var, expr = None): return env.expect.that_value( result_fn_wrapper(format_string_indexes)(var), factory = subjects.result(subjects.collection), expr = expr or "format_string_indexes(%r)" % var, ) def _format_string_indexes_test(env, _): _expect_that_format_string_indexes(env, "foo").ok().contains_exactly([]) _expect_that_format_string_indexes(env, "%%").ok().contains_exactly([]) _expect_that_format_string_indexes(env, "%").err().equals( '% should always either of the form %s, or escaped with %%. Instead, got "%"', ) _expect_that_format_string_indexes(env, "%a").err().equals( '% should always either of the form %s, or escaped with %%. Instead, got "%a"', ) _expect_that_format_string_indexes(env, "%s").ok().contains_exactly([0]) _expect_that_format_string_indexes(env, "%%%s%s").ok().contains_exactly([2, 4]) _expect_that_format_string_indexes(env, "%%{").ok().contains_exactly([]) _expect_that_format_string_indexes(env, "%%s").ok().contains_exactly([]) _expect_that_format_string_indexes(env, "%{foo}").err().equals( 'Using the old mechanism for variables, %{variable}, but we instead use format_arg("--foo=%s", "//cc/toolchains/variables:"). Got "%{foo}"', ) def _formats_raw_strings_test(env, _): _expect_that_formatted( env, raw_string("foo"), ).ok().equals("foo") _expect_that_formatted( env, raw_string("%s"), ).err().contains("Can't use %s with a raw string. Either escape it with %%s or use format_arg") def _formats_variables_test(env, targets): _expect_that_formatted( env, format_arg("ab %s cd", targets.foo[VariableInfo]), ).ok().equals("ab %{foo} cd") _expect_that_formatted( env, format_arg("foo", targets.foo[VariableInfo]), ).err().equals('format_arg requires a "%s" in the format string, but got "foo"') _expect_that_formatted( env, format_arg("%s%s", targets.foo[VariableInfo]), ).err().equals('Only one %s can be used in a format string, but got "%s%s"') _expect_that_formatted( env, format_arg("%s"), iterate_over = "foo", ).ok().equals("%{foo}") _expect_that_formatted( env, format_arg("%s"), ).err().contains("format_arg requires either a variable to format, or iterate_over must be provided") def _iterate_over_test(env, _): inner = _expect_that_nested( env, args = [raw_string("--foo")], ).ok().actual env.expect.that_str(inner.legacy_flag_group).equals(flag_group(flags = ["--foo"])) nested = _expect_that_nested( env, nested = [inner], iterate_over = "my_list", ).ok() nested.iterate_over().some().equals("my_list") nested.legacy_flag_group().equals(flag_group( iterate_over = "my_list", flag_groups = [inner.legacy_flag_group], )) nested.requires_types().contains_exactly({}) def _requires_types_test(env, targets): _expect_that_nested( env, requires_not_none = "abc", requires_none = "def", args = [raw_string("--foo")], expr = "mutually_exclusive", ).err().equals(REQUIRES_MUTUALLY_EXCLUSIVE_ERR) _expect_that_nested( env, requires_none = "var", args = [raw_string("--foo")], expr = "requires_none", ).ok().requires_types().contains_exactly( {"var": [struct( msg = REQUIRES_NONE_ERR, valid_types = ["option"], after_option_unwrap = False, )]}, ) _expect_that_nested( env, args = [raw_string("foo %s baz")], expr = "no_variable", ).err().contains("Can't use %s with a raw string") _expect_that_nested( env, args = [format_arg("foo %s baz", targets.foo[VariableInfo])], expr = "type_validation", ).ok().requires_types().contains_exactly( {"foo": [struct( msg = FORMAT_ARGS_ERR, valid_types = ["string", "file", "directory"], after_option_unwrap = True, )]}, ) nested = _expect_that_nested( env, requires_equal = "foo", requires_equal_value = "value", args = [format_arg("--foo=%s", targets.foo[VariableInfo])], expr = "type_and_requires_equal_validation", ).ok() nested.requires_types().contains_exactly( {"foo": [ struct( msg = REQUIRES_EQUAL_ERR, valid_types = ["string"], after_option_unwrap = True, ), struct( msg = FORMAT_ARGS_ERR, valid_types = ["string", "file", "directory"], after_option_unwrap = True, ), ]}, ) nested.legacy_flag_group().equals(flag_group( expand_if_equal = variable_with_value(name = "foo", value = "value"), flags = ["--foo=%{foo}"], )) TARGETS = [ ":foo", ] TESTS = { "format_string_indexes_test": _format_string_indexes_test, "formats_raw_strings_test": _formats_raw_strings_test, "formats_variables_test": _formats_variables_test, "iterate_over_test": _iterate_over_test, "requires_types_test": _requires_types_test, }