Skip to content

Commit

Permalink
Fix FlatMappedPrinter to always delegate printing to the output dom…
Browse files Browse the repository at this point in the history
…ain.

Printing the invocation of the flat mapper on the input values doesn't make
sense: the result of that is a domain, and the user needs the value from that
domain that causes the test to fail.
PiperOrigin-RevId: 680832142
  • Loading branch information
fniksic authored and copybara-github committed Oct 2, 2024
1 parent 0021f30 commit 6eefa1c
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 72 deletions.
7 changes: 2 additions & 5 deletions e2e_tests/functional_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1644,11 +1644,8 @@ TEST_P(FuzzingModeCrashFindingTest, MappedDomainShowsMappedValue) {
TEST_P(FuzzingModeCrashFindingTest, FlatMappedDomainShowsMappedValue) {
auto [status, std_out, std_err] = Run("MySuite.FlatMapping");
EXPECT_THAT(std_err, AllOf(HasSubstr("argument 0: {\"abc\", 2}"),
HasReproducerTest(
"MySuite", "FlatMapping",
// Account for the possibility that the symbol
// StringAndValidIndex may be mangled.
R"re(.*StringAndValidIndex.*\("abc"\))re")));
HasReproducerTest("MySuite", "FlatMapping",
"{\"abc\", 2}")));
ExpectTargetAbort(status, std_err);
}

Expand Down
31 changes: 3 additions & 28 deletions fuzztest/internal/type_support.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,34 +442,9 @@ struct FlatMappedPrinter {
std::get<I>(inner).GetValue(std::get<I + 1>(corpus_value))...);
});

switch (mode) {
case domain_implementor::PrintMode::kHumanReadable: {
// Delegate to the output domain's printer.
domain_implementor::PrintValue(output_domain, std::get<0>(corpus_value),
out, mode);
break;
}
case domain_implementor::PrintMode::kSourceCode:
if constexpr (!HasFunctionName<FlatMapper>()) {
domain_implementor::PrintValue(output_domain,
std::get<0>(corpus_value), out, mode);
break;
}

// In source code mode we print the mapping expression.
// This should give a better chance of valid code, given that the result
// of the mapping function can easily be a user defined type we can't
// generate otherwise.
absl::Format(out, "%s(",
GetFunctionName(mapper, "<FLAT_MAP_FUNCTION>"));
const auto print_one = [&](auto I) {
if (I != 0) absl::Format(out, ", ");
domain_implementor::PrintValue(
std::get<I>(inner), std::get<I + 1>(corpus_value), out, mode);
};
ApplyIndex<sizeof...(Inner)>([&](auto... Is) { (print_one(Is), ...); });
absl::Format(out, ")");
}
// Delegate to the output domain's printer.
domain_implementor::PrintValue(output_domain, std::get<0>(corpus_value),
out, mode);
}
};

Expand Down
81 changes: 42 additions & 39 deletions fuzztest/internal/type_support_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ TEST(DomainTest, Printer) {
};
EXPECT_THAT(print('a', Domain<char>(Arbitrary<char>())),
ElementsAre("'a' (97)", "'a'"));
EXPECT_THAT(print(typename decltype(color_domain)::corpus_type{0},
EXPECT_THAT(print(corpus_type_t<decltype(color_domain)>{0},
Domain<Color>(color_domain)),
ElementsAre("Color{1}", "static_cast<Color>(1)"));
}
Expand All @@ -323,13 +323,13 @@ TEST(OptionalTest, Printer) {
auto optional_int_domain = OptionalOf(Arbitrary<int>());
EXPECT_THAT(TestPrintValue({}, optional_int_domain), Each("std::nullopt"));
EXPECT_THAT(
TestPrintValue(Domain<int>::corpus_type(std::in_place_type<int>, 1),
TestPrintValue(corpus_type_t<Domain<int>>(std::in_place_type<int>, 1),
optional_int_domain),
ElementsAre("(1)", "1"));

auto optional_string_domain = OptionalOf(Arbitrary<std::string>());
EXPECT_THAT(TestPrintValue({}, optional_string_domain), Each("std::nullopt"));
EXPECT_THAT(TestPrintValue(Domain<std::string>::corpus_type(
EXPECT_THAT(TestPrintValue(corpus_type_t<Domain<std::string>>(
std::in_place_type<std::string>, "ABC"),
optional_string_domain),
ElementsAre("(\"ABC\")", "\"ABC\""));
Expand All @@ -339,11 +339,11 @@ TEST(SmartPointerTest, Printer) {
EXPECT_THAT(TestPrintValue({}, Arbitrary<std::unique_ptr<int>>()),
Each("nullptr"));
EXPECT_THAT(
TestPrintValue(Domain<int>::corpus_type(std::in_place_type<int>, 7),
TestPrintValue(corpus_type_t<Domain<int>>(std::in_place_type<int>, 7),
Arbitrary<std::unique_ptr<int>>()),
ElementsAre("(7)", "std::make_unique<int>(7)"));
EXPECT_THAT(
TestPrintValue(Domain<std::string>::corpus_type(
TestPrintValue(corpus_type_t<Domain<std::string>>(
std::in_place_type<std::string>, "ABC"),
Arbitrary<std::shared_ptr<std::string>>()),
ElementsAre(
Expand Down Expand Up @@ -403,41 +403,44 @@ TEST(MapTest, PrintsMapperOutsideNamespace) {
MatchesRegex(R"re(DoubleValueOutsideNamespace.*\(3\))re")));
}

auto ValueInRange(int a, int b) {
int min = std::min(a, b);
int max = std::max(a, b);
return InRange(min, max);
}

TEST(FlatMapTest, PrinterWithNamedFunction) {
auto domain = FlatMap(ValueInRange, Arbitrary<int>(), Arbitrary<int>());
decltype(domain)::corpus_type corpus_value = {2, 3, 1};
EXPECT_THAT(TestPrintValue(corpus_value, domain),
ElementsAre("2", "ValueInRange(3, 1)"));
}

TEST(FlatMapTest, PrinterWithLambda) {
auto domain =
FlatMap([](int a) { return ValueInRange(a, a + 100); }, Arbitrary<int>());
decltype(domain)::corpus_type corpus_value = {42, 0};
EXPECT_THAT(TestPrintValue(corpus_value, domain), Each("42"));
}

auto VectorWithSize(int size) {
return VectorOf(Arbitrary<int>()).WithSize(size);
}

TEST(FlatMapTest, PrintVector) {
auto domain = FlatMap(VectorWithSize, InRange(2, 4));
decltype(domain)::corpus_type corpus_value = {{1, 2, 3}, 3};

EXPECT_THAT(TestPrintValue(corpus_value, domain),
ElementsAre("{1, 2, 3}", "VectorWithSize(3)"));
TEST(FlatMapTest, DelegatesToOutputDomainPrinter) {
auto optional_sized_strings = [](int size) {
return OptionalOf(String().WithSize(size));
};
auto input_domain = InRange(1, 3);
auto flat_map_domain = FlatMap(optional_sized_strings, input_domain);

corpus_type_t<decltype(flat_map_domain)> abc_corpus_val = {
// String of size
GenericDomainCorpusType(std::in_place_type<std::string>, "ABC"),
// Size
3};
// Sanity checks that the components of `abc_corpus_val` are in the respective
// domains.
ASSERT_TRUE(
input_domain.ValidateCorpusValue(std::get<1>(abc_corpus_val)).ok());
ASSERT_TRUE(
optional_sized_strings(input_domain.GetValue(std::get<1>(abc_corpus_val)))
.ValidateCorpusValue(std::get<0>(abc_corpus_val))
.ok());
EXPECT_THAT(TestPrintValue(abc_corpus_val, flat_map_domain),
ElementsAre("(\"ABC\")", "\"ABC\""));

auto lambda = [](int size) { return VectorWithSize(size); };
auto lambda_domain = FlatMap(lambda, InRange(2, 4));
EXPECT_THAT(TestPrintValue(corpus_value, lambda_domain),
ElementsAre("{1, 2, 3}", "{1, 2, 3}"));
corpus_type_t<decltype(flat_map_domain)> nullopt_corpus_val = {
// Corpus value of nullopt
std::monostate{},
// Size (here irrelevant)
2};
// Sanity checks that the components of `nullopt_corpus_val` are in the
// respective domains.
ASSERT_TRUE(
input_domain.ValidateCorpusValue(std::get<1>(nullopt_corpus_val)).ok());
ASSERT_TRUE(optional_sized_strings(
input_domain.GetValue(std::get<1>(nullopt_corpus_val)))
.ValidateCorpusValue(std::get<0>(nullopt_corpus_val))
.ok());
EXPECT_THAT(TestPrintValue(nullopt_corpus_val, flat_map_domain),
Each("std::nullopt"));
}

TEST(ConstructorOfTest, Printer) {
Expand Down

0 comments on commit 6eefa1c

Please sign in to comment.