/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef intl_components_gtest_TestBuffer_h_ #define intl_components_gtest_TestBuffer_h_ #include #include "mozilla/DebugOnly.h" #include "mozilla/Utf8.h" #include "mozilla/Vector.h" namespace mozilla::intl { /** * A test buffer for interfacing with unified intl classes. * Closely resembles the FormatBuffer class, but without * JavaScript-specific implementation details. */ template class TestBuffer { public: using CharType = C; // Only allow moves, and not copies, as this class owns the mozilla::Vector. TestBuffer(TestBuffer&& other) noexcept = default; TestBuffer& operator=(TestBuffer&& other) noexcept = default; explicit TestBuffer(const size_t aSize = 0) { reserve(aSize); } /** * Ensures the buffer has enough space to accommodate |aSize| elemtns. */ bool reserve(const size_t aSize) { return mBuffer.reserve(aSize); } /** * Returns the raw data inside the buffer. */ CharType* data() { return mBuffer.begin(); } /** * Returns the count of elements in written to the buffer. */ size_t length() const { return mBuffer.length(); } /** * Returns the buffer's overall capacity. */ size_t capacity() const { return mBuffer.capacity(); } /** * Resizes the buffer to the given amount of written elements. * This is necessary because the buffer gets written to across * FFI boundaries, so this needs to happen in a separate step. */ void written(size_t aAmount) { MOZ_ASSERT(aAmount <= mBuffer.capacity()); mozilla::DebugOnly result = mBuffer.resizeUninitialized(aAmount); MOZ_ASSERT(result); } /** * Get a string view into the buffer, which is useful for test assertions. */ std::basic_string_view get_string_view() { return std::basic_string_view(data(), length()); } /** * Clear the buffer, allowing it to be re-used. */ void clear() { mBuffer.clear(); } /** * A utility function to convert UTF-16 strings to UTF-8 strings so that they * can be logged to stderr. */ static std::string toUtf8(mozilla::Span input) { size_t buff_len = input.Length() * 3; std::string result(buff_len, ' '); result.reserve(buff_len); size_t result_len = ConvertUtf16toUtf8(input, mozilla::Span(result.data(), buff_len)); result.resize(result_len); return result; } /** * String buffers, especially UTF-16, do not assert nicely, and are difficult * to debug. This function is verbose in that it prints the buffer contents * and expected contents to stderr when they do not match. * * Usage: * ASSERT_TRUE(buffer.assertStringView(u"9/23/2002, 8:07:30 PM")); * * Here is what gtests output: * * Expected equality of these values: * buffer.get_string_view() * Which is: { '0' (48, 0x30), '9' (57, 0x39), '/' (47, 0x2F), ... } * "9/23/2002, 8:07:30 PM" * Which is: 0x11600afb9 * * Here is what this method outputs: * * The buffer did not match: * Buffer: * u"9/23/2002, 8:07:30 PM" * Expected: * u"09/23/2002, 08:07:30 PM" */ [[nodiscard]] bool verboseMatches(const CharType* aExpected) { std::basic_string_view actualSV(data(), length()); std::basic_string_view expectedSV(aExpected); if (actualSV.compare(expectedSV) == 0) { return true; } static_assert(std::is_same_v || std::is_same_v); std::string actual; std::string expected; const char* startQuote; if constexpr (std::is_same_v) { actual = std::string(actualSV); expected = std::string(expectedSV); startQuote = "\""; } if constexpr (std::is_same_v) { actual = toUtf8(actualSV); expected = toUtf8(expectedSV); startQuote = "u\""; } fprintf(stderr, "The buffer did not match:\n"); fprintf(stderr, " Buffer:\n %s%s\"\n", startQuote, actual.c_str()); fprintf(stderr, " Expected:\n %s%s\"\n", startQuote, expected.c_str()); return false; } Vector mBuffer{}; }; } // namespace mozilla::intl #endif