From 3f5450c64e0e2a02100fd25f7a1285483a3655de Mon Sep 17 00:00:00 2001 From: Joshua Scott Date: Sat, 20 Oct 2018 18:17:35 +0100 Subject: [PATCH] util: Fix buffer expansion and reformat unit tests --- azure-pipelines.yml | 2 +- include/ki/util/BitStream.h | 5 + src/util/BitStream.cpp | 10 +- test/CMakeLists.txt | 3 +- test/src/unit-bitstream.cpp | 274 +++++++++++++++++++++--------------- 5 files changed, 179 insertions(+), 115 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3c527f5..71e858a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,4 +21,4 @@ steps: - task: PublishTestResults@2 inputs: testResultsFormat: 'JUnit' - testResultsFiles: 'build/**/test-*.xml' + testResultsFiles: 'build/Testing/reports/test-*.xml' diff --git a/include/ki/util/BitStream.h b/include/ki/util/BitStream.h index 1f537ab..709a30c 100644 --- a/include/ki/util/BitStream.h +++ b/include/ki/util/BitStream.h @@ -56,6 +56,11 @@ namespace ki */ void seek(stream_pos position); + /** + * @return The current size of the internal buffer. + */ + std::size_t capacity() const; + /** * @return A pointer to the start of the internal buffer. */ diff --git a/src/util/BitStream.cpp b/src/util/BitStream.cpp index 61f9b5c..d368498 100644 --- a/src/util/BitStream.cpp +++ b/src/util/BitStream.cpp @@ -141,7 +141,12 @@ namespace ki validate_buffer(); } - const uint8_t* BitStream::data() const + std::size_t BitStream::capacity() const + { + return m_buffer_size; + } + + const uint8_t *BitStream::data() const { return m_buffer; } @@ -149,7 +154,7 @@ namespace ki void BitStream::expand_buffer() { // Work out a new buffer size - auto new_size = (2 << (uint64_t)log2(m_position.get_byte())) + 2; + auto new_size = (2 << (uint64_t)log2(m_position.get_byte()) + 1) + 2; if (new_size < m_buffer_size) new_size = std::numeric_limits::max(); @@ -162,6 +167,7 @@ namespace ki std::memcpy(new_buffer, m_buffer, m_buffer_size); delete[] m_buffer; m_buffer = new_buffer; + m_buffer_size = new_size; } void BitStream::validate_buffer() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ed4d4ab..4827994 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,6 +3,7 @@ add_library(Catch INTERFACE) target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR}) file(COPY "samples" DESTINATION "${PROJECT_BINARY_DIR}/test") +file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/Testing/reports/") file(GLOB files "src/unit-*.cpp") foreach (file ${files}) @@ -15,5 +16,5 @@ foreach (file ${files}) CXX_STANDARD 11 ) target_link_libraries(${testcase} Catch ${PROJECT_NAME}) - add_test(${testcase} ${testcase} -s -r junit -o ${PROJECT_BINARY_DIR}/Testing/${testcase}.xml) + add_test(${testcase} ${testcase} -s -r junit -o "${PROJECT_BINARY_DIR}/Testing/reports/${testcase}.xml") endforeach() diff --git a/test/src/unit-bitstream.cpp b/test/src/unit-bitstream.cpp index cc9930f..5d077a2 100644 --- a/test/src/unit-bitstream.cpp +++ b/test/src/unit-bitstream.cpp @@ -1,147 +1,199 @@ #define CATCH_CONFIG_MAIN #include - #include +/* + * Define values we expect during testing. + */ +#define KI_TEST_BITSTREAM_BUI1 0b1 +#define KI_TEST_BITSTREAM_BUI2 0b10 +#define KI_TEST_BITSTREAM_BUI3 0b010 +#define KI_TEST_BITSTREAM_BUI4 0b0101 +#define KI_TEST_BITSTREAM_BUI5 0b10101 +#define KI_TEST_BITSTREAM_BUI6 0b101010 +#define KI_TEST_BITSTREAM_BUI7 0b0101010 +#define KI_TEST_BITSTREAM_U8 0x01 +#define KI_TEST_BITSTREAM_U16 0x0302 +#define KI_TEST_BITSTREAM_U24 0x060504 +#define KI_TEST_BITSTREAM_U32 0x0A090807 +#define KI_TEST_BITSTREAM_U64 0x1211100F0E0D0C0BL + +#define KI_TEST_WRITE_BUI(n) bit_stream->write(KI_TEST_BITSTREAM_BUI##n, n) +#define KI_TEST_READ_BUI(n) bit_stream->read(n) == KI_TEST_BITSTREAM_BUI##n + using namespace ki; -TEST_CASE("Write bits", "[bit-stream]") +TEST_CASE("BitStream Functionality", "[bit-stream]") { auto *bit_stream = new BitStream(); - // Write an alternating pattern of bits - bit_stream->write(0b1, 1); - bit_stream->write(0b10, 2); - bit_stream->write(0b010, 3); - bit_stream->write(0b0101, 4); - bit_stream->write(0b10101, 5); - bit_stream->write(0b101010, 6); - bit_stream->write(0b0101010, 7); - bit_stream->write(0b0101, 4); + SECTION("Writing values with a size less than 8 bits") + { + // Write an alternating pattern of bits + KI_TEST_WRITE_BUI(1); + KI_TEST_WRITE_BUI(2); + KI_TEST_WRITE_BUI(3); + KI_TEST_WRITE_BUI(4); + KI_TEST_WRITE_BUI(5); + KI_TEST_WRITE_BUI(6); + KI_TEST_WRITE_BUI(7); + KI_TEST_WRITE_BUI(4); - // Make sure tell is reporting the right position - auto position = bit_stream->tell(); - if (position.get_byte() != 4 || position.get_bit() != 0) - FAIL(); - const auto size = position.get_byte(); + // Make sure tell is reporting the right position + auto position = bit_stream->tell(); + if (position.get_byte() != 4 || position.get_bit() != 0) + FAIL(); + const auto size = position.get_byte(); - // Validate what we've got here with a hand-written sample - std::ifstream sample("samples/bitstream1.bin", std::ios::binary); - if (!sample.is_open()) - FAIL(); + // Validate what we've got here with a hand-written sample + std::ifstream sample("samples/bitstream1.bin", std::ios::binary); + if (!sample.is_open()) + FAIL(); - // Load the sample data and compare - auto *sample_data = new char[size + 1] { 0 }; - sample.read(sample_data, size); - if (strcmp(sample_data, (char *)bit_stream->data()) != 0) - FAIL(); + // Load the sample data and compare + auto *sample_data = new char[size + 1]{ 0 }; + sample.read(sample_data, size); + if (strcmp(sample_data, (char *)bit_stream->data()) != 0) + FAIL(); - // Free resources - delete bit_stream; - delete[] sample_data; -} + // Free resources + delete[] sample_data; + SUCCEED(); + } -TEST_CASE("Write bytes", "[bit-stream]") -{ - auto *bit_stream = new BitStream(); + SECTION("Writing values with a size greater than 8 bits") + { + // Write some values + bit_stream->write(KI_TEST_BITSTREAM_U8, 8); + bit_stream->write(KI_TEST_BITSTREAM_U16, 16); + bit_stream->write(KI_TEST_BITSTREAM_U24, 24); + bit_stream->write(KI_TEST_BITSTREAM_U32, 32); + bit_stream->write(KI_TEST_BITSTREAM_U64, 64); - // Write an alternating pattern of bits - bit_stream->write(0x01, 8); - bit_stream->write(0x0302, 16); - bit_stream->write(0x060504, 24); - bit_stream->write(0x0A090807, 32); - bit_stream->write(0x1211100F0E0D0C0BL, 64); + // Make sure tell is reporting the right position + auto position = bit_stream->tell(); + if (position.get_byte() != 18 || position.get_bit() != 0) + FAIL(); + const auto size = position.get_byte(); - // Make sure tell is reporting the right position - auto position = bit_stream->tell(); - if (position.get_byte() != 18 || position.get_bit() != 0) - FAIL(); - const auto size = position.get_byte(); + // Validate what we've got here with a hand-written sample + std::ifstream sample("samples/bitstream2.bin", std::ios::binary); + if (!sample.is_open()) + FAIL(); - // Validate what we've got here with a hand-written sample - std::ifstream sample("samples/bitstream2.bin", std::ios::binary); - if (!sample.is_open()) - FAIL(); + // Load the sample data and compare + auto *sample_data = new char[size + 1]{ 0 }; + sample.read(sample_data, size); + if (strcmp(sample_data, (char *)bit_stream->data()) != 0) + FAIL(); - // Load the sample data and compare - auto *sample_data = new char[size + 1]{ 0 }; - sample.read(sample_data, size); - if (strcmp(sample_data, (char *)bit_stream->data()) != 0) - FAIL(); + // Free resources + delete[] sample_data; + SUCCEED(); + } - // Free resources - delete bit_stream; - delete[] sample_data; -} + SECTION("Reading values with a size lower than 8 bits") + { + // Open a previously hand-written sample + std::ifstream sample("samples/bitstream1.bin", std::ios::binary); + if (!sample.is_open()) + FAIL(); -TEST_CASE("Read bits", "[bit-stream]") -{ - auto *bit_stream = new BitStream(); + // Load the sample data into the bit stream + const auto begin = sample.tellg(); + sample.seekg(0, std::ios::end); + const auto end = sample.tellg(); + const size_t size = end - begin; + sample.seekg(std::ios::beg); + sample.read((char *)bit_stream->data(), size); - // Validate what we've got here with a hand-written sample - std::ifstream sample("samples/bitstream1.bin", std::ios::binary); - if (!sample.is_open()) - FAIL(); + // Read the values and check they are what we are expecting + if (!KI_TEST_READ_BUI(1)) + FAIL(); + if (!KI_TEST_READ_BUI(2)) + FAIL(); + if (!KI_TEST_READ_BUI(3)) + FAIL(); + if (!KI_TEST_READ_BUI(4)) + FAIL(); + if (!KI_TEST_READ_BUI(5)) + FAIL(); + if (!KI_TEST_READ_BUI(6)) + FAIL(); + if (!KI_TEST_READ_BUI(7)) + FAIL(); + if (!KI_TEST_READ_BUI(4)) + FAIL(); - // Load the sample data into the bit stream - const auto begin = sample.tellg(); - sample.seekg(0, std::ios::end); - const auto end = sample.tellg(); - const size_t size = end - begin; - sample.seekg(std::ios::beg); - sample.read((char *)bit_stream->data(), size); + SUCCEED(); + } - // Read the values and check they are what we are expecting - if (bit_stream->read(1) != 0b1) - FAIL(); - if (bit_stream->read(2) != 0b10) - FAIL(); - if (bit_stream->read(3) != 0b010) - FAIL(); - if (bit_stream->read(4) != 0b0101) - FAIL(); - if (bit_stream->read(5) != 0b10101) - FAIL(); - if (bit_stream->read(6) != 0b101010) - FAIL(); - if (bit_stream->read(7) != 0b0101010) - FAIL(); - if (bit_stream->read(4) != 0b0101) - FAIL(); + SECTION("Reading values with a size greater than 8 bits") + { + // Open a previously hand-written sample + std::ifstream sample("samples/bitstream2.bin", std::ios::binary); + if (!sample.is_open()) + FAIL(); + + // Load the sample data into the bit stream + const auto begin = sample.tellg(); + sample.seekg(0, std::ios::end); + const auto end = sample.tellg(); + const size_t size = end - begin; + sample.seekg(std::ios::beg); + sample.read((char *)bit_stream->data(), size); + + // Read the values and check they are what we are expecting + if (bit_stream->read(8) != KI_TEST_BITSTREAM_U8) + FAIL(); + if (bit_stream->read(16) != KI_TEST_BITSTREAM_U16) + FAIL(); + if (bit_stream->read(24) != KI_TEST_BITSTREAM_U24) + FAIL(); + if (bit_stream->read(32) != KI_TEST_BITSTREAM_U32) + FAIL(); + if (bit_stream->read(64) != KI_TEST_BITSTREAM_U64) + FAIL(); + + SUCCEED(); + } + + SECTION("Buffer underflow") + { + try + { + // Attempt to set the position less than 0 + bit_stream->seek(BitStream::stream_pos(-1, 0)); + FAIL(); + } + catch (std::runtime_error &e) + { + // An exception was thrown, which is intended behaviour + SUCCEED(); + } + } // Free resources delete bit_stream; } -TEST_CASE("Read bytes", "[bit-stream]") +TEST_CASE("BitStream buffer expansion", "[bit-stream]") { - auto *bit_stream = new BitStream(); + // Create a very small buffer that we know is going to expand + auto *bit_stream = new BitStream(1); - // Validate what we've got here with a hand-written sample - std::ifstream sample("samples/bitstream2.bin", std::ios::binary); - if (!sample.is_open()) + // Write a byte, and then check if the capacity grows + bit_stream->write(0x55, 8); + if (bit_stream->capacity() != 6) FAIL(); - - // Load the sample data into the bit stream - const auto begin = sample.tellg(); - sample.seekg(0, std::ios::end); - const auto end = sample.tellg(); - const size_t size = end - begin; - sample.seekg(std::ios::beg); - sample.read((char *)bit_stream->data(), size); - - // Read the values and check they are what we are expecting - if (bit_stream->read(8) != 0x01) - FAIL(); - if (bit_stream->read(16) != 0x0302) - FAIL(); - if (bit_stream->read(24) != 0x060504) - FAIL(); - if (bit_stream->read(32) != 0x0A090807) - FAIL(); - if (bit_stream->read(64) != 0x1211100F0E0D0C0BU) + + // Go back to the first byte, and make sure what we wrote stuck + // around after the expansion + bit_stream->seek(BitStream::stream_pos(0, 0)); + if (bit_stream->read(8) != 0x55) FAIL(); // Free resources delete bit_stream; + SUCCEED(); }