| # 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)` : : |