1# Truth Guide 2 3Also see: [Truth API reference](api/truth.md) 4 5## What is Truth? 6 7Truth is a style of doing asserts that makes it easy to perform complex 8assertions that are easy to understand and give actionable error messages. 9 10The basic way it works is wrapping a value in a type-specific object that 11provides type-specific assertion methods. This style provides several benefits: 12 13* A fluent API that more directly expresses the assertion 14* More egonomic assert functions 15* Error messages with more informative context 16* Promotes code reuses at the type-level. 17 18## Example Usage 19 20Note that all examples assume usage of the rules_testing `analysis_test` 21framework, but truth itself does not require it. 22 23``` 24def test_foo(env, target): 25 subject = env.expect.that_target(target) 26 subject.runfiles().contains_at_least(["foo.txt"]) 27 subject.executable().equals("bar.exe") 28 29 subject = env.expect.that_action(...) 30 subject.contains_at_least_args(...) 31``` 32 33## Subjects 34 35Subjects are wrappers around a value that provide ways to assert on the value, 36access sub-values of it, or otherwise augment interacting with the wrapped 37value. For example, `TargetSubject` wraps Bazel `Target` objects and 38`RunfilesSubject` wraps Bazel `runfiles` objects. Normally accessing a target's 39runfiles and verifying the runfiles contents would require the verbose 40`target[DefaultInfo].default_runfiles`, plus additional code to convert a 41`runfiles` object's `files`, `symlinks`, `root_symlinks`, and `empty_filenames` 42into a single list to verify. With subject classes, however, it can be concisely 43expressed as `expect.that_target(target).runfiles().contains(path)`. 44 45The Truth library provides subjects for types that are built into Bazel, but 46custom subjects can be implemented to handle custom providers or other objects. 47 48## Predicates 49 50Because Starlark's data model doesn't allow customizing equality checking, some 51subjects allow matching values by using a predicate function. This makes it 52easier to, for example, ignore a platform-specific file extension. 53 54This is implemented using the structural `Matcher` "interface". This is a struct 55that contains the predicate function and a description of what the function 56does, which allows for more intelligible error messages. 57 58A variety of matchers are in `truth.bzl#matching`, but custom matches can be 59implemented using `matching.custom_matcher` 60 61## Writing a new Subject 62 63Writing a new Subject involves two basic pieces: 64 651. Creating a constructor function, e.g. `_foo_subject_new`, that takes the 66 actual value and an `ExpectMeta` object (see `_expect_meta_new()`). 67 682. Adding a method to `expect` or another Subject class to pass along state and 69 instantiate the new subject; both may be modified if the actual object can 70 be independenly created or obtained through another subject. 71 72 For top-level subjects, a method named `that_foo()` should be added to the 73 `expect` class. 74 75 For child-subjects, an appropriately named method should be added to the 76 parent subject, and the parent subject should call `ExpectMeta.derive()` to 77 create a new set of meta data for the child subject. 78 79The assert methods a subject provides are up to the subject, but try to follow 80the naming scheme of other subjects. The purpose of a custom subject is to make 81it easier to write tests that are correct and informative. It's common to have a 82combination of ergonomic asserts for common cases, and delegating to 83child-subjects for other cases. 84 85## Adding asserts to a subject 86 87Fundamentally, an assert method calls `ExpectMeta.add_failure()` to record when 88there is a failure. That method will wire together any surrounding context with 89the provided error message information. Otherwise an assertion is free to 90implement checks how it pleases. 91 92The naming of functions should mostly read naturally, but doesn't need to be 93perfect grammatically. Be aware of ambiguous words like "contains" or "matches". 94For example, `contains_flag("--foo")` -- does this check that "--flag" was 95specified at all (ignoring value), or that it was specified and has no value? 96 97Assertion functions can make use of a variety of helper methods in processing 98values, comparing them, and generating error messages. Helpers of particular 99note are: 100 101* `_check_*`: These functions implement comparison, error formatting, and 102 error reporting. 103* `_compare_*`: These functions implements comparison for different cases 104 and take care of various edge cases. 105* `_format_failure_*`: These functions create human-friendly messages 106 describing both the observed values and the problem with them. 107* `_format_problem_*`: These functions format only the problem identified. 108* `_format_actual_*`: These functions format only the observed values. 109