Project import generated by Copybara.

PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/qpack/qpack_decoder_test.cc b/quic/core/qpack/qpack_decoder_test.cc
new file mode 100644
index 0000000..7292c50
--- /dev/null
+++ b/quic/core/qpack/qpack_decoder_test.cc
@@ -0,0 +1,701 @@
+// Copyright (c) 2018 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/quic/core/qpack/qpack_decoder.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
+
+using ::testing::Eq;
+using ::testing::Sequence;
+using ::testing::StrictMock;
+using ::testing::Values;
+
+namespace quic {
+namespace test {
+namespace {
+
+// Header Acknowledgement decoder stream instruction with stream_id = 1.
+const char* const kHeaderAcknowledgement = "\x81";
+
+class QpackDecoderTest : public QuicTestWithParam<FragmentMode> {
+ protected:
+  QpackDecoderTest()
+      : qpack_decoder_(&encoder_stream_error_delegate_,
+                       &decoder_stream_sender_delegate_),
+        fragment_mode_(GetParam()) {
+    qpack_decoder_.SetMaximumDynamicTableCapacity(1024);
+  }
+
+  ~QpackDecoderTest() override = default;
+
+  void DecodeEncoderStreamData(QuicStringPiece data) {
+    qpack_decoder_.DecodeEncoderStreamData(data);
+  }
+
+  void DecodeHeaderBlock(QuicStringPiece data) {
+    auto fragment_size_generator =
+        FragmentModeToFragmentSizeGenerator(fragment_mode_);
+    auto progressive_decoder =
+        qpack_decoder_.DecodeHeaderBlock(/* stream_id = */ 1, &handler_);
+    while (!data.empty()) {
+      size_t fragment_size = std::min(fragment_size_generator(), data.size());
+      progressive_decoder->Decode(data.substr(0, fragment_size));
+      data = data.substr(fragment_size);
+    }
+    progressive_decoder->EndHeaderBlock();
+  }
+
+  StrictMock<MockEncoderStreamErrorDelegate> encoder_stream_error_delegate_;
+  StrictMock<MockDecoderStreamSenderDelegate> decoder_stream_sender_delegate_;
+  StrictMock<MockHeadersHandler> handler_;
+
+ private:
+  QpackDecoder qpack_decoder_;
+  const FragmentMode fragment_mode_;
+};
+
+INSTANTIATE_TEST_SUITE_P(, QpackDecoderTest, Values(FragmentMode::kSingleChunk,
+                                                  FragmentMode::kOctetByOctet));
+
+TEST_P(QpackDecoderTest, NoPrefix) {
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Incomplete header data prefix.")));
+
+  // Header Data Prefix is at least two bytes long.
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("00"));
+}
+
+TEST_P(QpackDecoderTest, EmptyHeaderBlock) {
+  EXPECT_CALL(handler_, OnDecodingCompleted());
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("0000"));
+}
+
+TEST_P(QpackDecoderTest, LiteralEntryEmptyName) {
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("foo")));
+  EXPECT_CALL(handler_, OnDecodingCompleted());
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("00002003666f6f"));
+}
+
+TEST_P(QpackDecoderTest, LiteralEntryEmptyValue) {
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
+  EXPECT_CALL(handler_, OnDecodingCompleted());
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f00"));
+}
+
+TEST_P(QpackDecoderTest, LiteralEntryEmptyNameAndValue) {
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("")));
+  EXPECT_CALL(handler_, OnDecodingCompleted());
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("00002000"));
+}
+
+TEST_P(QpackDecoderTest, SimpleLiteralEntry) {
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
+  EXPECT_CALL(handler_, OnDecodingCompleted());
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f03626172"));
+}
+
+TEST_P(QpackDecoderTest, MultipleLiteralEntries) {
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
+  QuicString str(127, 'a');
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foobaar"), QuicStringPiece(str)));
+  EXPECT_CALL(handler_, OnDecodingCompleted());
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0000"                // prefix
+      "23666f6f03626172"    // foo: bar
+      "2700666f6f62616172"  // 7 octet long header name, the smallest number
+                            // that does not fit on a 3-bit prefix.
+      "7f0061616161616161"  // 127 octet long header value, the smallest number
+      "616161616161616161"  // that does not fit on a 7-bit prefix.
+      "6161616161616161616161616161616161616161616161616161616161616161616161"
+      "6161616161616161616161616161616161616161616161616161616161616161616161"
+      "6161616161616161616161616161616161616161616161616161616161616161616161"
+      "616161616161"));
+}
+
+// Name Length value is too large for varint decoder to decode.
+TEST_P(QpackDecoderTest, NameLenTooLargeForVarintDecoder) {
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Encoded integer too large.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("000027ffffffffffffffffffff"));
+}
+
+// Name Length value can be decoded by varint decoder but exceeds 1 MB limit.
+TEST_P(QpackDecoderTest, NameLenExceedsLimit) {
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("String literal too long.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("000027ffff7f"));
+}
+
+// Value Length value is too large for varint decoder to decode.
+TEST_P(QpackDecoderTest, ValueLenTooLargeForVarintDecoder) {
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Encoded integer too large.")));
+
+  DecodeHeaderBlock(
+      QuicTextUtils::HexDecode("000023666f6f7fffffffffffffffffffff"));
+}
+
+// Value Length value can be decoded by varint decoder but exceeds 1 MB limit.
+TEST_P(QpackDecoderTest, ValueLenExceedsLimit) {
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("String literal too long.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f7fffff7f"));
+}
+
+TEST_P(QpackDecoderTest, IncompleteHeaderBlock) {
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Incomplete header block.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("00002366"));
+}
+
+TEST_P(QpackDecoderTest, HuffmanSimple) {
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")));
+  EXPECT_CALL(handler_, OnDecodingCompleted());
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+  DecodeHeaderBlock(
+      QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"));
+}
+
+TEST_P(QpackDecoderTest, AlternatingHuffmanNonHuffman) {
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")))
+      .Times(4);
+  EXPECT_CALL(handler_, OnDecodingCompleted());
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0000"                        // Prefix.
+      "2f0125a849e95ba97d7f"        // Huffman-encoded name.
+      "8925a849e95bb8e8b4bf"        // Huffman-encoded value.
+      "2703637573746f6d2d6b6579"    // Non-Huffman encoded name.
+      "0c637573746f6d2d76616c7565"  // Non-Huffman encoded value.
+      "2f0125a849e95ba97d7f"        // Huffman-encoded name.
+      "0c637573746f6d2d76616c7565"  // Non-Huffman encoded value.
+      "2703637573746f6d2d6b6579"    // Non-Huffman encoded name.
+      "8925a849e95bb8e8b4bf"));     // Huffman-encoded value.
+}
+
+TEST_P(QpackDecoderTest, HuffmanNameDoesNotHaveEOSPrefix) {
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(QuicStringPiece(
+                            "Error in Huffman-encoded string.")));
+
+  // 'y' ends in 0b0 on the most significant bit of the last byte.
+  // The remaining 7 bits must be a prefix of EOS, which is all 1s.
+  DecodeHeaderBlock(
+      QuicTextUtils::HexDecode("00002f0125a849e95ba97d7e8925a849e95bb8e8b4bf"));
+}
+
+TEST_P(QpackDecoderTest, HuffmanValueDoesNotHaveEOSPrefix) {
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(QuicStringPiece(
+                            "Error in Huffman-encoded string.")));
+
+  // 'e' ends in 0b101, taking up the 3 most significant bits of the last byte.
+  // The remaining 5 bits must be a prefix of EOS, which is all 1s.
+  DecodeHeaderBlock(
+      QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4be"));
+}
+
+TEST_P(QpackDecoderTest, HuffmanNameEOSPrefixTooLong) {
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(QuicStringPiece(
+                            "Error in Huffman-encoded string.")));
+
+  // The trailing EOS prefix must be at most 7 bits long.  Appending one octet
+  // with value 0xff is invalid, even though 0b111111111111111 (15 bits) is a
+  // prefix of EOS.
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "00002f0225a849e95ba97d7fff8925a849e95bb8e8b4bf"));
+}
+
+TEST_P(QpackDecoderTest, HuffmanValueEOSPrefixTooLong) {
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(QuicStringPiece(
+                            "Error in Huffman-encoded string.")));
+
+  // The trailing EOS prefix must be at most 7 bits long.  Appending one octet
+  // with value 0xff is invalid, even though 0b1111111111111 (13 bits) is a
+  // prefix of EOS.
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "00002f0125a849e95ba97d7f8a25a849e95bb8e8b4bfff"));
+}
+
+TEST_P(QpackDecoderTest, StaticTable) {
+  // A header name that has multiple entries with different values.
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("POST")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("TRACE")));
+
+  // A header name that has a single entry with non-empty value.
+  EXPECT_CALL(handler_,
+              OnHeaderDecoded(Eq("accept-encoding"), Eq("gzip, deflate, br")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("accept-encoding"), Eq("compress")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("accept-encoding"), Eq("")));
+
+  // A header name that has a single entry with empty value.
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("location"), Eq("")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("location"), Eq("foo")));
+
+  EXPECT_CALL(handler_, OnDecodingCompleted());
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0000d1dfccd45f108621e9aec2a11f5c8294e75f000554524143455f1000"));
+}
+
+TEST_P(QpackDecoderTest, TooHighStaticTableIndex) {
+  // This is the last entry in the static table with index 98.
+  EXPECT_CALL(handler_,
+              OnHeaderDecoded(Eq("x-frame-options"), Eq("sameorigin")));
+
+  // Addressing entry 99 should trigger an error.
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Static table entry not found.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("0000ff23ff24"));
+}
+
+TEST_P(QpackDecoderTest, DynamicTable) {
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode(
+      "6294e703626172"  // Add literal entry with name "foo" and value "bar".
+      "80035a5a5a"      // Add entry with name of dynamic table entry index 0
+                        // (relative index) and value "ZZZ".
+      "cf8294e7"        // Add entry with name of static table entry index 15
+                        // and value "foo".
+      "01"));           // Duplicate entry with relative index 1.
+
+  // Now there are four entries in the dynamic table.
+  // Entry 0: "foo", "bar"
+  // Entry 1: "foo", "ZZZ"
+  // Entry 2: ":method", "foo"
+  // Entry 3: "foo", "ZZZ"
+
+  // Use a Sequence to test that mock methods are called in order.
+  Sequence s;
+
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar"))).InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("foo")))
+      .InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
+      .InSequence(s);
+  EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0500"  // Required Insert Count 4 and Delta Base 0.
+              // Base is 4 + 0 = 4.
+      "83"    // Dynamic table entry with relative index 3, absolute index 0.
+      "82"    // Dynamic table entry with relative index 2, absolute index 1.
+      "81"    // Dynamic table entry with relative index 1, absolute index 2.
+      "80"    // Dynamic table entry with relative index 0, absolute index 3.
+      "41025a5a"));  // Name of entry 1 (relative index) from dynamic table,
+                     // with value "ZZ".
+
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar"))).InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("foo")))
+      .InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
+      .InSequence(s);
+  EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0502"  // Required Insert Count 4 and Delta Base 2.
+              // Base is 4 + 2 = 6.
+      "85"    // Dynamic table entry with relative index 5, absolute index 0.
+      "84"    // Dynamic table entry with relative index 4, absolute index 1.
+      "83"    // Dynamic table entry with relative index 3, absolute index 2.
+      "82"    // Dynamic table entry with relative index 2, absolute index 3.
+      "43025a5a"));  // Name of entry 3 (relative index) from dynamic table,
+                     // with value "ZZ".
+
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar"))).InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("foo")))
+      .InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
+      .InSequence(s);
+  EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0582"  // Required Insert Count 4 and Delta Base 2 with sign bit set.
+              // Base is 4 - 2 - 1 = 1.
+      "80"    // Dynamic table entry with relative index 0, absolute index 0.
+      "10"    // Dynamic table entry with post-base index 0, absolute index 1.
+      "11"    // Dynamic table entry with post-base index 1, absolute index 2.
+      "12"    // Dynamic table entry with post-base index 2, absolute index 3.
+      "01025a5a"));  // Name of entry 1 (post-base index) from dynamic table,
+                     // with value "ZZ".
+}
+
+TEST_P(QpackDecoderTest, DecreasingDynamicTableCapacityEvictsEntries) {
+  // Add literal entry with name "foo" and value "bar".
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
+
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
+  EXPECT_CALL(handler_, OnDecodingCompleted());
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0200"   // Required Insert Count 1 and Delta Base 0.
+               // Base is 1 + 0 = 1.
+      "80"));  // Dynamic table entry with relative index 0, absolute index 0.
+
+  // Change dynamic table capacity to 32 bytes, smaller than the entry.
+  // This must cause the entry to be evicted.
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("3f01"));
+
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0200"   // Required Insert Count 1 and Delta Base 0.
+               // Base is 1 + 0 = 1.
+      "80"));  // Dynamic table entry with relative index 0, absolute index 0.
+}
+
+TEST_P(QpackDecoderTest, EncoderStreamErrorEntryTooLarge) {
+  EXPECT_CALL(encoder_stream_error_delegate_,
+              OnEncoderStreamError(Eq("Error inserting literal entry.")));
+
+  // Set dynamic table capacity to 34.
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("3f03"));
+  // Add literal entry with name "foo" and value "bar", size is 32 + 3 + 3 = 38.
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
+}
+
+TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidStaticTableEntry) {
+  EXPECT_CALL(encoder_stream_error_delegate_,
+              OnEncoderStreamError(Eq("Invalid static table entry.")));
+
+  // Address invalid static table entry index 99.
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("ff2400"));
+}
+
+TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidDynamicTableEntry) {
+  EXPECT_CALL(encoder_stream_error_delegate_,
+              OnEncoderStreamError(Eq("Dynamic table entry not found.")));
+
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode(
+      "6294e703626172"  // Add literal entry with name "foo" and value "bar".
+      "8100"));  // Address dynamic table entry with relative index 1.  Such
+                 // entry does not exist.  The most recently added and only
+                 // dynamic table entry has relative index 0.
+}
+
+TEST_P(QpackDecoderTest, EncoderStreamErrorDuplicateInvalidEntry) {
+  EXPECT_CALL(encoder_stream_error_delegate_,
+              OnEncoderStreamError(Eq("Dynamic table entry not found.")));
+
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode(
+      "6294e703626172"  // Add literal entry with name "foo" and value "bar".
+      "01"));  // Duplicate dynamic table entry with relative index 1.  Such
+               // entry does not exist.  The most recently added and only
+               // dynamic table entry has relative index 0.
+}
+
+TEST_P(QpackDecoderTest, EncoderStreamErrorTooLargeInteger) {
+  EXPECT_CALL(encoder_stream_error_delegate_,
+              OnEncoderStreamError(Eq("Encoded integer too large.")));
+
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fffffffffffffffffffff"));
+}
+
+TEST_P(QpackDecoderTest, InvalidDynamicEntryWhenBaseIsZero) {
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0280"   // Required Insert Count is 1.  Base 1 - 1 - 0 = 0 is explicitly
+               // permitted by the spec.
+      "80"));  // However, addressing entry with relative index 0 would point to
+               // absolute index -1, which is invalid.
+}
+
+TEST_P(QpackDecoderTest, InvalidNegativeBase) {
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Error calculating Base.")));
+
+  // Required Insert Count 1, Delta Base 1 with sign bit set, Base would
+  // be 1 - 1 - 1 = -1, but it is not allowed to be negative.
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("0281"));
+}
+
+TEST_P(QpackDecoderTest, InvalidDynamicEntryByRelativeIndex) {
+  // Add literal entry with name "foo" and value "bar".
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
+
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0500"   // Required Insert Count 4 and Delta Base 0.
+               // Base is 4 + 0 = 4.
+      "82"));  // Indexed Header Field instruction addressing relative index 2.
+               // This is absolute index 1. Such entry does not exist.
+
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0500"   // Required Insert Count 4 and Delta Base 0.
+               // Base is 4 + 0 = 4.
+      "84"));  // Indexed Header Field instruction addressing relative index 4.
+               // This is absolute index -1, which is invalid.
+
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0500"     // Required Insert Count 4 and Delta Base 0.
+                 // Base is 4 + 0 = 4.
+      "4200"));  // Literal Header Field with Name Reference instruction
+                 // addressing relative index 2.  This is absolute index 1. Such
+                 // entry does not exist.
+
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0500"     // Required Insert Count 4 and Delta Base 0.
+                 // Base is 4 + 0 = 4.
+      "4400"));  // Literal Header Field with Name Reference instruction
+                 // addressing relative index 4.  This is absolute index -1,
+                 // which is invalid.
+}
+
+TEST_P(QpackDecoderTest, InvalidDynamicEntryByPostBaseIndex) {
+  // Add literal entry with name "foo" and value "bar".
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
+
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0380"   // Required Insert Count 2 and Delta Base 0 with sign bit set.
+               // Base is 2 - 0 - 1 = 1
+      "10"));  // Indexed Header Field instruction addressing dynamic table
+               // entry with post-base index 0, absolute index 1.  Such entry
+               // does not exist.
+
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0380"     // Required Insert Count 2 and Delta Base 0 with sign bit set.
+                 // Base is 2 - 0 - 1 = 1
+      "0000"));  // Literal Header Field With Name Reference instruction
+                 // addressing dynamic table entry with post-base index 0,
+                 // absolute index 1.  Such entry does not exist.
+}
+
+TEST_P(QpackDecoderTest, TableCapacityMustNotExceedMaximum) {
+  EXPECT_CALL(
+      encoder_stream_error_delegate_,
+      OnEncoderStreamError(Eq("Error updating dynamic table capacity.")));
+
+  // Try to update dynamic table capacity to 2048, which exceeds the maximum.
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe10f"));
+}
+
+TEST_P(QpackDecoderTest, SetMaximumDynamicTableCapacity) {
+  // Update dynamic table capacity to 128, which does not exceed the maximum.
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("3f61"));
+}
+
+TEST_P(QpackDecoderTest, InvalidEncodedRequiredInsertCount) {
+  // Maximum dynamic table capacity is 1024.
+  // MaxEntries is 1024 / 32 = 32.
+  // Required Insert Count is decoded modulo 2 * MaxEntries, that is, modulo 64.
+  // A value of 1 cannot be encoded as 65 even though it has the same remainder.
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(
+                            Eq("Error decoding Required Insert Count.")));
+  DecodeHeaderBlock(QuicTextUtils::HexDecode("4100"));
+}
+
+TEST_P(QpackDecoderTest, WrappedRequiredInsertCount) {
+  // Maximum dynamic table capacity is 1024.
+  // MaxEntries is 1024 / 32 = 32.
+
+  // Add literal entry with name "foo" and a 600 byte long value.  This will fit
+  // in the dynamic table once but not twice.
+  DecodeEncoderStreamData(
+      QuicTextUtils::HexDecode("6294e7"     // Name "foo".
+                               "7fd903"));  // Value length 600.
+  QuicString header_value(600, 'Z');
+  DecodeEncoderStreamData(header_value);
+
+  // Duplicate most recent entry 200 times.
+  DecodeEncoderStreamData(QuicString(200, '\x00'));
+
+  // Now there is only one entry in the dynamic table, with absolute index 200.
+
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq(header_value)));
+  EXPECT_CALL(handler_, OnDecodingCompleted());
+  EXPECT_CALL(decoder_stream_sender_delegate_,
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+  // Send header block with Required Insert Count = 201.
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0a00"   // Encoded Required Insert Count 10, Required Insert Count 201,
+               // Delta Base 0, Base 201.
+      "80"));  // Emit dynamic table entry with relative index 0.
+}
+
+TEST_P(QpackDecoderTest, NonZeroRequiredInsertCountButNoDynamicEntries) {
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0200"   // Required Insert Count is 1.
+      "d1"));  // But the only instruction references the static table.
+}
+
+TEST_P(QpackDecoderTest, AddressEntryNotAllowedByRequiredInsertCount) {
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0201"   // Required Insert Count 1 and Delta Base 1.
+               // Base is 1 + 1 = 2.
+      "80"));  // Indexed Header Field instruction addressing dynamic table
+               // entry with relative index 0, absolute index 1.  This is not
+               // allowed by Required Insert Count.
+
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0201"     // Required Insert Count 1 and Delta Base 1.
+                 // Base is 1 + 1 = 2.
+      "4000"));  // Literal Header Field with Name Reference instruction
+                 // addressing dynamic table entry with relative index 0,
+                 // absolute index 1.  This is not allowed by Required Index
+                 // Count.
+
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0200"   // Required Insert Count 1 and Delta Base 0.
+               // Base is 1 + 0 = 1.
+      "10"));  // Indexed Header Field with Post-Base Index instruction
+               // addressing dynamic table entry with post-base index 0,
+               // absolute index 1.  This is not allowed by Required Insert
+               // Count.
+
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0200"     // Required Insert Count 1 and Delta Base 0.
+                 // Base is 1 + 0 = 1.
+      "0000"));  // Literal Header Field with Post-Base Name Reference
+                 // instruction addressing dynamic table entry with post-base
+                 // index 0, absolute index 1.  This is not allowed by Required
+                 // Index Count.
+}
+
+TEST_P(QpackDecoderTest, PromisedRequiredInsertCountLargerThanActual) {
+  // Add literal entry with name "foo" and value "bar".
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
+  // Duplicate entry.
+  DecodeEncoderStreamData(QuicTextUtils::HexDecode("00"));
+
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0300"   // Required Insert Count 2 and Delta Base 0.
+               // Base is 2 + 0 = 2.
+      "81"));  // Indexed Header Field instruction addressing dynamic table
+               // entry with relative index 1, absolute index 0.  Header block
+               // requires insert count of 1, even though Required Insert Count
+               // is 2.
+
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0300"     // Required Insert Count 2 and Delta Base 0.
+                 // Base is 2 + 0 = 2.
+      "4100"));  // Literal Header Field with Name Reference instruction
+                 // addressing dynamic table entry with relative index 1,
+                 // absolute index 0.  Header block requires insert count of 1,
+                 // even though Required Insert Count is 2.
+
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0481"   // Required Insert Count 3 and Delta Base 1 with sign bit set.
+               // Base is 3 - 1 - 1 = 1.
+      "10"));  // Indexed Header Field with Post-Base Index instruction
+               // addressing dynamic table entry with post-base index 0,
+               // absolute index 1.  Header block requires insert count of 2,
+               // even though Required Insert Count is 3.
+
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
+
+  DecodeHeaderBlock(QuicTextUtils::HexDecode(
+      "0481"     // Required Insert Count 3 and Delta Base 1 with sign bit set.
+                 // Base is 3 - 1 - 1 = 1.
+      "0000"));  // Literal Header Field with Post-Base Name Reference
+                 // instruction addressing dynamic table entry with post-base
+                 // index 0, absolute index 1.  Header block requires insert
+                 // count of 2, even though Required Insert Count is 3.
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace quic