Skip to content

Commit

Permalink
Print the type name for aggregate values of user-defined types.
Browse files Browse the repository at this point in the history
For example, say the user defines a fuzz test that takes a struct:

```
struct Foo {
  int bar = 0;
};

void TakesFoo(Foo foo) {}
FUZZ_TEST(MySuite, TakesFoo)
  .WithDomains(StructOf<Foo>(Arbitrary<int>()));
```

Previously, the printed value for this looked like `{42}`, and now it looks
like `Foo{42}`.

PiperOrigin-RevId: 681540261
  • Loading branch information
fniksic authored and copybara-github committed Oct 2, 2024
1 parent 7940b0e commit f57e2c0
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 15 deletions.
18 changes: 9 additions & 9 deletions e2e_tests/functional_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -380,41 +380,41 @@ TEST_F(UnitTestModeTest, WorksWithRecursiveStructs) {
auto [status, std_out, std_err] = Run("MySuite.WorksWithRecursiveStructs");
EXPECT_THAT(status, Eq(Signal(SIGABRT)));
// Nullptr has multiple possible human-readable representations.
EXPECT_THAT(std_err, AnyOf(HasSubstr("argument 0: {0, 1}"),
HasSubstr("argument 0: {(nil), 1}")));
EXPECT_THAT(std_err, AnyOf(HasSubstr("argument 0: LinkedList{0, 1}"),
HasSubstr("argument 0: LinkedList{(nil), 1}")));
}

TEST_F(UnitTestModeTest, WorksWithStructsWithConstructors) {
auto [status, std_out, std_err] =
Run("MySuite.WorksWithStructsWithConstructors");
EXPECT_THAT(status, Eq(Signal(SIGABRT)));
EXPECT_THAT(std_err, HasSubstr("argument 0: {1, \"abc\"}"));
EXPECT_THAT(std_err, HasSubstr("argument 0: HasConstructor{1, \"abc\"}"));
}

TEST_F(UnitTestModeTest, WorksWithStructsWithEmptyTuples) {
auto [status, std_out, std_err] =
Run("MySuite.WorksWithStructsWithEmptyTuples");
EXPECT_THAT(status, Eq(Signal(SIGABRT)));
EXPECT_THAT(std_err, HasSubstr("argument 0: {}"));
EXPECT_THAT(std_err, HasSubstr("argument 0: ContainsEmptyTuple{}"));
}

TEST_F(UnitTestModeTest, WorksWithEmptyStructs) {
auto [status, std_out, std_err] = Run("MySuite.WorksWithEmptyStructs");
EXPECT_THAT(status, Eq(Signal(SIGABRT)));
EXPECT_THAT(std_err, HasSubstr("argument 0: {}"));
EXPECT_THAT(std_err, HasSubstr("argument 0: Empty{}"));
}

TEST_F(UnitTestModeTest, WorksWithStructsWithEmptyFields) {
auto [status, std_out, std_err] =
Run("MySuite.WorksWithStructsWithEmptyFields");
EXPECT_THAT(status, Eq(Signal(SIGABRT)));
EXPECT_THAT(std_err, HasSubstr("argument 0: {{}}"));
EXPECT_THAT(std_err, HasSubstr("argument 0: ContainsEmpty{{}}"));
}

TEST_F(UnitTestModeTest, WorksWithEmptyInheritance) {
auto [status, std_out, std_err] = Run("MySuite.WorksWithEmptyInheritance");
EXPECT_THAT(status, Eq(Signal(SIGABRT)));
EXPECT_THAT(std_err, HasSubstr("argument 0: {0, \"abc\"}"));
EXPECT_THAT(std_err, HasSubstr("argument 0: Child{0, \"abc\"}"));
}

TEST_F(UnitTestModeTest, ArbitraryWorksWithEmptyInheritance) {
Expand Down Expand Up @@ -1691,13 +1691,13 @@ TEST_P(FuzzingModeCrashFindingTest, UnprintableTypeRunsAndPrintsSomething) {

TEST_P(FuzzingModeCrashFindingTest, MyStructTestArbitraryCanPrint) {
auto [status, std_out, std_err] = Run("MySuite.MyStructArbitrary");
EXPECT_THAT(std_err, HasSubstr("argument 0: {0, \"X"));
EXPECT_THAT(std_err, HasSubstr("argument 0: MyStruct{0, \"X"));
ExpectTargetAbort(status, std_err);
}

TEST_P(FuzzingModeCrashFindingTest, MyStructTestWithDomainsCanPrint) {
auto [status, std_out, std_err] = Run("MySuite.MyStructWithDomains");
EXPECT_THAT(std_err, HasSubstr("argument 0: {0, \"X"));
EXPECT_THAT(std_err, HasSubstr("argument 0: MyStruct{0, \"X"));
ExpectTargetAbort(status, std_err);
}

Expand Down
4 changes: 3 additions & 1 deletion fuzztest/internal/domains/aggregate_of_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ class AggregateOfImpl
}
}

auto GetPrinter() const { return AggregatePrinter<Inner...>{inner_}; }
auto GetPrinter() const {
return AggregatePrinter<Inner...>{inner_, GetTypeNameIfUserDefined<T>()};
}

value_type GetValue(const corpus_type& value) const {
if constexpr (has_custom_corpus_type) {
Expand Down
16 changes: 15 additions & 1 deletion fuzztest/internal/type_support.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ absl::string_view GetTypeName() {
#endif
}

template <typename T>
absl::string_view GetTypeNameIfUserDefined() {
using CleanT = std::remove_cv_t<std::remove_reference_t<T>>;
absl::string_view type_name = GetTypeName<CleanT>();
// Exclude aggregate types like `std::pair`, `std::tuple`, and `std::array`,
// for which we don't want to print a long and unwieldy type name.
if (type_name == "<TYPE>" || absl::StartsWith(type_name, "std::")) {
return "";
}
return type_name;
}

template <typename T>
inline constexpr bool has_absl_stringify_v = absl::HasAbslStringify<T>::value;

Expand Down Expand Up @@ -176,10 +188,12 @@ struct StringPrinter {
template <typename... Inner>
struct AggregatePrinter {
const std::tuple<Inner...>& inner;
absl::string_view type_name;

template <typename T>
void PrintCorpusValue(const T& v, domain_implementor::RawSink out,
domain_implementor::PrintMode mode) const {
absl::Format(out, "%s", type_name);
PrintFormattedAggregateValue(
v, out, mode, "{", "}",
[](absl::FormatRawSink out, size_t idx, absl::string_view element) {
Expand Down Expand Up @@ -466,7 +480,7 @@ struct AutodetectAggregatePrinter {
std::remove_reference_t<std::tuple_element_t<I, decltype(bound)>>>()
.PrintUserValue(std::get<I>(bound), out, mode);
};
absl::Format(out, "{");
absl::Format(out, "%s{", GetTypeNameIfUserDefined<T>());
ApplyIndex<std::tuple_size_v<decltype(bound)>>(
[&](auto... Is) { (print_one(Is), ...); });
absl::Format(out, "}");
Expand Down
10 changes: 6 additions & 4 deletions fuzztest/internal/type_support_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ TEST(CompoundTest, Printer) {
std::tuple{2, -3.5, "Foo"},
StructOf<UserDefined>(Arbitrary<int>(), Arbitrary<double>(),
Arbitrary<std::string>())),
Each("{2, -3.5, \"Foo\"}"));
Each("UserDefined{2, -3.5, \"Foo\"}"));
}

TEST(ProtobufTest, Printer) {
Expand Down Expand Up @@ -489,9 +489,11 @@ TEST(AutodetectAggregateTest, Printer) {
EXPECT_THAT(TestPrintValue(std::pair{123, 456}), Each("{123, 456}"));
EXPECT_THAT(TestPrintValue(std::array{123, 456}), Each("{123, 456}"));
EXPECT_THAT(TestPrintValue(AggregateStructWithNoAbslStringify{}),
Each(R"({1, {"Foo", "Bar"}})"));
EXPECT_THAT(TestPrintValue(AggregateStructWithAbslStringify{}),
ElementsAre("value={1, {Foo, Bar}}", R"({1, {"Foo", "Bar"}})"));
Each(R"(AggregateStructWithNoAbslStringify{1, {"Foo", "Bar"}})"));
EXPECT_THAT(
TestPrintValue(AggregateStructWithAbslStringify{}),
ElementsAre("value={1, {Foo, Bar}}",
R"(AggregateStructWithAbslStringify{1, {"Foo", "Bar"}})"));
}

TEST(DurationTest, Printer) {
Expand Down

0 comments on commit f57e2c0

Please sign in to comment.