xref: /aosp_15_r20/external/bazelbuild-rules_testing/lib/private/expect.bzl (revision d605057434dcabba796c020773aab68d9790ff9f)
1# Copyright 2023 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
15"""# Expect"""
16
17load(":action_subject.bzl", "ActionSubject")
18load(":bool_subject.bzl", "BoolSubject")
19load(":collection_subject.bzl", "CollectionSubject")
20load(":depset_file_subject.bzl", "DepsetFileSubject")
21load(":dict_subject.bzl", "DictSubject")
22load(":expect_meta.bzl", "ExpectMeta")
23load(":file_subject.bzl", "FileSubject")
24load(":int_subject.bzl", "IntSubject")
25load(":str_subject.bzl", "StrSubject")
26load(":struct_subject.bzl", "StructSubject")
27load(":target_subject.bzl", "TargetSubject")
28
29def _expect_new_from_env(env):
30    """Wrapper around `env`.
31
32    This is the entry point to the Truth-style assertions. Example usage:
33        expect = expect(env)
34        expect.that_action(action).contains_at_least_args(...)
35
36    The passed in `env` object allows optional attributes to be set to
37    customize behavior. Usually this is helpful for testing. See `_fake_env()`
38    in truth_tests.bzl for examples.
39      * `fail`: callable that takes a failure message. If present, it
40        will be called instead of the regular `Expect.add_failure` logic.
41      * `get_provider`: callable that takes 2 positional args (target and
42        provider) and returns the found provider or fails.
43      * `has_provider`: callable that takes 2 positional args (a [`Target`] and
44        a [`provider`]) and returns [`bool`] (`True` if present, `False` otherwise) or fails.
45
46    Args:
47        env: unittest env struct, or some approximation. There are several
48            attributes that override regular behavior; see above doc.
49
50    Returns:
51        [`Expect`] object
52    """
53    return _expect_new(env, None)
54
55def _expect_new(env, meta):
56    """Creates a new Expect object.
57
58    Internal; only other `Expect` methods should be calling this.
59
60    Args:
61        env: unittest env struct or some approximation.
62        meta: ([`ExpectMeta`]) metadata about call chain and state.
63
64    Returns:
65        [`Expect`] object
66    """
67
68    meta = meta or ExpectMeta.new(env)
69
70    # buildifier: disable=uninitialized
71    public = struct(
72        # keep sorted start
73        meta = meta,
74        that_action = lambda *a, **k: _expect_that_action(self, *a, **k),
75        that_bool = lambda *a, **k: _expect_that_bool(self, *a, **k),
76        that_collection = lambda *a, **k: _expect_that_collection(self, *a, **k),
77        that_depset_of_files = lambda *a, **k: _expect_that_depset_of_files(self, *a, **k),
78        that_dict = lambda *a, **k: _expect_that_dict(self, *a, **k),
79        that_file = lambda *a, **k: _expect_that_file(self, *a, **k),
80        that_int = lambda *a, **k: _expect_that_int(self, *a, **k),
81        that_str = lambda *a, **k: _expect_that_str(self, *a, **k),
82        that_struct = lambda *a, **k: _expect_that_struct(self, *a, **k),
83        that_target = lambda *a, **k: _expect_that_target(self, *a, **k),
84        where = lambda *a, **k: _expect_where(self, *a, **k),
85        # keep sorted end
86        # Attributes used by Subject classes and internal helpers
87    )
88    self = struct(env = env, public = public, meta = meta)
89    return public
90
91def _expect_that_action(self, action):
92    """Creates a subject for asserting Actions.
93
94    Args:
95        self: implicitly added.
96        action: ([`Action`]) the action to check.
97
98    Returns:
99        [`ActionSubject`] object.
100    """
101    return ActionSubject.new(
102        action,
103        self.meta.derive(
104            expr = "action",
105            details = ["action: [{}] {}".format(action.mnemonic, action)],
106        ),
107    )
108
109def _expect_that_bool(self, value, expr = "boolean"):
110    """Creates a subject for asserting a boolean.
111
112    Args:
113        self: implicitly added.
114        value: ([`bool`]) the bool to check.
115        expr: ([`str`]) the starting "value of" expression to report in errors.
116
117    Returns:
118        [`BoolSubject`] object.
119    """
120    return BoolSubject.new(
121        value,
122        meta = self.meta.derive(expr = expr),
123    )
124
125def _expect_that_collection(self, collection, expr = "collection", **kwargs):
126    """Creates a subject for asserting collections.
127
128    Args:
129        self: implicitly added.
130        collection: The collection (list or depset) to assert.
131        expr: ([`str`]) the starting "value of" expression to report in errors.
132        **kwargs: Additional kwargs to pass onto CollectionSubject.new
133
134    Returns:
135        [`CollectionSubject`] object.
136    """
137    return CollectionSubject.new(collection, self.meta.derive(expr), **kwargs)
138
139def _expect_that_depset_of_files(self, depset_files):
140    """Creates a subject for asserting a depset of files.
141
142    Method: Expect.that_depset_of_files
143
144    Args:
145        self: implicitly added.
146        depset_files: ([`depset`] of [`File`]) the values to assert on.
147
148    Returns:
149        [`DepsetFileSubject`] object.
150    """
151    return DepsetFileSubject.new(depset_files, self.meta.derive("depset_files"))
152
153def _expect_that_dict(self, mapping, meta = None):
154    """Creates a subject for asserting a dict.
155
156    Method: Expect.that_dict
157
158    Args:
159        self: implicitly added
160        mapping: ([`dict`]) the values to assert on
161        meta: ([`ExpectMeta`]) optional custom call chain information to use instead
162
163    Returns:
164        [`DictSubject`] object.
165    """
166    meta = meta or self.meta.derive("dict")
167    return DictSubject.new(mapping, meta = meta)
168
169def _expect_that_file(self, file, meta = None):
170    """Creates a subject for asserting a file.
171
172    Method: Expect.that_file
173
174    Args:
175        self: implicitly added.
176        file: ([`File`]) the value to assert.
177        meta: ([`ExpectMeta`]) optional custom call chain information to use instead
178
179    Returns:
180        [`FileSubject`] object.
181    """
182    meta = meta or self.meta.derive("file")
183    return FileSubject.new(file, meta = meta)
184
185def _expect_that_int(self, value, expr = "integer"):
186    """Creates a subject for asserting an `int`.
187
188    Method: Expect.that_int
189
190    Args:
191        self: implicitly added.
192        value: ([`int`]) the value to check against.
193        expr: ([`str`]) the starting "value of" expression to report in errors.
194
195    Returns:
196        [`IntSubject`] object.
197    """
198    return IntSubject.new(value, self.meta.derive(expr))
199
200def _expect_that_str(self, value):
201    """Creates a subject for asserting a `str`.
202
203    Args:
204        self: implicitly added.
205        value: ([`str`]) the value to check against.
206
207    Returns:
208        [`StrSubject`] object.
209    """
210    return StrSubject.new(value, self.meta.derive("string"))
211
212def _expect_that_struct(self, value):
213    """Creates a subject for asserting a `struct`.
214
215    Args:
216        self: implicitly added.
217        value: ([`struct`]) the value to check against.
218
219    Returns:
220        [`StructSubject`] object.
221    """
222    return StructSubject.new(value, self.meta.derive("string"))
223
224def _expect_that_target(self, target):
225    """Creates a subject for asserting a `Target`.
226
227    This adds the following parameters to `ExpectMeta.format_str`:
228      {package}: The target's package, e.g. "foo/bar" from "//foo/bar:baz"
229      {name}: The target's base name, e.g., "baz" from "//foo/bar:baz"
230
231    Args:
232        self: implicitly added.
233        target: ([`Target`]) subject target to check against.
234
235    Returns:
236        [`TargetSubject`] object.
237    """
238    return TargetSubject.new(target, self.meta.derive(
239        expr = "target({})".format(target.label),
240        details = ["target: {}".format(target.label)],
241        format_str_kwargs = {
242            "name": target.label.name,
243            "package": target.label.package,
244        },
245    ))
246
247def _expect_where(self, **details):
248    """Add additional information about the assertion.
249
250    This is useful for attaching information that isn't part of the call
251    chain or some reason. Example usage:
252
253        expect(env).where(platform=ctx.attr.platform).that_str(...)
254
255    Would include "platform: {ctx.attr.platform}" in failure messages.
256
257    Args:
258        self: implicitly added.
259        **details: ([`dict`] of [`str`] to value) Each named arg is added to
260            the metadata details with the provided string, which is printed as
261            part of displaying any failures.
262
263    Returns:
264        [`Expect`] object with separate metadata derived from the original self.
265    """
266    meta = self.meta.derive(
267        details = ["{}: {}".format(k, v) for k, v in details.items()],
268    )
269    return _expect_new(env = self.env, meta = meta)
270
271# We use this name so it shows up nice in docs.
272# buildifier: disable=name-conventions
273Expect = struct(
274    # keep sorted start
275    new_from_env = _expect_new_from_env,
276    new = _expect_new,
277    that_action = _expect_that_action,
278    that_bool = _expect_that_bool,
279    that_collection = _expect_that_collection,
280    that_depset_of_files = _expect_that_depset_of_files,
281    that_dict = _expect_that_dict,
282    that_file = _expect_that_file,
283    that_int = _expect_that_int,
284    that_str = _expect_that_str,
285    that_struct = _expect_that_struct,
286    that_target = _expect_that_target,
287    where = _expect_where,
288    # keep sorted end
289)
290