Move MoqtParserTestVisitor to a library

This is mostly a behavior-preserving refactor. The only change is that logging is now conditional on a boolean passed to the constructor. This enables the visitor to be used silently in a fuzzer without crowding out the fuzzer's status output.

PiperOrigin-RevId: 768198326
diff --git a/build/source_list.bzl b/build/source_list.bzl
index 5a8ee78..9d46977 100644
--- a/build/source_list.bzl
+++ b/build/source_list.bzl
@@ -1556,6 +1556,7 @@
     "quic/moqt/moqt_track.h",
     "quic/moqt/test_tools/mock_moqt_session.h",
     "quic/moqt/test_tools/moqt_framer_utils.h",
+    "quic/moqt/test_tools/moqt_parser_test_visitor.h",
     "quic/moqt/test_tools/moqt_session_peer.h",
     "quic/moqt/test_tools/moqt_simulator_harness.h",
     "quic/moqt/test_tools/moqt_test_message.h",
diff --git a/build/source_list.gni b/build/source_list.gni
index 89c4626..c3436a9 100644
--- a/build/source_list.gni
+++ b/build/source_list.gni
@@ -1560,6 +1560,7 @@
     "src/quiche/quic/moqt/moqt_track.h",
     "src/quiche/quic/moqt/test_tools/mock_moqt_session.h",
     "src/quiche/quic/moqt/test_tools/moqt_framer_utils.h",
+    "src/quiche/quic/moqt/test_tools/moqt_parser_test_visitor.h",
     "src/quiche/quic/moqt/test_tools/moqt_session_peer.h",
     "src/quiche/quic/moqt/test_tools/moqt_simulator_harness.h",
     "src/quiche/quic/moqt/test_tools/moqt_test_message.h",
diff --git a/build/source_list.json b/build/source_list.json
index 3a262e2..93ee1ee 100644
--- a/build/source_list.json
+++ b/build/source_list.json
@@ -1559,6 +1559,7 @@
     "quiche/quic/moqt/moqt_track.h",
     "quiche/quic/moqt/test_tools/mock_moqt_session.h",
     "quiche/quic/moqt/test_tools/moqt_framer_utils.h",
+    "quiche/quic/moqt/test_tools/moqt_parser_test_visitor.h",
     "quiche/quic/moqt/test_tools/moqt_session_peer.h",
     "quiche/quic/moqt/test_tools/moqt_simulator_harness.h",
     "quiche/quic/moqt/test_tools/moqt_test_message.h",
diff --git a/quiche/quic/moqt/moqt_parser_test.cc b/quiche/quic/moqt/moqt_parser_test.cc
index d979ffe..9b8bd29 100644
--- a/quiche/quic/moqt/moqt_parser_test.cc
+++ b/quiche/quic/moqt/moqt_parser_test.cc
@@ -11,16 +11,18 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <utility>
 #include <variant>
 #include <vector>
 
-#include "absl/strings/str_join.h"
 #include "absl/strings/string_view.h"
 #include "quiche/quic/core/quic_data_writer.h"
 #include "quiche/quic/core/quic_time.h"
 #include "quiche/quic/moqt/moqt_messages.h"
+#include "quiche/quic/moqt/test_tools/moqt_parser_test_visitor.h"
 #include "quiche/quic/moqt/test_tools/moqt_test_message.h"
 #include "quiche/quic/platform/api/quic_test.h"
+#include "quiche/common/platform/api/quiche_test.h"
 #include "quiche/web_transport/test_tools/in_memory_stream.h"
 
 namespace moqt::test {
@@ -28,8 +30,6 @@
 namespace {
 
 using ::testing::AnyOf;
-using ::testing::HasSubstr;
-using ::testing::Optional;
 
 constexpr std::array kMessageTypes{
     MoqtMessageType::kSubscribe,
@@ -112,129 +112,6 @@
          "_" + (info.param.uses_web_transport ? "WebTransport" : "QUIC");
 }
 
-class MoqtParserTestVisitor : public MoqtControlParserVisitor,
-                              public MoqtDataParserVisitor {
- public:
-  ~MoqtParserTestVisitor() = default;
-
-  void OnObjectMessage(const MoqtObject& message, absl::string_view payload,
-                       bool end_of_message) override {
-    MoqtObject object = message;
-    object_payloads_.push_back(std::string(payload));
-    end_of_message_ = end_of_message;
-    if (end_of_message) {
-      ++messages_received_;
-    }
-    last_message_ = TestMessageBase::MessageStructuredData(object);
-  }
-  template <typename Message>
-  void OnControlMessage(const Message& message) {
-    end_of_message_ = true;
-    ++messages_received_;
-    last_message_ = TestMessageBase::MessageStructuredData(message);
-  }
-  void OnClientSetupMessage(const MoqtClientSetup& message) override {
-    OnControlMessage(message);
-  }
-  void OnServerSetupMessage(const MoqtServerSetup& message) override {
-    OnControlMessage(message);
-  }
-  void OnSubscribeMessage(const MoqtSubscribe& message) override {
-    OnControlMessage(message);
-  }
-  void OnSubscribeOkMessage(const MoqtSubscribeOk& message) override {
-    OnControlMessage(message);
-  }
-  void OnSubscribeErrorMessage(const MoqtSubscribeError& message) override {
-    OnControlMessage(message);
-  }
-  void OnSubscribeUpdateMessage(const MoqtSubscribeUpdate& message) override {
-    OnControlMessage(message);
-  }
-  void OnUnsubscribeMessage(const MoqtUnsubscribe& message) override {
-    OnControlMessage(message);
-  }
-  void OnSubscribeDoneMessage(const MoqtSubscribeDone& message) override {
-    OnControlMessage(message);
-  }
-  void OnAnnounceMessage(const MoqtAnnounce& message) override {
-    OnControlMessage(message);
-  }
-  void OnAnnounceOkMessage(const MoqtAnnounceOk& message) override {
-    OnControlMessage(message);
-  }
-  void OnAnnounceErrorMessage(const MoqtAnnounceError& message) override {
-    OnControlMessage(message);
-  }
-  void OnAnnounceCancelMessage(const MoqtAnnounceCancel& message) override {
-    OnControlMessage(message);
-  }
-  void OnTrackStatusRequestMessage(
-      const MoqtTrackStatusRequest& message) override {
-    OnControlMessage(message);
-  }
-  void OnUnannounceMessage(const MoqtUnannounce& message) override {
-    OnControlMessage(message);
-  }
-  void OnTrackStatusMessage(const MoqtTrackStatus& message) override {
-    OnControlMessage(message);
-  }
-  void OnGoAwayMessage(const MoqtGoAway& message) override {
-    OnControlMessage(message);
-  }
-  void OnSubscribeAnnouncesMessage(
-      const MoqtSubscribeAnnounces& message) override {
-    OnControlMessage(message);
-  }
-  void OnSubscribeAnnouncesOkMessage(
-      const MoqtSubscribeAnnouncesOk& message) override {
-    OnControlMessage(message);
-  }
-  void OnSubscribeAnnouncesErrorMessage(
-      const MoqtSubscribeAnnouncesError& message) override {
-    OnControlMessage(message);
-  }
-  void OnUnsubscribeAnnouncesMessage(
-      const MoqtUnsubscribeAnnounces& message) override {
-    OnControlMessage(message);
-  }
-  void OnMaxRequestIdMessage(const MoqtMaxRequestId& message) override {
-    OnControlMessage(message);
-  }
-  void OnFetchMessage(const MoqtFetch& message) override {
-    OnControlMessage(message);
-  }
-  void OnFetchCancelMessage(const MoqtFetchCancel& message) override {
-    OnControlMessage(message);
-  }
-  void OnFetchOkMessage(const MoqtFetchOk& message) override {
-    OnControlMessage(message);
-  }
-  void OnFetchErrorMessage(const MoqtFetchError& message) override {
-    OnControlMessage(message);
-  }
-  void OnRequestsBlockedMessage(const MoqtRequestsBlocked& message) override {
-    OnControlMessage(message);
-  }
-  void OnObjectAckMessage(const MoqtObjectAck& message) override {
-    OnControlMessage(message);
-  }
-  void OnParsingError(MoqtError code, absl::string_view reason) override {
-    QUIC_LOG(INFO) << "Parsing error: " << reason;
-    parsing_error_ = reason;
-    parsing_error_code_ = code;
-  }
-
-  std::string object_payload() { return absl::StrJoin(object_payloads_, ""); }
-
-  std::vector<std::string> object_payloads_;
-  bool end_of_message_ = false;
-  std::optional<std::string> parsing_error_;
-  MoqtError parsing_error_code_;
-  uint64_t messages_received_ = 0;
-  std::optional<TestMessageBase::MessageStructuredData> last_message_;
-};
-
 class MoqtParserTest
     : public quic::test::QuicTestWithParam<MoqtParserTestParams> {
  public:
diff --git a/quiche/quic/moqt/test_tools/moqt_parser_test_visitor.h b/quiche/quic/moqt/test_tools/moqt_parser_test_visitor.h
new file mode 100644
index 0000000..759922c
--- /dev/null
+++ b/quiche/quic/moqt/test_tools/moqt_parser_test_visitor.h
@@ -0,0 +1,150 @@
+// Copyright (c) 2025 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_MOQT_TEST_TOOLS_MOQT_PARSER_TEST_VISITOR_H_
+#define QUICHE_QUIC_MOQT_TEST_TOOLS_MOQT_PARSER_TEST_VISITOR_H_
+
+#include <cstdint>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "absl/strings/str_join.h"
+#include "absl/strings/string_view.h"
+#include "quiche/quic/moqt/moqt_messages.h"
+#include "quiche/quic/moqt/moqt_parser.h"
+#include "quiche/quic/moqt/test_tools/moqt_test_message.h"
+#include "quiche/common/platform/api/quiche_logging.h"
+
+namespace moqt::test {
+
+class MoqtParserTestVisitor : public MoqtControlParserVisitor,
+                              public MoqtDataParserVisitor {
+ public:
+  explicit MoqtParserTestVisitor(bool enable_logging = true)
+      : enable_logging_(enable_logging) {}
+  ~MoqtParserTestVisitor() = default;
+
+  void OnObjectMessage(const MoqtObject& message, absl::string_view payload,
+                       bool end_of_message) override {
+    MoqtObject object = message;
+    object_payloads_.push_back(std::string(payload));
+    end_of_message_ = end_of_message;
+    if (end_of_message) {
+      ++messages_received_;
+    }
+    last_message_ = TestMessageBase::MessageStructuredData(object);
+  }
+  template <typename Message>
+  void OnControlMessage(const Message& message) {
+    end_of_message_ = true;
+    ++messages_received_;
+    last_message_ = TestMessageBase::MessageStructuredData(message);
+  }
+  void OnClientSetupMessage(const MoqtClientSetup& message) override {
+    OnControlMessage(message);
+  }
+  void OnServerSetupMessage(const MoqtServerSetup& message) override {
+    OnControlMessage(message);
+  }
+  void OnSubscribeMessage(const MoqtSubscribe& message) override {
+    OnControlMessage(message);
+  }
+  void OnSubscribeOkMessage(const MoqtSubscribeOk& message) override {
+    OnControlMessage(message);
+  }
+  void OnSubscribeErrorMessage(const MoqtSubscribeError& message) override {
+    OnControlMessage(message);
+  }
+  void OnSubscribeUpdateMessage(const MoqtSubscribeUpdate& message) override {
+    OnControlMessage(message);
+  }
+  void OnUnsubscribeMessage(const MoqtUnsubscribe& message) override {
+    OnControlMessage(message);
+  }
+  void OnSubscribeDoneMessage(const MoqtSubscribeDone& message) override {
+    OnControlMessage(message);
+  }
+  void OnAnnounceMessage(const MoqtAnnounce& message) override {
+    OnControlMessage(message);
+  }
+  void OnAnnounceOkMessage(const MoqtAnnounceOk& message) override {
+    OnControlMessage(message);
+  }
+  void OnAnnounceErrorMessage(const MoqtAnnounceError& message) override {
+    OnControlMessage(message);
+  }
+  void OnAnnounceCancelMessage(const MoqtAnnounceCancel& message) override {
+    OnControlMessage(message);
+  }
+  void OnTrackStatusRequestMessage(
+      const MoqtTrackStatusRequest& message) override {
+    OnControlMessage(message);
+  }
+  void OnUnannounceMessage(const MoqtUnannounce& message) override {
+    OnControlMessage(message);
+  }
+  void OnTrackStatusMessage(const MoqtTrackStatus& message) override {
+    OnControlMessage(message);
+  }
+  void OnGoAwayMessage(const MoqtGoAway& message) override {
+    OnControlMessage(message);
+  }
+  void OnSubscribeAnnouncesMessage(
+      const MoqtSubscribeAnnounces& message) override {
+    OnControlMessage(message);
+  }
+  void OnSubscribeAnnouncesOkMessage(
+      const MoqtSubscribeAnnouncesOk& message) override {
+    OnControlMessage(message);
+  }
+  void OnSubscribeAnnouncesErrorMessage(
+      const MoqtSubscribeAnnouncesError& message) override {
+    OnControlMessage(message);
+  }
+  void OnUnsubscribeAnnouncesMessage(
+      const MoqtUnsubscribeAnnounces& message) override {
+    OnControlMessage(message);
+  }
+  void OnMaxRequestIdMessage(const MoqtMaxRequestId& message) override {
+    OnControlMessage(message);
+  }
+  void OnFetchMessage(const MoqtFetch& message) override {
+    OnControlMessage(message);
+  }
+  void OnFetchCancelMessage(const MoqtFetchCancel& message) override {
+    OnControlMessage(message);
+  }
+  void OnFetchOkMessage(const MoqtFetchOk& message) override {
+    OnControlMessage(message);
+  }
+  void OnFetchErrorMessage(const MoqtFetchError& message) override {
+    OnControlMessage(message);
+  }
+  void OnRequestsBlockedMessage(const MoqtRequestsBlocked& message) override {
+    OnControlMessage(message);
+  }
+  void OnObjectAckMessage(const MoqtObjectAck& message) override {
+    OnControlMessage(message);
+  }
+  void OnParsingError(MoqtError code, absl::string_view reason) override {
+    QUICHE_LOG_IF(INFO, enable_logging_) << "Parsing error: " << reason;
+    parsing_error_ = reason;
+    parsing_error_code_ = code;
+  }
+
+  std::string object_payload() { return absl::StrJoin(object_payloads_, ""); }
+
+  bool enable_logging_ = true;
+  std::vector<std::string> object_payloads_;
+  bool end_of_message_ = false;
+  std::optional<std::string> parsing_error_;
+  MoqtError parsing_error_code_;
+  uint64_t messages_received_ = 0;
+  std::optional<TestMessageBase::MessageStructuredData> last_message_;
+};
+
+}  // namespace moqt::test
+
+#endif  // QUICHE_QUIC_MOQT_TEST_TOOLS_MOQT_PARSER_TEST_VISITOR_H_