Skip to content

Commit 0ff80ad

Browse files
FuzzTest Teamcopybara-github
FuzzTest Team
authored andcommitted
Add flatbuffers domain
PiperOrigin-RevId: 732932597
1 parent 998cda3 commit 0ff80ad

File tree

7 files changed

+1073
-0
lines changed

7 files changed

+1073
-0
lines changed

MODULE.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ bazel_dep(
4747
version = "28.2",
4848
repo_name = "com_google_protobuf",
4949
)
50+
bazel_dep(
51+
name = "flatbuffers",
52+
version = "25.2.10"
53+
)
5054
bazel_dep(
5155
name = "rules_proto",
5256
version = "5.3.0-21.7",

domain_tests/BUILD

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ cc_test(
3333
],
3434
)
3535

36+
cc_test(
37+
name = "arbitrary_domains_flatbuffers_test",
38+
srcs = ["arbitrary_domains_flatbuffers_test.cc"],
39+
deps = [
40+
":domain_testing",
41+
"@com_google_absl//absl/random",
42+
"@com_google_fuzztest//fuzztest:domain",
43+
"@com_google_fuzztest//fuzztest:test_flatbuffers_cc_fbs",
44+
"@com_google_googletest//:gtest_main",
45+
"@flatbuffers//:runtime_cc",
46+
],
47+
)
48+
3649
cc_test(
3750
name = "arbitrary_domains_protobuf_test",
3851
srcs = ["arbitrary_domains_protobuf_test.cc"],
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
#include <cstdint>
2+
#include <optional>
3+
#include <string_view>
4+
#include <utility>
5+
#include <vector>
6+
7+
#include "gmock/gmock.h"
8+
#include "gtest/gtest.h"
9+
#include "absl/random/random.h"
10+
#include "flatbuffers/base.h"
11+
#include "flatbuffers/buffer.h"
12+
#include "flatbuffers/flatbuffer_builder.h"
13+
#include "flatbuffers/reflection.h"
14+
#include "flatbuffers/reflection_generated.h"
15+
#include "flatbuffers/string.h"
16+
#include "flatbuffers/table.h"
17+
#include "flatbuffers/verifier.h"
18+
#include "./fuzztest/domain.h"
19+
#include "./domain_tests/domain_testing.h"
20+
#include "./fuzztest/internal/domains/flatbuffers_domain_impl.h"
21+
#include "./fuzztest/test_flatbuffers_generated.h"
22+
23+
namespace fuzztest {
24+
namespace {
25+
using internal::OptionalRequiredTestFbsTable;
26+
using internal::SimpleTestFbsTable;
27+
using ::testing::Contains;
28+
using ::testing::IsTrue;
29+
using ::testing::ResultOf;
30+
31+
TEST(FlatbuffersTableImplTest, TypeGetters) {
32+
::testing::StaticAssertTypeEq<reflection::Object,
33+
internal::get_object_t<reflection::Schema>>();
34+
::testing::StaticAssertTypeEq<reflection::Field,
35+
internal::get_field_t<reflection::Object>>();
36+
::testing::StaticAssertTypeEq<flatbuffers::String,
37+
internal::get_string_t<reflection::Object>>();
38+
::testing::StaticAssertTypeEq<flatbuffers::Offset<reflection::Field>,
39+
internal::get_offset_t<reflection::Object>>();
40+
::testing::StaticAssertTypeEq<reflection::BaseType,
41+
internal::get_base_type_t<reflection::Field>>();
42+
::testing::StaticAssertTypeEq<flatbuffers::FlatBufferBuilder,
43+
internal::get_builder_t<SimpleTestFbsTable>>();
44+
::testing::StaticAssertTypeEq<flatbuffers::uoffset_t,
45+
internal::get_uoffset_t<reflection::Object>>();
46+
::testing::StaticAssertTypeEq<uint16_t,
47+
internal::get_field_id_t<reflection::Field>>();
48+
}
49+
50+
TEST(FlatbuffersTableImplTest, SimpleTestFbsTableValueRoundTrip) {
51+
auto domain =
52+
internal::FlatbuffersTableImpl<SimpleTestFbsTable, flatbuffers::Table,
53+
reflection::Schema, flatbuffers::Verifier>{
54+
reflection::GetSchema, reflection::VerifySchemaBuffer,
55+
flatbuffers::GetTypeSize, flatbuffers::GetRoot<SimpleTestFbsTable>};
56+
57+
flatbuffers::FlatBufferBuilder fbb;
58+
auto table_offset = internal::CreateSimpleTestFbsTableDirect(
59+
fbb, true, 1.0, "foo bar baz", internal::TestFbsEnum_Second);
60+
fbb.Finish(table_offset);
61+
auto table = flatbuffers::GetRoot<SimpleTestFbsTable>(fbb.GetBufferPointer());
62+
63+
auto corpus = domain.FromValue(table);
64+
ASSERT_TRUE(corpus.has_value());
65+
ASSERT_OK(domain.ValidateCorpusValue(*corpus));
66+
67+
auto ir = domain.SerializeCorpus(corpus.value());
68+
69+
auto new_corpus = domain.ParseCorpus(ir);
70+
ASSERT_TRUE(new_corpus.has_value());
71+
ASSERT_OK(domain.ValidateCorpusValue(*new_corpus));
72+
73+
auto new_table = domain.GetValue(*new_corpus);
74+
EXPECT_EQ(new_table->b(), true);
75+
EXPECT_EQ(new_table->f(), 1.0);
76+
EXPECT_EQ(new_table->str()->str(), "foo bar baz");
77+
EXPECT_TRUE(new_table->e() == internal::TestFbsEnum_Second);
78+
}
79+
80+
TEST(FlatbuffersTableImplTest, InitGeneratesSeeds) {
81+
auto domain =
82+
internal::FlatbuffersTableImpl<SimpleTestFbsTable, flatbuffers::Table,
83+
reflection::Schema, flatbuffers::Verifier>{
84+
reflection::GetSchema, reflection::VerifySchemaBuffer,
85+
flatbuffers::GetTypeSize, flatbuffers::GetRoot<SimpleTestFbsTable>};
86+
87+
flatbuffers::FlatBufferBuilder fbb;
88+
auto table_offset = internal::CreateSimpleTestFbsTableDirect(
89+
fbb, true, 1.0, "foo bar baz", internal::TestFbsEnum_Second);
90+
fbb.Finish(table_offset);
91+
auto table = flatbuffers::GetRoot<SimpleTestFbsTable>(fbb.GetBufferPointer());
92+
93+
domain = domain.WithSeeds({table});
94+
95+
std::vector<Value<decltype(domain)>> values;
96+
absl::BitGen bitgen;
97+
values.reserve(1000);
98+
for (int i = 0; i < 1000; ++i) {
99+
Value value(domain, bitgen);
100+
values.push_back(std::move(value));
101+
}
102+
103+
EXPECT_THAT(
104+
values,
105+
Contains(ResultOf(
106+
[table](const auto& val) {
107+
bool has_same_str =
108+
val.user_value->str() == nullptr && table->str() == nullptr;
109+
if (val.user_value->str() != nullptr && table->str() != nullptr) {
110+
has_same_str =
111+
val.user_value->str()->str() == table->str()->str();
112+
}
113+
return (val.user_value->b() == table->b() &&
114+
val.user_value->f() == table->f() &&
115+
val.user_value->e() == table->e() && has_same_str);
116+
},
117+
IsTrue())));
118+
}
119+
120+
TEST(FlatbuffersTableImplTest, EventuallyMutatesAllTableFields) {
121+
auto domain =
122+
internal::FlatbuffersTableImpl<SimpleTestFbsTable, flatbuffers::Table,
123+
reflection::Schema, flatbuffers::Verifier>{
124+
reflection::GetSchema, reflection::VerifySchemaBuffer,
125+
flatbuffers::GetTypeSize, flatbuffers::GetRoot<SimpleTestFbsTable>};
126+
127+
absl::BitGen bitgen;
128+
Value val(domain, bitgen);
129+
130+
const auto verify_field_changes = [&](std::string_view name, auto has,
131+
auto get) {
132+
Set<decltype(get(val.user_value))> values;
133+
134+
int iterations = 10'000;
135+
while (--iterations > 0 && values.size() < 2) {
136+
values.insert(get(val.user_value));
137+
val.Mutate(domain, bitgen, {}, false);
138+
}
139+
EXPECT_GT(iterations, 0)
140+
<< "Field: " << name << " -- " << testing::PrintToString(values);
141+
};
142+
143+
verify_field_changes(
144+
"b", [](auto v) { return true; }, [](auto v) { return v->b(); });
145+
verify_field_changes(
146+
"f", [](auto v) { return true; }, [](auto v) { return v->f(); });
147+
verify_field_changes(
148+
"str", [](auto v) { return v->str() != nullptr; },
149+
[](auto v) { return v->str()->str(); });
150+
verify_field_changes(
151+
"e", [](auto v) { return true; }, [](auto v) { return v->e(); });
152+
}
153+
154+
TEST(FlatbuffersTableImplTest, OptionalFieldsEventuallyBecomeEmpty) {
155+
auto domain =
156+
internal::FlatbuffersTableImpl<OptionalRequiredTestFbsTable,
157+
flatbuffers::Table, reflection::Schema,
158+
flatbuffers::Verifier>{
159+
reflection::GetSchema, reflection::VerifySchemaBuffer,
160+
flatbuffers::GetTypeSize,
161+
flatbuffers::GetRoot<OptionalRequiredTestFbsTable>};
162+
163+
absl::BitGen bitgen;
164+
Value val(domain, bitgen);
165+
166+
const auto verify_field_becomes_null = [&](std::string_view name, auto has) {
167+
for (int i = 0; i < 10'000; ++i) {
168+
val.Mutate(domain, bitgen, {}, false);
169+
if (!has(val.user_value)) {
170+
break;
171+
}
172+
}
173+
EXPECT_FALSE(has(val.user_value)) << "Field never became unset: " << name;
174+
};
175+
176+
verify_field_becomes_null("opt_scalar",
177+
[](auto v) { return v->opt_scalar().has_value(); });
178+
verify_field_becomes_null("opt_str",
179+
[](auto v) { return v->opt_str() != nullptr; });
180+
}
181+
182+
TEST(FlatbuffersTableImplTest, DefaultAndRequiredFieldsAlwaysSet) {
183+
auto domain =
184+
internal::FlatbuffersTableImpl<OptionalRequiredTestFbsTable,
185+
flatbuffers::Table, reflection::Schema,
186+
flatbuffers::Verifier>{
187+
reflection::GetSchema, reflection::VerifySchemaBuffer,
188+
flatbuffers::GetTypeSize,
189+
flatbuffers::GetRoot<OptionalRequiredTestFbsTable>};
190+
191+
absl::BitGen bitgen;
192+
Value val(domain, bitgen);
193+
194+
const auto verify_field_always_set = [&](std::string_view name, auto has) {
195+
for (int i = 0; i < 10'000; ++i) {
196+
val.Mutate(domain, bitgen, {}, false);
197+
if (!has(val.user_value)) {
198+
break;
199+
}
200+
}
201+
EXPECT_TRUE(has(val.user_value)) << "Field is not set: " << name;
202+
};
203+
204+
verify_field_always_set("def_scalar", [](auto v) { return true; });
205+
verify_field_always_set("req_str",
206+
[](auto v) { return v->req_str() != nullptr; });
207+
}
208+
} // namespace
209+
} // namespace fuzztest

fuzztest/BUILD

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# FuzzTest: a coverage-guided fuzzing / property-based testing framework.
1616

1717
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
18+
load("@flatbuffers//:build_defs.bzl", "flatbuffer_library_public")
1819
load("@rules_proto//proto:defs.bzl", "proto_library")
1920

2021
package(default_visibility = ["//visibility:public"])
@@ -330,6 +331,7 @@ cc_library(
330331
srcs = ["internal/domains/in_grammar_impl.cc"],
331332
hdrs = [
332333
"domain.h",
334+
"internal/domains/flatbuffers_domain_impl.h",
333335
"internal/domains/in_grammar_impl.h",
334336
"internal/domains/in_regexp_impl.h",
335337
"internal/domains/protobuf_domain_impl.h",
@@ -345,6 +347,7 @@ cc_library(
345347
":serialization",
346348
":status",
347349
":type_support",
350+
"@com_google_absl//absl/algorithm:container",
348351
"@com_google_absl//absl/base:core_headers",
349352
"@com_google_absl//absl/base:no_destructor",
350353
"@com_google_absl//absl/container:flat_hash_map",
@@ -770,6 +773,28 @@ cc_proto_library(
770773
deps = [":test_protobuf"],
771774
)
772775

776+
flatbuffer_library_public(
777+
name = "test_flatbuffers_fbs",
778+
srcs = ["internal/test_flatbuffers.fbs"],
779+
outs = [
780+
"test_flatbuffers_bfbs_generated.h",
781+
"test_flatbuffers_generated.h",
782+
],
783+
flatc_args = [
784+
"--bfbs-gen-embed",
785+
"--gen-name-strings",
786+
],
787+
language_flag = "-c",
788+
)
789+
790+
cc_library(
791+
name = "test_flatbuffers_cc_fbs",
792+
srcs = [":test_flatbuffers_fbs"],
793+
hdrs = [":test_flatbuffers_fbs"],
794+
features = ["-parse_headers"],
795+
deps = ["@flatbuffers//:runtime_cc"],
796+
)
797+
773798
cc_library(
774799
name = "type_support",
775800
srcs = ["internal/type_support.cc"],

fuzztest/domain.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define FUZZTEST_FUZZTEST_DOMAIN_H_
2020

2121
#include "./fuzztest/domain_core.h" // IWYU pragma: export
22+
#include "./fuzztest/internal/domains/flatbuffers_domain_impl.h" // IWYU pragma: export
2223
#include "./fuzztest/internal/domains/in_regexp_impl.h"
2324
#include "./fuzztest/internal/domains/protobuf_domain_impl.h"
2425

0 commit comments

Comments
 (0)