Add equality operators for public data types in BinaryHttp*

PiperOrigin-RevId: 475643555
diff --git a/quiche/binary_http/binary_http_message.h b/quiche/binary_http/binary_http_message.h
index d7da4fe..852df93 100644
--- a/quiche/binary_http/binary_http_message.h
+++ b/quiche/binary_http/binary_http_message.h
@@ -30,6 +30,10 @@
       return name == rhs.name && value == rhs.value;
     }
 
+    bool operator!=(const BinaryHttpMessage::Field& rhs) const {
+      return !(*this == rhs);
+    }
+
     std::string DebugString() const;
   };
   virtual ~BinaryHttpMessage() = default;
@@ -87,6 +91,12 @@
     std::vector<BinaryHttpMessage::Field> fields_;
   };
 
+  bool operator==(const BinaryHttpMessage& rhs) const {
+    // `has_host_` is derived from `header_fields_` so it doesn't need to be
+    // tested directly.
+    return body_ == rhs.body_ && header_fields_ == rhs.header_fields_;
+  }
+
   absl::Status EncodeKnownLengthFieldsAndBody(
       quiche::QuicheDataWriter& writer) const;
   uint64_t EncodedKnownLengthFieldsAndBodySize() const;
@@ -114,6 +124,9 @@
       return method == rhs.method && scheme == rhs.scheme &&
              authority == rhs.authority && path == rhs.path;
     }
+    bool operator!=(const BinaryHttpRequest::ControlData& rhs) const {
+      return !(*this == rhs);
+    }
   };
   explicit BinaryHttpRequest(ControlData control_data)
       : control_data_(std::move(control_data)) {}
@@ -126,6 +139,15 @@
 
   virtual std::string DebugString() const override;
 
+  bool operator==(const BinaryHttpRequest& rhs) const {
+    return control_data_ == rhs.control_data_ &&
+           BinaryHttpMessage::operator==(rhs);
+  }
+
+  bool operator!=(const BinaryHttpRequest& rhs) const {
+    return !(*this == rhs);
+  }
+
  private:
   absl::Status EncodeControlData(quiche::QuicheDataWriter& writer) const;
 
@@ -164,6 +186,11 @@
       return status_code_ == rhs.status_code_ && fields_ == rhs.fields_;
     }
 
+    bool operator!=(
+        const BinaryHttpResponse::InformationalResponse& rhs) const {
+      return !(*this == rhs);
+    }
+
     // Adds a field with the provided name, converted to lower case.
     // Fields are in the order they are added.
     void AddField(absl::string_view name, std::string value);
@@ -211,6 +238,16 @@
 
   virtual std::string DebugString() const override;
 
+  bool operator==(const BinaryHttpResponse& rhs) const {
+    return informational_response_control_data_ ==
+               rhs.informational_response_control_data_ &&
+           status_code_ == rhs.status_code_ &&
+           BinaryHttpMessage::operator==(rhs);
+  }
+  bool operator!=(const BinaryHttpResponse& rhs) const {
+    return !(*this == rhs);
+  }
+
  private:
   // Returns Binary Http known length request formatted response.
   absl::StatusOr<std::string> EncodeAsKnownLength() const;
diff --git a/quiche/binary_http/binary_http_message_test.cc b/quiche/binary_http/binary_http_message_test.cc
index 3ce4b0e..f98a375 100644
--- a/quiche/binary_http/binary_http_message_test.cc
+++ b/quiche/binary_http/binary_http_message_test.cc
@@ -262,6 +262,50 @@
             "body that I used to post.\r\n}}}"));
 }
 
+TEST(BinaryHttpRequest, Equality) {
+  BinaryHttpRequest request({"POST", "https", "www.example.com", "/hello.txt"});
+  request.AddHeaderField({"User-Agent", "not/telling"})
+      ->set_body({"hello, world!\r\n"});
+
+  BinaryHttpRequest same({"POST", "https", "www.example.com", "/hello.txt"});
+  same.AddHeaderField({"User-Agent", "not/telling"})
+      ->set_body({"hello, world!\r\n"});
+  EXPECT_EQ(request, same);
+}
+
+TEST(BinaryHttpRequest, Inequality) {
+  BinaryHttpRequest request({"POST", "https", "www.example.com", "/hello.txt"});
+  request.AddHeaderField({"User-Agent", "not/telling"})
+      ->set_body({"hello, world!\r\n"});
+
+  BinaryHttpRequest different_control(
+      {"PUT", "https", "www.example.com", "/hello.txt"});
+  different_control.AddHeaderField({"User-Agent", "not/telling"})
+      ->set_body({"hello, world!\r\n"});
+  EXPECT_NE(request, different_control);
+
+  BinaryHttpRequest different_header(
+      {"PUT", "https", "www.example.com", "/hello.txt"});
+  different_header.AddHeaderField({"User-Agent", "told/you"})
+      ->set_body({"hello, world!\r\n"});
+  EXPECT_NE(request, different_header);
+
+  BinaryHttpRequest no_header(
+      {"PUT", "https", "www.example.com", "/hello.txt"});
+  no_header.set_body({"hello, world!\r\n"});
+  EXPECT_NE(request, no_header);
+
+  BinaryHttpRequest different_body(
+      {"POST", "https", "www.example.com", "/hello.txt"});
+  different_body.AddHeaderField({"User-Agent", "not/telling"})
+      ->set_body({"goodbye, world!\r\n"});
+  EXPECT_NE(request, different_body);
+
+  BinaryHttpRequest no_body({"POST", "https", "www.example.com", "/hello.txt"});
+  no_body.AddHeaderField({"User-Agent", "not/telling"});
+  EXPECT_NE(request, no_body);
+}
+
 TEST(BinaryHttpResponse, EncodeNoBody) {
   /*
     HTTP/1.1 404 Not Found
@@ -572,4 +616,68 @@
   EXPECT_EQ(other, "hello, world!");
 }
 
+TEST(BinaryHttpResponse, Equality) {
+  BinaryHttpResponse response(200);
+  response.AddHeaderField({"Server", "Apache"})->set_body("Hello, world!\r\n");
+  ASSERT_OK(
+      response.AddInformationalResponse(102, {{"Running", "\"sleep 15\""}}));
+
+  BinaryHttpResponse same(200);
+  same.AddHeaderField({"Server", "Apache"})->set_body("Hello, world!\r\n");
+  ASSERT_OK(same.AddInformationalResponse(102, {{"Running", "\"sleep 15\""}}));
+  ASSERT_EQ(response, same);
+}
+
+TEST(BinaryHttpResponse, Inequality) {
+  BinaryHttpResponse response(200);
+  response.AddHeaderField({"Server", "Apache"})->set_body("Hello, world!\r\n");
+  ASSERT_OK(
+      response.AddInformationalResponse(102, {{"Running", "\"sleep 15\""}}));
+
+  BinaryHttpResponse different_status(201);
+  different_status.AddHeaderField({"Server", "Apache"})
+      ->set_body("Hello, world!\r\n");
+  EXPECT_OK(different_status.AddInformationalResponse(
+      102, {{"Running", "\"sleep 15\""}}));
+  EXPECT_NE(response, different_status);
+
+  BinaryHttpResponse different_header(200);
+  different_header.AddHeaderField({"Server", "python3"})
+      ->set_body("Hello, world!\r\n");
+  EXPECT_OK(different_header.AddInformationalResponse(
+      102, {{"Running", "\"sleep 15\""}}));
+  EXPECT_NE(response, different_header);
+
+  BinaryHttpResponse no_header(200);
+  no_header.set_body("Hello, world!\r\n");
+  EXPECT_OK(
+      no_header.AddInformationalResponse(102, {{"Running", "\"sleep 15\""}}));
+  EXPECT_NE(response, no_header);
+
+  BinaryHttpResponse different_body(200);
+  different_body.AddHeaderField({"Server", "Apache"})
+      ->set_body("Goodbye, world!\r\n");
+  EXPECT_OK(different_body.AddInformationalResponse(
+      102, {{"Running", "\"sleep 15\""}}));
+  EXPECT_NE(response, different_body);
+
+  BinaryHttpResponse no_body(200);
+  no_body.AddHeaderField({"Server", "Apache"});
+  EXPECT_OK(
+      no_body.AddInformationalResponse(102, {{"Running", "\"sleep 15\""}}));
+  EXPECT_NE(response, no_body);
+
+  BinaryHttpResponse different_informational(200);
+  different_informational.AddHeaderField({"Server", "Apache"})
+      ->set_body("Hello, world!\r\n");
+  EXPECT_OK(different_informational.AddInformationalResponse(
+      198, {{"Running", "\"sleep 15\""}}));
+  EXPECT_NE(response, different_informational);
+
+  BinaryHttpResponse no_informational(200);
+  no_informational.AddHeaderField({"Server", "Apache"})
+      ->set_body("Hello, world!\r\n");
+  EXPECT_NE(response, no_informational);
+}
+
 }  // namespace quiche