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 |