root/net/spdy/hpack_output_stream_test.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. TEST
  2. EncodeUint32
  3. TEST
  4. TEST
  5. TEST
  6. TEST
  7. TEST
  8. TEST
  9. TEST
  10. TEST
  11. TEST
  12. TEST
  13. TEST
  14. TEST
  15. TEST
  16. TEST
  17. TEST
  18. TEST
  19. TEST
  20. TEST

// Copyright 2014 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/spdy/hpack_output_stream.h"

#include <cstddef>

#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace net {

namespace {

using std::string;

// Make sure that AppendBits() appends bits starting from the most
// significant bit, and that it can handle crossing a byte boundary.
TEST(HpackOutputStreamTest, AppendBits) {
  HpackOutputStream output_stream(kuint32max);
  string expected_str;

  output_stream.AppendBitsForTest(0x1, 1);
  expected_str.append(1, 0x00);
  *expected_str.rbegin() |= (0x1 << 7);

  output_stream.AppendBitsForTest(0x0, 1);

  output_stream.AppendBitsForTest(0x3, 2);
  *expected_str.rbegin() |= (0x3 << 4);

  output_stream.AppendBitsForTest(0x0, 2);

  // Byte-crossing append.
  output_stream.AppendBitsForTest(0x7, 3);
  *expected_str.rbegin() |= (0x7 >> 1);
  expected_str.append(1, 0x00);
  *expected_str.rbegin() |= (0x7 << 7);

  output_stream.AppendBitsForTest(0x0, 7);

  string str;
  output_stream.TakeString(&str);
  EXPECT_EQ(expected_str, str);
}

// Utility function to return I as a string encoded with an N-bit
// prefix.
string EncodeUint32(uint8 N, uint32 I) {
  HpackOutputStream output_stream(kuint32max);
  if (N < 8) {
    output_stream.AppendBitsForTest(0x00, 8 - N);
  }
  output_stream.AppendUint32ForTest(I);
  string str;
  output_stream.TakeString(&str);
  return str;
}

// The {Number}ByteIntegersEightBitPrefix tests below test that
// certain integers are encoded correctly with an 8-bit prefix in
// exactly {Number} bytes.

TEST(HpackOutputStreamTest, OneByteIntegersEightBitPrefix) {
  // Minimum.
  EXPECT_EQ(string("\x00", 1), EncodeUint32(8, 0x00));
  EXPECT_EQ("\x7f", EncodeUint32(8, 0x7f));
  // Maximum.
  EXPECT_EQ("\xfe", EncodeUint32(8, 0xfe));
}

TEST(HpackOutputStreamTest, TwoByteIntegersEightBitPrefix) {
  // Minimum.
  EXPECT_EQ(string("\xff\x00", 2), EncodeUint32(8, 0xff));
  EXPECT_EQ("\xff\x01", EncodeUint32(8, 0x0100));
  // Maximum.
  EXPECT_EQ("\xff\x7f", EncodeUint32(8, 0x017e));
}

TEST(HpackOutputStreamTest, ThreeByteIntegersEightBitPrefix) {
  // Minimum.
  EXPECT_EQ("\xff\x80\x01", EncodeUint32(8, 0x017f));
  EXPECT_EQ("\xff\x80\x1e", EncodeUint32(8, 0x0fff));
  // Maximum.
  EXPECT_EQ("\xff\xff\x7f", EncodeUint32(8, 0x40fe));
}

TEST(HpackOutputStreamTest, FourByteIntegersEightBitPrefix) {
  // Minimum.
  EXPECT_EQ("\xff\x80\x80\x01", EncodeUint32(8, 0x40ff));
  EXPECT_EQ("\xff\x80\xfe\x03", EncodeUint32(8, 0xffff));
  // Maximum.
  EXPECT_EQ("\xff\xff\xff\x7f", EncodeUint32(8, 0x002000fe));
}

TEST(HpackOutputStreamTest, FiveByteIntegersEightBitPrefix) {
  // Minimum.
  EXPECT_EQ("\xff\x80\x80\x80\x01", EncodeUint32(8, 0x002000ff));
  EXPECT_EQ("\xff\x80\xfe\xff\x07", EncodeUint32(8, 0x00ffffff));
  // Maximum.
  EXPECT_EQ("\xff\xff\xff\xff\x7f", EncodeUint32(8, 0x100000fe));
}

TEST(HpackOutputStreamTest, SixByteIntegersEightBitPrefix) {
  // Minimum.
  EXPECT_EQ("\xff\x80\x80\x80\x80\x01", EncodeUint32(8, 0x100000ff));
  // Maximum.
  EXPECT_EQ("\xff\x80\xfe\xff\xff\x0f", EncodeUint32(8, 0xffffffff));
}

// The {Number}ByteIntegersOneToSevenBitPrefix tests below test that
// certain integers are encoded correctly with an N-bit prefix in
// exactly {Number} bytes for N in {1, 2, ..., 7}.

TEST(HpackOutputStreamTest, OneByteIntegersOneToSevenBitPrefixes) {
  // Minimums.
  EXPECT_EQ(string("\x00", 1), EncodeUint32(7, 0x00));
  EXPECT_EQ(string("\x00", 1), EncodeUint32(6, 0x00));
  EXPECT_EQ(string("\x00", 1), EncodeUint32(5, 0x00));
  EXPECT_EQ(string("\x00", 1), EncodeUint32(4, 0x00));
  EXPECT_EQ(string("\x00", 1), EncodeUint32(3, 0x00));
  EXPECT_EQ(string("\x00", 1), EncodeUint32(2, 0x00));
  EXPECT_EQ(string("\x00", 1), EncodeUint32(1, 0x00));

  // Maximums.
  EXPECT_EQ("\x7e", EncodeUint32(7, 0x7e));
  EXPECT_EQ("\x3e", EncodeUint32(6, 0x3e));
  EXPECT_EQ("\x1e", EncodeUint32(5, 0x1e));
  EXPECT_EQ("\x0e", EncodeUint32(4, 0x0e));
  EXPECT_EQ("\x06", EncodeUint32(3, 0x06));
  EXPECT_EQ("\x02", EncodeUint32(2, 0x02));
  EXPECT_EQ(string("\x00", 1), EncodeUint32(1, 0x00));
}

TEST(HpackOutputStreamTest, TwoByteIntegersOneToSevenBitPrefixes) {
  // Minimums.
  EXPECT_EQ(string("\x7f\x00", 2), EncodeUint32(7, 0x7f));
  EXPECT_EQ(string("\x3f\x00", 2), EncodeUint32(6, 0x3f));
  EXPECT_EQ(string("\x1f\x00", 2), EncodeUint32(5, 0x1f));
  EXPECT_EQ(string("\x0f\x00", 2), EncodeUint32(4, 0x0f));
  EXPECT_EQ(string("\x07\x00", 2), EncodeUint32(3, 0x07));
  EXPECT_EQ(string("\x03\x00", 2), EncodeUint32(2, 0x03));
  EXPECT_EQ(string("\x01\x00", 2), EncodeUint32(1, 0x01));

  // Maximums.
  EXPECT_EQ("\x7f\x7f", EncodeUint32(7, 0xfe));
  EXPECT_EQ("\x3f\x7f", EncodeUint32(6, 0xbe));
  EXPECT_EQ("\x1f\x7f", EncodeUint32(5, 0x9e));
  EXPECT_EQ("\x0f\x7f", EncodeUint32(4, 0x8e));
  EXPECT_EQ("\x07\x7f", EncodeUint32(3, 0x86));
  EXPECT_EQ("\x03\x7f", EncodeUint32(2, 0x82));
  EXPECT_EQ("\x01\x7f", EncodeUint32(1, 0x80));
}

TEST(HpackOutputStreamTest, ThreeByteIntegersOneToSevenBitPrefixes) {
  // Minimums.
  EXPECT_EQ("\x7f\x80\x01", EncodeUint32(7, 0xff));
  EXPECT_EQ("\x3f\x80\x01", EncodeUint32(6, 0xbf));
  EXPECT_EQ("\x1f\x80\x01", EncodeUint32(5, 0x9f));
  EXPECT_EQ("\x0f\x80\x01", EncodeUint32(4, 0x8f));
  EXPECT_EQ("\x07\x80\x01", EncodeUint32(3, 0x87));
  EXPECT_EQ("\x03\x80\x01", EncodeUint32(2, 0x83));
  EXPECT_EQ("\x01\x80\x01", EncodeUint32(1, 0x81));

  // Maximums.
  EXPECT_EQ("\x7f\xff\x7f", EncodeUint32(7, 0x407e));
  EXPECT_EQ("\x3f\xff\x7f", EncodeUint32(6, 0x403e));
  EXPECT_EQ("\x1f\xff\x7f", EncodeUint32(5, 0x401e));
  EXPECT_EQ("\x0f\xff\x7f", EncodeUint32(4, 0x400e));
  EXPECT_EQ("\x07\xff\x7f", EncodeUint32(3, 0x4006));
  EXPECT_EQ("\x03\xff\x7f", EncodeUint32(2, 0x4002));
  EXPECT_EQ("\x01\xff\x7f", EncodeUint32(1, 0x4000));
}

TEST(HpackOutputStreamTest, FourByteIntegersOneToSevenBitPrefixes) {
  // Minimums.
  EXPECT_EQ("\x7f\x80\x80\x01", EncodeUint32(7, 0x407f));
  EXPECT_EQ("\x3f\x80\x80\x01", EncodeUint32(6, 0x403f));
  EXPECT_EQ("\x1f\x80\x80\x01", EncodeUint32(5, 0x401f));
  EXPECT_EQ("\x0f\x80\x80\x01", EncodeUint32(4, 0x400f));
  EXPECT_EQ("\x07\x80\x80\x01", EncodeUint32(3, 0x4007));
  EXPECT_EQ("\x03\x80\x80\x01", EncodeUint32(2, 0x4003));
  EXPECT_EQ("\x01\x80\x80\x01", EncodeUint32(1, 0x4001));

  // Maximums.
  EXPECT_EQ("\x7f\xff\xff\x7f", EncodeUint32(7, 0x20007e));
  EXPECT_EQ("\x3f\xff\xff\x7f", EncodeUint32(6, 0x20003e));
  EXPECT_EQ("\x1f\xff\xff\x7f", EncodeUint32(5, 0x20001e));
  EXPECT_EQ("\x0f\xff\xff\x7f", EncodeUint32(4, 0x20000e));
  EXPECT_EQ("\x07\xff\xff\x7f", EncodeUint32(3, 0x200006));
  EXPECT_EQ("\x03\xff\xff\x7f", EncodeUint32(2, 0x200002));
  EXPECT_EQ("\x01\xff\xff\x7f", EncodeUint32(1, 0x200000));
}

TEST(HpackOutputStreamTest, FiveByteIntegersOneToSevenBitPrefixes) {
  // Minimums.
  EXPECT_EQ("\x7f\x80\x80\x80\x01", EncodeUint32(7, 0x20007f));
  EXPECT_EQ("\x3f\x80\x80\x80\x01", EncodeUint32(6, 0x20003f));
  EXPECT_EQ("\x1f\x80\x80\x80\x01", EncodeUint32(5, 0x20001f));
  EXPECT_EQ("\x0f\x80\x80\x80\x01", EncodeUint32(4, 0x20000f));
  EXPECT_EQ("\x07\x80\x80\x80\x01", EncodeUint32(3, 0x200007));
  EXPECT_EQ("\x03\x80\x80\x80\x01", EncodeUint32(2, 0x200003));
  EXPECT_EQ("\x01\x80\x80\x80\x01", EncodeUint32(1, 0x200001));

  // Maximums.
  EXPECT_EQ("\x7f\xff\xff\xff\x7f", EncodeUint32(7, 0x1000007e));
  EXPECT_EQ("\x3f\xff\xff\xff\x7f", EncodeUint32(6, 0x1000003e));
  EXPECT_EQ("\x1f\xff\xff\xff\x7f", EncodeUint32(5, 0x1000001e));
  EXPECT_EQ("\x0f\xff\xff\xff\x7f", EncodeUint32(4, 0x1000000e));
  EXPECT_EQ("\x07\xff\xff\xff\x7f", EncodeUint32(3, 0x10000006));
  EXPECT_EQ("\x03\xff\xff\xff\x7f", EncodeUint32(2, 0x10000002));
  EXPECT_EQ("\x01\xff\xff\xff\x7f", EncodeUint32(1, 0x10000000));
}

TEST(HpackOutputStreamTest, SixByteIntegersOneToSevenBitPrefixes) {
  // Minimums.
  EXPECT_EQ("\x7f\x80\x80\x80\x80\x01", EncodeUint32(7, 0x1000007f));
  EXPECT_EQ("\x3f\x80\x80\x80\x80\x01", EncodeUint32(6, 0x1000003f));
  EXPECT_EQ("\x1f\x80\x80\x80\x80\x01", EncodeUint32(5, 0x1000001f));
  EXPECT_EQ("\x0f\x80\x80\x80\x80\x01", EncodeUint32(4, 0x1000000f));
  EXPECT_EQ("\x07\x80\x80\x80\x80\x01", EncodeUint32(3, 0x10000007));
  EXPECT_EQ("\x03\x80\x80\x80\x80\x01", EncodeUint32(2, 0x10000003));
  EXPECT_EQ("\x01\x80\x80\x80\x80\x01", EncodeUint32(1, 0x10000001));

  // Maximums.
  EXPECT_EQ("\x7f\x80\xff\xff\xff\x0f", EncodeUint32(7, 0xffffffff));
  EXPECT_EQ("\x3f\xc0\xff\xff\xff\x0f", EncodeUint32(6, 0xffffffff));
  EXPECT_EQ("\x1f\xe0\xff\xff\xff\x0f", EncodeUint32(5, 0xffffffff));
  EXPECT_EQ("\x0f\xf0\xff\xff\xff\x0f", EncodeUint32(4, 0xffffffff));
  EXPECT_EQ("\x07\xf8\xff\xff\xff\x0f", EncodeUint32(3, 0xffffffff));
  EXPECT_EQ("\x03\xfc\xff\xff\xff\x0f", EncodeUint32(2, 0xffffffff));
  EXPECT_EQ("\x01\xfe\xff\xff\xff\x0f", EncodeUint32(1, 0xffffffff));
}

// Test that encoding an integer with an N-bit prefix preserves the
// upper (8-N) bits of the first byte.
TEST(HpackOutputStreamTest, AppendUint32PreservesUpperBits) {
  HpackOutputStream output_stream(kuint32max);
  output_stream.AppendBitsForTest(0x7f, 7);
  output_stream.AppendUint32ForTest(0x01);
  string str;
  output_stream.TakeString(&str);
  EXPECT_EQ(string("\xff\x00", 2), str);
}

// Test that encoding a string literal without huffman encoding
// encodes the size first with a 7-bit prefix and then the bytes of
// the string.
TEST(HpackOutputStreamTest, AppendStringLiteralNoHuffmanEncoding) {
  HpackOutputStream output_stream(kuint32max);

  string literal(0x7f, 'x');
  EXPECT_TRUE(output_stream.AppendStringLiteralForTest(literal));

  string str;
  output_stream.TakeString(&str);
  EXPECT_EQ(string("\x7f\x00", 2) + literal, str);
}

// Test that trying to encode a too-long string literal will fail.
TEST(HpackOutputStreamTest, AppendStringLiteralTooLong) {
  HpackOutputStream output_stream(kuint32max - 1);

  EXPECT_FALSE(output_stream.AppendStringLiteralForTest(
      base::StringPiece(NULL, kuint32max)));
}

// Test that encoding an indexed header simply encodes the index.
TEST(HpackOutputStreamTest, AppendIndexedHeader) {
  HpackOutputStream output_stream(kuint32max);
  output_stream.AppendIndexedHeader(0xffffffff);

  string str;
  output_stream.TakeString(&str);
  EXPECT_EQ("\xff\x80\xff\xff\xff\x0f", str);
}

// Test that encoding a literal header without indexing with a name
// encodes both the name and value as string literals.
TEST(HpackOutputStreamTest, AppendLiteralHeaderNoIndexingWithName) {
  HpackOutputStream output_stream(kuint32max);
  EXPECT_TRUE(
      output_stream.AppendLiteralHeaderNoIndexingWithName("name", "value"));

  string str;
  output_stream.TakeString(&str);
  EXPECT_EQ("\x40\x04name\x05value", str);
}

// Test that trying to encode a header with a too-long header name or
// value will fail.
TEST(HpackOutputStreamTest, AppendLiteralHeaderNoIndexingWithNameTooLong) {
  {
    HpackOutputStream output_stream(10);
    EXPECT_FALSE(output_stream.AppendLiteralHeaderNoIndexingWithName(
        "name", "too-long value"));
  }
  {
    HpackOutputStream output_stream(10);
    EXPECT_FALSE(output_stream.AppendLiteralHeaderNoIndexingWithName(
        "too-long name", "value"));
  }
}

}  // namespace

}  // namespace net

/* [<][>][^][v][top][bottom][index][help] */