TestBuffer.h (4472B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 #ifndef intl_components_gtest_TestBuffer_h_ 5 #define intl_components_gtest_TestBuffer_h_ 6 7 #include <string_view> 8 #include "mozilla/DebugOnly.h" 9 #include "mozilla/Utf8.h" 10 #include "mozilla/Vector.h" 11 12 namespace mozilla::intl { 13 14 /** 15 * A test buffer for interfacing with unified intl classes. 16 * Closely resembles the FormatBuffer class, but without 17 * JavaScript-specific implementation details. 18 */ 19 template <typename C, size_t inlineCapacity = 0> 20 class TestBuffer { 21 public: 22 using CharType = C; 23 24 // Only allow moves, and not copies, as this class owns the mozilla::Vector. 25 TestBuffer(TestBuffer&& other) noexcept = default; 26 TestBuffer& operator=(TestBuffer&& other) noexcept = default; 27 28 explicit TestBuffer(const size_t aSize = 0) { reserve(aSize); } 29 30 /** 31 * Ensures the buffer has enough space to accommodate |aSize| elemtns. 32 */ 33 bool reserve(const size_t aSize) { return mBuffer.reserve(aSize); } 34 35 /** 36 * Returns the raw data inside the buffer. 37 */ 38 CharType* data() { return mBuffer.begin(); } 39 40 /** 41 * Returns the count of elements in written to the buffer. 42 */ 43 size_t length() const { return mBuffer.length(); } 44 45 /** 46 * Returns the buffer's overall capacity. 47 */ 48 size_t capacity() const { return mBuffer.capacity(); } 49 50 /** 51 * Resizes the buffer to the given amount of written elements. 52 * This is necessary because the buffer gets written to across 53 * FFI boundaries, so this needs to happen in a separate step. 54 */ 55 void written(size_t aAmount) { 56 MOZ_ASSERT(aAmount <= mBuffer.capacity()); 57 mozilla::DebugOnly<bool> result = mBuffer.resizeUninitialized(aAmount); 58 MOZ_ASSERT(result); 59 } 60 61 /** 62 * Get a string view into the buffer, which is useful for test assertions. 63 */ 64 std::basic_string_view<CharType> get_string_view() { 65 return std::basic_string_view<CharType>(data(), length()); 66 } 67 68 /** 69 * Clear the buffer, allowing it to be re-used. 70 */ 71 void clear() { mBuffer.clear(); } 72 73 /** 74 * A utility function to convert UTF-16 strings to UTF-8 strings so that they 75 * can be logged to stderr. 76 */ 77 static std::string toUtf8(mozilla::Span<const char16_t> input) { 78 size_t buff_len = input.Length() * 3; 79 std::string result(buff_len, ' '); 80 result.reserve(buff_len); 81 size_t result_len = 82 ConvertUtf16toUtf8(input, mozilla::Span(result.data(), buff_len)); 83 result.resize(result_len); 84 return result; 85 } 86 87 /** 88 * String buffers, especially UTF-16, do not assert nicely, and are difficult 89 * to debug. This function is verbose in that it prints the buffer contents 90 * and expected contents to stderr when they do not match. 91 * 92 * Usage: 93 * ASSERT_TRUE(buffer.assertStringView(u"9/23/2002, 8:07:30 PM")); 94 * 95 * Here is what gtests output: 96 * 97 * Expected equality of these values: 98 * buffer.get_string_view() 99 * Which is: { '0' (48, 0x30), '9' (57, 0x39), '/' (47, 0x2F), ... } 100 * "9/23/2002, 8:07:30 PM" 101 * Which is: 0x11600afb9 102 * 103 * Here is what this method outputs: 104 * 105 * The buffer did not match: 106 * Buffer: 107 * u"9/23/2002, 8:07:30 PM" 108 * Expected: 109 * u"09/23/2002, 08:07:30 PM" 110 */ 111 [[nodiscard]] bool verboseMatches(const CharType* aExpected) { 112 std::basic_string_view<CharType> actualSV(data(), length()); 113 std::basic_string_view<CharType> expectedSV(aExpected); 114 115 if (actualSV.compare(expectedSV) == 0) { 116 return true; 117 } 118 119 static_assert(std::is_same_v<CharType, char> || 120 std::is_same_v<CharType, char16_t>); 121 122 std::string actual; 123 std::string expected; 124 const char* startQuote; 125 126 if constexpr (std::is_same_v<CharType, char>) { 127 actual = std::string(actualSV); 128 expected = std::string(expectedSV); 129 startQuote = "\""; 130 } 131 if constexpr (std::is_same_v<CharType, char16_t>) { 132 actual = toUtf8(actualSV); 133 expected = toUtf8(expectedSV); 134 startQuote = "u\""; 135 } 136 137 fprintf(stderr, "The buffer did not match:\n"); 138 fprintf(stderr, " Buffer:\n %s%s\"\n", startQuote, actual.c_str()); 139 fprintf(stderr, " Expected:\n %s%s\"\n", startQuote, expected.c_str()); 140 141 return false; 142 } 143 144 Vector<C, inlineCapacity> mBuffer{}; 145 }; 146 147 } // namespace mozilla::intl 148 149 #endif