Run only fuzz tests in fuzzing mode when no test or test filter is specified.

PiperOrigin-RevId: 633330603
diff --git a/e2e_tests/BUILD b/e2e_tests/BUILD
index 31631e2..868ac5f 100644
--- a/e2e_tests/BUILD
+++ b/e2e_tests/BUILD
@@ -31,6 +31,7 @@
         "@com_google_fuzztest//e2e_tests/testdata:dynamically_registered_fuzz_tests.stripped",
         "@com_google_fuzztest//e2e_tests/testdata:fuzz_tests_for_functional_testing.stripped",
         "@com_google_fuzztest//e2e_tests/testdata:fuzz_tests_with_invalid_seeds.stripped",
+        "@com_google_fuzztest//e2e_tests/testdata:unit_test_and_fuzz_tests.stripped",
     ],
     defines = select({
         "@com_google_fuzztest//fuzztest:use_centipede": ["FUZZTEST_USE_CENTIPEDE"],
diff --git a/e2e_tests/functional_test.cc b/e2e_tests/functional_test.cc
index 2875444..39d317c 100644
--- a/e2e_tests/functional_test.cc
+++ b/e2e_tests/functional_test.cc
@@ -17,7 +17,7 @@
 #include <cstdint>
 #include <cstdio>
 #include <cstdlib>
-#include <filesystem>
+#include <filesystem>  // NOLINT
 #include <optional>
 #include <string>
 #include <tuple>
@@ -1135,6 +1135,37 @@
   EXPECT_THAT(status, Eq(Signal(SIGABRT)));
 }
 
+// TODO: b/340232436 - Once fixed, remove this test since we will no longer need
+// to restrict the filter to only fuzz tests.
+TEST_F(FuzzingModeCommandLineInterfaceTest,
+       RunsOnlyFuzzTestsWhenNoFilterIsSpecified) {
+  auto [status, std_out, std_err] =
+      RunWith({{"fuzz_for", "1ns"}}, /*env=*/{}, /*timeout=*/absl::Seconds(10),
+              "testdata/unit_test_and_fuzz_tests");
+
+  EXPECT_THAT(std_out, Not(HasSubstr("[ RUN      ] UnitTest.AlwaysPasses")));
+  EXPECT_THAT(std_out, HasSubstr("[ RUN      ] FuzzTest.AlwaysPasses"));
+  EXPECT_THAT(std_out, HasSubstr("[ RUN      ] FuzzTest.AlsoAlwaysPasses"));
+  EXPECT_THAT(std_out, HasSubstr("2 tests from 1 test suite ran."));
+  EXPECT_THAT(status, Eq(ExitCode(0)));
+}
+
+TEST_F(FuzzingModeCommandLineInterfaceTest,
+       AllowsSpecifyingFilterWithFuzzForDuration) {
+  auto [status, std_out, std_err] =
+      RunWith({{"fuzz_for", "1ns"}}, /*env=*/{}, /*timeout=*/absl::Seconds(10),
+              "testdata/unit_test_and_fuzz_tests",
+              {{GTEST_FLAG_PREFIX_ "filter",
+                "UnitTest.AlwaysPasses:FuzzTest.AlwaysPasses"}});
+
+  EXPECT_THAT(std_out, HasSubstr("[ RUN      ] UnitTest.AlwaysPasses"));
+  EXPECT_THAT(std_out, HasSubstr("[ RUN      ] FuzzTest.AlwaysPasses"));
+  EXPECT_THAT(std_out,
+              Not(HasSubstr("[ RUN      ] FuzzTest.AlsoAlwaysPasses")));
+  EXPECT_THAT(std_out, HasSubstr("2 tests from 2 test suites ran."));
+  EXPECT_THAT(status, Eq(ExitCode(0)));
+}
+
 std::string CentipedePath() {
   const auto test_srcdir = absl::NullSafeStringView(getenv("TEST_SRCDIR"));
   FUZZTEST_INTERNAL_CHECK_PRECONDITION(
diff --git a/e2e_tests/testdata/BUILD b/e2e_tests/testdata/BUILD
index 620a38e..ae40eef 100644
--- a/e2e_tests/testdata/BUILD
+++ b/e2e_tests/testdata/BUILD
@@ -122,3 +122,13 @@
         "@com_google_fuzztest//fuzztest:fuzztest_gtest_main",
     ],
 )
+
+cc_binary(
+    name = "unit_test_and_fuzz_tests",
+    testonly = 1,
+    srcs = ["unit_test_and_fuzz_tests.cc"],
+    deps = [
+        "@com_google_fuzztest//fuzztest:fuzztest_core",
+        "@com_google_fuzztest//fuzztest:fuzztest_gtest_main",
+    ],
+)
diff --git a/e2e_tests/testdata/CMakeLists.txt b/e2e_tests/testdata/CMakeLists.txt
index a46f818..36d28cf 100644
--- a/e2e_tests/testdata/CMakeLists.txt
+++ b/e2e_tests/testdata/CMakeLists.txt
@@ -83,4 +83,15 @@
   domain_tests.stripped
   PROPERTIES RUNTIME_OUTPUT_DIRECTORY
   "${CMAKE_BINARY_DIR}/com_google_fuzztest/e2e_tests/testdata"
+)
+
+add_executable(
+  unit_test_and_fuzz_tests.stripped
+  unit_test_and_fuzz_tests.cc
+)
+link_fuzztest(unit_test_and_fuzz_tests.stripped)
+set_target_properties(
+  unit_test_and_fuzz_tests.stripped
+  PROPERTIES RUNTIME_OUTPUT_DIRECTORY
+  "${CMAKE_BINARY_DIR}/com_google_fuzztest/e2e_tests/testdata"
 )
\ No newline at end of file
diff --git a/e2e_tests/testdata/unit_test_and_fuzz_tests.cc b/e2e_tests/testdata/unit_test_and_fuzz_tests.cc
new file mode 100644
index 0000000..dc5d41c
--- /dev/null
+++ b/e2e_tests/testdata/unit_test_and_fuzz_tests.cc
@@ -0,0 +1,28 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "gtest/gtest.h"
+#include "./fuzztest/fuzztest_core.h"
+
+namespace {
+
+TEST(UnitTest, AlwaysPasses) {}
+
+void AlwaysPasses(int) {}
+FUZZ_TEST(FuzzTest, AlwaysPasses);
+
+void AlsoAlwaysPasses(int) {}
+FUZZ_TEST(FuzzTest, AlsoAlwaysPasses);
+
+}  // namespace
diff --git a/fuzztest/init_fuzztest.cc b/fuzztest/init_fuzztest.cc
index e7a0531..0577e03 100644
--- a/fuzztest/init_fuzztest.cc
+++ b/fuzztest/init_fuzztest.cc
@@ -75,10 +75,9 @@
     absl::Duration, fuzz_for, absl::InfiniteDuration(),
     "Runs all fuzz tests in fuzzing mode for the specified duration. Can "
     "be combined with --" FUZZTEST_FLAG_PREFIX
-    "fuzz to select a single fuzz tests, or "
-    "with --" FUZZTEST_FLAG_PREFIX
-    "filter to select a subset of fuzz tests. Recommended "
-    "to use with test sharding.");
+    "fuzz to select a single fuzz tests, or with --" GTEST_FLAG_PREFIX_
+    "filter to select a subset of fuzz tests. Recommended to use with test "
+    "sharding.");
 
 FUZZTEST_DEFINE_FLAG(
     std::string, corpus_database,
@@ -277,6 +276,20 @@
   const RunMode run_mode = is_test_to_fuzz_specified || has_time_limit_per_test
                                ? RunMode::kFuzz
                                : RunMode::kUnitTest;
+
+  if (run_mode == RunMode::kFuzz && !is_test_to_fuzz_specified &&
+      GTEST_FLAG_GET(filter) == "*") {
+    // Run only the fuzz tests, and not the unit tests when the user doesn't
+    // set the test filter.
+    // TODO: b/340232436 -- This is needed because we currently rely on a fuzz
+    // test being the first test to run so that Centipede can get the serialized
+    // configuration from the binary. For simplicity, we don't restrict the
+    // filter to fuzz tests when the user explicitly sets the filter. Instead of
+    // improving the logic here, once we fix b/340232436 we will remove this
+    // altogether and allow a mix of fuzz tests and unit tests in all cases.
+    GTEST_FLAG_SET(filter, absl::StrJoin(configuration.fuzz_tests, ":"));
+  }
+
   // TODO(b/307513669): Use the Configuration class instead of Runtime.
   internal::Runtime::instance().SetRunMode(run_mode);
 }