| Index: net/http2/hpack/decoder/hpack_string_decoder_test.cc
 | 
| diff --git a/net/http2/hpack/decoder/hpack_string_decoder_test.cc b/net/http2/hpack/decoder/hpack_string_decoder_test.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..e4afc61e4e74bb3a02c34877e6cd534e435a5c85
 | 
| --- /dev/null
 | 
| +++ b/net/http2/hpack/decoder/hpack_string_decoder_test.cc
 | 
| @@ -0,0 +1,194 @@
 | 
| +// 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_string_decoder.h"
 | 
| +
 | 
| +// Tests of HpackStringDecoder.
 | 
| +
 | 
| +#include "base/bind.h"
 | 
| +#include "base/bind_helpers.h"
 | 
| +#include "base/strings/string_piece.h"
 | 
| +#include "net/http2/hpack/decoder/hpack_string_collector.h"
 | 
| +#include "net/http2/hpack/decoder/hpack_string_decoder_listener.h"
 | 
| +#include "net/http2/hpack/tools/hpack_block_builder.h"
 | 
| +#include "net/http2/tools/failure.h"
 | 
| +#include "net/http2/tools/http2_random.h"
 | 
| +#include "net/http2/tools/random_decoder_test.h"
 | 
| +#include "testing/gtest/include/gtest/gtest.h"
 | 
| +
 | 
| +using ::testing::AssertionResult;
 | 
| +using ::testing::AssertionSuccess;
 | 
| +using base::StringPiece;
 | 
| +using std::string;
 | 
| +
 | 
| +namespace net {
 | 
| +namespace test {
 | 
| +namespace {
 | 
| +
 | 
| +const bool kMayReturnZeroOnFirst = false;
 | 
| +const bool kCompressed = true;
 | 
| +const bool kUncompressed = false;
 | 
| +
 | 
| +enum StartMethod {
 | 
| +  kStart,
 | 
| +  kStartOnly,
 | 
| +  kStartAndDecodeLength,
 | 
| +  kStartSpecialCaseShort,
 | 
| +};
 | 
| +
 | 
| +class HpackStringDecoderTest
 | 
| +    : public RandomDecoderTest,
 | 
| +      public ::testing::WithParamInterface<StartMethod> {
 | 
| + protected:
 | 
| +  HpackStringDecoderTest()
 | 
| +      : start_method_(GetParam()), listener_(&collector_) {}
 | 
| +
 | 
| +  DecodeStatus StartDecoding(DecodeBuffer* b) override {
 | 
| +    ++start_decoding_calls_;
 | 
| +    collector_.Clear();
 | 
| +    switch (start_method_) {
 | 
| +      case kStart:
 | 
| +        return decoder_.Start(b, &listener_);
 | 
| +      case kStartOnly:
 | 
| +        return decoder_.StartOnly(b, &listener_);
 | 
| +      case kStartAndDecodeLength:
 | 
| +        return decoder_.StartAndDecodeLength(b, &listener_);
 | 
| +      case kStartSpecialCaseShort:
 | 
| +        return decoder_.StartSpecialCaseShort(b, &listener_);
 | 
| +      default:
 | 
| +        return DecodeStatus::kDecodeError;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  DecodeStatus ResumeDecoding(DecodeBuffer* b) override {
 | 
| +    // Provides coverage of DebugString and StateToString.
 | 
| +    // Not validating output.
 | 
| +    VLOG(1) << decoder_.DebugString();
 | 
| +    VLOG(2) << collector_;
 | 
| +    return decoder_.Resume(b, &listener_);
 | 
| +  }
 | 
| +
 | 
| +  AssertionResult Collected(StringPiece s, bool huffman_encoded) {
 | 
| +    VLOG(1) << collector_;
 | 
| +    return collector_.Collected(s, huffman_encoded);
 | 
| +  }
 | 
| +
 | 
| +  // Note that base::Bind() makes a copy of |expected_str| even though it is
 | 
| +  // taken as a constant reference, so even if MakeValidator is called with a
 | 
| +  // C-style string that is cast to a temporary std::string that gets destroyed
 | 
| +  // after the call to MakeValidator, |expected_str| is still valid later when
 | 
| +  // the Validator is run.
 | 
| +  AssertionResult StringValidator(const string& expected_str,
 | 
| +                                  bool expected_huffman,
 | 
| +                                  const DecodeBuffer& input,
 | 
| +                                  DecodeStatus status) {
 | 
| +    AssertionResult result = Collected(expected_str, expected_huffman);
 | 
| +    if (result) {
 | 
| +      VERIFY_EQ(collector_,
 | 
| +                HpackStringCollector(expected_str, expected_huffman));
 | 
| +    } else {
 | 
| +      VERIFY_NE(collector_,
 | 
| +                HpackStringCollector(expected_str, expected_huffman));
 | 
| +    }
 | 
| +    VLOG(2) << collector_.ToString();
 | 
| +    collector_.Clear();
 | 
| +    VLOG(2) << collector_;
 | 
| +    return result;
 | 
| +  }
 | 
| +
 | 
| +  Validator MakeValidator(const string& expected_str, bool expected_huffman) {
 | 
| +    return base::Bind(&HpackStringDecoderTest::StringValidator,
 | 
| +                      base::Unretained(this), expected_str, expected_huffman);
 | 
| +  }
 | 
| +
 | 
| +  const StartMethod start_method_;
 | 
| +  HpackStringDecoder decoder_;
 | 
| +  HpackStringCollector collector_;
 | 
| +  HpackStringDecoderVLoggingListener listener_;
 | 
| +  size_t start_decoding_calls_ = 0;
 | 
| +};
 | 
| +
 | 
| +TEST_P(HpackStringDecoderTest, DecodeEmptyString) {
 | 
| +  {
 | 
| +    Validator validator = ValidateDoneAndEmpty(MakeValidator("", kCompressed));
 | 
| +    const char kData[] = {0x80u};
 | 
| +    DecodeBuffer b(kData);
 | 
| +    EXPECT_TRUE(
 | 
| +        DecodeAndValidateSeveralWays(&b, kMayReturnZeroOnFirst, validator));
 | 
| +  }
 | 
| +  {
 | 
| +    // Make sure it stops after decoding the empty string.
 | 
| +    Validator validator =
 | 
| +        ValidateDoneAndOffset(1, MakeValidator("", kUncompressed));
 | 
| +    const char kData[] = {0x00, 0xffu};
 | 
| +    DecodeBuffer b(kData);
 | 
| +    EXPECT_EQ(2u, b.Remaining());
 | 
| +    EXPECT_TRUE(
 | 
| +        DecodeAndValidateSeveralWays(&b, kMayReturnZeroOnFirst, validator));
 | 
| +    EXPECT_EQ(1u, b.Remaining());
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +TEST_P(HpackStringDecoderTest, DecodeShortString) {
 | 
| +  {
 | 
| +    // Make sure it stops after decoding the non-empty string.
 | 
| +    Validator validator =
 | 
| +        ValidateDoneAndOffset(11, MakeValidator("start end.", kCompressed));
 | 
| +    const char kData[] = "\x8astart end.Don't peek at this.";
 | 
| +    DecodeBuffer b(kData);
 | 
| +    EXPECT_TRUE(
 | 
| +        DecodeAndValidateSeveralWays(&b, kMayReturnZeroOnFirst, validator));
 | 
| +  }
 | 
| +  {
 | 
| +    Validator validator =
 | 
| +        ValidateDoneAndOffset(11, MakeValidator("start end.", kUncompressed));
 | 
| +    StringPiece data("\x0astart end.");
 | 
| +    DecodeBuffer b(data);
 | 
| +    EXPECT_TRUE(
 | 
| +        DecodeAndValidateSeveralWays(&b, kMayReturnZeroOnFirst, validator));
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +TEST_P(HpackStringDecoderTest, DecodeLongStrings) {
 | 
| +  string name = Random().RandString(1024);
 | 
| +  string value = Random().RandString(65536);
 | 
| +  HpackBlockBuilder hbb;
 | 
| +
 | 
| +  hbb.AppendString(false, name);
 | 
| +  uint32_t offset_after_name = hbb.size();
 | 
| +  EXPECT_EQ(3 + name.size(), offset_after_name);
 | 
| +
 | 
| +  hbb.AppendString(true, value);
 | 
| +  uint32_t offset_after_value = hbb.size();
 | 
| +  EXPECT_EQ(3 + name.size() + 4 + value.size(), offset_after_value);
 | 
| +
 | 
| +  DecodeBuffer b(hbb.buffer());
 | 
| +
 | 
| +  // Decode the name...
 | 
| +  EXPECT_TRUE(DecodeAndValidateSeveralWays(
 | 
| +      &b, kMayReturnZeroOnFirst,
 | 
| +      ValidateDoneAndOffset(offset_after_name,
 | 
| +                            MakeValidator(name, kUncompressed))));
 | 
| +  EXPECT_EQ(offset_after_name, b.Offset());
 | 
| +  EXPECT_EQ(offset_after_value - offset_after_name, b.Remaining());
 | 
| +
 | 
| +  // Decode the value...
 | 
| +  EXPECT_TRUE(DecodeAndValidateSeveralWays(
 | 
| +      &b, kMayReturnZeroOnFirst,
 | 
| +      ValidateDoneAndOffset(offset_after_value - offset_after_name,
 | 
| +                            MakeValidator(value, kCompressed))));
 | 
| +  EXPECT_EQ(offset_after_value, b.Offset());
 | 
| +  EXPECT_EQ(0u, b.Remaining());
 | 
| +}
 | 
| +
 | 
| +INSTANTIATE_TEST_CASE_P(AllStartMethods,
 | 
| +                        HpackStringDecoderTest,
 | 
| +                        ::testing::Values(kStart,
 | 
| +                                          kStartOnly,
 | 
| +                                          kStartAndDecodeLength,
 | 
| +                                          kStartSpecialCaseShort));
 | 
| +
 | 
| +}  // namespace
 | 
| +}  // namespace test
 | 
| +}  // namespace net
 | 
| 
 |