blob: 198be50e113acfe24ac0157d045048a5fc358b4a [file] [log] [blame]
/*
* Copyright 2015 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/bit_buffer.h"
#include <limits>
#include "api/array_view.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/bitstream_reader.h"
#include "rtc_base/byte_buffer.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace rtc {
using ::testing::ElementsAre;
using ::webrtc::BitstreamReader;
TEST(BitBufferWriterTest, ConsumeBits) {
uint8_t bytes[64] = {0};
BitBufferWriter buffer(bytes, 32);
uint64_t total_bits = 32 * 8;
EXPECT_EQ(total_bits, buffer.RemainingBitCount());
EXPECT_TRUE(buffer.ConsumeBits(3));
total_bits -= 3;
EXPECT_EQ(total_bits, buffer.RemainingBitCount());
EXPECT_TRUE(buffer.ConsumeBits(3));
total_bits -= 3;
EXPECT_EQ(total_bits, buffer.RemainingBitCount());
EXPECT_TRUE(buffer.ConsumeBits(15));
total_bits -= 15;
EXPECT_EQ(total_bits, buffer.RemainingBitCount());
EXPECT_TRUE(buffer.ConsumeBits(37));
total_bits -= 37;
EXPECT_EQ(total_bits, buffer.RemainingBitCount());
EXPECT_FALSE(buffer.ConsumeBits(32 * 8));
EXPECT_EQ(total_bits, buffer.RemainingBitCount());
}
TEST(BitBufferWriterDeathTest, SetOffsetValues) {
uint8_t bytes[4] = {0};
BitBufferWriter buffer(bytes, 4);
size_t byte_offset, bit_offset;
// Bit offsets are [0,7].
EXPECT_TRUE(buffer.Seek(0, 0));
EXPECT_TRUE(buffer.Seek(0, 7));
buffer.GetCurrentOffset(&byte_offset, &bit_offset);
EXPECT_EQ(0u, byte_offset);
EXPECT_EQ(7u, bit_offset);
EXPECT_FALSE(buffer.Seek(0, 8));
buffer.GetCurrentOffset(&byte_offset, &bit_offset);
EXPECT_EQ(0u, byte_offset);
EXPECT_EQ(7u, bit_offset);
// Byte offsets are [0,length]. At byte offset length, the bit offset must be
// 0.
EXPECT_TRUE(buffer.Seek(0, 0));
EXPECT_TRUE(buffer.Seek(2, 4));
buffer.GetCurrentOffset(&byte_offset, &bit_offset);
EXPECT_EQ(2u, byte_offset);
EXPECT_EQ(4u, bit_offset);
EXPECT_TRUE(buffer.Seek(4, 0));
EXPECT_FALSE(buffer.Seek(5, 0));
buffer.GetCurrentOffset(&byte_offset, &bit_offset);
EXPECT_EQ(4u, byte_offset);
EXPECT_EQ(0u, bit_offset);
EXPECT_FALSE(buffer.Seek(4, 1));
// Disable death test on Android because it relies on fork() and doesn't play
// nicely.
#if GTEST_HAS_DEATH_TEST
#if !defined(WEBRTC_ANDROID)
// Passing a null out parameter is death.
EXPECT_DEATH(buffer.GetCurrentOffset(&byte_offset, nullptr), "");
#endif
#endif
}
TEST(BitBufferWriterTest,
WriteNonSymmetricSameNumberOfBitsWhenNumValuesPowerOf2) {
uint8_t bytes[2] = {};
BitBufferWriter writer(bytes, 2);
ASSERT_EQ(writer.RemainingBitCount(), 16u);
EXPECT_TRUE(writer.WriteNonSymmetric(0xf, /*num_values=*/1 << 4));
ASSERT_EQ(writer.RemainingBitCount(), 12u);
EXPECT_TRUE(writer.WriteNonSymmetric(0x3, /*num_values=*/1 << 4));
ASSERT_EQ(writer.RemainingBitCount(), 8u);
EXPECT_TRUE(writer.WriteNonSymmetric(0xa, /*num_values=*/1 << 4));
ASSERT_EQ(writer.RemainingBitCount(), 4u);
EXPECT_TRUE(writer.WriteNonSymmetric(0x0, /*num_values=*/1 << 4));
ASSERT_EQ(writer.RemainingBitCount(), 0u);
EXPECT_THAT(bytes, ElementsAre(0xf3, 0xa0));
}
TEST(BitBufferWriterTest, NonSymmetricReadsMatchesWrites) {
uint8_t bytes[2] = {};
BitBufferWriter writer(bytes, 2);
EXPECT_EQ(BitBufferWriter::SizeNonSymmetricBits(/*val=*/1, /*num_values=*/6),
2u);
EXPECT_EQ(BitBufferWriter::SizeNonSymmetricBits(/*val=*/2, /*num_values=*/6),
3u);
// Values [0, 1] can fit into two bit.
ASSERT_EQ(writer.RemainingBitCount(), 16u);
EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/0, /*num_values=*/6));
ASSERT_EQ(writer.RemainingBitCount(), 14u);
EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/1, /*num_values=*/6));
ASSERT_EQ(writer.RemainingBitCount(), 12u);
// Values [2, 5] require 3 bits.
EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/2, /*num_values=*/6));
ASSERT_EQ(writer.RemainingBitCount(), 9u);
EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/3, /*num_values=*/6));
ASSERT_EQ(writer.RemainingBitCount(), 6u);
EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/4, /*num_values=*/6));
ASSERT_EQ(writer.RemainingBitCount(), 3u);
EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/5, /*num_values=*/6));
ASSERT_EQ(writer.RemainingBitCount(), 0u);
// Bit values are
// 00.01.100.101.110.111 = 00011001|01110111 = 0x19|77
EXPECT_THAT(bytes, ElementsAre(0x19, 0x77));
BitstreamReader reader(bytes);
EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 0u);
EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 1u);
EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 2u);
EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 3u);
EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 4u);
EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 5u);
EXPECT_TRUE(reader.Ok());
}
TEST(BitBufferWriterTest, WriteNonSymmetricOnlyValueConsumesNoBits) {
uint8_t bytes[2] = {};
BitBufferWriter writer(bytes, 2);
ASSERT_EQ(writer.RemainingBitCount(), 16u);
EXPECT_TRUE(writer.WriteNonSymmetric(0, /*num_values=*/1));
EXPECT_EQ(writer.RemainingBitCount(), 16u);
}
TEST(BitBufferWriterTest, SymmetricReadWrite) {
uint8_t bytes[16] = {0};
BitBufferWriter buffer(bytes, 4);
// Write some bit data at various sizes.
EXPECT_TRUE(buffer.WriteBits(0x2u, 3));
EXPECT_TRUE(buffer.WriteBits(0x1u, 2));
EXPECT_TRUE(buffer.WriteBits(0x53u, 7));
EXPECT_TRUE(buffer.WriteBits(0x0u, 2));
EXPECT_TRUE(buffer.WriteBits(0x1u, 1));
EXPECT_TRUE(buffer.WriteBits(0x1ABCDu, 17));
// That should be all that fits in the buffer.
EXPECT_FALSE(buffer.WriteBits(1, 1));
BitstreamReader reader(rtc::MakeArrayView(bytes, 4));
EXPECT_EQ(reader.ReadBits(3), 0x2u);
EXPECT_EQ(reader.ReadBits(2), 0x1u);
EXPECT_EQ(reader.ReadBits(7), 0x53u);
EXPECT_EQ(reader.ReadBits(2), 0x0u);
EXPECT_EQ(reader.ReadBits(1), 0x1u);
EXPECT_EQ(reader.ReadBits(17), 0x1ABCDu);
// And there should be nothing left.
EXPECT_EQ(reader.RemainingBitCount(), 0);
}
TEST(BitBufferWriterTest, SymmetricBytesMisaligned) {
uint8_t bytes[16] = {0};
BitBufferWriter buffer(bytes, 16);
// Offset 3, to get things misaligned.
EXPECT_TRUE(buffer.ConsumeBits(3));
EXPECT_TRUE(buffer.WriteUInt8(0x12u));
EXPECT_TRUE(buffer.WriteUInt16(0x3456u));
EXPECT_TRUE(buffer.WriteUInt32(0x789ABCDEu));
BitstreamReader reader(bytes);
reader.ConsumeBits(3);
EXPECT_EQ(reader.Read<uint8_t>(), 0x12u);
EXPECT_EQ(reader.Read<uint16_t>(), 0x3456u);
EXPECT_EQ(reader.Read<uint32_t>(), 0x789ABCDEu);
EXPECT_TRUE(reader.Ok());
}
TEST(BitBufferWriterTest, SymmetricGolomb) {
char test_string[] = "my precious";
uint8_t bytes[64] = {0};
BitBufferWriter buffer(bytes, 64);
for (size_t i = 0; i < arraysize(test_string); ++i) {
EXPECT_TRUE(buffer.WriteExponentialGolomb(test_string[i]));
}
BitstreamReader reader(bytes);
for (size_t i = 0; i < arraysize(test_string); ++i) {
EXPECT_EQ(int64_t{reader.ReadExponentialGolomb()}, int64_t{test_string[i]});
}
EXPECT_TRUE(reader.Ok());
}
TEST(BitBufferWriterTest, WriteClearsBits) {
uint8_t bytes[] = {0xFF, 0xFF};
BitBufferWriter buffer(bytes, 2);
EXPECT_TRUE(buffer.ConsumeBits(3));
EXPECT_TRUE(buffer.WriteBits(0, 1));
EXPECT_EQ(0xEFu, bytes[0]);
EXPECT_TRUE(buffer.WriteBits(0, 3));
EXPECT_EQ(0xE1u, bytes[0]);
EXPECT_TRUE(buffer.WriteBits(0, 2));
EXPECT_EQ(0xE0u, bytes[0]);
EXPECT_EQ(0x7F, bytes[1]);
}
} // namespace rtc