| Index: net/http2/decoder/http2_structure_decoder_test.cc
 | 
| diff --git a/net/http2/decoder/http2_structure_decoder_test.cc b/net/http2/decoder/http2_structure_decoder_test.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..68479a167dd40d51f9133264a634927a2430326f
 | 
| --- /dev/null
 | 
| +++ b/net/http2/decoder/http2_structure_decoder_test.cc
 | 
| @@ -0,0 +1,512 @@
 | 
| +// 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/decoder/http2_structure_decoder.h"
 | 
| +
 | 
| +// Tests decoding all of the fixed size HTTP/2 structures (i.e. those defined in
 | 
| +// net/http2/http2_structures.h) using Http2StructureDecoder, which handles
 | 
| +// buffering of structures split across input buffer boundaries, and in turn
 | 
| +// uses DoDecode when it has all of a structure in a contiguous buffer.
 | 
| +
 | 
| +// NOTE: This tests the first pair of Start and Resume, which don't take
 | 
| +// a remaining_payload parameter. The other pair are well tested via the
 | 
| +// payload decoder tests, though...
 | 
| +// TODO(jamessynge): Create type parameterized tests for Http2StructureDecoder
 | 
| +// where the type is the type of structure, and with testing of both pairs of
 | 
| +// Start and Resume methods; note that it appears that the first pair will be
 | 
| +// used only for Http2FrameHeader, and the other pair only for structures in the
 | 
| +// frame payload.
 | 
| +
 | 
| +#include <stddef.h>
 | 
| +#include <string>
 | 
| +
 | 
| +#include "base/bind.h"
 | 
| +#include "base/bind_helpers.h"
 | 
| +#include "base/logging.h"
 | 
| +#include "base/strings/string_piece.h"
 | 
| +#include "net/http2/decoder/decode_buffer.h"
 | 
| +#include "net/http2/decoder/decode_status.h"
 | 
| +#include "net/http2/http2_constants.h"
 | 
| +#include "net/http2/http2_structures_test_util.h"
 | 
| +#include "net/http2/tools/failure.h"
 | 
| +#include "net/http2/tools/http2_frame_builder.h"
 | 
| +#include "net/http2/tools/random_decoder_test.h"
 | 
| +#include "testing/gtest/include/gtest/gtest.h"
 | 
| +
 | 
| +using ::testing::AssertionFailure;
 | 
| +using ::testing::AssertionResult;
 | 
| +using ::testing::AssertionSuccess;
 | 
| +using base::StringPiece;
 | 
| +using std::string;
 | 
| +
 | 
| +namespace net {
 | 
| +namespace test {
 | 
| +namespace {
 | 
| +const bool kMayReturnZeroOnFirst = false;
 | 
| +
 | 
| +template <class S>
 | 
| +string SerializeStructure(const S& s) {
 | 
| +  Http2FrameBuilder fb;
 | 
| +  fb.Append(s);
 | 
| +  EXPECT_EQ(S::EncodedSize(), fb.size());
 | 
| +  return fb.buffer();
 | 
| +}
 | 
| +
 | 
| +template <class S>
 | 
| +class Http2StructureDecoderTest : public RandomDecoderTest {
 | 
| + protected:
 | 
| +  typedef S Structure;
 | 
| +
 | 
| +  Http2StructureDecoderTest() {
 | 
| +    // IF the test adds more data after the encoded structure, stop as
 | 
| +    // soon as the structure is decoded.
 | 
| +    stop_decode_on_done_ = true;
 | 
| +  }
 | 
| +
 | 
| +  DecodeStatus StartDecoding(DecodeBuffer* b) override {
 | 
| +    // Overwrite the current contents of |structure_|, in to which we'll
 | 
| +    // decode the buffer, so that we can be confident that we really decoded
 | 
| +    // the structure every time.
 | 
| +    structure_.~S();
 | 
| +    new (&structure_) S;
 | 
| +    uint32_t old_remaining = b->Remaining();
 | 
| +    if (structure_decoder_.Start(&structure_, b)) {
 | 
| +      EXPECT_EQ(old_remaining - S::EncodedSize(), b->Remaining());
 | 
| +      ++fast_decode_count_;
 | 
| +      return DecodeStatus::kDecodeDone;
 | 
| +    } else {
 | 
| +      EXPECT_LT(structure_decoder_.offset(), S::EncodedSize());
 | 
| +      EXPECT_EQ(0u, b->Remaining());
 | 
| +      EXPECT_EQ(old_remaining - structure_decoder_.offset(), b->Remaining());
 | 
| +      ++incomplete_start_count_;
 | 
| +      return DecodeStatus::kDecodeInProgress;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  DecodeStatus ResumeDecoding(DecodeBuffer* b) override {
 | 
| +    uint32_t old_offset = structure_decoder_.offset();
 | 
| +    EXPECT_LT(old_offset, S::EncodedSize());
 | 
| +    uint32_t avail = b->Remaining();
 | 
| +    if (structure_decoder_.Resume(&structure_, b)) {
 | 
| +      EXPECT_LE(S::EncodedSize(), old_offset + avail);
 | 
| +      EXPECT_EQ(b->Remaining(), avail - (S::EncodedSize() - old_offset));
 | 
| +      ++slow_decode_count_;
 | 
| +      return DecodeStatus::kDecodeDone;
 | 
| +    } else {
 | 
| +      EXPECT_LT(structure_decoder_.offset(), S::EncodedSize());
 | 
| +      EXPECT_EQ(0u, b->Remaining());
 | 
| +      EXPECT_GT(S::EncodedSize(), old_offset + avail);
 | 
| +      ++incomplete_resume_count_;
 | 
| +      return DecodeStatus::kDecodeInProgress;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  AssertionResult ValidatorForDecodeLeadingStructure(const S* expected,
 | 
| +                                                     const DecodeBuffer& db,
 | 
| +                                                     DecodeStatus status) {
 | 
| +    VERIFY_EQ(*expected, structure_);
 | 
| +    return AssertionSuccess();
 | 
| +  }
 | 
| +
 | 
| +  // Fully decodes the Structure at the start of data, and confirms it matches
 | 
| +  // *expected (if provided).
 | 
| +  AssertionResult DecodeLeadingStructure(const S* expected, StringPiece data) {
 | 
| +    VERIFY_LE(S::EncodedSize(), data.size());
 | 
| +    DecodeBuffer original(data);
 | 
| +
 | 
| +    // The validator is called after each of the several times that the input
 | 
| +    // DecodeBuffer is decoded, each with a different segmentation of the input.
 | 
| +    // Validate that structure_ matches the expected value, if provided.
 | 
| +    Validator validator =
 | 
| +        (expected == nullptr)
 | 
| +            ? base::Bind(&SucceedingValidator)
 | 
| +            : base::Bind(&Http2StructureDecoderTest::
 | 
| +                             ValidatorForDecodeLeadingStructure,
 | 
| +                         base::Unretained(this), expected);
 | 
| +
 | 
| +    // Before that, validate that decoding is done and that we've advanced
 | 
| +    // the cursor the expected amount.
 | 
| +    Validator wrapped_validator =
 | 
| +        ValidateDoneAndOffset(S::EncodedSize(), validator);
 | 
| +
 | 
| +    // Decode several times, with several segmentations of the input buffer.
 | 
| +    fast_decode_count_ = 0;
 | 
| +    slow_decode_count_ = 0;
 | 
| +    incomplete_start_count_ = 0;
 | 
| +    incomplete_resume_count_ = 0;
 | 
| +    VERIFY_SUCCESS(DecodeAndValidateSeveralWays(
 | 
| +        &original, kMayReturnZeroOnFirst, wrapped_validator));
 | 
| +    VERIFY_FALSE(HasFailure());
 | 
| +    VERIFY_EQ(S::EncodedSize(), structure_decoder_.offset());
 | 
| +    VERIFY_EQ(S::EncodedSize(), original.Offset());
 | 
| +    VERIFY_LT(0u, fast_decode_count_);
 | 
| +    VERIFY_LT(0u, slow_decode_count_);
 | 
| +    VERIFY_LT(0u, incomplete_start_count_);
 | 
| +
 | 
| +    // If the structure is large enough so that SelectZeroOrOne will have
 | 
| +    // caused Resume to return false, check that occurred.
 | 
| +    if (S::EncodedSize() >= 2) {
 | 
| +      VERIFY_LE(0u, incomplete_resume_count_);
 | 
| +    } else {
 | 
| +      VERIFY_EQ(0u, incomplete_resume_count_);
 | 
| +    }
 | 
| +    if (expected != nullptr) {
 | 
| +      DVLOG(1) << "DecodeLeadingStructure expected: " << *expected;
 | 
| +      DVLOG(1) << "DecodeLeadingStructure   actual: " << structure_;
 | 
| +      VERIFY_EQ(*expected, structure_);
 | 
| +    }
 | 
| +    return AssertionSuccess();
 | 
| +  }
 | 
| +
 | 
| +  template <size_t N>
 | 
| +  AssertionResult DecodeLeadingStructure(const char (&data)[N]) {
 | 
| +    VERIFY_AND_RETURN_SUCCESS(
 | 
| +        DecodeLeadingStructure(nullptr, StringPiece(data, N)));
 | 
| +  }
 | 
| +
 | 
| +  // Encode the structure |in_s| into bytes, then decode the bytes
 | 
| +  // and validate that the decoder produced the same field values.
 | 
| +  AssertionResult EncodeThenDecode(const S& in_s) {
 | 
| +    string bytes = SerializeStructure(in_s);
 | 
| +    VERIFY_EQ(S::EncodedSize(), bytes.size());
 | 
| +    VERIFY_AND_RETURN_SUCCESS(DecodeLeadingStructure(&in_s, bytes));
 | 
| +  }
 | 
| +
 | 
| +  // Repeatedly fill a structure with random but valid contents, encode it, then
 | 
| +  // decode it, and finally validate that the decoded structure matches the
 | 
| +  // random input. Lather-rinse-and-repeat.
 | 
| +  AssertionResult TestDecodingRandomizedStructures(size_t count) {
 | 
| +    for (size_t i = 0; i < count; ++i) {
 | 
| +      Structure input;
 | 
| +      Randomize(&input, RandomPtr());
 | 
| +      VERIFY_SUCCESS(EncodeThenDecode(input));
 | 
| +    }
 | 
| +    return AssertionSuccess();
 | 
| +  }
 | 
| +
 | 
| +  AssertionResult TestDecodingRandomizedStructures() {
 | 
| +    VERIFY_SUCCESS(TestDecodingRandomizedStructures(100));
 | 
| +    return AssertionSuccess();
 | 
| +  }
 | 
| +
 | 
| +  uint32_t decode_offset_ = 0;
 | 
| +  S structure_;
 | 
| +  Http2StructureDecoder structure_decoder_;
 | 
| +  size_t fast_decode_count_ = 0;
 | 
| +  size_t slow_decode_count_ = 0;
 | 
| +  size_t incomplete_start_count_ = 0;
 | 
| +  size_t incomplete_resume_count_ = 0;
 | 
| +};
 | 
| +
 | 
| +class Http2FrameHeaderDecoderTest
 | 
| +    : public Http2StructureDecoderTest<Http2FrameHeader> {};
 | 
| +
 | 
| +TEST_F(Http2FrameHeaderDecoderTest, DecodesLiteral) {
 | 
| +  {
 | 
| +    // Realistic input.
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x00, 0x05,        // Payload length: 5
 | 
| +        0x01,                    // Frame type: HEADERS
 | 
| +        0x08,                    // Flags: PADDED
 | 
| +        0x00, 0x00, 0x00, 0x01,  // Stream ID: 1
 | 
| +        0x04,                    // Padding length: 4
 | 
| +        0x00, 0x00, 0x00, 0x00,  // Padding bytes
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(5u, structure_.payload_length);
 | 
| +    EXPECT_EQ(Http2FrameType::HEADERS, structure_.type);
 | 
| +    EXPECT_EQ(Http2FrameFlag::FLAG_PADDED, structure_.flags);
 | 
| +    EXPECT_EQ(1u, structure_.stream_id);
 | 
| +  }
 | 
| +  {
 | 
| +    // Unlikely input.
 | 
| +    const char kData[] = {
 | 
| +        0xffu, 0xffu, 0xffu,         // Payload length: uint24 max
 | 
| +        0xffu,                       // Frame type: Unknown
 | 
| +        0xffu,                       // Flags: Unknown/All
 | 
| +        0xffu, 0xffu, 0xffu, 0xffu,  // Stream ID: uint31 max, plus R-bit
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ((1u << 24) - 1u, structure_.payload_length);
 | 
| +    EXPECT_EQ(static_cast<Http2FrameType>(255), structure_.type);
 | 
| +    EXPECT_EQ(255, structure_.flags);
 | 
| +    EXPECT_EQ(0x7FFFFFFFu, structure_.stream_id);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +TEST_F(Http2FrameHeaderDecoderTest, DecodesRandomized) {
 | 
| +  TestDecodingRandomizedStructures();
 | 
| +}
 | 
| +
 | 
| +//------------------------------------------------------------------------------
 | 
| +
 | 
| +class Http2PriorityFieldsDecoderTest
 | 
| +    : public Http2StructureDecoderTest<Http2PriorityFields> {};
 | 
| +
 | 
| +TEST_F(Http2PriorityFieldsDecoderTest, DecodesLiteral) {
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0x80u, 0x00, 0x00, 0x05,  // Exclusive (yes) and Dependency (5)
 | 
| +        0xffu,                    // Weight: 256 (after adding 1)
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(5u, structure_.stream_dependency);
 | 
| +    EXPECT_EQ(256u, structure_.weight);
 | 
| +    EXPECT_EQ(true, structure_.is_exclusive);
 | 
| +  }
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0x7fu, 0xffu,
 | 
| +        0xffu, 0xffu,  // Exclusive (no) and Dependency (0x7fffffff)
 | 
| +        0x00u,         // Weight: 1 (after adding 1)
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(StreamIdMask(), structure_.stream_dependency);
 | 
| +    EXPECT_EQ(1u, structure_.weight);
 | 
| +    EXPECT_FALSE(structure_.is_exclusive);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +TEST_F(Http2PriorityFieldsDecoderTest, DecodesRandomized) {
 | 
| +  TestDecodingRandomizedStructures();
 | 
| +}
 | 
| +
 | 
| +//------------------------------------------------------------------------------
 | 
| +
 | 
| +class Http2RstStreamFieldsDecoderTest
 | 
| +    : public Http2StructureDecoderTest<Http2RstStreamFields> {};
 | 
| +
 | 
| +TEST_F(Http2RstStreamFieldsDecoderTest, DecodesLiteral) {
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x00, 0x00, 0x01,  // Error: PROTOCOL_ERROR
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_TRUE(structure_.IsSupportedErrorCode());
 | 
| +    EXPECT_EQ(Http2ErrorCode::PROTOCOL_ERROR, structure_.error_code);
 | 
| +  }
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0xffu, 0xffu, 0xffu, 0xffu,  // Error: max uint32 (Unknown error code)
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_FALSE(structure_.IsSupportedErrorCode());
 | 
| +    EXPECT_EQ(static_cast<Http2ErrorCode>(0xffffffff), structure_.error_code);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +TEST_F(Http2RstStreamFieldsDecoderTest, DecodesRandomized) {
 | 
| +  TestDecodingRandomizedStructures();
 | 
| +}
 | 
| +
 | 
| +//------------------------------------------------------------------------------
 | 
| +
 | 
| +class Http2SettingFieldsDecoderTest
 | 
| +    : public Http2StructureDecoderTest<Http2SettingFields> {};
 | 
| +
 | 
| +TEST_F(Http2SettingFieldsDecoderTest, DecodesLiteral) {
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x01,              // Setting: HEADER_TABLE_SIZE
 | 
| +        0x00, 0x00, 0x40, 0x00,  // Value: 16K
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_TRUE(structure_.IsSupportedParameter());
 | 
| +    EXPECT_EQ(Http2SettingsParameter::HEADER_TABLE_SIZE, structure_.parameter);
 | 
| +    EXPECT_EQ(1u << 14, structure_.value);
 | 
| +  }
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0x00,  0x00,                 // Setting: Unknown (0)
 | 
| +        0xffu, 0xffu, 0xffu, 0xffu,  // Value: max uint32
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_FALSE(structure_.IsSupportedParameter());
 | 
| +    EXPECT_EQ(static_cast<Http2SettingsParameter>(0), structure_.parameter);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +TEST_F(Http2SettingFieldsDecoderTest, DecodesRandomized) {
 | 
| +  TestDecodingRandomizedStructures();
 | 
| +}
 | 
| +
 | 
| +//------------------------------------------------------------------------------
 | 
| +
 | 
| +class Http2PushPromiseFieldsDecoderTest
 | 
| +    : public Http2StructureDecoderTest<Http2PushPromiseFields> {};
 | 
| +
 | 
| +TEST_F(Http2PushPromiseFieldsDecoderTest, DecodesLiteral) {
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x01, 0x8au, 0x92u,  // Promised Stream ID: 101010
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(101010u, structure_.promised_stream_id);
 | 
| +  }
 | 
| +  {
 | 
| +    // Promised stream id has R-bit (reserved for future use) set, which
 | 
| +    // should be cleared by the decoder.
 | 
| +    const char kData[] = {
 | 
| +        0xffu, 0xffu, 0xffu, 0xffu,  // Promised Stream ID: max uint31 and R-bit
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(StreamIdMask(), structure_.promised_stream_id);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +TEST_F(Http2PushPromiseFieldsDecoderTest, DecodesRandomized) {
 | 
| +  TestDecodingRandomizedStructures();
 | 
| +}
 | 
| +
 | 
| +//------------------------------------------------------------------------------
 | 
| +
 | 
| +class Http2PingFieldsDecoderTest
 | 
| +    : public Http2StructureDecoderTest<Http2PingFields> {};
 | 
| +
 | 
| +TEST_F(Http2PingFieldsDecoderTest, DecodesLiteral) {
 | 
| +  {
 | 
| +    // Each byte is different, so can detect if order changed.
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(StringPiece(kData, 8), ToStringPiece(structure_.opaque_data));
 | 
| +  }
 | 
| +  {
 | 
| +    // All zeros, detect problems handling NULs.
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(StringPiece(kData, 8), ToStringPiece(structure_.opaque_data));
 | 
| +  }
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(StringPiece(kData, 8), ToStringPiece(structure_.opaque_data));
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +TEST_F(Http2PingFieldsDecoderTest, DecodesRandomized) {
 | 
| +  TestDecodingRandomizedStructures();
 | 
| +}
 | 
| +
 | 
| +//------------------------------------------------------------------------------
 | 
| +
 | 
| +class Http2GoAwayFieldsDecoderTest
 | 
| +    : public Http2StructureDecoderTest<Http2GoAwayFields> {};
 | 
| +
 | 
| +TEST_F(Http2GoAwayFieldsDecoderTest, DecodesLiteral) {
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x00, 0x00, 0x00,  // Last Stream ID: 0
 | 
| +        0x00, 0x00, 0x00, 0x00,  // Error: NO_ERROR (0)
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(0u, structure_.last_stream_id);
 | 
| +    EXPECT_TRUE(structure_.IsSupportedErrorCode());
 | 
| +    EXPECT_EQ(Http2ErrorCode::HTTP2_NO_ERROR, structure_.error_code);
 | 
| +  }
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x00, 0x00, 0x01,  // Last Stream ID: 1
 | 
| +        0x00, 0x00, 0x00, 0x0d,  // Error: HTTP_1_1_REQUIRED
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(1u, structure_.last_stream_id);
 | 
| +    EXPECT_TRUE(structure_.IsSupportedErrorCode());
 | 
| +    EXPECT_EQ(Http2ErrorCode::HTTP_1_1_REQUIRED, structure_.error_code);
 | 
| +  }
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0xffu, 0xffu, 0xffu, 0xffu,  // Last Stream ID: max uint31 and R-bit
 | 
| +        0xffu, 0xffu, 0xffu, 0xffu,  // Error: max uint32 (Unknown error code)
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(StreamIdMask(), structure_.last_stream_id);  // No high-bit.
 | 
| +    EXPECT_FALSE(structure_.IsSupportedErrorCode());
 | 
| +    EXPECT_EQ(static_cast<Http2ErrorCode>(0xffffffff), structure_.error_code);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +TEST_F(Http2GoAwayFieldsDecoderTest, DecodesRandomized) {
 | 
| +  TestDecodingRandomizedStructures();
 | 
| +}
 | 
| +
 | 
| +//------------------------------------------------------------------------------
 | 
| +
 | 
| +class Http2WindowUpdateFieldsDecoderTest
 | 
| +    : public Http2StructureDecoderTest<Http2WindowUpdateFields> {};
 | 
| +
 | 
| +TEST_F(Http2WindowUpdateFieldsDecoderTest, DecodesLiteral) {
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x01, 0x00, 0x00,  // Window Size Increment: 2 ^ 16
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(1u << 16, structure_.window_size_increment);
 | 
| +  }
 | 
| +  {
 | 
| +    // Increment must be non-zero, but we need to be able to decode the invalid
 | 
| +    // zero to detect it.
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x00, 0x00, 0x00,  // Window Size Increment: 0
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(0u, structure_.window_size_increment);
 | 
| +  }
 | 
| +  {
 | 
| +    // Increment has R-bit (reserved for future use) set, which
 | 
| +    // should be cleared by the decoder.
 | 
| +    const char kData[] = {
 | 
| +        0xffu, 0xffu, 0xffu,
 | 
| +        0xffu,  // Window Size Increment: max uint31 and R-bit
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(StreamIdMask(), structure_.window_size_increment);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +TEST_F(Http2WindowUpdateFieldsDecoderTest, DecodesRandomized) {
 | 
| +  TestDecodingRandomizedStructures();
 | 
| +}
 | 
| +
 | 
| +//------------------------------------------------------------------------------
 | 
| +
 | 
| +class Http2AltSvcFieldsDecoderTest
 | 
| +    : public Http2StructureDecoderTest<Http2AltSvcFields> {};
 | 
| +
 | 
| +TEST_F(Http2AltSvcFieldsDecoderTest, DecodesLiteral) {
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x00,  // Origin Length: 0
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(0, structure_.origin_length);
 | 
| +  }
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0x00, 0x14,  // Origin Length: 20
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(20, structure_.origin_length);
 | 
| +  }
 | 
| +  {
 | 
| +    const char kData[] = {
 | 
| +        0xffu, 0xffu,  // Origin Length: uint16 max
 | 
| +    };
 | 
| +    ASSERT_TRUE(DecodeLeadingStructure(kData));
 | 
| +    EXPECT_EQ(65535, structure_.origin_length);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +TEST_F(Http2AltSvcFieldsDecoderTest, DecodesRandomized) {
 | 
| +  TestDecodingRandomizedStructures();
 | 
| +}
 | 
| +
 | 
| +}  // namespace
 | 
| +}  // namespace test
 | 
| +}  // namespace net
 | 
| 
 |