Move init related functions to init_fuzztest. PiperOrigin-RevId: 564413561
diff --git a/fuzztest/BUILD b/fuzztest/BUILD index a12162f..6733654 100644 --- a/fuzztest/BUILD +++ b/fuzztest/BUILD
@@ -241,9 +241,6 @@ ":domain", ":io", ":registry", - ":runtime", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/strings:str_format", ], ) @@ -253,11 +250,12 @@ srcs = ["init_fuzztest.cc"], hdrs = ["init_fuzztest.h"], deps = [ - ":fuzztest", ":googletest_adaptor", + ":registry", ":runtime", "@com_google_absl//absl/flags:flag", "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/time", "@com_google_googletest//:gtest", ],
diff --git a/fuzztest/fuzztest.cc b/fuzztest/fuzztest.cc index 8ca454c..b2461cd 100644 --- a/fuzztest/fuzztest.cc +++ b/fuzztest/fuzztest.cc
@@ -14,75 +14,15 @@ #include "./fuzztest/fuzztest.h" -#include <cstdio> -#include <cstdlib> #include <string> #include <string_view> #include <tuple> -#include <utility> #include <vector> -#include "absl/strings/match.h" -#include "absl/strings/str_format.h" #include "./fuzztest/internal/io.h" -#include "./fuzztest/internal/registry.h" -#include "./fuzztest/internal/runtime.h" namespace fuzztest { -std::vector<std::string> ListRegisteredTests() { - std::vector<std::string> result; - internal::ForEachTest( - [&](const auto& test) { result.push_back(test.full_name()); }); - return result; -} - -std::string GetMatchingFuzzTestOrExit(std::string_view name) { - const std::string partial_name(name); - const std::vector<std::string> full_names = ListRegisteredTests(); - std::vector<const std::string*> matches; - for (const std::string& full_name : full_names) { - if (absl::StrContains(full_name, partial_name)) { - if (full_name == partial_name) { - // In case of an exact match, we end the search and use it. This is to - // handle the case when we want to select `MySuite.MyTest`, but the - // binary has both `MySuite.MyTest` and `MySuite.MyTestX`. - return full_name; - } else { - matches.push_back(&full_name); - } - } - } - - if (matches.empty()) { - absl::FPrintF(stderr, "\n\nNo FUZZ_TEST matches the name: %s\n\n", name); - absl::FPrintF(stderr, "Valid tests:\n"); - for (const std::string& full_name : full_names) { - absl::FPrintF(stderr, " %s\n", full_name); - } - exit(1); - } else if (matches.size() > 1) { - absl::FPrintF(stderr, "\n\nMultiple FUZZ_TESTs match the name: %s\n\n", - name); - absl::FPrintF(stderr, "Please select one. Matching tests:\n"); - for (const std::string* full_name : matches) { - absl::FPrintF(stderr, " %s\n", *full_name); - } - exit(1); - } - return *matches[0]; -} - -void RunSpecifiedFuzzTest(std::string_view name) { - const std::string matching_fuzz_test = GetMatchingFuzzTestOrExit(name); - internal::ForEachTest([&](auto& test) { - if (test.full_name() == matching_fuzz_test) { - exit(std::move(test).make()->RunInFuzzingMode(/*argc=*/nullptr, - /*argv=*/nullptr)); - } - }); -} - std::vector<std::tuple<std::string>> ReadFilesFromDirectory( std::string_view dir) { std::vector<internal::FilePathAndData> files =
diff --git a/fuzztest/fuzztest.h b/fuzztest/fuzztest.h index e28ca93..8f50528 100644 --- a/fuzztest/fuzztest.h +++ b/fuzztest/fuzztest.h
@@ -108,41 +108,16 @@ #define FUZZ_TEST_F(fixture, func) \ INTERNAL_FUZZ_TEST_F(fixture, func, fixture, func) -// Returns a list of all registered fuzz test names in the form of -// "<suite_name>.<property_function_name>", e.g., `MySuite.MyFuzzTest". -// -// REQUIRES: `main()` has started before calling this function. -std::vector<std::string> ListRegisteredTests(); - -// Returns the full name of the single registered fuzz test that matches `name`. -// If there are zero or multiple tests that match `name`, exits with an error -// message. -// -// A test matches `name` if its full name (e.g., "MySuite.MyFuzzTest") contains -// `name` (e.g., "MyFuzz") as a substring. If there is a test whose full name -// exactly matches `name`, then this will be the returned name. -// -// REQUIRES: `main()` has started before calling this function. -std::string GetMatchingFuzzTestOrExit(std::string_view name); - -// Runs the FUZZ_TEST specified by `name` in fuzzing mode. -// -// The `name` can be a full name, e.g., "MySuite.MyFuzzTest". It can also be a -// part of the full name, e.g., "MyFuzz", if it matches only a single fuzz test -// in the binary. If there is only one fuzz test in binary, name can also be -// empty string. If `name` matches exactly one FUZZ_TEST, it runs the selected -// test in fuzzing mode, until a bug is found or until manually stopped. -// Otherwise, it exits. -// -// REQUIRES: `main()` has started before calling this function. -// REQUIRES: Binary must be built with SanCov instrumentation on. -void RunSpecifiedFuzzTest(std::string_view name); - // Reads files as strings from the directory `dir` and returns a vector usable // by .WithSeeds(). -// Example usage: -// FUZZ_TEST(SuiteName, TestName) -// .WithSeeds(ReadFilesFromDirectory(kCorpusPath)); +// +// 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);
diff --git a/fuzztest/init_fuzztest.cc b/fuzztest/init_fuzztest.cc index e28e97f..9d05df0 100644 --- a/fuzztest/init_fuzztest.cc +++ b/fuzztest/init_fuzztest.cc
@@ -3,13 +3,18 @@ #include <cstdlib> #include <iostream> #include <string> +#include <string_view> +#include <utility> +#include <vector> #include "gtest/gtest.h" #include "absl/flags/flag.h" +#include "absl/strings/match.h" +#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" -#include "./fuzztest/fuzztest.h" #include "./fuzztest/internal/googletest_adaptor.h" +#include "./fuzztest/internal/registry.h" #include "./fuzztest/internal/runtime.h" #define FUZZTEST_FLAG_PREFIX "" @@ -57,6 +62,59 @@ namespace fuzztest { +std::vector<std::string> ListRegisteredTests() { + std::vector<std::string> result; + internal::ForEachTest( + [&](const auto& test) { result.push_back(test.full_name()); }); + return result; +} + +std::string GetMatchingFuzzTestOrExit(std::string_view name) { + const std::string partial_name(name); + const std::vector<std::string> full_names = ListRegisteredTests(); + std::vector<const std::string*> matches; + for (const std::string& full_name : full_names) { + if (absl::StrContains(full_name, partial_name)) { + if (full_name == partial_name) { + // In case of an exact match, we end the search and use it. This is to + // handle the case when we want to select `MySuite.MyTest`, but the + // binary has both `MySuite.MyTest` and `MySuite.MyTestX`. + return full_name; + } else { + matches.push_back(&full_name); + } + } + } + + if (matches.empty()) { + absl::FPrintF(stderr, "\n\nNo FUZZ_TEST matches the name: %s\n\n", name); + absl::FPrintF(stderr, "Valid tests:\n"); + for (const std::string& full_name : full_names) { + absl::FPrintF(stderr, " %s\n", full_name); + } + exit(1); + } else if (matches.size() > 1) { + absl::FPrintF(stderr, "\n\nMultiple FUZZ_TESTs match the name: %s\n\n", + name); + absl::FPrintF(stderr, "Please select one. Matching tests:\n"); + for (const std::string* full_name : matches) { + absl::FPrintF(stderr, " %s\n", *full_name); + } + exit(1); + } + return *matches[0]; +} + +void RunSpecifiedFuzzTest(std::string_view name) { + const std::string matching_fuzz_test = GetMatchingFuzzTestOrExit(name); + internal::ForEachTest([&](auto& test) { + if (test.full_name() == matching_fuzz_test) { + exit(std::move(test).make()->RunInFuzzingMode(/*argc=*/nullptr, + /*argv=*/nullptr)); + } + }); +} + void InitFuzzTest(int* argc, char*** argv) { const bool is_listing = absl::GetFlag(FUZZTEST_FLAG(list_fuzz_tests)); if (is_listing) {
diff --git a/fuzztest/init_fuzztest.h b/fuzztest/init_fuzztest.h index eb661c3..547e7ff 100644 --- a/fuzztest/init_fuzztest.h +++ b/fuzztest/init_fuzztest.h
@@ -1,17 +1,59 @@ #ifndef FUZZTEST_FUZZTEST_INIT_FUZZTEST_H_ #define FUZZTEST_FUZZTEST_INIT_FUZZTEST_H_ +#include <string> +#include <string_view> +#include <tuple> +#include <vector> + namespace fuzztest { -// Handles FuzzTest related flags and registers FUZZ_TEST-s in the binary as -// GoogleTest TEST-s. +// Initializes FuzzTest. Handles the FuzzTest related flags and registers +// FUZZ_TEST-s in the binary as GoogleTest TEST-s. // // The command line arguments (argc, argv) are passed only to support the // "compatibility mode" with external engines via the LLVMFuzzerRunDriver // interface: // https://llvm.org/docs/LibFuzzer.html#using-libfuzzer-as-a-library +// +// REQUIRES: `main()` has started before calling this function. void InitFuzzTest(int* argc, char*** argv); +// Returns a list of all registered fuzz test names in the form of +// "<suite_name>.<property_function_name>", e.g., `MySuite.MyFuzzTest". +// +// REQUIRES: `main()` has started before calling this function. +std::vector<std::string> ListRegisteredTests(); + +// Returns the full name of the fuzz test that "matches" the provided `name` +// specification. If no match is found, it exists. +// +// 1) The provided `name` specification can be a full name, e.g., +// "MySuite.MyFuzzTest". If such fuzz test exists, the full name is returned. +// +// 2) The `name` specification can also be a strict sub-string of a full name, +// e.g., "MyFuzz". If there's exactly one fuzz test that contains the (strict) +// sub-string, its full name is returned. +// +// 3) The `name` specification can also be an empty string. If there's only one +// fuzz test in the binary, its full name is returned. +// +// If no single match is found, it exits with an error message. +// +// REQUIRES: `main()` has started before calling this function. +std::string GetMatchingFuzzTestOrExit(std::string_view name); + +// Runs the FUZZ_TEST specified by `name` in fuzzing mode. +// +// Selects the fuzz test to run using GetMatchingFuzzTestOrExit(name). +// +// If `name` matches exactly one FUZZ_TEST, it runs the selected test in fuzzing +// mode, until a bug is found or until manually stopped. Otherwise, it exits. +// +// REQUIRES: `main()` has started before calling this function. +// REQUIRES: Binary must be built with SanCov instrumentation on. +void RunSpecifiedFuzzTest(std::string_view name); + } // namespace fuzztest #endif // FUZZTEST_FUZZTEST_INIT_FUZZTEST_H_