Internal change
PiperOrigin-RevId: 521826652
diff --git a/e2e_tests/functional_test.cc b/e2e_tests/functional_test.cc
index 8bdbc7f..bada079 100644
--- a/e2e_tests/functional_test.cc
+++ b/e2e_tests/functional_test.cc
@@ -316,6 +316,14 @@
1, CountSubstrs(std_err, "<<CallCountGoogleTest::TearDownTestSuite()>>"));
}
+TEST(UnitTestModeTest, DynamicFuzzTestsAreUsed) {
+ auto [status, std_out, std_err] =
+ RunWith(GetGTestFilterFlag("MySuiteSeedsFixture.AddCall"));
+ EXPECT_THAT(
+ std_err,
+ HasSubstr("<MySuiteSeedsFixture::GuessedUnguessableExampleSeed>>"));
+}
+
TEST(UnitTestModeTest, GoogleTestWorksWithProtoExtensionsUsedInSeeds) {
auto [status, std_out, std_err] =
RunWith(GetGTestFilterFlag("MySuite.CheckProtoExtensions"));
diff --git a/e2e_tests/testdata/BUILD b/e2e_tests/testdata/BUILD
index 382143e..b49dbf0 100644
--- a/e2e_tests/testdata/BUILD
+++ b/e2e_tests/testdata/BUILD
@@ -42,6 +42,7 @@
name = "fuzz_tests_for_functional_testing",
testonly = 1,
srcs = [
+ "fuzz_test_with_dynamic_seeds.cc",
"fuzz_tests_for_functional_testing.cc",
"fuzz_tests_for_microbenchmarking.cc",
"fuzz_tests_using_googletest.cc",
diff --git a/e2e_tests/testdata/fuzz_test_with_dynamic_seeds.cc b/e2e_tests/testdata/fuzz_test_with_dynamic_seeds.cc
new file mode 100644
index 0000000..fd03192
--- /dev/null
+++ b/e2e_tests/testdata/fuzz_test_with_dynamic_seeds.cc
@@ -0,0 +1,39 @@
+// 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.
+
+// Example fuzz tests that require GoogleTest, for functional testing.
+//
+// Used by `functional_test` only. We separate these into a different .cc file
+// to show that regular FUZZ_TEST work without having to #include GoogleTest.
+
+#include <cstdio>
+#include <limits>
+
+#include "gtest/gtest.h"
+#include "./fuzztest/fuzztest.h"
+#include "./fuzztest/googletest_fixture_adapter.h"
+
+struct MySuiteSeedsFixture {
+ void AddCall(std::string s) {
+ if (s == "UnguessableExampleSeed") {
+ fprintf(stderr,
+ "<<MySuiteSeedsFixture::GuessedUnguessableExampleSeed>>\n");
+ }
+ }
+
+ std::vector<std::tuple<std::string>> GetDynamicFuzzTestSeeds() {
+ return {"UnguessableExampleSeed"};
+ }
+};
+FUZZ_TEST_F(MySuiteSeedsFixture, AddCall);
diff --git a/fuzztest/BUILD b/fuzztest/BUILD
index 7bd5dc7..72b487c 100644
--- a/fuzztest/BUILD
+++ b/fuzztest/BUILD
@@ -160,6 +160,7 @@
srcs = ["internal/fixture_driver.cc"],
hdrs = ["internal/fixture_driver.h"],
deps = [
+ ":domain",
":logging",
":registration",
":type_support",
@@ -171,6 +172,7 @@
size = "small",
srcs = ["internal/fixture_driver_test.cc"],
deps = [
+ ":any",
":domain",
":fixture_driver",
":registration",
diff --git a/fuzztest/internal/fixture_driver.cc b/fuzztest/internal/fixture_driver.cc
index e5c5443..c175c88 100644
--- a/fuzztest/internal/fixture_driver.cc
+++ b/fuzztest/internal/fixture_driver.cc
@@ -25,9 +25,15 @@
void UntypedFixtureDriver::SetUpIteration() {}
void UntypedFixtureDriver::TearDownIteration() {}
void UntypedFixtureDriver::TearDownFuzzTest() {}
+std::vector<GenericDomainCorpusType> GetDynamicSeeds() { return {}; }
+
std::vector<GenericDomainCorpusType> UntypedFixtureDriver::GetSeeds() const {
return seeds_;
}
+std::vector<GenericDomainCorpusType> UntypedFixtureDriver::GetDynamicSeeds() {
+ return {};
+}
+
std::unique_ptr<UntypedDomainInterface> UntypedFixtureDriver::GetDomains()
const {
return domain_->Clone();
diff --git a/fuzztest/internal/fixture_driver.h b/fuzztest/internal/fixture_driver.h
index fc55add..77e8523 100644
--- a/fuzztest/internal/fixture_driver.h
+++ b/fuzztest/internal/fixture_driver.h
@@ -16,10 +16,12 @@
#define FUZZTEST_FUZZTEST_INTERNAL_FIXTURE_DRIVER_H_
#include <memory>
+#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
+#include "./fuzztest/internal/domains/domain_base.h"
#include "./fuzztest/internal/logging.h"
#include "./fuzztest/internal/registration.h"
#include "./fuzztest/internal/type_support.h"
@@ -78,6 +80,7 @@
virtual void Test(MoveOnlyAny&& args_untyped) const = 0;
std::vector<GenericDomainCorpusType> GetSeeds() const;
+ virtual std::vector<GenericDomainCorpusType> GetDynamicSeeds();
std::unique_ptr<UntypedDomainInterface> GetDomains() const;
private:
@@ -205,6 +208,16 @@
using FixtureDriver<DomainT, NoFixture, TargetFunction>::FixtureDriver;
};
+// HasGetDynamicSeeds<T>::value is true_type if T has a
+// GetDynamicSeeds() member.
+template <typename T, typename = void>
+struct HasGetDynamicFuzzTestSeeds : std::false_type {};
+
+template <typename T>
+struct HasGetDynamicFuzzTestSeeds<
+ T, std::void_t<decltype(std::declval<T>().GetDynamicFuzzTestSeeds())>>
+ : std::true_type {};
+
// The fixture driver for default-constructible classes that act like fixtures:
// their setup is in the constructor, teardown is in the destructor, and they
// have a target function. Such fixtures are instantiated and destructed once
@@ -223,6 +236,19 @@
this->fixture_ = std::make_unique<Fixture>();
}
void TearDownFuzzTest() override { this->fixture_ = nullptr; }
+
+ std::vector<GenericDomainCorpusType> GetDynamicSeeds() override {
+ std::vector<GenericDomainCorpusType> seeds;
+ if constexpr (HasGetDynamicFuzzTestSeeds<Fixture>::value) {
+ auto typed_seeds = this->fixture_->GetDynamicFuzzTestSeeds();
+ seeds.reserve(typed_seeds.size());
+ for (auto& seed : typed_seeds) {
+ seeds.emplace_back(std::in_place_type<std::decay_t<decltype(seed)>>,
+ std::move(seed));
+ }
+ }
+ return seeds;
+ }
};
// The fixture driver for test fixtures with explicit setup that assume the
diff --git a/fuzztest/internal/fixture_driver_test.cc b/fuzztest/internal/fixture_driver_test.cc
index 45f6f26..2394a09 100644
--- a/fuzztest/internal/fixture_driver_test.cc
+++ b/fuzztest/internal/fixture_driver_test.cc
@@ -17,11 +17,13 @@
#include <string>
#include <tuple>
#include <type_traits>
+#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/types/span.h"
#include "./fuzztest/domain.h"
+#include "./fuzztest/internal/any.h"
#include "./fuzztest/internal/registration.h"
#include "./fuzztest/internal/type_support.h"
@@ -98,6 +100,37 @@
EXPECT_EQ(CallCountFixture::call_count, 3);
}
+struct SeedsFixture {
+ void AddCall(int n) { calls.push_back(n); }
+ inline static std::vector<int> calls;
+ inline static std::vector<int> dynamic_seeds;
+
+ std::vector<int> GetDynamicFuzzTestSeeds() {
+ std::vector<int> ret;
+ ret.swap(dynamic_seeds);
+ return ret;
+ }
+};
+
+using AddCallFunc = decltype(&SeedsFixture::AddCall);
+using AddCallRegBase = DefaultRegistrationBase<CallCountFixture, AddCallFunc>;
+
+TEST(FixtureDriverTest, DynamicSeeds) {
+ FixtureDriverImpl<Domain<std::tuple<int>>, SeedsFixture, AddCallFunc>
+ fixture_driver(&SeedsFixture::AddCall, Arbitrary<std::tuple<int>>(), {});
+
+ fixture_driver.SetUpFuzzTest();
+ std::vector<int> seeds = {177, 182731};
+ SeedsFixture::dynamic_seeds = seeds;
+
+ auto output_seeds = fixture_driver.GetDynamicSeeds();
+ std::vector<int> int_outputs;
+ for (const auto& output_seed : output_seeds) {
+ int_outputs.push_back(output_seed.GetAs<int>());
+ }
+ EXPECT_THAT(int_outputs, UnorderedElementsAre(177, 182731));
+}
+
struct LifecycleRecordingFixture {
LifecycleRecordingFixture() { was_constructed = true; }
~LifecycleRecordingFixture() { was_destructed = true; }
diff --git a/fuzztest/internal/runtime.cc b/fuzztest/internal/runtime.cc
index 8d1a049..2bb7785 100644
--- a/fuzztest/internal/runtime.cc
+++ b/fuzztest/internal/runtime.cc
@@ -585,6 +585,10 @@
TrySampleAndUpdateInMemoryCorpus(Input{seed},
/*write_to_file=*/false);
}
+ for (const auto& seed : fixture_driver_->GetDynamicSeeds()) {
+ TrySampleAndUpdateInMemoryCorpus(Input{seed},
+ /*write_to_file=*/false);
+ }
}
void FuzzTestFuzzerImpl::RunInUnitTestMode() {