| # Copyright 2023 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. |
| |
| """# Expect""" |
| |
| load(":action_subject.bzl", "ActionSubject") |
| load(":bool_subject.bzl", "BoolSubject") |
| load(":collection_subject.bzl", "CollectionSubject") |
| load(":depset_file_subject.bzl", "DepsetFileSubject") |
| load(":dict_subject.bzl", "DictSubject") |
| load(":expect_meta.bzl", "ExpectMeta") |
| load(":file_subject.bzl", "FileSubject") |
| load(":int_subject.bzl", "IntSubject") |
| load(":str_subject.bzl", "StrSubject") |
| load(":struct_subject.bzl", "StructSubject") |
| load(":target_subject.bzl", "TargetSubject") |
| |
| def _expect_new_from_env(env): |
| """Wrapper around `env`. |
| |
| This is the entry point to the Truth-style assertions. Example usage: |
| expect = expect(env) |
| expect.that_action(action).contains_at_least_args(...) |
| |
| The passed in `env` object allows optional attributes to be set to |
| customize behavior. Usually this is helpful for testing. See `_fake_env()` |
| in truth_tests.bzl for examples. |
| * `fail`: callable that takes a failure message. If present, it |
| will be called instead of the regular `Expect.add_failure` logic. |
| * `get_provider`: callable that takes 2 positional args (target and |
| provider) and returns the found provider or fails. |
| * `has_provider`: callable that takes 2 positional args (a [`Target`] and |
| a [`provider`]) and returns [`bool`] (`True` if present, `False` otherwise) or fails. |
| |
| Args: |
| env: unittest env struct, or some approximation. There are several |
| attributes that override regular behavior; see above doc. |
| |
| Returns: |
| [`Expect`] object |
| """ |
| return _expect_new(env, None) |
| |
| def _expect_new(env, meta): |
| """Creates a new Expect object. |
| |
| Internal; only other `Expect` methods should be calling this. |
| |
| Args: |
| env: unittest env struct or some approximation. |
| meta: ([`ExpectMeta`]) metadata about call chain and state. |
| |
| Returns: |
| [`Expect`] object |
| """ |
| |
| meta = meta or ExpectMeta.new(env) |
| |
| # buildifier: disable=uninitialized |
| public = struct( |
| # keep sorted start |
| meta = meta, |
| that_action = lambda *a, **k: _expect_that_action(self, *a, **k), |
| that_bool = lambda *a, **k: _expect_that_bool(self, *a, **k), |
| that_collection = lambda *a, **k: _expect_that_collection(self, *a, **k), |
| that_depset_of_files = lambda *a, **k: _expect_that_depset_of_files(self, *a, **k), |
| that_dict = lambda *a, **k: _expect_that_dict(self, *a, **k), |
| that_file = lambda *a, **k: _expect_that_file(self, *a, **k), |
| that_int = lambda *a, **k: _expect_that_int(self, *a, **k), |
| that_str = lambda *a, **k: _expect_that_str(self, *a, **k), |
| that_struct = lambda *a, **k: _expect_that_struct(self, *a, **k), |
| that_target = lambda *a, **k: _expect_that_target(self, *a, **k), |
| where = lambda *a, **k: _expect_where(self, *a, **k), |
| # keep sorted end |
| # Attributes used by Subject classes and internal helpers |
| ) |
| self = struct(env = env, public = public, meta = meta) |
| return public |
| |
| def _expect_that_action(self, action): |
| """Creates a subject for asserting Actions. |
| |
| Args: |
| self: implicitly added. |
| action: ([`Action`]) the action to check. |
| |
| Returns: |
| [`ActionSubject`] object. |
| """ |
| return ActionSubject.new( |
| action, |
| self.meta.derive( |
| expr = "action", |
| details = ["action: [{}] {}".format(action.mnemonic, action)], |
| ), |
| ) |
| |
| def _expect_that_bool(self, value, expr = "boolean"): |
| """Creates a subject for asserting a boolean. |
| |
| Args: |
| self: implicitly added. |
| value: ([`bool`]) the bool to check. |
| expr: ([`str`]) the starting "value of" expression to report in errors. |
| |
| Returns: |
| [`BoolSubject`] object. |
| """ |
| return BoolSubject.new( |
| value, |
| meta = self.meta.derive(expr = expr), |
| ) |
| |
| def _expect_that_collection(self, collection, expr = "collection", **kwargs): |
| """Creates a subject for asserting collections. |
| |
| Args: |
| self: implicitly added. |
| collection: The collection (list or depset) to assert. |
| expr: ([`str`]) the starting "value of" expression to report in errors. |
| **kwargs: Additional kwargs to pass onto CollectionSubject.new |
| |
| Returns: |
| [`CollectionSubject`] object. |
| """ |
| return CollectionSubject.new(collection, self.meta.derive(expr), **kwargs) |
| |
| def _expect_that_depset_of_files(self, depset_files): |
| """Creates a subject for asserting a depset of files. |
| |
| Method: Expect.that_depset_of_files |
| |
| Args: |
| self: implicitly added. |
| depset_files: ([`depset`] of [`File`]) the values to assert on. |
| |
| Returns: |
| [`DepsetFileSubject`] object. |
| """ |
| return DepsetFileSubject.new(depset_files, self.meta.derive("depset_files")) |
| |
| def _expect_that_dict(self, mapping, meta = None): |
| """Creates a subject for asserting a dict. |
| |
| Method: Expect.that_dict |
| |
| Args: |
| self: implicitly added |
| mapping: ([`dict`]) the values to assert on |
| meta: ([`ExpectMeta`]) optional custom call chain information to use instead |
| |
| Returns: |
| [`DictSubject`] object. |
| """ |
| meta = meta or self.meta.derive("dict") |
| return DictSubject.new(mapping, meta = meta) |
| |
| def _expect_that_file(self, file, meta = None): |
| """Creates a subject for asserting a file. |
| |
| Method: Expect.that_file |
| |
| Args: |
| self: implicitly added. |
| file: ([`File`]) the value to assert. |
| meta: ([`ExpectMeta`]) optional custom call chain information to use instead |
| |
| Returns: |
| [`FileSubject`] object. |
| """ |
| meta = meta or self.meta.derive("file") |
| return FileSubject.new(file, meta = meta) |
| |
| def _expect_that_int(self, value, expr = "integer"): |
| """Creates a subject for asserting an `int`. |
| |
| Method: Expect.that_int |
| |
| Args: |
| self: implicitly added. |
| value: ([`int`]) the value to check against. |
| expr: ([`str`]) the starting "value of" expression to report in errors. |
| |
| Returns: |
| [`IntSubject`] object. |
| """ |
| return IntSubject.new(value, self.meta.derive(expr)) |
| |
| def _expect_that_str(self, value): |
| """Creates a subject for asserting a `str`. |
| |
| Args: |
| self: implicitly added. |
| value: ([`str`]) the value to check against. |
| |
| Returns: |
| [`StrSubject`] object. |
| """ |
| return StrSubject.new(value, self.meta.derive("string")) |
| |
| def _expect_that_struct(self, value): |
| """Creates a subject for asserting a `struct`. |
| |
| Args: |
| self: implicitly added. |
| value: ([`struct`]) the value to check against. |
| |
| Returns: |
| [`StructSubject`] object. |
| """ |
| return StructSubject.new(value, self.meta.derive("string")) |
| |
| def _expect_that_target(self, target): |
| """Creates a subject for asserting a `Target`. |
| |
| This adds the following parameters to `ExpectMeta.format_str`: |
| {package}: The target's package, e.g. "foo/bar" from "//foo/bar:baz" |
| {name}: The target's base name, e.g., "baz" from "//foo/bar:baz" |
| |
| Args: |
| self: implicitly added. |
| target: ([`Target`]) subject target to check against. |
| |
| Returns: |
| [`TargetSubject`] object. |
| """ |
| return TargetSubject.new(target, self.meta.derive( |
| expr = "target({})".format(target.label), |
| details = ["target: {}".format(target.label)], |
| format_str_kwargs = { |
| "name": target.label.name, |
| "package": target.label.package, |
| }, |
| )) |
| |
| def _expect_where(self, **details): |
| """Add additional information about the assertion. |
| |
| This is useful for attaching information that isn't part of the call |
| chain or some reason. Example usage: |
| |
| expect(env).where(platform=ctx.attr.platform).that_str(...) |
| |
| Would include "platform: {ctx.attr.platform}" in failure messages. |
| |
| Args: |
| self: implicitly added. |
| **details: ([`dict`] of [`str`] to value) Each named arg is added to |
| the metadata details with the provided string, which is printed as |
| part of displaying any failures. |
| |
| Returns: |
| [`Expect`] object with separate metadata derived from the original self. |
| """ |
| meta = self.meta.derive( |
| details = ["{}: {}".format(k, v) for k, v in details.items()], |
| ) |
| return _expect_new(env = self.env, meta = meta) |
| |
| # We use this name so it shows up nice in docs. |
| # buildifier: disable=name-conventions |
| Expect = struct( |
| # keep sorted start |
| new_from_env = _expect_new_from_env, |
| new = _expect_new, |
| that_action = _expect_that_action, |
| that_bool = _expect_that_bool, |
| that_collection = _expect_that_collection, |
| that_depset_of_files = _expect_that_depset_of_files, |
| that_dict = _expect_that_dict, |
| that_file = _expect_that_file, |
| that_int = _expect_that_int, |
| that_str = _expect_that_str, |
| that_struct = _expect_that_struct, |
| that_target = _expect_that_target, |
| where = _expect_where, |
| # keep sorted end |
| ) |