Print specific reproduction instruction if only one reproducer is exported. PiperOrigin-RevId: 756386768
diff --git a/e2e_tests/functional_test.cc b/e2e_tests/functional_test.cc index 349b2e4..196daca 100644 --- a/e2e_tests/functional_test.cc +++ b/e2e_tests/functional_test.cc
@@ -762,10 +762,9 @@ EXPECT_THAT(args, Optional(FieldsAre(StartsWith("Fuzz")))) << std_err; EXPECT_THAT(std_err, AllOf(HasSubstr("Reproducer file was dumped at:"), - HasSubstr(out_dir.path()), - HasSubstr(Basename(replay_files[0].path)), + HasSubstr(replay_files[0].path), HasSubstr(absl::StrCat("--test_env=FUZZTEST_REPLAY=", - out_dir.path().string())))) + replay_files[0].path)))) << std_err; } @@ -785,14 +784,14 @@ ASSERT_TRUE(parsed) << std_err; auto args = parsed->ToCorpus<std::tuple<std::string>>(); EXPECT_THAT(args, Optional(FieldsAre(StartsWith("Fuzz")))) << std_err; - EXPECT_THAT( - std_err, - AllOf(HasSubstr("Reproducer file was dumped under " - "TEST_UNDECLARED_OUTPUTS_DIR" - ), - HasSubstr(out_dir.path()), - HasSubstr(Basename(replay_files[0].path)), - HasSubstr("--test_env=FUZZTEST_REPLAY=/tmp/fuzztest_repro/"))) + EXPECT_THAT(std_err, + AllOf(HasSubstr("Reproducer file was dumped under " + "TEST_UNDECLARED_OUTPUTS_DIR" + ), + HasSubstr(replay_files[0].path), + HasSubstr(absl::StrCat( + "--test_env=FUZZTEST_REPLAY=/tmp/fuzztest_repro/", + Basename(replay_files[0].path))))) << std_err; }
diff --git a/fuzztest/internal/centipede_adaptor.cc b/fuzztest/internal/centipede_adaptor.cc index fb5bda9..c019d9f 100644 --- a/fuzztest/internal/centipede_adaptor.cc +++ b/fuzztest/internal/centipede_adaptor.cc
@@ -751,6 +751,8 @@ "to report reproducers from Centipede"); } + // Will be set when there is only one reproducer - nullopt otherwise. + std::optional<std::string> single_reproducer_path; for (const auto& exported_crash_file : *exported_crash_files) { if (!absl::EndsWith(exported_crash_file, ".data")) { continue; @@ -790,16 +792,32 @@ absl::FPrintF(GetStderr(), "[.] Saved reproducer with ID %s and crash metadata %s\n", Basename(reproducer_path), metadata); + if (!single_reproducer_path.has_value()) { + single_reproducer_path = reproducer_path; + } else { + // More than one reproducers are exported - use the placeholder for + // the instruction. + single_reproducer_path = std::nullopt; + } } - absl::FPrintF(GetStderr(), - "[.] Please follow the guide below for fetching and/or " - "replaying each reproducer files. You would need to replace " - "REPRODUCER_ID with the actual reproducer ID to be used.\n"); ReportSink report_sink; - PrintReproducerIfRequested( - &report_sink, test, &configuration, - std::filesystem::path{output.dir_path}.append("REPRODUCER_ID").string()); + if (single_reproducer_path.has_value()) { + PrintReproducerIfRequested(&report_sink, test, &configuration, + *single_reproducer_path); + } else { + // TODO: b/385113025 - Test this branch when we no longer need to emulate + // the legacy exit-on-crash behavior. + absl::FPrintF(GetStderr(), + "[.] Please follow the guide below for fetching and/or " + "replaying each reproducer files. You would need to replace " + "REPRODUCER_ID with the actual reproducer ID to be used.\n"); + PrintReproducerIfRequested(&report_sink, test, &configuration, + std::filesystem::path{output.dir_path} + .append("REPRODUCER_ID") + .string()); + } + return absl::OkStatus(); }