Project import generated by Copybara.

PiperOrigin-RevId: 229942388
Change-Id: Ib5a23c152c95ed4294cece9f902227c21ce531ef
diff --git a/spdy/core/spdy_deframer_visitor_test.cc b/spdy/core/spdy_deframer_visitor_test.cc
new file mode 100644
index 0000000..ede1a20
--- /dev/null
+++ b/spdy/core/spdy_deframer_visitor_test.cc
@@ -0,0 +1,247 @@
+// Copyright 2016 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.
+
+#include "net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.h"
+
+#include <stdlib.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
+#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
+#include "net/third_party/quiche/src/spdy/core/mock_spdy_framer_visitor.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_frame_reader.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_framer.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
+
+namespace spdy {
+namespace test {
+namespace {
+
+class SpdyDeframerVisitorTest : public ::testing::Test {
+ protected:
+  SpdyDeframerVisitorTest() : encoder_(SpdyFramer::ENABLE_COMPRESSION) {
+    decoder_.set_process_single_input_frame(true);
+    auto collector =
+        SpdyMakeUnique<DeframerCallbackCollector>(&collected_frames_);
+    auto log_and_collect =
+        SpdyDeframerVisitorInterface::LogBeforeVisiting(std::move(collector));
+    deframer_ = SpdyTestDeframer::CreateConverter(std::move(log_and_collect));
+    decoder_.set_visitor(deframer_.get());
+  }
+
+  bool DeframeInput(const char* input, size_t size) {
+    size_t input_remaining = size;
+    while (input_remaining > 0 &&
+           decoder_.spdy_framer_error() ==
+               http2::Http2DecoderAdapter::SPDY_NO_ERROR) {
+      // To make the tests more interesting, we feed random (and small) chunks
+      // into the framer.  This simulates getting strange-sized reads from
+      // the socket.
+      const size_t kMaxReadSize = 32;
+      size_t bytes_read =
+          (random_.Uniform(std::min(input_remaining, kMaxReadSize))) + 1;
+      size_t bytes_processed = decoder_.ProcessInput(input, bytes_read);
+      input_remaining -= bytes_processed;
+      input += bytes_processed;
+      if (decoder_.state() ==
+          http2::Http2DecoderAdapter::SPDY_READY_FOR_FRAME) {
+        deframer_->AtFrameEnd();
+      }
+    }
+    return (input_remaining == 0 &&
+            decoder_.spdy_framer_error() ==
+                http2::Http2DecoderAdapter::SPDY_NO_ERROR);
+  }
+
+  SpdyFramer encoder_;
+  http2::Http2DecoderAdapter decoder_;
+  std::vector<CollectedFrame> collected_frames_;
+  std::unique_ptr<SpdyTestDeframer> deframer_;
+
+ private:
+  http2::test::Http2Random random_;
+};
+
+TEST_F(SpdyDeframerVisitorTest, DataFrame) {
+  const char kFrameData[] = {
+      0x00, 0x00, 0x0d,        // Length = 13.
+      0x00,                    // DATA
+      0x08,                    // PADDED
+      0x00, 0x00, 0x00, 0x01,  // Stream 1
+      0x07,                    // Pad length field.
+      'h',  'e',  'l',  'l',   // Data
+      'o',                     // More Data
+      0x00, 0x00, 0x00, 0x00,  // Padding
+      0x00, 0x00, 0x00         // More Padding
+  };
+
+  EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
+  ASSERT_EQ(1u, collected_frames_.size());
+  const CollectedFrame& cf0 = collected_frames_[0];
+  ASSERT_NE(cf0.frame_ir, nullptr);
+
+  SpdyDataIR expected_ir(/* stream_id = */ 1, "hello");
+  expected_ir.set_padding_len(8);
+  EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+}
+
+TEST_F(SpdyDeframerVisitorTest, HeaderFrameWithContinuation) {
+  const char kFrameData[] = {
+      0x00, 0x00, 0x05,        // Payload Length: 5
+      0x01,                    // Type: HEADERS
+      0x09,                    // Flags: PADDED | END_STREAM
+      0x00, 0x00, 0x00, 0x01,  // Stream: 1
+      0x04,                    // Padding Length: 4
+      0x00, 0x00, 0x00, 0x00,  // Padding
+      /* Second Frame */
+      0x00, 0x00, 0x12,        // Payload Length: 18
+      0x09,                    // Type: CONTINUATION
+      0x04,                    // Flags: END_HEADERS
+      0x00, 0x00, 0x00, 0x01,  // Stream: 1
+      0x00,                    // Unindexed, literal name & value
+      0x03, 0x62, 0x61, 0x72,  // Name len and name (3, "bar")
+      0x03, 0x66, 0x6f, 0x6f,  // Value len and value (3, "foo")
+      0x00,                    // Unindexed, literal name & value
+      0x03, 0x66, 0x6f, 0x6f,  // Name len and name (3, "foo")
+      0x03, 0x62, 0x61, 0x72,  // Value len and value (3, "bar")
+  };
+
+  EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
+  ASSERT_EQ(1u, collected_frames_.size());
+  const CollectedFrame& cf0 = collected_frames_[0];
+
+  StringPairVector headers;
+  headers.push_back({"bar", "foo"});
+  headers.push_back({"foo", "bar"});
+
+  EXPECT_TRUE(cf0.VerifyHasHeaders(headers));
+
+  SpdyHeadersIR expected_ir(/* stream_id = */ 1);
+  // Yet again SpdyFramerVisitorInterface is lossy: it doesn't call OnPadding
+  // for HEADERS, just for DATA. Sigh.
+  //    expected_ir.set_padding_len(5);
+  expected_ir.set_fin(true);
+  for (const auto& nv : headers) {
+    expected_ir.SetHeader(nv.first, nv.second);
+  }
+
+  EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+  // Confirm that mismatches are also detected.
+  headers.push_back({"baz", "bing"});
+  EXPECT_FALSE(cf0.VerifyHasHeaders(headers));
+  EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+  headers.pop_back();
+  EXPECT_TRUE(cf0.VerifyHasHeaders(headers));
+  EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+  expected_ir.SetHeader("baz", "bing");
+  EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir));
+  EXPECT_TRUE(cf0.VerifyHasHeaders(headers));
+}
+
+TEST_F(SpdyDeframerVisitorTest, PriorityFrame) {
+  const char kFrameData[] = {
+      0x00,   0x00, 0x05,        // Length: 5
+      0x02,                      //   Type: PRIORITY
+      0x00,                      //  Flags: none
+      0x00,   0x00, 0x00, 0x65,  // Stream: 101
+      '\x80', 0x00, 0x00, 0x01,  // Parent: 1 (Exclusive)
+      0x10,                      // Weight: 17
+  };
+
+  EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
+  ASSERT_EQ(1u, collected_frames_.size());
+  const CollectedFrame& cf0 = collected_frames_[0];
+
+  SpdyPriorityIR expected_ir(/* stream_id = */ 101,
+                             /* parent_stream_id = */ 1, /* weight = */ 17,
+                             /* exclusive = */ true);
+  EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+  // Confirm that mismatches are also detected.
+  EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 1, 16, true)));
+  EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 50, 17, true)));
+  EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(201, 1, 17, true)));
+  EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 1, 17, false)));
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_RstStreamFrame) {
+  // TODO(jamessynge): Please implement.
+}
+
+TEST_F(SpdyDeframerVisitorTest, SettingsFrame) {
+  // Settings frame with two entries for the same parameter but with different
+  // values. The last one will be in the decoded SpdySettingsIR, but the vector
+  // of settings will have both, in the same order.
+  const char kFrameData[] = {
+      0x00, 0x00, 0x0c,          // Length
+      0x04,                      // Type (SETTINGS)
+      0x00,                      // Flags
+      0x00, 0x00, 0x00, 0x00,    // Stream id (must be zero)
+      0x00, 0x04,                // Setting id (SETTINGS_INITIAL_WINDOW_SIZE)
+      0x0a, 0x0b, 0x0c, 0x0d,    // Setting value
+      0x00, 0x04,                // Setting id (SETTINGS_INITIAL_WINDOW_SIZE)
+      0x00, 0x00, 0x00, '\xff',  // Setting value
+  };
+
+  EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
+  ASSERT_EQ(1u, collected_frames_.size());
+  const CollectedFrame& cf0 = collected_frames_[0];
+  ASSERT_NE(cf0.frame_ir, nullptr);
+
+  SpdySettingsIR expected_ir;
+  expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 255);
+  EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+  SettingVector expected_settings;
+  expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 0x0a0b0c0d});
+  expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 255});
+
+  EXPECT_TRUE(cf0.VerifyHasSettings(expected_settings));
+
+  // Confirm that mismatches are also detected.
+  expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 65536});
+  EXPECT_FALSE(cf0.VerifyHasSettings(expected_settings));
+
+  expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 65536);
+  EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir));
+
+  SpdySettingsIR unexpected_ir;
+  unexpected_ir.set_is_ack(true);
+  EXPECT_FALSE(cf0.VerifyHasFrame(unexpected_ir));
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_PushPromiseFrame) {
+  // TODO(jamessynge): Please implement.
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_PingFrame) {
+  // TODO(jamessynge): Please implement.
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_GoAwayFrame) {
+  // TODO(jamessynge): Please implement.
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_WindowUpdateFrame) {
+  // TODO(jamessynge): Please implement.
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_AltSvcFrame) {
+  // TODO(jamessynge): Please implement.
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace spdy