Skip to content

Commit 711fa43

Browse files
lowdaniecopybara-github
authored andcommitted
No public description
PiperOrigin-RevId: 928534194
1 parent 3290214 commit 711fa43

16 files changed

Lines changed: 854 additions & 22 deletions

domain_tests/BUILD

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ cc_test(
3636
"@com_google_fuzztest//fuzztest:domain_core",
3737
"@com_google_fuzztest//fuzztest/internal:serialization",
3838
"@com_google_fuzztest//fuzztest/internal:type_support",
39+
"@com_google_fuzztest//fuzztest/internal/domains:core_domains_impl",
3940
"@googletest//:gtest_main",
4041
],
4142
)
@@ -137,6 +138,7 @@ cc_test(
137138
"@abseil-cpp//absl/random",
138139
"@com_google_fuzztest//fuzztest:domain_core",
139140
"@com_google_fuzztest//fuzztest/internal:table_of_recent_compares",
141+
"@com_google_fuzztest//fuzztest/internal/domains:core_domains_impl",
140142
"@googletest//:gtest_main",
141143
],
142144
)
@@ -199,7 +201,9 @@ cc_test(
199201
":domain_testing",
200202
"@abseil-cpp//absl/algorithm:container",
201203
"@abseil-cpp//absl/random",
204+
"@abseil-cpp//absl/status",
202205
"@com_google_fuzztest//fuzztest:domain_core",
206+
"@com_google_fuzztest//fuzztest/internal/domains:core_domains_impl",
203207
"@googletest//:gtest_main",
204208
],
205209
)
@@ -256,6 +260,17 @@ cc_test(
256260
":domain_testing",
257261
"@abseil-cpp//absl/random",
258262
"@com_google_fuzztest//fuzztest:domain_core",
263+
"@com_google_fuzztest//fuzztest/internal/domains:core_domains_impl",
264+
"@googletest//:gtest_main",
265+
],
266+
)
267+
268+
cc_test(
269+
name = "traversal_context_test",
270+
srcs = ["traversal_context_test.cc"],
271+
deps = [
272+
"@abseil-cpp//absl/status",
273+
"@com_google_fuzztest//fuzztest/internal/domains:core_domains_impl",
259274
"@googletest//:gtest_main",
260275
],
261276
)

domain_tests/aggregate_combinators_test.cc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "absl/types/optional.h"
3232
#include "./fuzztest/domain_core.h"
3333
#include "./domain_tests/domain_testing.h"
34+
#include "./fuzztest/internal/domains/traversal_context.h"
3435
#include "./fuzztest/internal/serialization.h"
3536
#include "./fuzztest/internal/type_support.h"
3637

@@ -491,5 +492,57 @@ TEST(TupleOf, DomainWithCustomPairCorpusType) {
491492
EXPECT_TRUE(optional_corpus_tuple.has_value());
492493
}
493494

495+
TEST(StructOf, InitWithTrackerUpdatesCount) {
496+
struct LocalStruct {
497+
int a;
498+
double b;
499+
};
500+
auto domain = StructOf<LocalStruct>(Arbitrary<int>(), Arbitrary<double>());
501+
502+
absl::BitGen prng;
503+
internal::TraversalState state;
504+
state.count = 10;
505+
506+
Value val(domain, prng, state);
507+
508+
// 1 (root) + 2 (fields: int, double) = 3 decrements
509+
EXPECT_EQ(*state.count, 7);
510+
}
511+
512+
TEST(StructOf, InitWithTrackerPropagatesFailureFromInnerDomain) {
513+
struct LocalStruct {
514+
int a;
515+
std::vector<int> v;
516+
};
517+
// Inner container cannot be empty.
518+
auto domain = StructOf<LocalStruct>(
519+
Arbitrary<int>(), VectorOf(Arbitrary<int>()).WithMinSize(1));
520+
521+
absl::BitGen prng;
522+
internal::TraversalState state;
523+
// Total budget is 2, which is not enough to satisfy the container's min size
524+
// of 1 (considering decrements for root and fields).
525+
state.count = 2;
526+
527+
Value val(domain, prng, state);
528+
529+
EXPECT_FALSE(state.status.ok());
530+
EXPECT_THAT(state.status.ToString(),
531+
testing::HasSubstr("Traversal budget exceeded"));
532+
}
533+
534+
TEST(StructOf, InitWithTrackerHandlesPreExistingFailure) {
535+
auto domain = StructOf<MyStruct>(Arbitrary<int>(), Arbitrary<std::string>());
536+
537+
absl::BitGen prng;
538+
internal::TraversalState state;
539+
state.status = absl::CancelledError("Pre-existing failure");
540+
541+
Value val(domain, prng, state);
542+
543+
EXPECT_FALSE(state.status.ok());
544+
EXPECT_EQ(state.status.message(), "Pre-existing failure");
545+
}
546+
494547
} // namespace
495548
} // namespace fuzztest

domain_tests/container_test.cc

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "absl/random/random.h"
3535
#include "./fuzztest/domain_core.h"
3636
#include "./domain_tests/domain_testing.h"
37+
#include "./fuzztest/internal/domains/traversal_context.h"
3738
#include "./fuzztest/internal/table_of_recent_compares.h"
3839

3940
namespace fuzztest {
@@ -369,5 +370,94 @@ TEST(Container, ValidatesMemoryDictionaryMutationForInnerDomain) {
369370
EXPECT_THAT(mutants, Not(Contains(std::vector<uint8_t>{129, 129, 129, 129})));
370371
}
371372

373+
TEST(ContainerTest,
374+
SequenceInitWithTrackerDepthExhaustedWithMinSizeReturnsEmptyAndFails) {
375+
auto domain = VectorOf(Arbitrary<int>()).WithMinSize(3);
376+
377+
absl::BitGen prng;
378+
internal::TraversalState state;
379+
state.depth = 0;
380+
381+
Value val(domain, prng, state);
382+
383+
EXPECT_TRUE(val.user_value.empty());
384+
EXPECT_FALSE(state.status.ok());
385+
EXPECT_THAT(state.status.ToString(),
386+
testing::HasSubstr("Traversal budget exceeded"));
387+
}
388+
389+
TEST(ContainerTest,
390+
SequenceInitWithTrackerDepthExhaustedNoMinSizeReturnsEmptyAndSucceeds) {
391+
auto domain = VectorOf(Arbitrary<int>());
392+
393+
absl::BitGen prng;
394+
internal::TraversalState state;
395+
state.depth = 0;
396+
397+
Value val(domain, prng, state);
398+
399+
EXPECT_TRUE(val.user_value.empty());
400+
EXPECT_TRUE(state.status.ok());
401+
}
402+
403+
TEST(ContainerTest, SequenceInitWithTrackerUpdatesCount) {
404+
auto domain = VectorOf(Arbitrary<int>()).WithSize(3);
405+
406+
absl::BitGen prng;
407+
internal::TraversalState state;
408+
state.count = 10;
409+
410+
Value val(domain, prng, state);
411+
412+
EXPECT_EQ(val.user_value.size(), 3);
413+
// 1 (root) + 3 (elements) = 4 decrements
414+
EXPECT_EQ(*state.count, 6);
415+
}
416+
417+
TEST(ContainerTest, SequenceInitWithTrackerCountExhaustedWithMinSizeFails) {
418+
auto domain = VectorOf(Arbitrary<int>()).WithMinSize(3);
419+
420+
absl::BitGen prng;
421+
internal::TraversalState state;
422+
state.count = 0; // Enter() will decrement to -1
423+
424+
Value val(domain, prng, state);
425+
426+
EXPECT_TRUE(val.user_value.empty());
427+
EXPECT_FALSE(state.status.ok());
428+
}
429+
430+
TEST(ContainerTest,
431+
SequenceInitWithTrackerCountExhaustedNoMinSizeReturnsEmptyAndSucceeds) {
432+
auto domain = VectorOf(Arbitrary<int>());
433+
434+
absl::BitGen prng;
435+
internal::TraversalState state;
436+
state.count = 0;
437+
438+
Value val(domain, prng, state);
439+
440+
EXPECT_TRUE(val.user_value.empty());
441+
EXPECT_TRUE(state.status.ok());
442+
}
443+
444+
TEST(ContainerTest,
445+
SequenceInitWithTrackerPropagatesFailureFromInnerExhaustion) {
446+
// Inner vector must have size >= 1.
447+
auto domain =
448+
VectorOf(VectorOf(Arbitrary<int>()).WithMinSize(1)).WithMinSize(2);
449+
450+
absl::BitGen prng;
451+
internal::TraversalState state;
452+
// Exhausts during 2nd inner vector init, failing due to its min_size = 1.
453+
state.count = 3;
454+
455+
Value val(domain, prng, state);
456+
457+
EXPECT_FALSE(state.status.ok());
458+
EXPECT_THAT(state.status.ToString(),
459+
testing::HasSubstr("Traversal budget exceeded"));
460+
}
461+
372462
} // namespace
373463
} // namespace fuzztest

domain_tests/domain_testing.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "absl/strings/string_view.h"
3838
#include "./common/logging.h"
3939
#include "./fuzztest/internal/domains/mutation_metadata.h"
40+
#include "./fuzztest/internal/domains/traversal_context.h"
4041
#include "./fuzztest/internal/logging.h"
4142
#include "./fuzztest/internal/meta.h"
4243
#include "./fuzztest/internal/serialization.h"
@@ -137,6 +138,11 @@ struct Value {
137138
: corpus_value(domain.Init(prng)),
138139
user_value(domain.GetValue(corpus_value)) {}
139140

141+
Value(Domain& domain, absl::BitGenRef prng, internal::TraversalState& state)
142+
: corpus_value(domain.InitWithTracker(
143+
prng, internal::TraversalContextWithTotalCount<Domain>(state))),
144+
user_value(domain.GetValue(corpus_value)) {}
145+
140146
// If the value_type is not copy constructible we have to copy the corpus and
141147
// regenerate the value.
142148
Value(const Value& other, Domain& domain)

domain_tests/map_filter_combinator_test.cc

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
#include "gtest/gtest.h"
2727
#include "absl/algorithm/container.h"
2828
#include "absl/random/random.h"
29+
#include "absl/status/status.h"
2930
#include "./fuzztest/domain_core.h"
3031
#include "./domain_tests/domain_testing.h"
32+
#include "./fuzztest/internal/domains/traversal_context.h"
3133

3234
namespace fuzztest {
3335
namespace {
@@ -408,5 +410,65 @@ TEST(Filter, ValidationRejectsInvalidValue) {
408410
HasSubstr("Invalid corpus value for the inner domain in Filter()")));
409411
}
410412

413+
TEST(Filter, InitWithTrackerRestoresBudgetOnPredicateFailure) {
414+
int attempts = 0;
415+
// Fails 50 times, then succeeds.
416+
auto domain =
417+
Filter([&attempts](int i) { return ++attempts > 50; }, Arbitrary<int>());
418+
419+
absl::BitGen prng;
420+
internal::TraversalState state;
421+
state.depth = 100;
422+
state.count = 10;
423+
424+
Value val(domain, prng, state);
425+
426+
EXPECT_TRUE(state.status.ok());
427+
// 10 - 1 (root) - 3 (successful inner with type erasure) = 6.
428+
// The 50 failed attempts are restored.
429+
EXPECT_EQ(*state.count, 6);
430+
EXPECT_EQ(state.depth, 100);
431+
}
432+
433+
TEST(Filter, InitWithTrackerReturnsEarlyOnPreExistingFailure) {
434+
auto domain = Filter(
435+
[](int i) {
436+
ADD_FAILURE() << "Predicate should not be called";
437+
return false;
438+
},
439+
Arbitrary<int>());
440+
441+
absl::BitGen prng;
442+
internal::TraversalState state;
443+
state.status = absl::CancelledError("Pre-existing failure");
444+
445+
Value val(domain, prng, state);
446+
447+
EXPECT_FALSE(state.status.ok());
448+
EXPECT_EQ(state.status.message(), "Pre-existing failure");
449+
}
450+
451+
TEST(Filter, InitWithTrackerReturnsInvalidValueOnFailure) {
452+
auto domain = Filter(
453+
[](const std::vector<int>& v) {
454+
ADD_FAILURE() << "Predicate should not be called";
455+
return false;
456+
},
457+
VectorOf(Arbitrary<int>()).WithMinSize(3));
458+
459+
absl::BitGen prng;
460+
internal::TraversalState state;
461+
// This causes the inner VectorOf initialization to fail due to budget
462+
// exhaustion.
463+
state.count = 2;
464+
465+
Value val(domain, prng, state);
466+
467+
EXPECT_FALSE(state.status.ok());
468+
EXPECT_THAT(state.status.ToString(),
469+
testing::HasSubstr("Traversal budget exceeded"));
470+
EXPECT_TRUE(val.user_value.empty());
471+
}
472+
411473
} // namespace
412474
} // namespace fuzztest

domain_tests/recursive_domains_test.cc

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
#include <utility>
1919
#include <vector>
2020

21+
#include "gmock/gmock.h"
2122
#include "gtest/gtest.h"
2223
#include "absl/random/random.h"
2324
#include "./fuzztest/domain_core.h"
2425
#include "./domain_tests/domain_testing.h"
26+
#include "./fuzztest/internal/domains/traversal_context.h"
2527

2628
namespace fuzztest {
2729
namespace {
@@ -105,5 +107,68 @@ TEST(DomainBuilder, DiesOnInvalidFinalize) {
105107
"Finalize\\(\\) has been called with an unknown name: typo");
106108
}
107109

110+
TEST(DomainBuilder, RecursiveDomainReachesDepthLimit) {
111+
DomainBuilder builder;
112+
builder.Set<Tree>(
113+
"tree", StructOf<Tree>(InRange(0, 10), ContainerOf<std::vector<Tree>>(
114+
builder.Get<Tree>("tree"))
115+
.WithSize(2)));
116+
Domain<Tree> domain = std::move(builder).Finalize<Tree>("tree");
117+
118+
absl::BitGen bitgen;
119+
internal::TraversalState state;
120+
state.depth = 5;
121+
122+
Value tree(domain, bitgen, state);
123+
124+
EXPECT_FALSE(state.status.ok());
125+
EXPECT_THAT(state.status.ToString(),
126+
testing::HasSubstr("Traversal budget exceeded"));
127+
EXPECT_FALSE(state.error_trace.empty());
128+
}
129+
130+
TEST(DomainBuilder, RecursiveDomainReachesNodeCountLimit) {
131+
DomainBuilder builder;
132+
builder.Set<Tree>(
133+
"tree", StructOf<Tree>(InRange(0, 10), ContainerOf<std::vector<Tree>>(
134+
builder.Get<Tree>("tree"))
135+
.WithSize(2)));
136+
Domain<Tree> domain = std::move(builder).Finalize<Tree>("tree");
137+
138+
absl::BitGen bitgen;
139+
internal::TraversalState state;
140+
state.depth = 100;
141+
state.count = 5;
142+
143+
Value tree(domain, bitgen, state);
144+
145+
EXPECT_FALSE(state.status.ok());
146+
EXPECT_THAT(state.status.ToString(),
147+
testing::HasSubstr("Traversal budget exceeded"));
148+
EXPECT_FALSE(state.error_trace.empty());
149+
}
150+
151+
TEST(DomainBuilder, RecursiveDomainWithFilterReachesDepthLimit) {
152+
DomainBuilder builder;
153+
builder.Set<Tree>(
154+
"tree",
155+
Filter([](const Tree& t) { return t.value % 2 == 0; },
156+
StructOf<Tree>(InRange(0, 10), ContainerOf<std::vector<Tree>>(
157+
builder.Get<Tree>("tree"))
158+
.WithSize(2))));
159+
Domain<Tree> domain = std::move(builder).Finalize<Tree>("tree");
160+
161+
absl::BitGen bitgen;
162+
internal::TraversalState state;
163+
state.depth = 5;
164+
165+
Value tree(domain, bitgen, state);
166+
167+
EXPECT_FALSE(state.status.ok());
168+
EXPECT_THAT(state.status.ToString(),
169+
testing::HasSubstr("Traversal budget exceeded"));
170+
EXPECT_FALSE(state.error_trace.empty());
171+
}
172+
108173
} // namespace
109174
} // namespace fuzztest

0 commit comments

Comments
 (0)