• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2024 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://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, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Utility functions for testing toolchain rules."""
15
16load(
17    "//cc_toolchain/private:providers.bzl",
18    "PwActionConfigSetInfo",
19    "PwExtraActionFilesSetInfo",
20    "PwFeatureConstraintInfo",
21    "PwFeatureInfo",
22    "PwFeatureSetInfo",
23    "PwFlagGroupInfo",
24    "PwFlagSetInfo",
25)
26load(
27    "//cc_toolchain/private:utils.bzl",
28    _to_untyped_config = "to_untyped_config",
29)
30load("//features:builtin_features.bzl", "BUILTIN_FEATURES")
31
32visibility("//cc_toolchain/tests/...")
33
34# Intentionally add two spaces after got, to ensure the lines are correctly
35# aligned.
36def assert_eq(got, want, msg = "\n\nGot  %r\n\nWant %r"):
37    if got != want:
38        fail(msg % (got, want))
39
40def assert_in(want, container, msg = "\n\nUnable to find %r\n\nIn %r"):
41    if want not in container:
42        fail(msg % (want, container))
43
44def assert_ne(got, bad, msg = "Got %r, wanted any value other than that"):
45    if got == bad:
46        fail(msg % got)
47
48def assert_not_none(got, msg = "Got None, wanted a non-None value"):
49    if got == None:
50        fail(msg)
51
52def assert_fail(fn, *args, want = None, **kwargs):
53    """Asserts that a function threw an exception
54
55    Args:
56        fn: A function that can take in a parameter "fail"
57        *args: Arguments to be passed to fn
58        **kwargs: Arguments to be papssed to fn
59        want: Option[str]: The expected error message.
60          If not provided, any error message is allowed.
61    """
62
63    # Use a mutable type so that the inner function can modify the outer scope.
64    fails = []
65
66    def set_fail_msg(msg):
67        fails.append(msg)
68
69    fn(fail = set_fail_msg, *args, **kwargs)
70    if want == None:
71        assert_ne(fails, [], msg = "Expected %r(**%r) to fail. Unexpectedly passed and got %%r" % (fn, kwargs))
72    else:
73        assert_ne(fails, [], msg = "Expected %r(**%r) to fail with msg %r. Unexpectedly passed and got %%r" % (fn, want, kwargs))
74        assert_eq(fails[0], want, msg = "\n\nGot failure message  %r\n\nWant failure message %r")
75
76def assert_labels_eq(got, want):
77    """Asserts that two lists of providers with the label attribute are equal
78
79    Args:
80        got: A list or depset of providers containing the attribute "label"
81        want: A list or depset of providers containing the attribute "label"
82    """
83    if type(got) == "depset":
84        got = got.to_list()
85    if type(want) == "depset":
86        want = want.to_list()
87    got = sorted([entry.label for entry in got])
88    want = sorted([entry.label for entry in want])
89    assert_eq(got, want)
90
91_RULES = {
92    PwFlagSetInfo: "flag_sets",
93    PwFlagGroupInfo: "flag_groups",
94    PwFeatureConstraintInfo: "feature_constraints",
95    PwFeatureInfo: "features",
96    PwFeatureSetInfo: "feature_sets",
97    PwActionConfigSetInfo: "action_configs",
98    PwExtraActionFilesSetInfo: "extra_action_files",
99}
100
101_PROVIDERS = {
102    "//cc_toolchain/tests/action_configs:all_c_compile": [PwActionConfigSetInfo],
103    "//cc_toolchain/tests/action_configs:assemble_from_bin": [PwActionConfigSetInfo],
104    "//cc_toolchain/tests/action_configs:c_compile": [PwActionConfigSetInfo],
105    "//cc_toolchain/tests/action_configs:c_compiler_data": [PwExtraActionFilesSetInfo],
106    "//cc_toolchain/tests/action_configs:cpp_compile_from_tool": [PwActionConfigSetInfo],
107    "//cc_toolchain/tests/action_configs:cpp_compiler_data": [PwExtraActionFilesSetInfo],
108    "//cc_toolchain/tests/action_configs:data": [PwExtraActionFilesSetInfo],
109    "//cc_toolchain/tests/action_configs:requires_foo": [PwActionConfigSetInfo],
110    "//cc_toolchain/tests/features:bar": [PwFeatureInfo, PwFeatureSetInfo],
111    "//cc_toolchain/tests/features:baz": [PwFeatureInfo, PwFeatureSetInfo],
112    "//cc_toolchain/tests/features:conflict": [PwFeatureInfo, PwFeatureSetInfo],
113    "//cc_toolchain/tests/features:constrained": [PwFeatureInfo, PwFeatureSetInfo],
114    "//cc_toolchain/tests/features:foo": [PwFeatureInfo, PwFeatureSetInfo],
115    "//cc_toolchain/tests/features:foo_not_baz": [PwFeatureConstraintInfo],
116    "//cc_toolchain/tests/features:foo_only": [PwFeatureConstraintInfo],
117    "//cc_toolchain/tests/features:foobar": [PwFeatureSetInfo],
118    "//cc_toolchain/tests/features:implies": [PwFeatureInfo, PwFeatureSetInfo],
119    "//cc_toolchain/tests/features:implies_supports_pic": [PwFeatureInfo, PwFeatureSetInfo],
120    "//cc_toolchain/tests/features:mutex_label": [PwFeatureInfo],
121    "//cc_toolchain/tests/features:mutex_provider": [PwFeatureInfo],
122    "//cc_toolchain/tests/features:primary_feature": [PwFeatureInfo],
123    "//cc_toolchain/tests/features:requires": [PwFeatureInfo, PwFeatureSetInfo],
124    "//cc_toolchain/tests/features:supports_pic": [PwFeatureInfo, PwFeatureSetInfo],
125    "//cc_toolchain/tests/features:supports_pic_no_override": [PwFeatureInfo, PwFeatureSetInfo],
126    "//cc_toolchain/tests/flag_sets:bar": [PwFlagSetInfo],
127    "//cc_toolchain/tests/flag_sets:baz": [PwFlagSetInfo],
128    "//cc_toolchain/tests/flag_sets:env": [PwFlagSetInfo],
129    "//cc_toolchain/tests/flag_sets:flag_group": [PwFlagGroupInfo],
130    "//cc_toolchain/tests/flag_sets:foo": [PwFlagSetInfo],
131    "//cc_toolchain/tests/flag_sets:multiple_actions": [PwFlagSetInfo],
132    "//cc_toolchain/tests/flag_sets:wraps_flag_group": [PwFlagSetInfo],
133}
134
135# This gives all tests access to all providers. This allows us to write
136# non-brittle tests, since now we can write something like:
137# assert_eq(features.foo.flag_sets, [flag_sets.foo])
138# Note that this namespaces by provider instead of by label. We do so because
139# this allows you to access both features.foo and feature_sets.foo (since a
140# feature defines both a feature and a feature set).
141def generate_test_rule(implementation):
142    def wrapper(ctx):
143        providers = {v: {} for v in _RULES.values()}
144        for target in ctx.attr.test_cases:
145            pkg = target.label.package
146            name = target.label.name
147            for provider in _PROVIDERS["//%s:%s" % (pkg, name)]:
148                providers[_RULES[provider]][name] = target[provider]
149
150        def to_untyped_config(features = [], feature_sets = [], action_configs = [], flag_sets = [], extra_action_files = [], fail = fail):
151            feature_set = PwFeatureSetInfo(features = depset(
152                features + [ft[PwFeatureInfo] for ft in ctx.attr.builtin_features],
153                transitive = [fs.features for fs in feature_sets],
154            ))
155            action_config_set = PwActionConfigSetInfo(
156                label = ctx.label,
157                action_configs = depset(transitive = [
158                    acs.action_configs
159                    for acs in action_configs
160                ]),
161            )
162            extra_action_files_combined = PwExtraActionFilesSetInfo(srcs = depset(transitive = [
163                ffa.srcs
164                for ffa in extra_action_files
165            ]))
166            return _to_untyped_config(feature_set, action_config_set, flag_sets, extra_action_files_combined, fail = fail)
167
168        kwargs = {k: struct(**v) for k, v in providers.items()}
169        return implementation(ctx, to_untyped_config = to_untyped_config, **kwargs)
170
171    return rule(
172        implementation = wrapper,
173        attrs = {
174            "builtin_features": attr.label_list(default = BUILTIN_FEATURES),
175            "test_cases": attr.label_list(default = _PROVIDERS.keys()),
176        },
177    )
178