xrpld
Loading...
Searching...
No Matches
Buffer.cpp
1#include <xrpl/basics/Buffer.h>
2
3#include <xrpl/basics/Slice.h>
4
5#include <gtest/gtest.h>
6
7#include <array>
8#include <cstddef>
9#include <cstdint>
10#include <cstring>
11#include <type_traits>
12#include <utility>
13
14namespace xrpl::test {
15
18
19struct BufferTest : public ::testing::Test
20{
21 static constexpr auto kRandomData = std::to_array<std::uint8_t>(
22 {0xa8, 0xa1, 0x38, 0x45, 0x23, 0xec, 0xe4, 0x23, 0x71, 0x6d, 0x2a,
23 0x18, 0xb4, 0x70, 0xcb, 0xf5, 0xac, 0x2d, 0x89, 0x4d, 0x19, 0x9c,
24 0xf0, 0x2c, 0x15, 0xd1, 0xf9, 0x9b, 0x66, 0xd2, 0x30, 0xd3});
25
26 static constexpr std::size_t kHalf = kRandomData.size() / 2;
27
28 static bool
29 sane(Buffer const& b)
30 {
31 if (b.empty())
32 return b.data() == nullptr;
33
34 return b.data() != nullptr;
35 }
36
49 static void
51 {
52 EXPECT_TRUE(sane(buf));
53 EXPECT_TRUE(buf.empty());
54 }
55
59 Buffer const whole{kRandomData.data(), kRandomData.size()};
60};
61
62TEST_F(BufferTest, default_constructed_is_empty)
63{
64 Buffer const b;
65
66 EXPECT_TRUE(sane(b));
67 EXPECT_TRUE(b.empty());
68 EXPECT_EQ(b.data(), nullptr);
69}
70
71TEST_F(BufferTest, zero_sized_construction_is_empty)
72{
73 Buffer const b{0};
74
75 EXPECT_TRUE(sane(b));
76 EXPECT_TRUE(b.empty());
77}
78
79TEST_F(BufferTest, alloc_grows_an_empty_buffer)
80{
81 Buffer b{0};
82 std::memcpy(b.alloc(kHalf), kRandomData.data(), kHalf);
83
84 EXPECT_TRUE(sane(b));
85 EXPECT_FALSE(b.empty());
86 EXPECT_EQ(b.size(), kHalf);
87 EXPECT_EQ(b, firstHalf);
88}
89
90TEST_F(BufferTest, sized_construction_reserves_without_filling)
91{
92 Buffer b{kHalf};
93
94 EXPECT_TRUE(sane(b));
95 EXPECT_FALSE(b.empty());
96 EXPECT_EQ(b.size(), kHalf);
97
98 std::memcpy(b.data(), kRandomData.data() + kHalf, kHalf);
99 EXPECT_EQ(b, secondHalf);
100}
101
102TEST_F(BufferTest, construction_copies_raw_memory)
103{
104 Buffer const b{kRandomData.data(), kRandomData.size()};
105
106 EXPECT_TRUE(sane(b));
107 EXPECT_FALSE(b.empty());
108 EXPECT_EQ(b.size(), kRandomData.size());
109 EXPECT_EQ(std::memcmp(b.data(), kRandomData.data(), b.size()), 0);
110}
111
112TEST_F(BufferTest, equality_compares_contents)
113{
114 // Uses EXPECT_TRUE rather than EXPECT_EQ/EXPECT_NE because the operators are what is under test
115 // here.
116 EXPECT_TRUE(emptyBuffer == emptyBuffer);
117 EXPECT_TRUE(firstHalf == firstHalf);
118
119 EXPECT_TRUE(emptyBuffer != firstHalf);
120 EXPECT_TRUE(firstHalf != secondHalf);
121 EXPECT_TRUE(secondHalf != whole);
122}
123
124TEST_F(BufferTest, copy_construction)
125{
126 Buffer const fromEmpty{emptyBuffer};
127 EXPECT_TRUE(sane(fromEmpty));
128 EXPECT_EQ(fromEmpty, emptyBuffer);
129
130 Buffer const fromNonEmpty{firstHalf};
131 EXPECT_TRUE(sane(fromNonEmpty));
132 EXPECT_EQ(fromNonEmpty, firstHalf);
133}
134
135TEST_F(BufferTest, copy_assignment)
136{
137 Buffer b{emptyBuffer};
138
139 // empty <- non-empty
140 b = secondHalf;
141 EXPECT_TRUE(sane(b));
142 EXPECT_EQ(b, secondHalf);
143
144 // non-empty <- non-empty of a different size
145 b = whole;
146 EXPECT_TRUE(sane(b));
147 EXPECT_EQ(b, whole);
148
149 // non-empty <- empty
150 b = emptyBuffer;
151 EXPECT_TRUE(sane(b));
152 EXPECT_EQ(b, emptyBuffer);
153}
154
155TEST_F(BufferTest, self_assignment_preserves_contents)
156{
157#ifdef __clang__
158#pragma clang diagnostic push
159#pragma clang diagnostic ignored "-Wself-assign-overloaded"
160#endif
161
162 Buffer emptyCopy{emptyBuffer};
163 emptyCopy = emptyCopy;
164 EXPECT_TRUE(sane(emptyCopy));
165 EXPECT_EQ(emptyCopy, emptyBuffer);
166
167 Buffer wholeCopy{whole};
168 wholeCopy = wholeCopy;
169 EXPECT_TRUE(sane(wholeCopy));
170 EXPECT_EQ(wholeCopy, whole);
171
172#ifdef __clang__
173#pragma clang diagnostic pop
174#endif
175}
176
177TEST_F(BufferTest, move_construct_from_empty)
178{
179 Buffer source;
180 Buffer const moved{std::move(source)};
181
182 checkEmptyAfterMove(source); // NOLINT(bugprone-use-after-move)
183 EXPECT_TRUE(sane(moved));
184 EXPECT_TRUE(moved.empty());
185}
186
187TEST_F(BufferTest, move_construct_from_non_empty)
188{
189 Buffer source{firstHalf};
190 Buffer const moved{std::move(source)};
191
192 checkEmptyAfterMove(source); // NOLINT(bugprone-use-after-move)
193 EXPECT_TRUE(sane(moved));
194 EXPECT_EQ(moved, firstHalf);
195}
196
197TEST_F(BufferTest, move_assign_empty_to_empty)
198{
199 Buffer target;
200 Buffer source;
201
202 target = std::move(source);
203
204 EXPECT_TRUE(sane(target));
205 EXPECT_TRUE(target.empty());
206 checkEmptyAfterMove(source); // NOLINT(bugprone-use-after-move)
207}
208
209TEST_F(BufferTest, move_assign_non_empty_to_empty)
210{
211 Buffer target;
212 Buffer source{firstHalf};
213
214 target = std::move(source);
215
216 EXPECT_TRUE(sane(target));
217 EXPECT_EQ(target, firstHalf);
218 checkEmptyAfterMove(source); // NOLINT(bugprone-use-after-move)
219}
220
221TEST_F(BufferTest, move_assign_empty_to_non_empty)
222{
223 Buffer target{firstHalf};
224 Buffer source;
225
226 target = std::move(source);
227
228 EXPECT_TRUE(sane(target));
229 EXPECT_TRUE(target.empty());
230 checkEmptyAfterMove(source); // NOLINT(bugprone-use-after-move)
231}
232
233TEST_F(BufferTest, move_assign_non_empty_to_non_empty)
234{
235 Buffer target{firstHalf};
236 Buffer sameSize{secondHalf};
237 Buffer largerSize{whole};
238
239 target = std::move(sameSize);
240 EXPECT_TRUE(sane(target));
241 EXPECT_EQ(target, secondHalf);
242 checkEmptyAfterMove(sameSize); // NOLINT(bugprone-use-after-move)
243
244 target = std::move(largerSize);
245 EXPECT_TRUE(sane(target));
246 EXPECT_EQ(target, whole);
247 checkEmptyAfterMove(largerSize); // NOLINT(bugprone-use-after-move)
248}
249
250TEST_F(BufferTest, construction_from_slice)
251{
252 Buffer const fromEmpty{static_cast<Slice>(emptyBuffer)};
253 EXPECT_TRUE(sane(fromEmpty));
254 EXPECT_EQ(fromEmpty, emptyBuffer);
255
256 Buffer const fromNonEmpty{static_cast<Slice>(whole)};
257 EXPECT_TRUE(sane(fromNonEmpty));
258 EXPECT_EQ(fromNonEmpty, whole);
259}
260
261TEST_F(BufferTest, assignment_from_slice)
262{
263 Buffer b;
264
265 // empty <- empty slice
266 b = static_cast<Slice>(emptyBuffer);
267 EXPECT_TRUE(sane(b));
268 EXPECT_EQ(b, emptyBuffer);
269
270 // empty <- non-empty slice
271 b = static_cast<Slice>(firstHalf);
272 EXPECT_TRUE(sane(b));
273 EXPECT_EQ(b, firstHalf);
274
275 // non-empty <- non-empty slice
276 b = static_cast<Slice>(secondHalf);
277 EXPECT_TRUE(sane(b));
278 EXPECT_EQ(b, secondHalf);
279
280 // non-empty <- empty slice
281 b = static_cast<Slice>(emptyBuffer);
282 EXPECT_TRUE(sane(b));
283 EXPECT_EQ(b, emptyBuffer);
284}
285
286TEST_F(BufferTest, resize_allocates_and_clear_releases)
287{
288 auto check = [](Buffer const& original, std::size_t size) {
289 SCOPED_TRACE(::testing::Message() << "size: " << size);
290
291 Buffer b{original};
292
293 // Resizing to zero is equivalent to clearing.
294 b(size);
295 EXPECT_TRUE(sane(b));
296 EXPECT_EQ(b.size(), size);
297 EXPECT_EQ(b.data() == nullptr, size == 0);
298
299 b(size + 1);
300 EXPECT_TRUE(sane(b));
301 EXPECT_EQ(b.size(), size + 1);
302 EXPECT_NE(b.data(), nullptr);
303
304 b.clear();
305 EXPECT_TRUE(sane(b));
306 EXPECT_TRUE(b.empty());
307 EXPECT_EQ(b.data(), nullptr);
308
309 // clear() is idempotent.
310 b.clear();
311 EXPECT_TRUE(sane(b));
312 EXPECT_TRUE(b.empty());
313 EXPECT_EQ(b.data(), nullptr);
314 };
315
316 for (auto size = 0uz; size < kHalf; ++size)
317 {
318 check(emptyBuffer, size);
319 check(firstHalf, size);
320 }
321}
322
323TEST_F(BufferTest, fill_sets_every_byte)
324{
325 Buffer b{4};
326 b.fill(0xab);
327
328 EXPECT_EQ(b.size(), 4);
329 for (auto const byte : Slice{b})
330 EXPECT_EQ(byte, 0xab);
331}
332
333TEST_F(BufferTest, fill_overwrites_and_keeps_size)
334{
335 Buffer b{4};
336 b.fill(0xab);
337 b.fill(0x00);
338
339 EXPECT_EQ(b.size(), 4);
340 for (auto const byte : Slice{b})
341 EXPECT_EQ(byte, 0x00);
342}
343
344TEST_F(BufferTest, fill_on_empty_buffer_is_a_noop)
345{
346 Buffer empty;
347 empty.fill(0xff);
348
349 EXPECT_TRUE(empty.empty());
350 EXPECT_EQ(empty.data(), nullptr);
351}
352
353} // namespace xrpl::test
Like std::vector<char> but better.
Definition Buffer.h:19
bool empty() const noexcept
Definition Buffer.h:129
std::uint8_t * alloc(std::size_t n)
Reallocate the storage.
Definition Buffer.h:189
std::size_t size() const noexcept
Returns the number of bytes in the buffer.
Definition Buffer.h:123
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition Buffer.h:148
void clear() noexcept
Reset the buffer.
Definition Buffer.h:178
void fill(std::uint8_t value) noexcept
Set every byte in the buffer to the given value.
Definition Buffer.h:168
An immutable linear range of bytes.
Definition Slice.h:28
T is_nothrow_move_assignable_v
T is_nothrow_move_constructible_v
T memcmp(T... args)
T memcpy(T... args)
Check operations.
Definition check.h:18
TEST_F(BaseUintDeathTest, fromRaw_size_mismatch)
static bool sane(Buffer const &b)
Definition Buffer.cpp:29
Buffer const firstHalf
Definition Buffer.cpp:57
static void checkEmptyAfterMove(Buffer const &buf)
Check the state Buffer documents for a moved-from buffer: "the other buffer is reset",...
Definition Buffer.cpp:50
Buffer const whole
Definition Buffer.cpp:59
Buffer const emptyBuffer
Definition Buffer.cpp:56
static constexpr std::size_t kHalf
Definition Buffer.cpp:26
Buffer const secondHalf
Definition Buffer.cpp:58
static constexpr auto kRandomData
Definition Buffer.cpp:21