| Index: net/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc
 | 
| diff --git a/net/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc b/net/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..313a4570c432b3b7855c871968d5e7d673fb7701
 | 
| --- /dev/null
 | 
| +++ b/net/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc
 | 
| @@ -0,0 +1,245 @@
 | 
| +// 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/http2/hpack/decoder/hpack_decoder_string_buffer.h"
 | 
| +
 | 
| +// Tests of HpackDecoderStringBuffer.
 | 
| +
 | 
| +#include <initializer_list>
 | 
| +#include <sstream>
 | 
| +#include <string>
 | 
| +
 | 
| +#include "base/logging.h"
 | 
| +#include "base/strings/string_piece.h"
 | 
| +#include "net/http2/tools/failure.h"
 | 
| +#include "net/spdy/spdy_test_utils.h"
 | 
| +#include "testing/gmock/include/gmock/gmock.h"
 | 
| +#include "testing/gtest/include/gtest/gtest.h"
 | 
| +
 | 
| +using ::testing::AssertionResult;
 | 
| +using ::testing::AssertionSuccess;
 | 
| +using ::testing::HasSubstr;
 | 
| +using base::StringPiece;
 | 
| +using std::string;
 | 
| +
 | 
| +namespace net {
 | 
| +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<string> strs) {
 | 
| +    VLOG(1) << buf_;
 | 
| +    std::ostringstream ss;
 | 
| +    buf_.OutputDebugStringTo(ss);
 | 
| +    string dbg_str(ss.str());
 | 
| +    for (const auto& expected : strs) {
 | 
| +      VERIFY_THAT(dbg_str, HasSubstr(expected));
 | 
| +    }
 | 
| +    return AssertionSuccess();
 | 
| +  }
 | 
| +
 | 
| +  HpackDecoderStringBuffer buf_;
 | 
| +};
 | 
| +
 | 
| +TEST_F(HpackDecoderStringBufferTest, SetStatic) {
 | 
| +  StringPiece 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) {
 | 
| +  StringPiece 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 StringPiece'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) {
 | 
| +  StringPiece data("some text.");
 | 
| +  StringPiece part1 = data.substr(0, 1);
 | 
| +  StringPiece 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_;
 | 
| +
 | 
| +  StringPiece 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) {
 | 
| +  string encoded = a2b_hex("f1e3c2e5f23a6ba0ab90f4ff");
 | 
| +  StringPiece 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}"}));
 | 
| +}
 | 
| +
 | 
| +TEST_F(HpackDecoderStringBufferTest, HuffmanSplit) {
 | 
| +  string encoded = a2b_hex("f1e3c2e5f23a6ba0ab90f4ff");
 | 
| +  string part1 = encoded.substr(0, 5);
 | 
| +  string part2 = encoded.substr(5);
 | 
| +  StringPiece 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_;
 | 
| +}
 | 
| +
 | 
| +TEST_F(HpackDecoderStringBufferTest, InvalidHuffmanOnData) {
 | 
| +  // Explicitly encode the End-of-String symbol, a no-no.
 | 
| +  string encoded = a2b_hex("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.
 | 
| +  string encoded = a2b_hex("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_;
 | 
| +}
 | 
| +
 | 
| +}  // namespace
 | 
| +}  // namespace test
 | 
| +}  // namespace net
 | 
| 
 |