| // 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 |