Project import generated by Copybara.

PiperOrigin-RevId: 224614037
Change-Id: I14e53449d4aeccb328f86828c76b5f09dea0d4b8
diff --git a/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc b/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc
new file mode 100644
index 0000000..009b894
--- /dev/null
+++ b/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc
@@ -0,0 +1,251 @@
+// 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/http2/hpack/decoder/hpack_decoder_string_buffer.h"
+
+// Tests of HpackDecoderStringBuffer.
+
+#include <initializer_list>
+
+#include "base/logging.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
+
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+using ::testing::HasSubstr;
+
+namespace http2 {
+namespace test {
+namespace {
+
+class HpackDecoderStringBufferTest : public ::testing::Test {
+ protected:
+  typedef HpackDecoderStringBuffer::State State;
+  typedef HpackDecoderStringBuffer::Backing Backing;
+
+  State state() const { return buf_.state_for_testing(); }
+  Backing backing() const { return buf_.backing_for_testing(); }
+
+  // We want to know that LOG(x) << buf_ will work in production should that
+  // be needed, so we test that it outputs the expected values.
+  AssertionResult VerifyLogHasSubstrs(std::initializer_list<Http2String> strs) {
+    VLOG(1) << buf_;
+    std::ostringstream ss;
+    buf_.OutputDebugStringTo(ss);
+    Http2String dbg_str(ss.str());
+    for (const auto& expected : strs) {
+      VERIFY_THAT(dbg_str, HasSubstr(expected));
+    }
+    return AssertionSuccess();
+  }
+
+  HpackDecoderStringBuffer buf_;
+};
+
+TEST_F(HpackDecoderStringBufferTest, SetStatic) {
+  Http2StringPiece data("static string");
+
+  EXPECT_EQ(state(), State::RESET);
+  EXPECT_TRUE(VerifyLogHasSubstrs({"state=RESET"}));
+
+  buf_.Set(data, /*is_static*/ true);
+  LOG(INFO) << buf_;
+  EXPECT_EQ(state(), State::COMPLETE);
+  EXPECT_EQ(backing(), Backing::STATIC);
+  EXPECT_EQ(data, buf_.str());
+  EXPECT_EQ(data.data(), buf_.str().data());
+  EXPECT_TRUE(VerifyLogHasSubstrs(
+      {"state=COMPLETE", "backing=STATIC", "value: static string"}));
+
+  // The string is static, so BufferStringIfUnbuffered won't change anything.
+  buf_.BufferStringIfUnbuffered();
+  EXPECT_EQ(state(), State::COMPLETE);
+  EXPECT_EQ(backing(), Backing::STATIC);
+  EXPECT_EQ(data, buf_.str());
+  EXPECT_EQ(data.data(), buf_.str().data());
+  EXPECT_TRUE(VerifyLogHasSubstrs(
+      {"state=COMPLETE", "backing=STATIC", "value: static string"}));
+}
+
+TEST_F(HpackDecoderStringBufferTest, PlainWhole) {
+  Http2StringPiece data("some text.");
+
+  LOG(INFO) << buf_;
+  EXPECT_EQ(state(), State::RESET);
+
+  buf_.OnStart(/*huffman_encoded*/ false, data.size());
+  EXPECT_EQ(state(), State::COLLECTING);
+  EXPECT_EQ(backing(), Backing::RESET);
+  LOG(INFO) << buf_;
+
+  EXPECT_TRUE(buf_.OnData(data.data(), data.size()));
+  EXPECT_EQ(state(), State::COLLECTING);
+  EXPECT_EQ(backing(), Backing::UNBUFFERED);
+
+  EXPECT_TRUE(buf_.OnEnd());
+  EXPECT_EQ(state(), State::COMPLETE);
+  EXPECT_EQ(backing(), Backing::UNBUFFERED);
+  EXPECT_EQ(0u, buf_.BufferedLength());
+  EXPECT_TRUE(VerifyLogHasSubstrs(
+      {"state=COMPLETE", "backing=UNBUFFERED", "value: some text."}));
+
+  // We expect that the string buffer points to the passed in Http2StringPiece's
+  // backing store.
+  EXPECT_EQ(data.data(), buf_.str().data());
+
+  // Now force it to buffer the string, after which it will still have the same
+  // string value, but the backing store will be different.
+  buf_.BufferStringIfUnbuffered();
+  LOG(INFO) << buf_;
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+  EXPECT_EQ(buf_.BufferedLength(), data.size());
+  EXPECT_EQ(data, buf_.str());
+  EXPECT_NE(data.data(), buf_.str().data());
+  EXPECT_TRUE(VerifyLogHasSubstrs(
+      {"state=COMPLETE", "backing=BUFFERED", "buffer: some text."}));
+}
+
+TEST_F(HpackDecoderStringBufferTest, PlainSplit) {
+  Http2StringPiece data("some text.");
+  Http2StringPiece part1 = data.substr(0, 1);
+  Http2StringPiece part2 = data.substr(1);
+
+  EXPECT_EQ(state(), State::RESET);
+  buf_.OnStart(/*huffman_encoded*/ false, data.size());
+  EXPECT_EQ(state(), State::COLLECTING);
+  EXPECT_EQ(backing(), Backing::RESET);
+
+  // OnData with only a part of the data, not the whole, so buf_ will buffer
+  // the data.
+  EXPECT_TRUE(buf_.OnData(part1.data(), part1.size()));
+  EXPECT_EQ(state(), State::COLLECTING);
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+  EXPECT_EQ(buf_.BufferedLength(), part1.size());
+  LOG(INFO) << buf_;
+
+  EXPECT_TRUE(buf_.OnData(part2.data(), part2.size()));
+  EXPECT_EQ(state(), State::COLLECTING);
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+  EXPECT_EQ(buf_.BufferedLength(), data.size());
+
+  EXPECT_TRUE(buf_.OnEnd());
+  EXPECT_EQ(state(), State::COMPLETE);
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+  EXPECT_EQ(buf_.BufferedLength(), data.size());
+  LOG(INFO) << buf_;
+
+  Http2StringPiece buffered = buf_.str();
+  EXPECT_EQ(data, buffered);
+  EXPECT_NE(data.data(), buffered.data());
+
+  // The string is already buffered, so BufferStringIfUnbuffered should not make
+  // any change.
+  buf_.BufferStringIfUnbuffered();
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+  EXPECT_EQ(buf_.BufferedLength(), data.size());
+  EXPECT_EQ(buffered, buf_.str());
+  EXPECT_EQ(buffered.data(), buf_.str().data());
+}
+
+TEST_F(HpackDecoderStringBufferTest, HuffmanWhole) {
+  Http2String encoded = Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff");
+  Http2StringPiece decoded("www.example.com");
+
+  EXPECT_EQ(state(), State::RESET);
+  buf_.OnStart(/*huffman_encoded*/ true, encoded.size());
+  EXPECT_EQ(state(), State::COLLECTING);
+
+  EXPECT_TRUE(buf_.OnData(encoded.data(), encoded.size()));
+  EXPECT_EQ(state(), State::COLLECTING);
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+
+  EXPECT_TRUE(buf_.OnEnd());
+  EXPECT_EQ(state(), State::COMPLETE);
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+  EXPECT_EQ(buf_.BufferedLength(), decoded.size());
+  EXPECT_EQ(decoded, buf_.str());
+  EXPECT_TRUE(VerifyLogHasSubstrs(
+      {"{state=COMPLETE", "backing=BUFFERED", "buffer: www.example.com}"}));
+
+  Http2String s = buf_.ReleaseString();
+  EXPECT_EQ(s, decoded);
+  EXPECT_EQ(state(), State::RESET);
+}
+
+TEST_F(HpackDecoderStringBufferTest, HuffmanSplit) {
+  Http2String encoded = Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff");
+  Http2String part1 = encoded.substr(0, 5);
+  Http2String part2 = encoded.substr(5);
+  Http2StringPiece decoded("www.example.com");
+
+  EXPECT_EQ(state(), State::RESET);
+  buf_.OnStart(/*huffman_encoded*/ true, encoded.size());
+  EXPECT_EQ(state(), State::COLLECTING);
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+  EXPECT_EQ(0u, buf_.BufferedLength());
+  LOG(INFO) << buf_;
+
+  EXPECT_TRUE(buf_.OnData(part1.data(), part1.size()));
+  EXPECT_EQ(state(), State::COLLECTING);
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+  EXPECT_GT(buf_.BufferedLength(), 0u);
+  EXPECT_LT(buf_.BufferedLength(), decoded.size());
+  LOG(INFO) << buf_;
+
+  EXPECT_TRUE(buf_.OnData(part2.data(), part2.size()));
+  EXPECT_EQ(state(), State::COLLECTING);
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+  EXPECT_EQ(buf_.BufferedLength(), decoded.size());
+  LOG(INFO) << buf_;
+
+  EXPECT_TRUE(buf_.OnEnd());
+  EXPECT_EQ(state(), State::COMPLETE);
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+  EXPECT_EQ(buf_.BufferedLength(), decoded.size());
+  EXPECT_EQ(decoded, buf_.str());
+  LOG(INFO) << buf_;
+
+  buf_.Reset();
+  EXPECT_EQ(state(), State::RESET);
+  LOG(INFO) << buf_;
+}
+
+TEST_F(HpackDecoderStringBufferTest, InvalidHuffmanOnData) {
+  // Explicitly encode the End-of-String symbol, a no-no.
+  Http2String encoded = Http2HexDecode("ffffffff");
+
+  buf_.OnStart(/*huffman_encoded*/ true, encoded.size());
+  EXPECT_EQ(state(), State::COLLECTING);
+
+  EXPECT_FALSE(buf_.OnData(encoded.data(), encoded.size()));
+  EXPECT_EQ(state(), State::COLLECTING);
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+
+  LOG(INFO) << buf_;
+}
+
+TEST_F(HpackDecoderStringBufferTest, InvalidHuffmanOnEnd) {
+  // Last byte of string doesn't end with prefix of End-of-String symbol.
+  Http2String encoded = Http2HexDecode("00");
+
+  buf_.OnStart(/*huffman_encoded*/ true, encoded.size());
+  EXPECT_EQ(state(), State::COLLECTING);
+
+  EXPECT_TRUE(buf_.OnData(encoded.data(), encoded.size()));
+  EXPECT_EQ(state(), State::COLLECTING);
+  EXPECT_EQ(backing(), Backing::BUFFERED);
+
+  EXPECT_FALSE(buf_.OnEnd());
+  LOG(INFO) << buf_;
+}
+
+// TODO(jamessynge): Add tests for ReleaseString().
+
+}  // namespace
+}  // namespace test
+}  // namespace http2