blob: 01f9645c1dcec2df7cbc81797d859acd381b6b86 [file] [log] [blame] [edit]
// Copyright 2022 Google LLC
//
// 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.
#ifndef FUZZTEST_FUZZTEST_FUZZTEST_MACROS_H_
#define FUZZTEST_FUZZTEST_FUZZTEST_MACROS_H_
#include <cstdint>
#include <string>
#include <string_view>
#include <tuple>
#include <vector>
// IWYU pragma: begin_exports
#include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "./fuzztest/internal/registration.h"
#include "./fuzztest/internal/registry.h"
// IWYU pragma: end_exports
namespace fuzztest {
// The FUZZ_TEST macro registers a fuzz test.
//
// Fuzz tests are parameterized unit tests, also called property-based tests.
// The tested property is captured by a function with some parameters, and the
// input domains of the parameters can be specified with the FUZZ_TEST macro
// that registers and instantiates the test:
//
// void CallingMyApiNeverCrashes(int x, const std::string& s) {
// bool result = MyApi(x, s); // This function call should never crash.
// ASSERT_TRUE(result); // Can have explicit assertions too.
// }
// FUZZ_TEST(MySuite, CallingMyApiNeverCrashes)
// .WithDomains(/*x:*/fuzztest::InRange(0,10),
// /*s:*/fuzztest::AsciiString())
// .WithSeeds({{5, "Foo"}, {10, "Bar"}});
//
// where `MySuite` is an identifier for a group of related tests, and
// `CallingMyApiNeverCrashes` is the name of the test and also the name of the
// "property function". The property function can have any number of parameters.
// The input domain of each parameter can be assigned using `.WithDomains()`,
// and the initial seed values can be provided using `.WithSeeds()`.
//
// When each parameter's input domain is `Arbitrary<T>()`, which allows any
// value of a given type T, i.e.:
//
// FUZZ_TEST(MySuite, CallingMyApiNeverCrashes)
// .WithDomains(/*x:*/fuzztest::Arbitrary<int>(),
// /*s:*/fuzztest::Arbitrary<std::string>());
//
// then the input domain assignment with `.WithDomains()` can be omitted:
//
// FUZZ_TEST(MySuite, CallingMyApiNeverCrashes);
//
// Note: When specifying both the domains and seeds, the domain clause has to
// be specified first.
#define FUZZ_TEST(suite_name, func) INTERNAL_FUZZ_TEST(suite_name, func)
// The FUZZ_TEST_F macro registers a fuzz test that uses a test fixture.
//
// The first parameter is the name of the fixture class, which is also used as
// the name of the test suite. The second parameter is the name of the property
// function (also used as the test name), which must be defined as a public
// member of the fixture class.
//
// A test fixture can be any default-constructible class. The fixture's setup
// code should be in its constructor, and the teardown code should be in its
// destructor. While running the fuzz test, which involves calling the property
// function multiple times with various inputs, the fixture will be instantiated
// only once at the beginning and destroyed at the end of the fuzz test. In
// particular, the same instance will be used in all calls to the property
// function.
//
// If the fixture you are using is a GoogleTest fixture (i.e., it extends
// `::testing::Test`, either directly or indirectly), then you will additionally
// need to wrap the fixture in an adapter. For more details, see
// https://github.com/google/fuzztest/blob/main/doc/fixtures.md.
//
// Just like the FUZZ_TEST macro, the FUZZ_TEST_F macro allows specifying the
// domains and seeds using the `.WithDomains()` and `.WithSeeds()` clauses.
//
// Example:
//
// class FooFuzzTest {
// public:
// FooFuzzTest() { foo_.SetUp(); }
// ~FooFuzzTest() { foo_.TearDown(); }
//
// void CallingFooBarNeverCrashes(int x, const std::string& s) {
// bool result = foo_.Bar(x, s);
// ASSERT_TRUE(result);
// }
//
// private:
// Foo foo_;
// };
// FUZZ_TEST_F(FooFuzzTest, CallingFooBarNeverCrashes)
// .WithDomains(/*x:*/fuzztest::Positive<int>(),
// /*s:*/fuzztest::AsciiString())
// .WithSeeds({{5, "Foo"}, {10, "Bar"}});
//
#define FUZZ_TEST_F(fixture, func) \
INTERNAL_FUZZ_TEST_F(fixture, func, fixture, func)
// Reads files as strings from the directory `dir` and returns a vector usable
// by .WithSeeds().
//
// Example:
//
// void MyThingNeverCrashes(const std::string& s) {
// DoThingsWith(s);
// }
// FUZZ_TEST(MySuite, MyThingNeverCrashes)
// .WithSeeds(ReadFilesFromDirectory(kCorpusPath));
std::vector<std::tuple<std::string>> ReadFilesFromDirectory(
std::string_view dir);
// Returns parsed dictionary entries from fuzzer dictionary definition in the
// format specified at https://llvm.org/docs/LibFuzzer.html#dictionaries.
// If dictionary is in wrong format, return error status.
absl::StatusOr<std::vector<std::string>> ParseDictionary(
absl::string_view text);
// Reads entries from `dictionary_file` and returns a vector usable by
// .WithDictionary().
//
// Example:
//
// void MyThingNeverCrashes(const std::string& s) {
// DoThingsWith(s);
// }
// FUZZ_TEST(MySuite, MyThingNeverCrashes)
// .WithDomains(String().WithDictionary(
// ReadDictionaryFromFile(kDictionaryPath)));
std::vector<std::string> ReadDictionaryFromFile(
std::string_view dictionary_file);
// Converts string_view into a byte-array, useful when working with the LLVM
// fuzzer interfaces.
inline std::vector<uint8_t> ToByteArray(std::string_view str) {
return std::vector<uint8_t>(str.begin(), str.end());
}
// When called during the fixture setup (in the constructor or SetUp()), skips
// calling property functions until the matching teardown (destructor or
// TearDown()). When called in a property function, skips adding the current
// input to the corpus when fuzzing.
//
// Note that this function should not be called frequently due to engine
// limitation and efficiency reasons. Consider refining the domain definitions
// to restrict input generation if possible.
inline void SkipTestsOrCurrentInput() {
internal::Runtime::instance().SetSkippingRequested(true);
}
} // namespace fuzztest
#endif // FUZZTEST_FUZZTEST_FUZZTEST_MACROS_H_