Project import generated by Copybara.

PiperOrigin-RevId: 224614037
Change-Id: I14e53449d4aeccb328f86828c76b5f09dea0d4b8
diff --git a/http2/hpack/huffman/hpack_huffman_decoder_test.cc b/http2/hpack/huffman/hpack_huffman_decoder_test.cc
new file mode 100644
index 0000000..6c07ca5
--- /dev/null
+++ b/http2/hpack/huffman/hpack_huffman_decoder_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/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h"
+
+// Tests of HpackHuffmanDecoder and HuffmanBitBuffer.
+
+#include <iostream>
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
+#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_arraysize.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"
+#include "net/third_party/quiche/src/http2/tools/random_decoder_test.h"
+
+using ::testing::AssertionResult;
+
+namespace http2 {
+namespace test {
+namespace {
+
+TEST(HuffmanBitBufferTest, Reset) {
+  HuffmanBitBuffer bb;
+  EXPECT_TRUE(bb.IsEmpty());
+  EXPECT_TRUE(bb.InputProperlyTerminated());
+  EXPECT_EQ(bb.count(), 0u);
+  EXPECT_EQ(bb.free_count(), 64u);
+  EXPECT_EQ(bb.value(), 0u);
+}
+
+TEST(HuffmanBitBufferTest, AppendBytesAligned) {
+  Http2String s;
+  s.push_back('\x11');
+  s.push_back('\x22');
+  s.push_back('\x33');
+  Http2StringPiece sp(s);
+
+  HuffmanBitBuffer bb;
+  sp.remove_prefix(bb.AppendBytes(sp));
+  EXPECT_TRUE(sp.empty());
+  EXPECT_FALSE(bb.IsEmpty()) << bb;
+  EXPECT_FALSE(bb.InputProperlyTerminated());
+  EXPECT_EQ(bb.count(), 24u) << bb;
+  EXPECT_EQ(bb.free_count(), 40u) << bb;
+  EXPECT_EQ(bb.value(), HuffmanAccumulator(0x112233) << 40) << bb;
+
+  s.clear();
+  s.push_back('\x44');
+  sp = s;
+
+  sp.remove_prefix(bb.AppendBytes(sp));
+  EXPECT_TRUE(sp.empty());
+  EXPECT_EQ(bb.count(), 32u) << bb;
+  EXPECT_EQ(bb.free_count(), 32u) << bb;
+  EXPECT_EQ(bb.value(), HuffmanAccumulator(0x11223344) << 32) << bb;
+
+  s.clear();
+  s.push_back('\x55');
+  s.push_back('\x66');
+  s.push_back('\x77');
+  s.push_back('\x88');
+  s.push_back('\x99');
+  sp = s;
+
+  sp.remove_prefix(bb.AppendBytes(sp));
+  EXPECT_EQ(sp.size(), 1u);
+  EXPECT_EQ('\x99', sp[0]);
+  EXPECT_EQ(bb.count(), 64u) << bb;
+  EXPECT_EQ(bb.free_count(), 0u) << bb;
+  EXPECT_EQ(bb.value(), HuffmanAccumulator(0x1122334455667788LL)) << bb;
+
+  sp.remove_prefix(bb.AppendBytes(sp));
+  EXPECT_EQ(sp.size(), 1u);
+  EXPECT_EQ('\x99', sp[0]);
+  EXPECT_EQ(bb.count(), 64u) << bb;
+  EXPECT_EQ(bb.free_count(), 0u) << bb;
+  EXPECT_EQ(bb.value(), HuffmanAccumulator(0x1122334455667788LL)) << bb;
+}
+
+TEST(HuffmanBitBufferTest, ConsumeBits) {
+  Http2String s;
+  s.push_back('\x11');
+  s.push_back('\x22');
+  s.push_back('\x33');
+  Http2StringPiece sp(s);
+
+  HuffmanBitBuffer bb;
+  sp.remove_prefix(bb.AppendBytes(sp));
+  EXPECT_TRUE(sp.empty());
+
+  bb.ConsumeBits(1);
+  EXPECT_EQ(bb.count(), 23u) << bb;
+  EXPECT_EQ(bb.free_count(), 41u) << bb;
+  EXPECT_EQ(bb.value(), HuffmanAccumulator(0x112233) << 41) << bb;
+
+  bb.ConsumeBits(20);
+  EXPECT_EQ(bb.count(), 3u) << bb;
+  EXPECT_EQ(bb.free_count(), 61u) << bb;
+  EXPECT_EQ(bb.value(), HuffmanAccumulator(0x3) << 61) << bb;
+}
+
+TEST(HuffmanBitBufferTest, AppendBytesUnaligned) {
+  Http2String s;
+  s.push_back('\x11');
+  s.push_back('\x22');
+  s.push_back('\x33');
+  s.push_back('\x44');
+  s.push_back('\x55');
+  s.push_back('\x66');
+  s.push_back('\x77');
+  s.push_back('\x88');
+  s.push_back('\x99');
+  s.push_back('\xaa');
+  s.push_back('\xbb');
+  s.push_back('\xcc');
+  s.push_back('\xdd');
+  Http2StringPiece sp(s);
+
+  HuffmanBitBuffer bb;
+  sp.remove_prefix(bb.AppendBytes(sp));
+  EXPECT_EQ(sp.size(), 5u);
+  EXPECT_FALSE(bb.InputProperlyTerminated());
+
+  bb.ConsumeBits(15);
+  EXPECT_EQ(bb.count(), 49u) << bb;
+  EXPECT_EQ(bb.free_count(), 15u) << bb;
+
+  HuffmanAccumulator expected(0x1122334455667788);
+  expected <<= 15;
+  EXPECT_EQ(bb.value(), expected);
+
+  sp.remove_prefix(bb.AppendBytes(sp));
+  EXPECT_EQ(sp.size(), 4u);
+  EXPECT_EQ(bb.count(), 57u) << bb;
+  EXPECT_EQ(bb.free_count(), 7u) << bb;
+
+  expected |= (HuffmanAccumulator(0x99) << 7);
+  EXPECT_EQ(bb.value(), expected)
+      << bb << std::hex << "\n   actual: " << bb.value()
+      << "\n expected: " << expected;
+}
+
+class HpackHuffmanDecoderTest : public RandomDecoderTest {
+ protected:
+  HpackHuffmanDecoderTest() {
+    // The decoder may return true, and its accumulator may be empty, at
+    // many boundaries while decoding, and yet the whole string hasn't
+    // been decoded.
+    stop_decode_on_done_ = false;
+  }
+
+  DecodeStatus StartDecoding(DecodeBuffer* b) override {
+    input_bytes_seen_ = 0;
+    output_buffer_.clear();
+    decoder_.Reset();
+    return ResumeDecoding(b);
+  }
+
+  DecodeStatus ResumeDecoding(DecodeBuffer* b) override {
+    input_bytes_seen_ += b->Remaining();
+    Http2StringPiece sp(b->cursor(), b->Remaining());
+    if (decoder_.Decode(sp, &output_buffer_)) {
+      b->AdvanceCursor(b->Remaining());
+      // Successfully decoded (or buffered) the bytes in Http2StringPiece.
+      EXPECT_LE(input_bytes_seen_, input_bytes_expected_);
+      // Have we reached the end of the encoded string?
+      if (input_bytes_expected_ == input_bytes_seen_) {
+        if (decoder_.InputProperlyTerminated()) {
+          return DecodeStatus::kDecodeDone;
+        } else {
+          return DecodeStatus::kDecodeError;
+        }
+      }
+      return DecodeStatus::kDecodeInProgress;
+    }
+    return DecodeStatus::kDecodeError;
+  }
+
+  HpackHuffmanDecoder decoder_;
+  Http2String output_buffer_;
+  size_t input_bytes_seen_;
+  size_t input_bytes_expected_;
+};
+
+TEST_F(HpackHuffmanDecoderTest, SpecRequestExamples) {
+  HpackHuffmanDecoder decoder;
+  Http2String test_table[] = {
+      Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff"),
+      "www.example.com",
+      Http2HexDecode("a8eb10649cbf"),
+      "no-cache",
+      Http2HexDecode("25a849e95ba97d7f"),
+      "custom-key",
+      Http2HexDecode("25a849e95bb8e8b4bf"),
+      "custom-value",
+  };
+  for (size_t i = 0; i != HTTP2_ARRAYSIZE(test_table); i += 2) {
+    const Http2String& huffman_encoded(test_table[i]);
+    const Http2String& plain_string(test_table[i + 1]);
+    Http2String buffer;
+    decoder.Reset();
+    EXPECT_TRUE(decoder.Decode(huffman_encoded, &buffer)) << decoder;
+    EXPECT_TRUE(decoder.InputProperlyTerminated()) << decoder;
+    EXPECT_EQ(buffer, plain_string);
+  }
+}
+
+TEST_F(HpackHuffmanDecoderTest, SpecResponseExamples) {
+  HpackHuffmanDecoder decoder;
+  // clang-format off
+  Http2String test_table[] = {
+    Http2HexDecode("6402"),
+    "302",
+    Http2HexDecode("aec3771a4b"),
+    "private",
+    Http2HexDecode("d07abe941054d444a8200595040b8166"
+            "e082a62d1bff"),
+    "Mon, 21 Oct 2013 20:13:21 GMT",
+    Http2HexDecode("9d29ad171863c78f0b97c8e9ae82ae43"
+            "d3"),
+    "https://www.example.com",
+    Http2HexDecode("94e7821dd7f2e6c7b335dfdfcd5b3960"
+            "d5af27087f3672c1ab270fb5291f9587"
+            "316065c003ed4ee5b1063d5007"),
+    "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
+  };
+  // clang-format on
+  for (size_t i = 0; i != HTTP2_ARRAYSIZE(test_table); i += 2) {
+    const Http2String& huffman_encoded(test_table[i]);
+    const Http2String& plain_string(test_table[i + 1]);
+    Http2String buffer;
+    decoder.Reset();
+    EXPECT_TRUE(decoder.Decode(huffman_encoded, &buffer)) << decoder;
+    EXPECT_TRUE(decoder.InputProperlyTerminated()) << decoder;
+    EXPECT_EQ(buffer, plain_string);
+  }
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace http2