@@ -48,6 +48,7 @@ class ByteBufferTestProxy : public ByteBuffer {
4848 bool GetHasFixedSizedElements () const { return has_fixed_sized_elements_; }
4949 size_t GetElementSize () const { return element_size_; }
5050 const std::vector<size_t >& GetOffsets () const { return offsets_; }
51+ const std::vector<uint8_t >& GetWriteBuffer () const { return write_buffer_; }
5152};
5253
5354namespace {
@@ -62,6 +63,14 @@ void ExpectCommonState(
6263 EXPECT_EQ (buffer.GetElementSize (), expected_element_size);
6364}
6465
66+ std::vector<uint8_t > MakePayload (size_t size, uint8_t seed) {
67+ std::vector<uint8_t > payload (size);
68+ for (size_t i = 0 ; i < size; ++i) {
69+ payload[i] = static_cast <uint8_t >(seed + static_cast <uint8_t >(i));
70+ }
71+ return payload;
72+ }
73+
6574} // namespace
6675
6776TEST (ByteBufferTest, ConstructFixedSize_ValidBuffer_InitializesExpectedState) {
@@ -184,6 +193,172 @@ TEST(ByteBufferTest, ConstructWithNumElements_VariableSize_AllocatesAndSets) {
184193 EXPECT_EQ (read_second[6 ], 0x26 );
185194}
186195
196+ TEST (ByteBufferTest, SetElement_VariableSize_OutOfOrderAndOverwrite_ReturnsLatestValues) {
197+ ByteBufferTestProxy buffer (3u , 32u , true );
198+
199+ std::vector<uint8_t > v2_first = {0xA0 , 0xA1 };
200+ std::vector<uint8_t > v0_first = {0xB0 , 0xB1 , 0xB2 };
201+ std::vector<uint8_t > v1_first = {0xC0 };
202+ std::vector<uint8_t > v0_second = {0xD0 , 0xD1 , 0xD2 , 0xD3 };
203+ std::vector<uint8_t > v2_second = {0xE0 , 0xE1 , 0xE2 };
204+
205+ // Write in non-sequential order.
206+ buffer.setElement (2 , tcb::span<const uint8_t >(v2_first));
207+ buffer.setElement (0 , tcb::span<const uint8_t >(v0_first));
208+ buffer.setElement (1 , tcb::span<const uint8_t >(v1_first));
209+
210+ const auto e0_before = buffer.getElement (0 );
211+ const auto e1_before = buffer.getElement (1 );
212+ const auto e2_before = buffer.getElement (2 );
213+ ASSERT_EQ (e0_before.size (), v0_first.size ());
214+ ASSERT_EQ (e1_before.size (), v1_first.size ());
215+ ASSERT_EQ (e2_before.size (), v2_first.size ());
216+ for (size_t i = 0 ; i < v0_first.size (); ++i) {
217+ EXPECT_EQ (e0_before[i], v0_first[i]);
218+ }
219+ for (size_t i = 0 ; i < v1_first.size (); ++i) {
220+ EXPECT_EQ (e1_before[i], v1_first[i]);
221+ }
222+ for (size_t i = 0 ; i < v2_first.size (); ++i) {
223+ EXPECT_EQ (e2_before[i], v2_first[i]);
224+ }
225+
226+ const size_t offset0_before_overwrite = buffer.GetOffsets ()[0 ];
227+ const size_t offset2_before_overwrite = buffer.GetOffsets ()[2 ];
228+
229+ // Overwrite previously written positions; latest append should win.
230+ buffer.setElement (0 , tcb::span<const uint8_t >(v0_second));
231+ buffer.setElement (2 , tcb::span<const uint8_t >(v2_second));
232+
233+ EXPECT_GT (buffer.GetOffsets ()[0 ], offset0_before_overwrite);
234+ EXPECT_GT (buffer.GetOffsets ()[2 ], offset2_before_overwrite);
235+
236+ const auto e0 = buffer.getElement (0 );
237+ const auto e1 = buffer.getElement (1 );
238+ const auto e2 = buffer.getElement (2 );
239+
240+ ASSERT_EQ (e0 .size (), v0_second.size ());
241+ ASSERT_EQ (e1 .size (), v1_first.size ());
242+ ASSERT_EQ (e2 .size (), v2_second.size ());
243+
244+ for (size_t i = 0 ; i < v0_second.size (); ++i) {
245+ EXPECT_EQ (e0 [i], v0_second[i]);
246+ }
247+ for (size_t i = 0 ; i < v1_first.size (); ++i) {
248+ EXPECT_EQ (e1 [i], v1_first[i]);
249+ }
250+ for (size_t i = 0 ; i < v2_second.size (); ++i) {
251+ EXPECT_EQ (e2 [i], v2_second[i]);
252+ }
253+ }
254+
255+ TEST (ByteBufferTest, VariableSizeWrite_ExactHint_NoReallocationAndExactUsedSize) {
256+ const std::vector<size_t > payload_sizes = {1u , 3u , 2u , 7u , 4u , 6u , 5u };
257+ const size_t num_elements = payload_sizes.size ();
258+
259+ size_t total_payload_bytes = 0 ;
260+ for (size_t size : payload_sizes) {
261+ total_payload_bytes += size;
262+ }
263+ const size_t exact_hint_bytes = (num_elements * 4u ) + total_payload_bytes;
264+
265+ ByteBufferTestProxy buffer (num_elements, exact_hint_bytes, true );
266+ const size_t initial_capacity = buffer.GetWriteBuffer ().capacity ();
267+ const uint8_t * const initial_data_ptr = buffer.GetWriteBuffer ().data ();
268+
269+ std::vector<std::vector<uint8_t >> payloads;
270+ payloads.reserve (num_elements);
271+ for (size_t i = 0 ; i < num_elements; ++i) {
272+ payloads.push_back (MakePayload (payload_sizes[i], static_cast <uint8_t >(0x10 + i)));
273+ buffer.setElement (i, tcb::span<const uint8_t >(payloads.back ()));
274+ }
275+
276+ EXPECT_EQ (buffer.GetWriteBuffer ().size (), exact_hint_bytes);
277+ EXPECT_EQ (buffer.GetWriteBuffer ().capacity (), initial_capacity);
278+ EXPECT_EQ (buffer.GetWriteBuffer ().data (), initial_data_ptr);
279+
280+ for (size_t i = 0 ; i < num_elements; ++i) {
281+ const auto value = buffer.getElement (i);
282+ ASSERT_EQ (value.size (), payloads[i].size ());
283+ for (size_t j = 0 ; j < payloads[i].size (); ++j) {
284+ EXPECT_EQ (value[j], payloads[i][j]);
285+ }
286+ }
287+ }
288+
289+ TEST (ByteBufferTest, VariableSizeWrite_ExceedsHint_ReallocatesBuffer) {
290+ const size_t num_elements = 7u ;
291+ ByteBufferTestProxy buffer (num_elements, 32u , true );
292+
293+ const size_t initial_capacity = buffer.GetWriteBuffer ().capacity ();
294+ const uint8_t * const initial_data_ptr = buffer.GetWriteBuffer ().data ();
295+
296+ std::vector<std::vector<uint8_t >> payloads;
297+ payloads.reserve (num_elements);
298+ for (size_t i = 0 ; i < num_elements; ++i) {
299+ payloads.push_back (MakePayload (64u + (i * 9u ), static_cast <uint8_t >(0x40 + i)));
300+ buffer.setElement (i, tcb::span<const uint8_t >(payloads.back ()));
301+ }
302+
303+ EXPECT_GT (buffer.GetWriteBuffer ().size (), initial_capacity);
304+ EXPECT_GT (buffer.GetWriteBuffer ().capacity (), initial_capacity);
305+ EXPECT_NE (buffer.GetWriteBuffer ().data (), initial_data_ptr);
306+
307+ for (size_t i = 0 ; i < num_elements; ++i) {
308+ const auto value = buffer.getElement (i);
309+ ASSERT_EQ (value.size (), payloads[i].size ());
310+ for (size_t j = 0 ; j < payloads[i].size (); ++j) {
311+ EXPECT_EQ (value[j], payloads[i][j]);
312+ }
313+ }
314+ }
315+
316+ TEST (ByteBufferTest, SetElement_FixedSize_OutOfOrderAndOverwrite_ReturnsLatestValues) {
317+ ByteBufferTestProxy buffer (3u , 2u );
318+
319+ std::vector<uint8_t > v2_first = {0xA0 , 0xA1 };
320+ std::vector<uint8_t > v0_first = {0xB0 , 0xB1 };
321+ std::vector<uint8_t > v1_first = {0xC0 , 0xC1 };
322+ std::vector<uint8_t > v0_second = {0xD0 , 0xD1 };
323+ std::vector<uint8_t > v2_second = {0xE0 , 0xE1 };
324+
325+ // Write in non-sequential order.
326+ buffer.setElement (2 , tcb::span<const uint8_t >(v2_first));
327+ buffer.setElement (0 , tcb::span<const uint8_t >(v0_first));
328+ buffer.setElement (1 , tcb::span<const uint8_t >(v1_first));
329+
330+ const auto e0_before = buffer.getElement (0 );
331+ const auto e1_before = buffer.getElement (1 );
332+ const auto e2_before = buffer.getElement (2 );
333+ ASSERT_EQ (e0_before.size (), 2u );
334+ ASSERT_EQ (e1_before.size (), 2u );
335+ ASSERT_EQ (e2_before.size (), 2u );
336+ EXPECT_EQ (e0_before[0 ], v0_first[0 ]);
337+ EXPECT_EQ (e0_before[1 ], v0_first[1 ]);
338+ EXPECT_EQ (e1_before[0 ], v1_first[0 ]);
339+ EXPECT_EQ (e1_before[1 ], v1_first[1 ]);
340+ EXPECT_EQ (e2_before[0 ], v2_first[0 ]);
341+ EXPECT_EQ (e2_before[1 ], v2_first[1 ]);
342+
343+ // Overwrite previously written positions; latest fixed-size bytes should win.
344+ buffer.setElement (0 , tcb::span<const uint8_t >(v0_second));
345+ buffer.setElement (2 , tcb::span<const uint8_t >(v2_second));
346+
347+ const auto e0 = buffer.getElement (0 );
348+ const auto e1 = buffer.getElement (1 );
349+ const auto e2 = buffer.getElement (2 );
350+
351+ ASSERT_EQ (e0 .size (), 2u );
352+ ASSERT_EQ (e1 .size (), 2u );
353+ ASSERT_EQ (e2 .size (), 2u );
354+ EXPECT_EQ (e0 [0 ], v0_second[0 ]);
355+ EXPECT_EQ (e0 [1 ], v0_second[1 ]);
356+ EXPECT_EQ (e1 [0 ], v1_first[0 ]);
357+ EXPECT_EQ (e1 [1 ], v1_first[1 ]);
358+ EXPECT_EQ (e2 [0 ], v2_second[0 ]);
359+ EXPECT_EQ (e2 [1 ], v2_second[1 ]);
360+ }
361+
187362TEST (ByteBufferTest, SetElement_FixedSize_WrongPayloadSize_Throws) {
188363 ByteBufferTestProxy buffer (1u , 4u );
189364 std::vector<uint8_t > wrong = {0x01 , 0x02 };
0 commit comments