Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions domain_tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ cc_test(
"@abseil-cpp//absl/random",
"@abseil-cpp//absl/random:bit_gen_ref",
"@abseil-cpp//absl/status",
"@abseil-cpp//absl/types:optional",
"@abseil-cpp//absl/types:span",
"@abseil-cpp//absl/types:variant",
"@com_google_fuzztest//fuzztest:domain_core",
"@com_google_fuzztest//fuzztest/internal:serialization",
"@com_google_fuzztest//fuzztest/internal:type_support",
"@com_google_fuzztest//fuzztest/internal/domains:core_domains_impl",
"@googletest//:gtest_main",
],
)
Expand Down Expand Up @@ -137,6 +135,7 @@ cc_test(
"@abseil-cpp//absl/random",
"@com_google_fuzztest//fuzztest:domain_core",
"@com_google_fuzztest//fuzztest/internal:table_of_recent_compares",
"@com_google_fuzztest//fuzztest/internal/domains:core_domains_impl",
"@googletest//:gtest_main",
],
)
Expand All @@ -153,8 +152,10 @@ cc_library(
"@abseil-cpp//absl/random",
"@abseil-cpp//absl/random:bit_gen_ref",
"@abseil-cpp//absl/status",
"@abseil-cpp//absl/status:statusor",
"@abseil-cpp//absl/strings",
"@com_google_fuzztest//common:logging",
"@com_google_fuzztest//common:status_macros",
"@com_google_fuzztest//fuzztest/internal:logging",
"@com_google_fuzztest//fuzztest/internal:meta",
"@com_google_fuzztest//fuzztest/internal:serialization",
Expand Down Expand Up @@ -199,7 +200,9 @@ cc_test(
":domain_testing",
"@abseil-cpp//absl/algorithm:container",
"@abseil-cpp//absl/random",
"@abseil-cpp//absl/status",
"@com_google_fuzztest//fuzztest:domain_core",
"@com_google_fuzztest//fuzztest/internal/domains:core_domains_impl",
"@googletest//:gtest_main",
],
)
Expand Down Expand Up @@ -256,6 +259,7 @@ cc_test(
":domain_testing",
"@abseil-cpp//absl/random",
"@com_google_fuzztest//fuzztest:domain_core",
"@com_google_fuzztest//fuzztest/internal/domains:core_domains_impl",
"@googletest//:gtest_main",
],
)
Expand Down
12 changes: 9 additions & 3 deletions domain_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ fuzztest_cc_test(
absl::flat_hash_set
absl::random_bit_gen_ref
absl::random_random
absl::optional
absl::span
absl::status
absl::variant
fuzztest::core_domains_impl
fuzztest::domain_core
fuzztest::serialization
fuzztest::type_support
Expand Down Expand Up @@ -122,6 +120,8 @@ fuzztest_cc_test(
absl::flat_hash_map
absl::flat_hash_set
absl::random_random
absl::status
fuzztest::core_domains_impl
fuzztest::domain_core
fuzztest::table_of_recent_compares
GTest::gmock_main
Expand All @@ -138,9 +138,11 @@ fuzztest_cc_library(
absl::random_random
absl::random_bit_gen_ref
absl::status
absl::statusor
absl::strings
fuzztest::domain_core
fuzztest::common_logging
fuzztest::status_macros
fuzztest::meta
fuzztest::serialization
fuzztest::test_protobuf_cc_proto
Expand Down Expand Up @@ -188,6 +190,7 @@ fuzztest_cc_test(
fuzztest::domain_testing
absl::algorithm_container
absl::random_random
fuzztest::core_domains_impl
fuzztest::domain_core
GTest::gmock_main
)
Expand Down Expand Up @@ -247,6 +250,7 @@ fuzztest_cc_test(
DEPS
fuzztest::domain_testing
absl::random_random
fuzztest::core_domains_impl
fuzztest::domain_core
GTest::gmock_main
)
Expand Down Expand Up @@ -281,3 +285,5 @@ fuzztest_cc_test(
fuzztest::table_of_recent_compares
GTest::gmock_main
)


59 changes: 59 additions & 0 deletions domain_tests/aggregate_combinators_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "absl/status/status.h"
#include "./fuzztest/domain_core.h"
#include "./domain_tests/domain_testing.h"
#include "./fuzztest/internal/domains/traversal_context.h"
#include "./fuzztest/internal/serialization.h"
#include "./fuzztest/internal/type_support.h"

Expand Down Expand Up @@ -490,5 +491,63 @@ TEST(TupleOf, DomainWithCustomPairCorpusType) {
EXPECT_TRUE(optional_corpus_tuple.has_value());
}

TEST(StructOf, InitWithTraversalCtxUpdatesInitBudget) {
struct Foo {
int a;
double b;
};
auto domain = StructOf<Foo>(Arbitrary<int>(), Arbitrary<double>());

absl::BitGen prng;
domain_implementor::TraversalState state;
state.init_budget = 10;

auto val =
Value<decltype(domain)>::BuildWithTraversalCtx(domain, prng, state);

ASSERT_OK(val.status());
// 1 (root) + 2 (fields: int, double) = 3 decrements
EXPECT_EQ(state.init_budget, 7);
}

TEST(StructOf, InitWithTraversalCtxPropagatesFailureFromInnerDomain) {
struct Foo {
int a;
std::vector<int> v;
};
// Inner container cannot be empty.
auto domain = StructOf<Foo>(Arbitrary<int>(),
VectorOf(Arbitrary<int>()).WithMinSize(1));

absl::BitGen prng;
domain_implementor::TraversalState state;
// The parent init decrements to 0 and the inner vector init decrements to -1
// and fails due to the min size constraint.
state.depth_budget = 1;

const auto val =
Value<decltype(domain)>::BuildWithTraversalCtx(domain, prng, state);

EXPECT_FALSE(val.ok());
EXPECT_FALSE(state.status.ok());
EXPECT_THAT(state.status.message(),
testing::HasSubstr("Traversal budget exceeded"));
}

TEST(StructOf, InitWithTraversalCtxHandlesPreExistingFailure) {
auto domain = StructOf<MyStruct>(Arbitrary<int>(), Arbitrary<std::string>());

absl::BitGen prng;
domain_implementor::TraversalState state;
state.status = absl::CancelledError("Pre-existing failure");

const auto val =
Value<decltype(domain)>::BuildWithTraversalCtx(domain, prng, state);

EXPECT_FALSE(val.ok());
EXPECT_FALSE(state.status.ok());
EXPECT_EQ(state.status.message(), "Pre-existing failure");
}

} // namespace
} // namespace fuzztest
105 changes: 103 additions & 2 deletions domain_tests/container_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "absl/random/random.h"
#include "./fuzztest/domain_core.h"
#include "./domain_tests/domain_testing.h"
#include "./fuzztest/internal/domains/traversal_context.h"
#include "./fuzztest/internal/table_of_recent_compares.h"

namespace fuzztest {
Expand Down Expand Up @@ -356,8 +357,7 @@ TEST(Container, ValidatesMemoryDictionaryMutationForInnerDomain) {
* 1.0 / 4 // to use cmp tables
* 1.0 / 2 // to pick the memcmp table
* 1.0 / 2 // to pick one of the entries
* 1.0 / 2 // to apply replacement
;
* 1.0 / 2; // to apply replacement
for (int i = 0; i < 1 * IterationsToHitAll(/*num_cases=*/2, hit_probability);
++i) {
std::vector<uint8_t> mutant = {10, 11, 12, 13};
Expand All @@ -369,5 +369,106 @@ TEST(Container, ValidatesMemoryDictionaryMutationForInnerDomain) {
EXPECT_THAT(mutants, Not(Contains(std::vector<uint8_t>{129, 129, 129, 129})));
}

TEST(ContainerTest,
SequenceInitWithTraversalCtxDepthExhaustedWithMinSizeFails) {
auto domain = VectorOf(Arbitrary<int>()).WithMinSize(3);

absl::BitGen prng;
domain_implementor::TraversalState state;
state.depth_budget = 0;

const auto val =
Value<decltype(domain)>::BuildWithTraversalCtx(domain, prng, state);

EXPECT_FALSE(val.ok());
EXPECT_FALSE(state.status.ok());
EXPECT_THAT(state.status.message(),
testing::HasSubstr("Traversal budget exceeded"));
}

TEST(ContainerTest,
SequenceInitWithTraversalCtxDepthExhaustedNoMinSizeSucceeds) {
auto domain = VectorOf(Arbitrary<int>());

absl::BitGen prng;
domain_implementor::TraversalState state;
state.depth_budget = 0;

const auto val =
Value<decltype(domain)>::BuildWithTraversalCtx(domain, prng, state);

ASSERT_OK(val.status());
EXPECT_TRUE(val->user_value.empty());
EXPECT_TRUE(state.status.ok());
}

TEST(ContainerTest, SequenceInitWithTraversalCtxUpdatesInitBudget) {
auto domain = VectorOf(Arbitrary<int>()).WithSize(3);

absl::BitGen prng;
domain_implementor::TraversalState state;
state.init_budget = 10;

const auto val =
Value<decltype(domain)>::BuildWithTraversalCtx(domain, prng, state);

ASSERT_OK(val.status());
EXPECT_EQ(val->user_value.size(), 3);
// 1 (root) + 3 (elements) = 4 decrements
EXPECT_EQ(state.init_budget, 6);
}

TEST(ContainerTest,
SequenceInitWithTraversalCtxInitBudgetExhaustedWithMinSizeFails) {
auto domain = VectorOf(Arbitrary<int>()).WithMinSize(3);

absl::BitGen prng;
domain_implementor::TraversalState state;
state.init_budget = 0; // Enter() will decrement to -1

const auto val =
Value<decltype(domain)>::BuildWithTraversalCtx(domain, prng, state);

EXPECT_FALSE(val.ok());
EXPECT_FALSE(state.status.ok());
}

TEST(ContainerTest,
SequenceInitWithTraversalCtxInitBudgetExhaustedNoMinSizeSucceeds) {
auto domain = VectorOf(Arbitrary<int>());

absl::BitGen prng;
domain_implementor::TraversalState state;
state.init_budget = 0;

const auto val =
Value<decltype(domain)>::BuildWithTraversalCtx(domain, prng, state);

ASSERT_OK(val.status());
EXPECT_TRUE(val->user_value.empty());
EXPECT_TRUE(state.status.ok());
}

TEST(ContainerTest,
SequenceInitWithTraversalCtxPropagatesFailureFromInnerExhaustion) {
// Both the parent and inner vectors must not be empty.
auto domain =
VectorOf(VectorOf(Arbitrary<int>()).WithMinSize(1)).WithMinSize(1);

absl::BitGen prng;
domain_implementor::TraversalState state;
// The parent init decrements to 0 and the inner init decrements to -1
// and fails due to the min size constraint.
state.depth_budget = 1;

const auto val =
Value<decltype(domain)>::BuildWithTraversalCtx(domain, prng, state);

EXPECT_FALSE(val.ok());
EXPECT_FALSE(state.status.ok());
EXPECT_THAT(state.status.message(),
testing::HasSubstr("Traversal budget exceeded"));
}

} // namespace
} // namespace fuzztest
30 changes: 24 additions & 6 deletions domain_tests/domain_testing.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@
#include "absl/random/bit_gen_ref.h"
#include "absl/random/random.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "./common/logging.h"
#include "./common/status_macros.h"
#include "./fuzztest/internal/domains/mutation_metadata.h"
#include "./fuzztest/internal/domains/traversal_context.h"
#include "./fuzztest/internal/logging.h"
#include "./fuzztest/internal/meta.h"
#include "./fuzztest/internal/serialization.h"
Expand Down Expand Up @@ -81,12 +84,12 @@ struct Hash {
template <typename T>
size_t operator()(const T& v) const {
if constexpr (internal::Requires<T>(
[](auto v) -> decltype(v && v.get()) {})) {
[](auto v) -> decltype(v&& v.get()) {})) {
// Smart pointers.
return v ? absl::HashOf(*v) : 0;
} else if constexpr (internal::Requires<T>(
[](auto v) -> decltype(std::isnan(
*std::optional(v))) {})) {
[](auto v) -> decltype(std::isnan(*std::optional(
v))) {})) {
auto o = std::optional(v);
return !o || std::isnan(*o) ? 0 : absl::Hash<T>{}(*o);
} else if constexpr (internal::Requires<T>(
Expand All @@ -108,12 +111,12 @@ struct Eq {
differencer.set_field_comparator(&cmp);
return differencer.Compare(a, b);
} else if constexpr (internal::Requires<T>(
[](auto v) -> decltype(v && v.get()) {})) {
[](auto v) -> decltype(v&& v.get()) {})) {
// Smart pointers.
return a ? b && *a == *b : !b;
} else if constexpr (internal::Requires<T>(
[](auto v) -> decltype(std::isnan(
*std::optional(v))) {})) {
[](auto v) -> decltype(std::isnan(*std::optional(
v))) {})) {
auto oa = std::optional(a), ob = std::optional(b);
return a == b || (oa && ob && std::isnan(*oa) && std::isnan(*ob));
} else {
Expand All @@ -127,6 +130,7 @@ using Set = absl::flat_hash_set<T, Hash, Eq>;

// The Value class keeps the corpus and value types together throughout tests to
// simplify their access and mutation.
// TODO(b/535145936): Update to a class and make the values private.
template <typename Domain>
struct Value {
using T = internal::value_type_t<Domain>;
Expand All @@ -152,6 +156,17 @@ struct Value {
}()),
user_value(std::move(user_value)) {}

static absl::StatusOr<Value> BuildWithTraversalCtx(
Domain& domain, absl::BitGenRef prng,
domain_implementor::TraversalState& state) {
ASSIGN_OR_RETURN_IF_NOT_OK(
auto corpus,
domain.InitWithTraversalCtx(
prng, domain_implementor::InitTraversalContext<Domain>(state)));
auto user = domain.GetValue(corpus);
return Value{std::move(corpus), std::move(user)};
}

void Mutate(Domain& domain, absl::BitGenRef prng,
const domain_implementor::MutationMetadata& metadata,
bool only_shrink) {
Expand Down Expand Up @@ -222,6 +237,9 @@ struct Value {
}

private:
Value(internal::corpus_type_t<Domain> corpus, T user)
: corpus_value(std::move(corpus)), user_value(std::move(user)) {}

// We don't test the printers here, just that we return one.
// The printers themselves are tested in type_support_test.cc
using Printer = decltype(std::declval<const Domain&>().GetPrinter());
Expand Down
Loading
Loading