123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- /*
- * Copyright (c) 2023, Tim Schumacher <timschumi@gmx.de>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <AK/BitStream.h>
- #include <AK/MemoryStream.h>
- #include <LibTest/TestCase.h>
- using namespace Test::Randomized;
- // Note: This does not do any checks on the internal representation, it just ensures that the behavior of the input and output streams match.
- TEST_CASE(little_endian_bit_stream_input_output_match)
- {
- auto memory_stream = make<AllocatingMemoryStream>();
- // Note: The bit stream only ever reads from/writes to the underlying stream in one byte chunks,
- // so testing with sizes that will not trigger a write will yield unexpected results.
- LittleEndianOutputBitStream bit_write_stream { MaybeOwned<Stream>(*memory_stream) };
- LittleEndianInputBitStream bit_read_stream { MaybeOwned<Stream>(*memory_stream) };
- // Test two mirrored chunks of a fully mirrored pattern to check that we are not dropping bits.
- {
- MUST(bit_write_stream.write_bits(0b1111u, 4));
- MUST(bit_write_stream.write_bits(0b1111u, 4));
- MUST(bit_write_stream.flush_buffer_to_stream());
- auto result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b1111u, result);
- result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b1111u, result);
- }
- {
- MUST(bit_write_stream.write_bits(0b0000u, 4));
- MUST(bit_write_stream.write_bits(0b0000u, 4));
- MUST(bit_write_stream.flush_buffer_to_stream());
- auto result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b0000u, result);
- result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b0000u, result);
- }
- // Test two mirrored chunks of a non-mirrored pattern to check that we are writing bits within a pattern in the correct order.
- {
- MUST(bit_write_stream.write_bits(0b1000u, 4));
- MUST(bit_write_stream.write_bits(0b1000u, 4));
- MUST(bit_write_stream.flush_buffer_to_stream());
- auto result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b1000u, result);
- result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b1000u, result);
- }
- // Test two different chunks to check that we are not confusing their order.
- {
- MUST(bit_write_stream.write_bits(0b1000u, 4));
- MUST(bit_write_stream.write_bits(0b0100u, 4));
- MUST(bit_write_stream.flush_buffer_to_stream());
- auto result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b1000u, result);
- result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b0100u, result);
- }
- // Test a pattern that spans multiple bytes.
- {
- MUST(bit_write_stream.write_bits(0b1101001000100001u, 16));
- MUST(bit_write_stream.flush_buffer_to_stream());
- auto result = MUST(bit_read_stream.read_bits(16));
- EXPECT_EQ(0b1101001000100001u, result);
- }
- }
- // Note: This does not do any checks on the internal representation, it just ensures that the behavior of the input and output streams match.
- TEST_CASE(big_endian_bit_stream_input_output_match)
- {
- auto memory_stream = make<AllocatingMemoryStream>();
- // Note: The bit stream only ever reads from/writes to the underlying stream in one byte chunks,
- // so testing with sizes that will not trigger a write will yield unexpected results.
- BigEndianOutputBitStream bit_write_stream { MaybeOwned<Stream>(*memory_stream) };
- BigEndianInputBitStream bit_read_stream { MaybeOwned<Stream>(*memory_stream) };
- // Test two mirrored chunks of a fully mirrored pattern to check that we are not dropping bits.
- {
- MUST(bit_write_stream.write_bits(0b1111u, 4));
- MUST(bit_write_stream.write_bits(0b1111u, 4));
- auto result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b1111u, result);
- result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b1111u, result);
- }
- {
- MUST(bit_write_stream.write_bits(0b0000u, 4));
- MUST(bit_write_stream.write_bits(0b0000u, 4));
- auto result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b0000u, result);
- result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b0000u, result);
- }
- // Test two mirrored chunks of a non-mirrored pattern to check that we are writing bits within a pattern in the correct order.
- {
- MUST(bit_write_stream.write_bits(0b1000u, 4));
- MUST(bit_write_stream.write_bits(0b1000u, 4));
- auto result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b1000u, result);
- result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b1000u, result);
- }
- // Test two different chunks to check that we are not confusing their order.
- {
- MUST(bit_write_stream.write_bits(0b1000u, 4));
- MUST(bit_write_stream.write_bits(0b0100u, 4));
- auto result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b1000u, result);
- result = MUST(bit_read_stream.read_bits(4));
- EXPECT_EQ(0b0100u, result);
- }
- // Test a pattern that spans multiple bytes.
- {
- MUST(bit_write_stream.write_bits(0b1101001000100001u, 16));
- auto result = MUST(bit_read_stream.read_bits(16));
- EXPECT_EQ(0b1101001000100001u, result);
- }
- }
- TEST_CASE(bit_reads_beyond_stream_limits)
- {
- Array<u8, 1> const test_data { 0xFF };
- {
- auto memory_stream = make<FixedMemoryStream>(test_data);
- auto bit_stream = make<LittleEndianInputBitStream>(move(memory_stream), LittleEndianInputBitStream::UnsatisfiableReadBehavior::Reject);
- {
- auto result = TRY_OR_FAIL(bit_stream->read_bits<u8>(6));
- EXPECT_EQ(result, 0b111111);
- }
- {
- auto result = bit_stream->read_bits<u8>(6);
- EXPECT(result.is_error());
- }
- {
- auto result = bit_stream->read_bits<u8>(6);
- EXPECT(result.is_error());
- }
- }
- {
- // LittleEndianInputBitStream allows reading null bits beyond the original data
- // for compatibility purposes if enabled.
- auto memory_stream = make<FixedMemoryStream>(test_data);
- auto bit_stream = make<LittleEndianInputBitStream>(move(memory_stream), LittleEndianInputBitStream::UnsatisfiableReadBehavior::FillWithZero);
- {
- auto result = TRY_OR_FAIL(bit_stream->read_bits<u8>(6));
- EXPECT_EQ(result, 0b111111);
- }
- {
- auto result = TRY_OR_FAIL(bit_stream->read_bits<u8>(6));
- EXPECT_EQ(result, 0b000011);
- }
- {
- auto result = TRY_OR_FAIL(bit_stream->read_bits<u8>(6));
- EXPECT_EQ(result, 0b000000);
- }
- }
- {
- auto memory_stream = make<FixedMemoryStream>(test_data);
- auto bit_stream = make<BigEndianInputBitStream>(move(memory_stream));
- {
- auto result = TRY_OR_FAIL(bit_stream->read_bits<u8>(6));
- EXPECT_EQ(result, 0b111111);
- }
- {
- auto result = bit_stream->read_bits<u8>(6);
- EXPECT(result.is_error());
- }
- {
- auto result = bit_stream->read_bits<u8>(6);
- EXPECT(result.is_error());
- }
- }
- }
- RANDOMIZED_TEST_CASE(roundtrip_u8_little_endian)
- {
- GEN(n, Gen::unsigned_int(NumericLimits<u8>::max()));
- auto memory_stream = make<AllocatingMemoryStream>();
- LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
- LittleEndianInputBitStream sut_read { MaybeOwned<Stream>(*memory_stream) };
- MUST(sut_write.write_bits(n, 8));
- MUST(sut_write.flush_buffer_to_stream());
- auto result = MUST(sut_read.read_bits<u64>(8));
- EXPECT_EQ(result, n);
- }
- RANDOMIZED_TEST_CASE(roundtrip_u16_little_endian)
- {
- GEN(n, Gen::unsigned_int(NumericLimits<u16>::max()));
- auto memory_stream = make<AllocatingMemoryStream>();
- LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
- LittleEndianInputBitStream sut_read { MaybeOwned<Stream>(*memory_stream) };
- MUST(sut_write.write_bits(n, 16));
- MUST(sut_write.flush_buffer_to_stream());
- auto result = MUST(sut_read.read_bits<u64>(16));
- EXPECT_EQ(result, n);
- }
- RANDOMIZED_TEST_CASE(roundtrip_u32_little_endian)
- {
- GEN(n, Gen::unsigned_int(NumericLimits<u32>::max()));
- auto memory_stream = make<AllocatingMemoryStream>();
- LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
- LittleEndianInputBitStream sut_read { MaybeOwned<Stream>(*memory_stream) };
- MUST(sut_write.write_bits(n, 32));
- MUST(sut_write.flush_buffer_to_stream());
- auto result = MUST(sut_read.read_bits<u64>(32));
- EXPECT_EQ(result, n);
- }
- RANDOMIZED_TEST_CASE(roundtrip_u8_big_endian)
- {
- GEN(n, Gen::unsigned_int(NumericLimits<u8>::max()));
- auto memory_stream = make<AllocatingMemoryStream>();
- BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
- BigEndianInputBitStream sut_read { MaybeOwned<Stream>(*memory_stream) };
- MUST(sut_write.write_bits(n, 8));
- auto result = MUST(sut_read.read_bits<u64>(8));
- EXPECT_EQ(result, n);
- }
- RANDOMIZED_TEST_CASE(roundtrip_u16_big_endian)
- {
- GEN(n, Gen::unsigned_int(NumericLimits<u16>::max()));
- auto memory_stream = make<AllocatingMemoryStream>();
- BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
- BigEndianInputBitStream sut_read { MaybeOwned<Stream>(*memory_stream) };
- MUST(sut_write.write_bits(n, 16));
- auto result = MUST(sut_read.read_bits<u64>(16));
- EXPECT_EQ(result, n);
- }
- RANDOMIZED_TEST_CASE(roundtrip_u32_big_endian)
- {
- GEN(n, Gen::unsigned_int(NumericLimits<u32>::max()));
- auto memory_stream = make<AllocatingMemoryStream>();
- BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
- BigEndianInputBitStream sut_read { MaybeOwned<Stream>(*memory_stream) };
- MUST(sut_write.write_bits(n, 32));
- auto result = MUST(sut_read.read_bits<u64>(32));
- EXPECT_EQ(result, n);
- }
|