| # FuzzTest Implementation Notes | |
| IMPORTANT: this document is an internal team document for extending | |
| FuzzTest. Do not extend your own types for FuzzTest without first | |
| consulting the | |
| FuzzTest team. | |
| Instead, use the existing domains or combinators of existing domains as noted | |
| within the [Domains Reference](../domains-reference.md). | |
| FuzzTest is an extensible framework. This guide documents how to extend | |
| FuzzTest to fuzz types appropriately and intelligently using custom | |
| domains. | |
| ## Domains | |
| This is a skeleton for a Domain implementation. Note that a Domain object is not | |
| designed to retain state, but only to create an instance of a type, and provide | |
| mutation services for an existing object of that type. | |
| Conceptually, a Domain represents a space of possible values, and a method for | |
| traversing that space. A concept of 'nearness' is useful if possible; for | |
| example, a Domain that mutates the string `cheese` to `chease` is useful in a | |
| way that one which is as likely to mutate it to `xyzzy` is not. | |
| ```c++ | |
| template <typename T> | |
| class MyDomain { | |
| public: | |
| using value_type = T; | |
| MyDomain(/* params */) { | |
| /* set up space of possible values here */ | |
| } | |
| T Init(absl::BitGenRef prng) {} | |
| void Mutate(T& val, absl::BitGenRef prng, bool only_shrink) {} | |
| private: | |
| /* params stored here */ | |
| } | |
| ``` | |
| ### Init | |
| ```c++ | |
| T Init(absl::BitGenRef prng); | |
| ``` | |
| The `Init` method returns an arbitrary value in the domain. This may be, for | |
| example, an empty container for a container type, or a random element for an | |
| `ElementOf` domain. Note that this is separate from a *constructor*; a | |
| constructor sets up a Domain, and `Init` produces an initial value from it. | |
| ### Mutate | |
| ```c++ | |
| void Mutate(T& val, absl::BitGenRef prng, bool only_shrink); | |
| ``` | |
| The `Mutate` method makes a small change on an existing value. The `only_shrink` | |
| parameter is used for case reduction; the precise semantics of what it means to | |
| grow or shrink a value of a given type are type-specific. | |
| There is no guarantee that `val` is within the Domain's possibility space. For | |
| example, a Domain representing positive integers could be given the number -1. | |
| In cases where this is possible, it is recommended that `Mutate` simply call | |
| `Init` on nonconforming inputs. | |
| ## Custom `corpus_type` | |
| Domains have a `value_type`; in many cases--for example, a domain consisting of | |
| integers--this value uniquely defines a point in the space of possible values. | |
| However, other types may not allow for this; for example, a domain which chooses | |
| one element from a list where they're not all necessarily unique. In this case, | |
| the domain can have a `corpus_type` representing its internal state, and a | |
| `value_type` representing its output. | |
| The `DomainTraits` class, which takes a `Domain` as a type parameter, wraps this | |
| idea. If your `Domain` sets `has_custom_corpus_type` to `true`, you can set a | |
| custom `corpus_type` property different from the `value_type`, and add a | |
| `GetValue` function to convert a `corpus_type` value into the corresponding | |
| `value_type`. | |
| For example, consider a domain which represents strings generated by a regular | |
| expression. It's much easier to mutate an explicit DFA path than to convert a | |
| string back and forth, so we use `std::string` as the `value_type` and a | |
| representation of the path as the `corpus_type`. | |
| ```c++ | |
| class RegexDomain { | |
| public: | |
| using value_type = std::string; | |
| static constexpr bool has_custom_corpus_type = true; | |
| using corpus_type = DFAPath; | |
| MyVectorDomain(std::string regex) : dfa_(DFA::Parse(regex)) {} | |
| corpus_type Init(absl::BitGenRef prng) { | |
| return dfa_.Generate(prng); | |
| } | |
| void Mutate(corpus_type& val, absl::BitGenRef prng, bool only_shrink) { | |
| dfa_.Mutate(prng, val); | |
| } | |
| value_type GetValue(const corpus_type& value) const { | |
| static_assert(has_custom_corpus_type); | |
| return dfa_.ToString(value); | |
| } | |
| private: | |
| DFA dfa_; | |
| } | |
| ``` | |
| Whether or not your domain (say, `MyDomain`) defines these explicitly, you can | |
| evaluate: | |
| | Function | Default value | | |
| | ------------------------------------------------ | ---------------------- | | |
| | `DomainTraits<MyDomain>::has_custom_corpus_type` | `false` | | |
| | `DomainTraits<MyDomain>::corpus_type` | `MyDomain::value_type` | | |
| | `DomainTraits<MyDomain>::GetValue(Domain& d, | Returns `value`. | | |
| : const corpus_type& value)` : : |