| # The `FUZZ_TEST` macro | |
| Fuzz tests are instantiated with the | |
| FUZZ_TEST | |
| macro. Here's an example: | |
| ```c++ | |
| void CallingMyApiNeverCrashes(int x, const std::string& s) { | |
| // Exercise MyApi() with different inputs trying to trigger a crash, e.g., | |
| // by invalidating assertions in the code or by causing undefined behaviour. | |
| bool result = MyApi(x, s); | |
| ASSERT_TRUE(result); // The test itself can have assertions too. | |
| } | |
| FUZZ_TEST(MyApiTestSuite, CallingMyApiNeverCrashes) | |
| .WithDomains(/*x:*/fuzztest::InRange(0,10), | |
| /*s:*/fuzztest::Arbitrary<std::string>()) | |
| .WithSeeds({{5, "Foo"}, {10, "Bar"}}); | |
| ``` | |
| The three parts of the instantiation that we discuss in more detail are the | |
| following: | |
| * The *property function* (called `CallingMyApiNeverCrashes` in the example). | |
| * The *input domains* for the property function's parameters, specified using | |
| the `.WithDomains()` clause. | |
| * The *initial seed* values for the parameters, specified using the | |
| `.WithSeeds()` clause. | |
| The property function is a mandatory part of the instantiation; the input | |
| domains and the seeds are optional. If you want to specify both the input | |
| domains and the seeds, you have to specify the input domains first. | |
| WARNING: The `FUZZ_TEST` macro expands into a global variable definition. Thus, | |
| you should be careful when initializing the input domains or seeds with other | |
| global objects. Never initialize the input domains or seeds with global objects | |
| that are initialized in other compilation units! Doing this may lead to the | |
| [static initialization order fiasco](https://en.cppreference.com/w/cpp/language/siof). | |
| You may use [seed providers](#seed-providers) to delay the initialization of | |
| seeds. | |
| ## The property function | |
| The most important part of the above example is the `CallingMyApiNeverCrashes` | |
| function, which we call the "property function". Fuzz tests are parameterized | |
| unit tests, also called *property-based tests*. The tested property is captured | |
| by a function with some parameters. The test will run this function with many | |
| different argument values. We call this function the "property function", | |
| because the name typically represent the tested property, for example | |
| `CallingMyApiNeverCrashes` in the example above. | |
| The `FUZZ_TEST` macro makes `CallingMyApiNeverCrashes` function an actual fuzz | |
| test. Note that `CallingMyApiNeverCrashes` is both the name of our property | |
| function and the test as well. The first parameter of the macro is the name of | |
| the test suite, and the second is the name of the test (similarly to | |
| [GoogleTest's](https://google.github.io/googletest/) | |
| `TEST()` macro). The test suite `MyApiTestSuite` can contain multiple | |
| `FUZZ_TEST`-s and regular unit `TEST`-s as well. The property function can have | |
| one or more of parameters. | |
| Important things to note about the property function: | |
| * The function will be run with many different inputs in the same process, | |
| trying to trigger a crash (assertion failure). | |
| * The return value should be `void`, as we only care about invalidating | |
| assertions and triggering undefined behavior. | |
| * The function should not `exit()` on any input, because that will terminate | |
| the test execution. | |
| * Ideally, it should be deterministic (same input arguments should trigger the | |
| same execution). Non-determinism can make fuzzing inefficient. | |
| * Ideally, it should not use any global state (only depend on input | |
| parameters). | |
| * It may use threads, but threads should be joined in the function. | |
| * It's better to write more smaller functions (and `FUZZ_TEST`s) than one big | |
| one. The simpler the function, the easier it is for the tool to cover it and | |
| find bugs. | |
| ## Input domains | |
| As opposed to | |
| [value-parameterized tests](https://google.github.io/googletest/advanced.html#value-parameterized-tests), | |
| the parameters in property-based tests are not assigned to a set of concrete | |
| values, but to an abstract input domain. The input domain of each parameter of | |
| the property function can be assigned using the `.WithDomains()` clause. An | |
| input domain is an abstraction representing a typed set of values. In the | |
| example above, we specify that the input domain of the first parameter is *"any | |
| integer between 0 and 10"* (closed interval), while the input domain of the | |
| second parameter is *"an arbitrary string"*. If we don't explicitly specify | |
| domains, for a parameter of type `T`, the `fuzztest::Arbitrary<T>()` domain will | |
| be used. | |
| Input domains are the central concept in FuzzTest. The input domain | |
| specifies the coverage of the property-based testing inputs. The most commonly | |
| used domain is `Arbitrary<T>()`, which represent all possible values of type | |
| `T`. This is also the "default" input domain. This means that when we want use | |
| `Arbitrary<T>()` for every parameter of our property function, for example: | |
| ```c++ | |
| FUZZ_TEST(MyApiTestSuite, CallingMyApiNeverCrashes) | |
| .WithDomains(/*x:*/fuzztest::Arbitrary<int>(), | |
| /*s:*/fuzztest::Arbitrary<std::string>()); | |
| ``` | |
| then the input domain assignment using `.WithDomains()` can be omitted | |
| completely: | |
| ```c++ | |
| FUZZ_TEST(MyApiTestSuite, CallingMyApiNeverCrashes); | |
| ``` | |
| See the [Domains Reference](domains-reference.md) for the descriptions of the | |
| various built-in domains and also how you can build your own domains. | |
| ## Initial seeds {#initial-seeds} | |
| You can use the `.WithSeeds()` clause to provide the initial seed values for the | |
| property function's parameters. The initial seed values are concrete inputs that | |
| FuzzTest deterministically runs and uses as a basis for creating other inputs. | |
| In the above example, the seed `{5, "Foo"}` causes FuzzTest to execute | |
| `CallingMyApiNeverCrashes(5, "Foo")`. In the subsequent runs, FuzzTest may | |
| generate similar values, like `{5, "Foooo"}` or `{10, "Foo"}`, and use them as | |
| inputs to the property function. | |
| Providing seeds is not necessary; if you don't provide them, FuzzTest will | |
| generate them at random. However, in certain cases providing seeds can greatly | |
| improve fuzzing efficiency. | |
| Note: Some domains don't support seeds. `ElementOf` and `Just` support seeds | |
| only for certain types (see [`ElementOf`](domains-reference.md#element-of)). | |
| Complex domains constructed using combinators `ConstructorOf`, `Map`, and | |
| `FlatMap` don't support seeds. | |
| ### Delaying seed initialization with a seed provider {#seed-providers} | |
| As noted earlier, fuzz tests are instantiated as global variables, so | |
| initializing seeds from other global objects (especially those coming from other | |
| compilation units) can lead to unexpected consequences or even undefined | |
| behavior. For cases when such initialization cannot be avoided, the | |
| `.WithSeeds()` clause also accepts a *seed provider*—a function that returns a | |
| vector of seeds. FuzzTest will call the seed provider in runtime, thus avoiding | |
| any static initialization issues. | |
| The seed provider can be any invocable (lambda, function pointer, callable | |
| object, etc.) that doesn't take inputs and returns | |
| `std::vector<std::tuple<Args...>>`, where `Args...` are the types of the | |
| property function's parameters. In the example from earlier, we could use the | |
| following seed provider: | |
| ```c++ | |
| FUZZ_TEST(MyApiTestSuite, CallingMyApiNeverCrashes) | |
| .WithSeeds([]() -> std::vector<std::tuple<int, std::string>> { | |
| return {{5, "Foo"}, {10, "Bar"}}; | |
| }); | |
| ``` | |
| If you are using a [test fixture](fixtures.md), the seed provider can also be a | |
| pointer to a member function of the fixture, as in the following example: | |
| ```c++ | |
| class MyFuzzTest { | |
| public: | |
| void CallingMyApiNeverCrashes(int x, const std::string& s); | |
| // The seed provider can depend on the fixture's state. | |
| std::vector<std::tuple<int, std::string>> seeds() { return seeds_; } | |
| private: | |
| std::vector<std::tuple<int, std::string>> seeds_ = {{5, "Foo"}, {10, "Bar"}}; | |
| }; | |
| FUZZ_TEST_F(MyFuzzTest, CallingMyApiNeverCrashes) | |
| // The seed provider can be a pointer to the fixture's member function. Note | |
| // that the member function can't be const. | |
| .WithSeeds(&MyFuzzTest::seeds); | |
| ``` | |
| ### Loading seed inputs from a directory | |
| You can also provide a checked-in corpus of seeds using | |
| `fuzztest::ReadFilesFromDirectory`, which supports loading | |
| strings. For example: | |
| ``` | |
| static constexpr absl::string_view kMyCorpusPath = "path/to/my_corpus"; | |
| void CallingMyApiNeverCrashes(const std::string& input) { | |
| ... | |
| } | |
| FUZZ_TEST(MyApiTestSuite, CallingMyApiNeverCrashes) | |
| .WithSeeds(fuzztest::ReadFilesFromDirectory( | |
| absl::StrCat(std::getenv("TEST_SRCDIR"), kMyCorpusPath))); | |
| ``` | |