diff --git a/docs/selects_doc.md b/docs/selects_doc.md index 8e2f31b3..bf013645 100755 --- a/docs/selects_doc.md +++ b/docs/selects_doc.md @@ -79,7 +79,7 @@ A dictionary usable by a native `select()`. ## selects.config_setting_group
-selects.config_setting_group(name, match_any, match_all, visibility)
+selects.config_setting_group(name, match_any, match_all, visibility, negated)
 
Matches if all or any of its member `config_setting`s match. @@ -115,5 +115,6 @@ Example: | match_any | A list of config_settings. This group matches if *any* member in the list matches. If this is set, match_all must not be set. | [] | | match_all | A list of config_settings. This group matches if *every* member in the list matches. If this is set, match_any must be not set. | [] | | visibility | Visibility of the config_setting_group. | None | +| negated | If set, this argument should list a subset of the targets passed to any_of or all_of. The targets listed here will be negated, such that groups can express things such as "match :condition1 and don't match :condition2". The special group //conditions:default may not be negated. | [] | diff --git a/lib/BUILD b/lib/BUILD index 23280816..ecdc98ec 100644 --- a/lib/BUILD +++ b/lib/BUILD @@ -1,4 +1,5 @@ load("//:bzl_library.bzl", "bzl_library") +load("//rules:common_settings.bzl", "string_setting") licenses(["notice"]) @@ -107,3 +108,34 @@ bzl_library( name = "old_sets", srcs = ["old_sets.bzl"], ) + +# Define a hidden setting which no other modules can change. +# No references to this setting other than the two config_setting targets below +# should exist. +string_setting( + name = "private_setting", + build_setting_default = "constant", + values = [ + "constant", + "not_constant", + ], + visibility = ["//visibility:private"], +) + +# Define a config setting that will always match, since nothing ever changes +# private_setting from its default value of "constant". +config_setting( + name = "always_true", + flag_values = { + ":private_setting": "constant", + }, +) + +# Define a config setting that will never match, since nothing ever changes +# private_setting from its default value of "constant". +config_setting( + name = "always_false", + flag_values = { + ":private_setting": "not_constant", + }, +) diff --git a/lib/selects.bzl b/lib/selects.bzl index c511fe5d..e3c44142 100644 --- a/lib/selects.bzl +++ b/lib/selects.bzl @@ -14,6 +14,14 @@ """Skylib module containing convenience interfaces for select().""" +# Target which will always resolve to True. Referenced through a top-level alias +# so that it will work with WORKSPACE files in bazel. +_TRUE_TARGET = Label("//lib:always_true") + +# Target which will always resolve to False. Referenced through a top-level alias +# so that it will work with WORKSPACE files in bazel. +_FALSE_TARGET = Label("//lib:always_false") + def _with_or(input_dict, no_match_error = ""): """Drop-in replacement for `select()` that supports ORed keys. @@ -76,7 +84,12 @@ def _with_or_dict(input_dict): output_dict[key] = value return output_dict -def _config_setting_group(name, match_any = [], match_all = [], visibility = None): +def _config_setting_group( + name, + match_any = [], + match_all = [], + visibility = None, + negated = []): """Matches if all or any of its member `config_setting`s match. Example: @@ -108,23 +121,36 @@ def _config_setting_group(name, match_any = [], match_all = [], visibility = Non member in the list matches. If this is set, `match_any` must be not set. visibility: Visibility of the config_setting_group. + negated: If set, this argument should list a subset of the targets + passed to `any_of` or `all_of`. The targets listed here will be + negated, such that groups can express things such as + "match :condition1 and don't match :condition2". The special group + `//conditions:default` may not be negated. """ - empty1 = not bool(len(match_any)) - empty2 = not bool(len(match_all)) - if (empty1 and empty2) or (not empty1 and not empty2): + any_empty = not bool(len(match_any)) + all_empty = not bool(len(match_all)) + if (any_empty and all_empty) or (not any_empty and not all_empty): fail('Either "match_any" or "match_all" must be set, but not both.') _check_duplicates(match_any) _check_duplicates(match_all) + _check_negated_is_subset( + match = match_any if not any_empty else match_all, + negated = negated, + ) + + negated_dict = {n: True for n in negated} + if "//conditions:default" in negated_dict: + fail("The special target //conditions:default may not be negated.") if ((len(match_any) == 1 and match_any[0] == "//conditions:default") or (len(match_all) == 1 and match_all[0] == "//conditions:default")): # If the only entry is "//conditions:default", the condition is # automatically true. - _config_setting_always_true(name, visibility) - elif not empty1: - _config_setting_or_group(name, match_any, visibility) + native.alias(name = name, actual = _TRUE_TARGET, visibility = visibility) + elif not any_empty: + _config_setting_or_group(name, match_any, visibility, negated_dict) else: - _config_setting_and_group(name, match_all, visibility) + _config_setting_and_group(name, match_all, visibility, negated_dict) def _check_duplicates(settings): """Fails if any entry in settings appears more than once.""" @@ -134,6 +160,14 @@ def _check_duplicates(settings): fail(setting + " appears more than once. Duplicates not allowed.") seen[setting] = True +def _check_negated_is_subset(match, negated): + """Fails if any item in negated does not appear in match.""" + match_dict = {item: True for item in match} + for negated_condition in negated: + if negated_condition not in match_dict: + fail("Negated condition " + negated_condition + " not found in " + + "match argument.") + def _remove_default_condition(settings): """Returns settings with "//conditions:default" entries filtered out.""" new_settings = [] @@ -142,105 +176,154 @@ def _remove_default_condition(settings): new_settings.append(setting) return new_settings -def _config_setting_or_group(name, settings, visibility): +def _config_setting_or_group(name, settings, visibility, negated_dict = {}): """ORs multiple config_settings together (inclusively). The core idea is to create a sequential chain of alias targets where each is select-resolved as follows: If alias n matches config_setting n, the chain - is true so it resolves to config_setting n. Else it resolves to alias n+1 + is true so it resolves to the always_true target. Else it resolves to alias n+1 (which checks config_setting n+1, and so on). If none of the config_settings - match, the final alias resolves to one of them arbitrarily, which by - definition doesn't match. + match, the final alias resolves to the always_false target. + + Negation of any target other than the final target is implemented by + swapping the select conditions. Negation on the final target is implemented + by constructing a not node (see _config_setting_not). """ # "//conditions:default" is present, the whole chain is automatically true. if len(_remove_default_condition(settings)) < len(settings): - _config_setting_always_true(name, visibility) + native.alias(name = name, actual = _TRUE_TARGET, visibility = visibility) return - elif len(settings) == 1: # One entry? Just alias directly to it. - native.alias( - name = name, - actual = settings[0], - visibility = visibility, - ) - return + elif len(settings) == 1: + if not settings[0] in negated_dict: + # One nonnegated entry? Just alias directly to it. + native.alias( + name = name, + actual = settings[0], + visibility = visibility, + ) + return + else: + # One negated config_setting input? That's just a not target. + _config_setting_not(name, settings[0], visibility) + return # We need n-1 aliases for n settings. The first alias has no extension. The # second alias is named name + "_2", and so on. For the first n-2 aliases, # if they don't match they reference the next alias over. If the n-1st alias # doesn't match, it references the final setting (which is then evaluated # directly to determine the final value of the AND chain). - actual = [name + "_" + str(i) for i in range(2, len(settings))] - actual.append(settings[-1]) + alias_names = [name + "_" + str(i) for i in range(2, len(settings))] + + # The final alias isn't evaluated by a select, so if it is negated, + # construct a final not node to invert it. + final_setting = settings[-1] + if final_setting in negated_dict: + final_setting = name + "_" + str(len(settings)) + "_not" + _config_setting_not(final_setting, settings[-1], ["//visibility:private"]) + alias_names.append(final_setting) for i in range(1, len(settings)): + this_setting = settings[i - 1] + next_alias_name = alias_names[i - 1] + if this_setting in negated_dict: + select_dict = { + this_setting: next_alias_name, + "//conditions:default": _TRUE_TARGET, + } + else: + select_dict = { + this_setting: _TRUE_TARGET, + "//conditions:default": next_alias_name, + } native.alias( name = name if i == 1 else name + "_" + str(i), - actual = select({ - settings[i - 1]: settings[i - 1], - "//conditions:default": actual[i - 1], - }), + actual = select(select_dict), visibility = visibility if i == 1 else ["//visibility:private"], ) -def _config_setting_and_group(name, settings, visibility): +def _config_setting_and_group(name, settings, visibility, negated_dict = {}): """ANDs multiple config_settings together. The core idea is to create a sequential chain of alias targets where each is select-resolved as follows: If alias n matches config_setting n, it resolves to alias n+1 (which evaluates config_setting n+1, and so on). Else it resolves to - config_setting n, which doesn't match by definition. The only way to get a - matching final result is if all config_settings match. + the always-false target. The only way to get a matching final result is if all + config_settings match. + + Negation of any target other than the final target is implemented by + swapping the select conditions. Negation on the final target is implemented + by constructing a not node (see _config_setting_not). """ # "//conditions:default" is automatically true so doesn't need checking. settings = _remove_default_condition(settings) - # One config_setting input? Just alias directly to it. if len(settings) == 1: - native.alias( - name = name, - actual = settings[0], - visibility = visibility, - ) - return + if not settings[0] in negated_dict: + # One non-negated config_setting input? Just alias directly to it. + native.alias( + name = name, + actual = settings[0], + visibility = visibility, + ) + return + else: + # One negated config_setting input? That's just the not target. + _config_setting_not(name, settings[0], visibility) + return # We need n-1 aliases for n settings. The first alias has no extension. The # second alias is named name + "_2", and so on. For the first n-2 aliases, # if they match they reference the next alias over. If the n-1st alias matches, # it references the final setting (which is then evaluated directly to determine # the final value of the AND chain). - actual = [name + "_" + str(i) for i in range(2, len(settings))] - actual.append(settings[-1]) + alias_names = [name + "_" + str(i) for i in range(2, len(settings))] + + # The final alias isn't evaluated by a select, so if it is negated, + # construct a final not node to invert it. + final_setting = settings[-1] + if final_setting in negated_dict: + final_setting = name + "_" + str(len(settings)) + "_not" + _config_setting_not(final_setting, settings[-1], ["//visibility:private"]) + alias_names.append(final_setting) for i in range(1, len(settings)): + this_setting = settings[i - 1] + next_alias = alias_names[i - 1] + if this_setting in negated_dict: + select_dict = { + this_setting: _FALSE_TARGET, + "//conditions:default": next_alias, + } + else: + select_dict = { + this_setting: next_alias, + "//conditions:default": _FALSE_TARGET, + } native.alias( name = name if i == 1 else name + "_" + str(i), - actual = select({ - settings[i - 1]: actual[i - 1], - "//conditions:default": settings[i - 1], - }), + actual = select(select_dict), visibility = visibility if i == 1 else ["//visibility:private"], ) -def _config_setting_always_true(name, visibility): - """Returns a config_setting with the given name that's always true. +def _config_setting_not(name, setting, visibility): + """Returns an alias that will match if the given setting does not match. - This is achieved by constructing a two-entry OR chain where each - config_setting takes opposite values of a boolean flag. + Args: + name: Name for the alias rule to define. + setting: The config_setting to invert. + visibility: The visibility to assign to the generated alias. """ - name_on = name + "_stamp_binary_on_check" - name_off = name + "_stamp_binary_off_check" - native.config_setting( - name = name_on, - values = {"stamp": "1"}, - ) - native.config_setting( - name = name_off, - values = {"stamp": "0"}, + native.alias( + name = name, + actual = select({ + setting: _FALSE_TARGET, + "//conditions:default": _TRUE_TARGET, + }), + visibility = visibility, ) - return _config_setting_or_group(name, [":" + name_on, ":" + name_off], visibility) selects = struct( with_or = _with_or, diff --git a/tests/selects_tests.bzl b/tests/selects_tests.bzl index a7697f21..27e5f967 100644 --- a/tests/selects_tests.bzl +++ b/tests/selects_tests.bzl @@ -85,18 +85,48 @@ def _create_config_setting_groups(): name = "1_and_2_and_3", match_all = [":condition1", ":condition2", ":condition3"], ) + selects.config_setting_group( + name = "not_1_and_2_and_3", + match_all = [":condition1", ":condition2", ":condition3"], + negated = [":condition1"], + ) + selects.config_setting_group( + name = "1_and_2_and_not_3", + match_all = [":condition1", ":condition2", ":condition3"], + negated = [":condition3"], + ) selects.config_setting_group( name = "1_and_nothing_else", match_all = [":condition1"], ) + selects.config_setting_group( + name = "not_1_and_nothing_else", + match_all = [":condition1"], + negated = [":condition1"], + ) selects.config_setting_group( name = "1_or_2_or_3", match_any = [":condition1", ":condition2", ":condition3"], ) + selects.config_setting_group( + name = "1_or_not_2_or_3", + match_any = [":condition1", ":condition2", ":condition3"], + negated = [":condition2"], + ) + selects.config_setting_group( + name = "1_or_2_or_not_3", + match_any = [":condition1", ":condition2", ":condition3"], + negated = [":condition3"], + ) selects.config_setting_group( name = "1_or_nothing_else", match_any = [":condition1"], ) + selects.config_setting_group( + name = "not_1_or_nothing_else", + match_any = [":condition1"], + negated = [":condition1"], + ) ################################################### # Support code for config_setting_group tests @@ -180,6 +210,54 @@ def _and_config_setting_group_matches_test(): target_under_test = ":and_config_setting_group_matches_rule", ) +################################################### +# and_not_1_config_setting_group_matches_test +################################################### +and_not_1_config_setting_group_matches_test = analysistest.make( + _expect_matches, + config_settings = _set_conditions([False, True, True]), +) + +def _and_not_1_config_setting_group_matches_test(): + """Test verifying match on an ANDing config_setting_group with negation.""" + boolean_attr_rule( + name = "and_not_1_config_setting_group_matches_rule", + myboolean = select( + { + ":not_1_and_2_and_3": True, + "//conditions:default": False, + }, + ), + ) + and_not_1_config_setting_group_matches_test( + name = "and_not_1_config_setting_group_matches_test", + target_under_test = ":and_not_1_config_setting_group_matches_rule", + ) + +################################################### +# and_not_3_config_setting_group_matches_test +################################################### +and_not_3_config_setting_group_matches_test = analysistest.make( + _expect_matches, + config_settings = _set_conditions([True, True, False]), +) + +def _and_not_3_config_setting_group_matches_test(): + """Test verifying match on an ANDing config_setting_group with negation.""" + boolean_attr_rule( + name = "and_not_3_config_setting_group_matches_rule", + myboolean = select( + { + ":1_and_2_and_not_3": True, + "//conditions:default": False, + }, + ), + ) + and_not_3_config_setting_group_matches_test( + name = "and_not_3_config_setting_group_matches_test", + target_under_test = ":and_not_3_config_setting_group_matches_rule", + ) + ################################################### # and_config_setting_group_first_match_fails_test ################################################### @@ -204,6 +282,54 @@ def _and_config_setting_group_first_match_fails_test(): target_under_test = ":and_config_setting_group_first_match_fails_rule", ) +################################################### +# and_not_1_config_setting_group_first_match_fails_test +################################################### +and_not_1_config_setting_group_first_match_fails_test = analysistest.make( + _expect_doesnt_match, + config_settings = _set_conditions([True, True, True]), +) + +def _and_not_1_config_setting_group_first_match_fails_test(): + """Test verifying first condition mismatch on an ANDing config_setting_group.""" + boolean_attr_rule( + name = "and_not_1_config_setting_group_first_match_fails_rule", + myboolean = select( + { + ":not_1_and_2_and_3": True, + "//conditions:default": False, + }, + ), + ) + and_not_1_config_setting_group_first_match_fails_test( + name = "and_not_1_config_setting_group_first_match_fails_test", + target_under_test = ":and_not_1_config_setting_group_first_match_fails_rule", + ) + +################################################### +# and_not_3_config_setting_group_first_match_fails_test +################################################### +and_not_3_config_setting_group_first_match_fails_test = analysistest.make( + _expect_doesnt_match, + config_settings = _set_conditions([False, True, False]), +) + +def _and_not_3_config_setting_group_first_match_fails_test(): + """Test verifying first condition mismatch on an ANDing config_setting_group.""" + boolean_attr_rule( + name = "and_not_3_config_setting_group_first_match_fails_rule", + myboolean = select( + { + ":1_and_2_and_not_3": True, + "//conditions:default": False, + }, + ), + ) + and_not_3_config_setting_group_first_match_fails_test( + name = "and_not_3_config_setting_group_first_match_fails_test", + target_under_test = ":and_not_3_config_setting_group_first_match_fails_rule", + ) + ################################################### # and_config_setting_group_middle_match_fails_test ################################################### @@ -252,6 +378,54 @@ def _and_config_setting_group_last_match_fails_test(): target_under_test = ":and_config_setting_group_last_match_fails_rule", ) +################################################### +# and_not_1_config_setting_group_last_match_fails_test +################################################### +and_not_1_config_setting_group_last_match_fails_test = analysistest.make( + _expect_doesnt_match, + config_settings = _set_conditions([False, True, False]), +) + +def _and_not_1_config_setting_group_last_match_fails_test(): + """Test verifying last condition mismatch on an ANDing config_setting_group.""" + boolean_attr_rule( + name = "and_not_1_config_setting_group_last_match_fails_rule", + myboolean = select( + { + ":not_1_and_2_and_3": True, + "//conditions:default": False, + }, + ), + ) + and_not_1_config_setting_group_last_match_fails_test( + name = "and_not_1_config_setting_group_last_match_fails_test", + target_under_test = ":and_not_1_config_setting_group_last_match_fails_rule", + ) + +################################################### +# and_not_3_config_setting_group_last_match_fails_test +################################################### +and_not_3_config_setting_group_last_match_fails_test = analysistest.make( + _expect_doesnt_match, + config_settings = _set_conditions([True, True, True]), +) + +def _and_not_3_config_setting_group_last_match_fails_test(): + """Test verifying last condition mismatch on an ANDing config_setting_group.""" + boolean_attr_rule( + name = "and_not_3_config_setting_group_last_match_fails_rule", + myboolean = select( + { + ":1_and_2_and_not_3": True, + "//conditions:default": False, + }, + ), + ) + and_not_3_config_setting_group_last_match_fails_test( + name = "and_not_3_config_setting_group_last_match_fails_test", + target_under_test = ":and_not_3_config_setting_group_last_match_fails_rule", + ) + ################################################### # and_config_setting_group_multiple_matches_fail_test ################################################### @@ -324,6 +498,30 @@ def _and_config_setting_group_single_setting_matches_test(): target_under_test = ":and_config_setting_group_single_setting_matches_rule", ) +################################################### +# and_config_setting_group_single_setting_matches_test +################################################### +and_not_config_setting_group_single_setting_matches_test = analysistest.make( + _expect_matches, + config_settings = {"//command_line_option:cpu": "x86"}, +) + +def _and_not_config_setting_group_single_setting_matches_test(): + """Test verifying match on single-entry AND-NOT-ing config_setting_group.""" + boolean_attr_rule( + name = "and_not_config_setting_group_single_setting_matches_rule", + myboolean = select( + { + ":not_1_and_nothing_else": True, + "//conditions:default": False, + }, + ), + ) + and_not_config_setting_group_single_setting_matches_test( + name = "and_not_config_setting_group_single_setting_matches_test", + target_under_test = ":and_not_config_setting_group_single_setting_matches_rule", + ) + ################################################### # and_config_setting_group_single_setting_fails_test ################################################### @@ -348,6 +546,30 @@ def _and_config_setting_group_single_setting_fails_test(): target_under_test = ":and_config_setting_group_single_setting_fails_rule", ) +################################################### +# and_not_config_setting_group_single_setting_fails_test +################################################### +and_not_config_setting_group_single_setting_fails_test = analysistest.make( + _expect_doesnt_match, + config_settings = {"//command_line_option:cpu": "ppc"}, +) + +def _and_not_config_setting_group_single_setting_fails_test(): + """Test verifying no match on single-entry ANDing config_setting_group.""" + boolean_attr_rule( + name = "and_not_config_setting_group_single_setting_fails_rule", + myboolean = select( + { + ":not_1_and_nothing_else": True, + "//conditions:default": False, + }, + ), + ) + and_not_config_setting_group_single_setting_fails_test( + name = "and_not_config_setting_group_single_setting_fails_test", + target_under_test = ":and_not_config_setting_group_single_setting_fails_rule", + ) + ################################################### # or_config_setting_group_no_match_test ################################################### @@ -372,6 +594,54 @@ def _or_config_setting_group_no_matches_test(): target_under_test = ":or_config_setting_group_no_matches_rule", ) +################################################### +# or_not_2_config_setting_group_no_match_test +################################################### +or_not_2_config_setting_group_no_matches_test = analysistest.make( + _expect_doesnt_match, + config_settings = _set_conditions([False, True, False]), +) + +def _or_not_2_config_setting_group_no_matches_test(): + """Test verifying no matches on an ORing config_setting_group.""" + boolean_attr_rule( + name = "or_not_2_config_setting_group_no_matches_rule", + myboolean = select( + { + ":1_or_not_2_or_3": True, + "//conditions:default": False, + }, + ), + ) + or_not_2_config_setting_group_no_matches_test( + name = "or_not_2_config_setting_group_no_matches_test", + target_under_test = ":or_not_2_config_setting_group_no_matches_rule", + ) + +################################################### +# or_not_3_config_setting_group_no_match_test +################################################### +or_not_3_config_setting_group_no_matches_test = analysistest.make( + _expect_doesnt_match, + config_settings = _set_conditions([False, False, True]), +) + +def _or_not_3_config_setting_group_no_matches_test(): + """Test verifying no matches on an ORing config_setting_group.""" + boolean_attr_rule( + name = "or_not_3_config_setting_group_no_matches_rule", + myboolean = select( + { + ":1_or_2_or_not_3": True, + "//conditions:default": False, + }, + ), + ) + or_not_3_config_setting_group_no_matches_test( + name = "or_not_3_config_setting_group_no_matches_test", + target_under_test = ":or_not_3_config_setting_group_no_matches_rule", + ) + ################################################### # or_config_setting_group_first_cond_matches_test ################################################### @@ -420,6 +690,54 @@ def _or_config_setting_group_middle_cond_matches_test(): target_under_test = ":or_config_setting_group_middle_cond_matches_rule", ) +################################################### +# or_not_2_config_setting_group_middle_cond_matches_test +################################################### +or_not_2_config_setting_group_middle_cond_matches_test = analysistest.make( + _expect_matches, + config_settings = _set_conditions([False, False, False]), +) + +def _or_not_2_config_setting_group_middle_cond_matches_test(): + """Test verifying middle condition matching on an ORing config_setting_group.""" + boolean_attr_rule( + name = "or_not_2_config_setting_group_middle_cond_matches_rule", + myboolean = select( + { + ":1_or_not_2_or_3": True, + "//conditions:default": False, + }, + ), + ) + or_not_2_config_setting_group_middle_cond_matches_test( + name = "or_not_2_config_setting_group_middle_cond_matches_test", + target_under_test = ":or_not_2_config_setting_group_middle_cond_matches_rule", + ) + +################################################### +# or_not_3_config_setting_group_last_cond_matches_test +################################################### +or_not_3_config_setting_group_last_cond_matches_test = analysistest.make( + _expect_matches, + config_settings = _set_conditions([False, False, False]), +) + +def _or_not_3_config_setting_group_last_cond_matches_test(): + """Test verifying middle condition matching on an ORing config_setting_group.""" + boolean_attr_rule( + name = "or_not_3_config_setting_group_last_cond_matches_rule", + myboolean = select( + { + ":1_or_2_or_not_3": True, + "//conditions:default": False, + }, + ), + ) + or_not_3_config_setting_group_last_cond_matches_test( + name = "or_not_3_config_setting_group_last_cond_matches_test", + target_under_test = ":or_not_3_config_setting_group_last_cond_matches_rule", + ) + ################################################### # or_config_setting_group_last_cond_matches_test ################################################### @@ -516,6 +834,30 @@ def _or_config_setting_group_single_setting_matches_test(): target_under_test = ":or_config_setting_group_single_setting_matches_rule", ) +################################################### +# or_not_config_setting_group_single_setting_matches_test +################################################### +or_not_config_setting_group_single_setting_matches_test = analysistest.make( + _expect_matches, + config_settings = {"//command_line_option:cpu": "x86"}, +) + +def _or_not_config_setting_group_single_setting_matches_test(): + """Test verifying match on single-entry ORing config_setting_group.""" + boolean_attr_rule( + name = "or_not_config_setting_group_single_setting_matches_rule", + myboolean = select( + { + ":not_1_or_nothing_else": True, + "//conditions:default": False, + }, + ), + ) + or_not_config_setting_group_single_setting_matches_test( + name = "or_not_config_setting_group_single_setting_matches_test", + target_under_test = ":or_not_config_setting_group_single_setting_matches_rule", + ) + ################################################### # or_config_setting_group_single_setting_fails_test ################################################### @@ -540,6 +882,30 @@ def _or_config_setting_group_single_setting_fails_test(): target_under_test = ":or_config_setting_group_single_setting_fails_rule", ) +################################################### +# or_not_config_setting_group_single_setting_fails_test +################################################### +or_not_config_setting_group_single_setting_fails_test = analysistest.make( + _expect_doesnt_match, + config_settings = {"//command_line_option:cpu": "ppc"}, +) + +def _or_not_config_setting_group_single_setting_fails_test(): + """Test verifying no match on single-entry ORing config_setting_group.""" + boolean_attr_rule( + name = "or_not_config_setting_group_single_setting_fails_rule", + myboolean = select( + { + ":not_1_or_nothing_else": True, + "//conditions:default": False, + }, + ), + ) + or_not_config_setting_group_single_setting_fails_test( + name = "or_not_config_setting_group_single_setting_fails_test", + target_under_test = ":or_not_config_setting_group_single_setting_fails_rule", + ) + ################################################### # always_true_match_all_test ################################################### @@ -619,22 +985,36 @@ def selects_test_suite(): _create_config_setting_groups() _and_config_setting_group_matches_test() + _and_not_1_config_setting_group_matches_test() + _and_not_3_config_setting_group_matches_test() _and_config_setting_group_first_match_fails_test() + _and_not_1_config_setting_group_first_match_fails_test() + _and_not_3_config_setting_group_first_match_fails_test() _and_config_setting_group_middle_match_fails_test() _and_config_setting_group_last_match_fails_test() + _and_not_1_config_setting_group_last_match_fails_test() + _and_not_3_config_setting_group_last_match_fails_test() _and_config_setting_group_multiple_matches_fail_test() _and_config_setting_group_all_matches_fail_test() _and_config_setting_group_single_setting_matches_test() + _and_not_config_setting_group_single_setting_matches_test() _and_config_setting_group_single_setting_fails_test() + _and_not_config_setting_group_single_setting_fails_test() _or_config_setting_group_no_matches_test() + _or_not_2_config_setting_group_no_matches_test() + _or_not_3_config_setting_group_no_matches_test() _or_config_setting_group_first_cond_matches_test() _or_config_setting_group_middle_cond_matches_test() + _or_not_2_config_setting_group_middle_cond_matches_test() _or_config_setting_group_last_cond_matches_test() + _or_not_3_config_setting_group_last_cond_matches_test() _or_config_setting_group_multiple_conds_match_test() _or_config_setting_group_all_conds_match_test() _or_config_setting_group_single_setting_matches_test() + _or_not_config_setting_group_single_setting_matches_test() _or_config_setting_group_single_setting_fails_test() + _or_not_config_setting_group_single_setting_fails_test() _always_true_match_all_test() _always_true_match_any_test()