| // Copyright 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_instruction_encoder.h" |
| |
| #include "net/third_party/quiche/src/quic/platform/api/quic_logging.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" |
| |
| using ::testing::Values; |
| |
| namespace quic { |
| namespace test { |
| namespace { |
| |
| class QpackInstructionEncoderTest : public QuicTest { |
| protected: |
| QpackInstructionEncoderTest() : verified_position_(0) {} |
| ~QpackInstructionEncoderTest() override = default; |
| |
| // Append encoded |instruction| to |output_|. |
| void EncodeInstruction(const QpackInstruction* instruction, |
| const QpackInstructionEncoder::Values& values) { |
| encoder_.Encode(instruction, values, &output_); |
| } |
| |
| // Compare substring appended to |output_| since last EncodedSegmentMatches() |
| // call against hex-encoded argument. |
| bool EncodedSegmentMatches(QuicStringPiece hex_encoded_expected_substring) { |
| auto recently_encoded = QuicStringPiece(output_).substr(verified_position_); |
| auto expected = QuicTextUtils::HexDecode(hex_encoded_expected_substring); |
| verified_position_ = output_.size(); |
| return recently_encoded == expected; |
| } |
| |
| private: |
| QpackInstructionEncoder encoder_; |
| std::string output_; |
| std::string::size_type verified_position_; |
| }; |
| |
| TEST_F(QpackInstructionEncoderTest, Varint) { |
| const QpackInstruction instruction{QpackInstructionOpcode{0x00, 0x80}, |
| {{QpackInstructionFieldType::kVarint, 7}}}; |
| |
| QpackInstructionEncoder::Values values; |
| values.varint = 5; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("05")); |
| |
| values.varint = 127; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("7f00")); |
| } |
| |
| TEST_F(QpackInstructionEncoderTest, SBitAndTwoVarint2) { |
| const QpackInstruction instruction{ |
| QpackInstructionOpcode{0x80, 0xc0}, |
| {{QpackInstructionFieldType::kSbit, 0x20}, |
| {QpackInstructionFieldType::kVarint, 5}, |
| {QpackInstructionFieldType::kVarint2, 8}}}; |
| |
| QpackInstructionEncoder::Values values; |
| values.s_bit = true; |
| values.varint = 5; |
| values.varint2 = 200; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("a5c8")); |
| |
| values.s_bit = false; |
| values.varint = 31; |
| values.varint2 = 356; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("9f00ff65")); |
| } |
| |
| TEST_F(QpackInstructionEncoderTest, SBitAndVarintAndValue) { |
| const QpackInstruction instruction{QpackInstructionOpcode{0xc0, 0xc0}, |
| {{QpackInstructionFieldType::kSbit, 0x20}, |
| {QpackInstructionFieldType::kVarint, 5}, |
| {QpackInstructionFieldType::kValue, 7}}}; |
| |
| QpackInstructionEncoder::Values values; |
| values.s_bit = true; |
| values.varint = 100; |
| values.value = "foo"; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("ff458294e7")); |
| |
| values.s_bit = false; |
| values.varint = 3; |
| values.value = "bar"; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("c303626172")); |
| } |
| |
| TEST_F(QpackInstructionEncoderTest, Name) { |
| const QpackInstruction instruction{QpackInstructionOpcode{0xe0, 0xe0}, |
| {{QpackInstructionFieldType::kName, 4}}}; |
| |
| QpackInstructionEncoder::Values values; |
| values.name = ""; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("e0")); |
| |
| values.name = "foo"; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("f294e7")); |
| |
| values.name = "bar"; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("e3626172")); |
| } |
| |
| TEST_F(QpackInstructionEncoderTest, Value) { |
| const QpackInstruction instruction{QpackInstructionOpcode{0xf0, 0xf0}, |
| {{QpackInstructionFieldType::kValue, 3}}}; |
| |
| QpackInstructionEncoder::Values values; |
| values.value = ""; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("f0")); |
| |
| values.value = "foo"; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("fa94e7")); |
| |
| values.value = "bar"; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("f3626172")); |
| } |
| |
| TEST_F(QpackInstructionEncoderTest, SBitAndNameAndValue) { |
| const QpackInstruction instruction{QpackInstructionOpcode{0xf0, 0xf0}, |
| {{QpackInstructionFieldType::kSbit, 0x08}, |
| {QpackInstructionFieldType::kName, 2}, |
| {QpackInstructionFieldType::kValue, 7}}}; |
| |
| QpackInstructionEncoder::Values values; |
| values.s_bit = false; |
| values.name = ""; |
| values.value = ""; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("f000")); |
| |
| values.s_bit = true; |
| values.name = "foo"; |
| values.value = "bar"; |
| EncodeInstruction(&instruction, values); |
| EXPECT_TRUE(EncodedSegmentMatches("fe94e703626172")); |
| } |
| |
| } // namespace |
| } // namespace test |
| } // namespace quic |