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