2 * Copyright 2013-present Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 #include <folly/io/IOBuf.h>
18 #include <folly/Format.h>
19 #include <folly/Range.h>
20 #include <folly/io/Cursor.h>
21 #include <folly/portability/GTest.h>
25 using folly::ByteRange;
28 using folly::StringPiece;
29 using std::unique_ptr;
30 using namespace folly::io;
32 TEST(IOBuf, RWCursor) {
33 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
35 unique_ptr<IOBuf> iobuf2(IOBuf::create(20));
39 iobuf1->prependChain(std::move(iobuf2));
41 EXPECT_TRUE(iobuf1->isChained());
43 RWPrivateCursor wcursor(iobuf1.get());
44 Cursor rcursor(iobuf1.get());
45 wcursor.writeLE((uint64_t)1);
46 wcursor.writeLE((uint64_t)1);
47 wcursor.writeLE((uint64_t)1);
48 wcursor.write((uint8_t)1);
50 EXPECT_EQ(1u, rcursor.readLE<uint64_t>());
52 EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
54 EXPECT_EQ(0u, rcursor.read<uint8_t>());
55 EXPECT_EQ(0u, rcursor.read<uint8_t>());
56 EXPECT_EQ(0u, rcursor.read<uint8_t>());
57 EXPECT_EQ(0u, rcursor.read<uint8_t>());
58 EXPECT_EQ(1u, rcursor.read<uint8_t>());
62 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
64 RWPrivateCursor wcursor(iobuf1.get());
65 wcursor.write((uint8_t)1);
66 wcursor.write((uint8_t)2);
67 Cursor cursor(iobuf1.get());
69 EXPECT_EQ(2, cursor.read<uint8_t>());
73 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
75 RWPrivateCursor wcursor(iobuf1.get());
76 wcursor.write((uint8_t)1);
77 wcursor.write((uint8_t)2);
78 wcursor.reset(iobuf1.get());
79 EXPECT_EQ(1, wcursor.read<uint8_t>());
82 TEST(IOBuf, copy_assign_convert) {
83 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
85 RWPrivateCursor wcursor(iobuf1.get());
86 RWPrivateCursor cursor2(wcursor);
87 RWPrivateCursor cursor3(iobuf1.get());
89 wcursor.write((uint8_t)1);
91 wcursor.write((uint8_t)2);
92 Cursor cursor4(wcursor);
93 RWPrivateCursor cursor5(wcursor);
94 wcursor.write((uint8_t)3);
96 EXPECT_EQ(1, cursor2.read<uint8_t>());
97 EXPECT_EQ(2, cursor3.read<uint8_t>());
98 EXPECT_EQ(3, cursor4.read<uint8_t>());
101 TEST(IOBuf, arithmetic) {
102 IOBuf iobuf1(IOBuf::CREATE, 20);
104 RWPrivateCursor wcursor(&iobuf1);
106 wcursor.write((uint8_t)1);
107 Cursor cursor(&iobuf1);
109 EXPECT_EQ(1, cursor.read<uint8_t>());
111 Cursor start(&iobuf1);
112 Cursor cursor2 = start + 9;
113 EXPECT_EQ(7, cursor2 - cursor);
114 EXPECT_NE(cursor, cursor2);
116 cursor2 = cursor2 + 1;
117 EXPECT_EQ(cursor, cursor2);
120 TEST(IOBuf, endian) {
121 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
123 RWPrivateCursor wcursor(iobuf1.get());
124 Cursor rcursor(iobuf1.get());
129 // Try a couple combinations to ensure they were generated correctly
134 EXPECT_EQ(v, rcursor.readBE<uint16_t>());
137 TEST(IOBuf, Cursor) {
138 unique_ptr<IOBuf> iobuf1(IOBuf::create(1));
140 RWPrivateCursor c(iobuf1.get());
141 c.write((uint8_t)40); // OK
143 c.write((uint8_t)10); // Bad write, checked should except.
149 TEST(IOBuf, UnshareCursor) {
151 unique_ptr<IOBuf> iobuf1(IOBuf::wrapBuffer(&buf, 1));
152 unique_ptr<IOBuf> iobuf2(IOBuf::wrapBuffer(&buf, 1));
153 RWUnshareCursor c1(iobuf1.get());
154 RWUnshareCursor c2(iobuf2.get());
156 c1.write((uint8_t)10); // This should duplicate the two buffers.
157 uint8_t t = c2.read<uint8_t>();
160 iobuf1 = IOBuf::wrapBuffer(&buf, 1);
161 iobuf2 = IOBuf::wrapBuffer(&buf, 1);
162 RWPrivateCursor c3(iobuf1.get());
163 RWPrivateCursor c4(iobuf2.get());
165 c3.write((uint8_t)10); // This should _not_ duplicate the two buffers.
166 t = c4.read<uint8_t>();
171 void append(std::unique_ptr<IOBuf>& buf, folly::StringPiece data) {
172 EXPECT_LE(data.size(), buf->tailroom());
173 memcpy(buf->writableData(), data.data(), data.size());
174 buf->append(data.size());
177 void append(Appender& appender, StringPiece data) {
178 appender.push(ByteRange(data));
181 std::string toString(const IOBuf& buf) {
185 while (!(b = cursor.peekBytes()).empty()) {
186 str.append(reinterpret_cast<const char*>(b.data()), b.size());
187 cursor.skip(b.size());
194 TEST(IOBuf, PullAndPeek) {
195 std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
196 append(iobuf1, "he");
197 std::unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
198 append(iobuf2, "llo ");
199 std::unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
200 append(iobuf3, "world");
201 iobuf1->prependChain(std::move(iobuf2));
202 iobuf1->prependChain(std::move(iobuf3));
203 EXPECT_EQ(3, iobuf1->countChainElements());
204 EXPECT_EQ(11, iobuf1->computeChainDataLength());
207 memset(buf, 0, sizeof(buf));
208 Cursor(iobuf1.get()).pull(buf, 11);
209 EXPECT_EQ("hello world", std::string(buf));
211 memset(buf, 0, sizeof(buf));
212 EXPECT_EQ(11, Cursor(iobuf1.get()).pullAtMost(buf, 20));
213 EXPECT_EQ("hello world", std::string(buf));
215 EXPECT_THROW({Cursor(iobuf1.get()).pull(buf, 20);},
219 RWPrivateCursor cursor(iobuf1.get());
220 auto b = cursor.peekBytes();
221 EXPECT_EQ("he", StringPiece(b));
222 cursor.skip(b.size());
223 b = cursor.peekBytes();
224 EXPECT_EQ("llo ", StringPiece(b));
225 cursor.skip(b.size());
226 b = cursor.peekBytes();
227 EXPECT_EQ("world", StringPiece(b));
228 cursor.skip(b.size());
229 EXPECT_EQ(3, iobuf1->countChainElements());
230 EXPECT_EQ(11, iobuf1->computeChainDataLength());
234 RWPrivateCursor cursor(iobuf1.get());
236 auto b = cursor.peekBytes();
237 EXPECT_EQ("hello world", StringPiece(b));
238 EXPECT_EQ(1, iobuf1->countChainElements());
239 EXPECT_EQ(11, iobuf1->computeChainDataLength());
243 TEST(IOBuf, pushCursorData) {
244 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
246 iobuf1->trimStart(5);
247 unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
248 unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
251 iobuf1->prependChain(std::move(iobuf2));
252 iobuf1->prependChain(std::move(iobuf3));
253 EXPECT_TRUE(iobuf1->isChained());
255 //write 20 bytes to the buffer chain
256 RWPrivateCursor wcursor(iobuf1.get());
257 EXPECT_FALSE(wcursor.isAtEnd());
258 wcursor.writeBE<uint64_t>(1);
259 wcursor.writeBE<uint64_t>(10);
260 wcursor.writeBE<uint32_t>(20);
261 EXPECT_TRUE(wcursor.isAtEnd());
263 // create a read buffer for the buffer chain
264 Cursor rcursor(iobuf1.get());
265 EXPECT_EQ(1, rcursor.readBE<uint64_t>());
266 EXPECT_EQ(10, rcursor.readBE<uint64_t>());
267 EXPECT_EQ(20, rcursor.readBE<uint32_t>());
268 EXPECT_EQ(0, rcursor.totalLength());
269 rcursor.reset(iobuf1.get());
270 EXPECT_EQ(20, rcursor.totalLength());
272 // create another write buffer
273 unique_ptr<IOBuf> iobuf4(IOBuf::create(30));
275 RWPrivateCursor wcursor2(iobuf4.get());
276 // write buffer chain data into it, now wcursor2 should only
277 // have 10 bytes writable space
278 wcursor2.push(rcursor, 20);
279 EXPECT_EQ(wcursor2.totalLength(), 10);
280 // write again with not enough space in rcursor
281 EXPECT_THROW(wcursor2.push(rcursor, 20), std::out_of_range);
283 // create a read cursor to check iobuf3 data back
284 Cursor rcursor2(iobuf4.get());
285 EXPECT_EQ(1, rcursor2.readBE<uint64_t>());
286 EXPECT_EQ(10, rcursor2.readBE<uint64_t>());
287 EXPECT_EQ(20, rcursor2.readBE<uint32_t>());
290 TEST(IOBuf, Gather) {
291 std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
292 append(iobuf1, "he");
293 std::unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
294 append(iobuf2, "llo ");
295 std::unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
296 append(iobuf3, "world");
297 iobuf1->prependChain(std::move(iobuf2));
298 iobuf1->prependChain(std::move(iobuf3));
299 EXPECT_EQ(3, iobuf1->countChainElements());
300 EXPECT_EQ(11, iobuf1->computeChainDataLength());
302 // Attempting to gather() more data than available in the chain should fail.
303 // Try from the very beginning of the chain.
304 RWPrivateCursor cursor(iobuf1.get());
305 EXPECT_THROW(cursor.gather(15), std::overflow_error);
306 // Now try from the middle of the chain
308 EXPECT_THROW(cursor.gather(10), std::overflow_error);
310 // Calling gatherAtMost() should succeed, however, and just gather
312 cursor.gatherAtMost(10);
313 EXPECT_EQ(8, cursor.length());
314 EXPECT_EQ(8, cursor.totalLength());
315 EXPECT_FALSE(cursor.isAtEnd());
316 EXPECT_EQ("lo world",
317 folly::StringPiece(reinterpret_cast<const char*>(cursor.data()),
319 EXPECT_EQ(2, iobuf1->countChainElements());
320 EXPECT_EQ(11, iobuf1->computeChainDataLength());
322 // Now try gather again on the chain head
323 cursor = RWPrivateCursor(iobuf1.get());
325 // Since gather() doesn't split buffers, everything should be collapsed into
326 // a single buffer now.
327 EXPECT_EQ(1, iobuf1->countChainElements());
328 EXPECT_EQ(11, iobuf1->computeChainDataLength());
329 EXPECT_EQ(11, cursor.length());
330 EXPECT_EQ(11, cursor.totalLength());
333 TEST(IOBuf, cloneAndInsert) {
334 std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
335 append(iobuf1, "he");
336 std::unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
337 append(iobuf2, "llo ");
338 std::unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
339 append(iobuf3, "world");
340 iobuf1->prependChain(std::move(iobuf2));
341 iobuf1->prependChain(std::move(iobuf3));
342 EXPECT_EQ(3, iobuf1->countChainElements());
343 EXPECT_EQ(11, iobuf1->computeChainDataLength());
345 std::unique_ptr<IOBuf> cloned;
347 Cursor(iobuf1.get()).clone(cloned, 3);
348 EXPECT_EQ(2, cloned->countChainElements());
349 EXPECT_EQ(3, cloned->computeChainDataLength());
352 EXPECT_EQ(11, Cursor(iobuf1.get()).cloneAtMost(cloned, 20));
353 EXPECT_EQ(3, cloned->countChainElements());
354 EXPECT_EQ(11, cloned->computeChainDataLength());
357 EXPECT_THROW({Cursor(iobuf1.get()).clone(cloned, 20);},
361 // Check that inserting in the middle of an iobuf splits
362 RWPrivateCursor cursor(iobuf1.get());
363 Cursor(iobuf1.get()).clone(cloned, 3);
364 EXPECT_EQ(2, cloned->countChainElements());
365 EXPECT_EQ(3, cloned->computeChainDataLength());
369 cursor.insert(std::move(cloned));
370 cursor.insert(folly::IOBuf::create(0));
371 EXPECT_EQ(4, cursor.getCurrentPosition());
372 EXPECT_EQ(7, iobuf1->countChainElements());
373 EXPECT_EQ(14, iobuf1->computeChainDataLength());
374 // Check that nextBuf got set correctly to the buffer with 1 byte left
375 EXPECT_EQ(1, cursor.peekBytes().size());
376 cursor.read<uint8_t>();
380 // Check that inserting at the end doesn't create empty buf
381 RWPrivateCursor cursor(iobuf1.get());
382 Cursor(iobuf1.get()).clone(cloned, 1);
383 EXPECT_EQ(1, cloned->countChainElements());
384 EXPECT_EQ(1, cloned->computeChainDataLength());
388 cursor.insert(std::move(cloned));
389 EXPECT_EQ(2, cursor.getCurrentPosition());
390 EXPECT_EQ(8, iobuf1->countChainElements());
391 EXPECT_EQ(15, iobuf1->computeChainDataLength());
392 // Check that nextBuf got set correctly
393 cursor.read<uint8_t>();
396 // Check that inserting at the beginning of a chunk (except first one)
397 // doesn't create empty buf
398 RWPrivateCursor cursor(iobuf1.get());
399 Cursor(iobuf1.get()).clone(cloned, 1);
400 EXPECT_EQ(1, cloned->countChainElements());
401 EXPECT_EQ(1, cloned->computeChainDataLength());
405 cursor.insert(std::move(cloned));
406 EXPECT_EQ(2, cursor.getCurrentPosition());
407 EXPECT_EQ(14, cursor.totalLength());
408 EXPECT_EQ(9, iobuf1->countChainElements());
409 EXPECT_EQ(16, iobuf1->computeChainDataLength());
410 // Check that nextBuf got set correctly
411 cursor.read<uint8_t>();
414 // Check that inserting at the beginning of a chain DOES keep an empty
416 RWPrivateCursor cursor(iobuf1.get());
417 Cursor(iobuf1.get()).clone(cloned, 1);
418 EXPECT_EQ(1, cloned->countChainElements());
419 EXPECT_EQ(1, cloned->computeChainDataLength());
421 cursor.insert(std::move(cloned));
422 EXPECT_EQ(1, cursor.getCurrentPosition());
423 EXPECT_EQ(16, cursor.totalLength());
424 EXPECT_EQ(11, iobuf1->countChainElements());
425 EXPECT_EQ(17, iobuf1->computeChainDataLength());
426 // Check that nextBuf got set correctly
427 cursor.read<uint8_t>();
430 // Check that inserting at the end of the buffer keeps it at the end.
431 RWPrivateCursor cursor(iobuf1.get());
432 Cursor(iobuf1.get()).clone(cloned, 1);
433 EXPECT_EQ(1, cloned->countChainElements());
434 EXPECT_EQ(1, cloned->computeChainDataLength());
436 cursor.advanceToEnd();
437 EXPECT_EQ(17, cursor.getCurrentPosition());
438 cursor.insert(std::move(cloned));
439 EXPECT_EQ(18, cursor.getCurrentPosition());
440 EXPECT_EQ(0, cursor.totalLength());
441 EXPECT_EQ(12, iobuf1->countChainElements());
442 EXPECT_EQ(18, iobuf1->computeChainDataLength());
443 EXPECT_TRUE(cursor.isAtEnd());
447 TEST(IOBuf, cloneWithEmptyBufAtStart) {
448 folly::IOBufEqual eq;
449 auto empty = IOBuf::create(0);
450 auto hel = IOBuf::create(3);
452 auto lo = IOBuf::create(2);
455 auto iobuf = empty->clone();
456 iobuf->prependChain(hel->clone());
457 iobuf->prependChain(lo->clone());
458 iobuf->prependChain(empty->clone());
459 iobuf->prependChain(hel->clone());
460 iobuf->prependChain(lo->clone());
461 iobuf->prependChain(empty->clone());
462 iobuf->prependChain(lo->clone());
463 iobuf->prependChain(hel->clone());
464 iobuf->prependChain(lo->clone());
465 iobuf->prependChain(lo->clone());
467 Cursor cursor(iobuf.get());
468 std::unique_ptr<IOBuf> cloned;
470 cursor.pull(&data, 3);
471 cursor.clone(cloned, 2);
472 EXPECT_EQ(1, cloned->countChainElements());
473 EXPECT_EQ(2, cloned->length());
474 EXPECT_TRUE(eq(lo, cloned));
476 cursor.pull(&data, 3);
477 EXPECT_EQ("hel", std::string(data, sizeof(data)));
480 cursor.clone(cloned, 2);
481 EXPECT_TRUE(eq(lo, cloned));
483 std::string hello = cursor.readFixedString(5);
484 cursor.clone(cloned, 2);
485 EXPECT_TRUE(eq(lo, cloned));
488 TEST(IOBuf, Appender) {
489 std::unique_ptr<IOBuf> head(IOBuf::create(10));
490 append(head, "hello");
492 Appender app(head.get(), 10);
493 auto cap = head->capacity();
494 auto len1 = app.length();
495 EXPECT_EQ(cap - 5, len1);
496 app.ensure(len1); // won't grow
497 EXPECT_EQ(len1, app.length());
498 app.ensure(len1 + 1); // will grow
499 EXPECT_LE(len1 + 1, app.length());
501 append(app, " world");
502 EXPECT_EQ("hello world", toString(*head));
505 TEST(IOBuf, Printf) {
506 IOBuf head(IOBuf::CREATE, 24);
507 Appender app(&head, 32);
509 app.printf("%s", "test");
510 EXPECT_EQ(head.length(), 4);
511 EXPECT_EQ(0, memcmp(head.data(), "test\0", 5));
513 app.printf("%d%s %s%s %#x", 32, "this string is",
514 "longer than our original allocation size,",
515 "and will therefore require a new allocation", 0x12345678);
516 // The tailroom should start with a nul byte now.
517 EXPECT_GE(head.prev()->tailroom(), 1u);
518 EXPECT_EQ(0, *head.prev()->tail());
520 EXPECT_EQ("test32this string is longer than our original "
521 "allocation size,and will therefore require a "
522 "new allocation 0x12345678",
523 head.moveToFbString().toStdString());
526 TEST(IOBuf, Format) {
527 IOBuf head(IOBuf::CREATE, 24);
528 Appender app(&head, 32);
530 format("{}", "test")(app);
531 EXPECT_EQ(head.length(), 4);
532 EXPECT_EQ(0, memcmp(head.data(), "test", 4));
534 auto fmt = format("{}{} {}{} {:#x}",
535 32, "this string is",
536 "longer than our original allocation size,",
537 "and will therefore require a new allocation",
540 EXPECT_EQ("test32this string is longer than our original "
541 "allocation size,and will therefore require a "
542 "new allocation 0x12345678",
543 head.moveToFbString().toStdString());
546 TEST(IOBuf, QueueAppender) {
547 folly::IOBufQueue queue;
549 // Allocate 100 bytes at once, but don't grow past 1024
550 QueueAppender app(&queue, 100);
551 size_t n = 1024 / sizeof(uint32_t);
552 for (uint32_t i = 0; i < n; ++i) {
556 // There must be a goodMallocSize between 100 and 1024...
557 EXPECT_LT(1u, queue.front()->countChainElements());
558 const IOBuf* buf = queue.front();
560 EXPECT_LE(100u, buf->capacity());
562 } while (buf != queue.front());
564 Cursor cursor(queue.front());
565 for (uint32_t i = 0; i < n; ++i) {
566 EXPECT_EQ(i, cursor.readBE<uint32_t>());
569 EXPECT_THROW({cursor.readBE<uint32_t>();}, std::out_of_range);
572 TEST(IOBuf, QueueAppenderPushAtMostFillBuffer) {
573 folly::IOBufQueue queue;
574 // There should be a goodMallocSize between 125 and 1000
575 QueueAppender appender{&queue, 125};
576 std::vector<uint8_t> data;
578 std::iota(data.begin(), data.end(), uint8_t(0));
580 appender.pushAtMost(data.data(), 100);
582 appender.pushAtMost(data.data() + 100, data.size() - 100);
583 const auto buf = queue.front();
584 // Should fill the current buffer before adding another
585 EXPECT_LE(2, buf->countChainElements());
586 EXPECT_EQ(0, buf->tailroom());
587 EXPECT_LE(125, buf->length());
588 EXPECT_EQ(1000, buf->computeChainDataLength());
589 const StringPiece sp{(const char*)data.data(), data.size()};
590 EXPECT_EQ(sp, toString(*buf));
593 TEST(IOBuf, QueueAppenderInsertOwn) {
594 auto buf = IOBuf::create(10);
595 folly::IOBufQueue queue;
596 QueueAppender appender{&queue, 128};
597 appender.insert(std::move(buf));
599 std::vector<uint8_t> data;
601 std::iota(data.begin(), data.end(), 0);
602 appender.pushAtMost(folly::range(data));
603 // Buffer is owned, so we should write to it
604 EXPECT_LE(2, queue.front()->countChainElements());
605 EXPECT_EQ(0, queue.front()->tailroom());
606 const StringPiece sp{(const char*)data.data(), data.size()};
607 EXPECT_EQ(sp, toString(*queue.front()));
610 TEST(IOBuf, QueueAppenderInsertClone) {
611 IOBuf buf{IOBuf::CREATE, 100};
612 folly::IOBufQueue queue;
613 QueueAppender appender{&queue, 100};
614 // Buffer is shared, so we create a new buffer to write to
615 appender.insert(buf);
617 appender.pushAtMost(&x, 1);
618 EXPECT_EQ(2, queue.front()->countChainElements());
619 EXPECT_EQ(0, queue.front()->length());
620 EXPECT_LT(0, queue.front()->tailroom());
621 EXPECT_EQ(1, queue.front()->next()->length());
622 EXPECT_EQ(x, queue.front()->next()->data()[0]);
625 TEST(IOBuf, CursorOperators) {
626 // Test operators on a single-item chain
628 std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
631 Cursor curs1(chain1.get());
632 EXPECT_EQ(0, curs1 - chain1.get());
633 EXPECT_FALSE(curs1.isAtEnd());
635 EXPECT_EQ(3, curs1 - chain1.get());
636 EXPECT_FALSE(curs1.isAtEnd());
638 EXPECT_EQ(10, curs1 - chain1.get());
639 EXPECT_TRUE(curs1.isAtEnd());
641 Cursor curs2(chain1.get());
642 EXPECT_EQ(0, curs2 - chain1.get());
643 EXPECT_EQ(10, curs1 - curs2);
644 EXPECT_THROW(curs2 - curs1, std::out_of_range);
647 // Test cross-chain operations
649 std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
651 std::unique_ptr<IOBuf> chain2 = chain1->clone();
653 Cursor curs1(chain1.get());
654 Cursor curs2(chain2.get());
655 EXPECT_THROW(curs1 - curs2, std::out_of_range);
656 EXPECT_THROW(curs1 - chain2.get(), std::out_of_range);
659 // Test operations on multi-item chains
661 std::unique_ptr<IOBuf> chain(IOBuf::create(20));
663 chain->appendChain(chain->clone());
664 EXPECT_EQ(20, chain->computeChainDataLength());
666 Cursor curs1(chain.get());
668 Cursor curs2(chain.get());
670 EXPECT_EQ(2, curs1 - curs2);
671 EXPECT_EQ(5, curs1 - chain.get());
672 EXPECT_THROW(curs2 - curs1, std::out_of_range);
675 EXPECT_EQ(9, curs1 - curs2);
676 EXPECT_EQ(12, curs1 - chain.get());
677 EXPECT_THROW(curs2 - curs1, std::out_of_range);
680 EXPECT_EQ(2, curs1 - curs2);
681 EXPECT_THROW(curs2 - curs1, std::out_of_range);
684 // Test isAtEnd() with empty buffers at the end of a chain
686 auto iobuf1 = IOBuf::create(20);
688 iobuf1->trimStart(5);
690 Cursor c(iobuf1.get());
691 EXPECT_FALSE(c.isAtEnd());
693 EXPECT_TRUE(c.isAtEnd());
695 iobuf1->prependChain(IOBuf::create(10));
696 iobuf1->prependChain(IOBuf::create(10));
697 EXPECT_TRUE(c.isAtEnd());
698 iobuf1->prev()->append(5);
699 EXPECT_FALSE(c.isAtEnd());
701 EXPECT_TRUE(c.isAtEnd());
704 // Test canAdvance with a chain of items
706 auto chain = IOBuf::create(10);
708 chain->appendChain(chain->clone());
709 EXPECT_EQ(2, chain->countChainElements());
710 EXPECT_EQ(20, chain->computeChainDataLength());
712 Cursor c(chain.get());
713 for (size_t i = 0; i <= 20; ++i) {
714 EXPECT_TRUE(c.canAdvance(i));
716 EXPECT_FALSE(c.canAdvance(21));
718 EXPECT_TRUE(c.canAdvance(10));
719 EXPECT_FALSE(c.canAdvance(11));
723 TEST(IOBuf, StringOperations) {
724 // Test a single buffer with two null-terminated strings and an extra uint8_t
727 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
728 Appender app(chain.get(), 0);
729 app.push(reinterpret_cast<const uint8_t*>("hello\0world\0\x01"), 13);
731 Cursor curs(chain.get());
732 EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
733 EXPECT_STREQ("world", curs.readTerminatedString().c_str());
734 EXPECT_EQ(1, curs.read<uint8_t>());
737 // Test multiple buffers where the first is empty and the string starts in
738 // the second buffer.
740 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
741 chain->prependChain(IOBuf::create(12));
742 Appender app(chain.get(), 0);
743 app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
745 Cursor curs(chain.get());
746 EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
749 // Test multiple buffers with a single null-terminated string spanning them
751 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
752 chain->prependChain(IOBuf::create(8));
754 chain->next()->append(4);
755 RWPrivateCursor rwc(chain.get());
756 rwc.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
758 Cursor curs(chain.get());
759 EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
762 // Test a reading a null-terminated string that's longer than the maximum
765 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
766 Appender app(chain.get(), 0);
767 app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
769 Cursor curs(chain.get());
770 EXPECT_THROW(curs.readTerminatedString('\0', 5), std::length_error);
773 // Test reading a null-terminated string from a chain with an empty buffer at
776 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
777 Appender app(buf.get(), 0);
778 app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
779 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
780 chain->prependChain(std::move(buf));
782 Cursor curs(chain.get());
783 EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
786 // Test reading a null-terminated string from a chain that doesn't contain the
789 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
790 Appender app(buf.get(), 0);
791 app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
792 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
793 chain->prependChain(std::move(buf));
795 Cursor curs(chain.get());
796 EXPECT_THROW(curs.readTerminatedString(),
800 // Test reading a null-terminated string past the maximum length
802 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
803 Appender app(buf.get(), 0);
804 app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
805 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
806 chain->prependChain(std::move(buf));
808 Cursor curs(chain.get());
809 EXPECT_THROW(curs.readTerminatedString('\0', 3),
813 // Test reading a two fixed-length strings from a single buffer with an extra
814 // uint8_t at the end
816 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
817 Appender app(chain.get(), 0);
818 app.push(reinterpret_cast<const uint8_t*>("helloworld\x01"), 11);
820 Cursor curs(chain.get());
821 EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
822 EXPECT_STREQ("world", curs.readFixedString(5).c_str());
823 EXPECT_EQ(1, curs.read<uint8_t>());
826 // Test multiple buffers where the first is empty and a fixed-length string
827 // starts in the second buffer.
829 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
830 chain->prependChain(IOBuf::create(16));
831 Appender app(chain.get(), 0);
832 app.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
834 Cursor curs(chain.get());
835 EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
838 // Test multiple buffers with a single fixed-length string spanning them
840 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
841 chain->prependChain(IOBuf::create(8));
843 chain->next()->append(4);
844 RWPrivateCursor rwc(chain.get());
845 rwc.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
847 Cursor curs(chain.get());
848 EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
851 // Test reading a fixed-length string from a chain with an empty buffer at
854 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
855 Appender app(buf.get(), 0);
856 app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
857 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
858 chain->prependChain(std::move(buf));
860 Cursor curs(chain.get());
861 EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
865 TEST(IOBuf, ReadWhileTrue) {
866 auto isAlpha = [](uint8_t ch) {
867 return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
869 auto isDigit = [](uint8_t ch) { return (ch >= '0' && ch <= '9'); };
871 // Test reading alternating alphabetic and numeric strings
873 std::unique_ptr<IOBuf> chain(IOBuf::create(32));
874 Appender app(chain.get(), 0);
875 app.push(StringPiece("hello123world456"));
877 Cursor curs(chain.get());
878 EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
879 EXPECT_STREQ("123", curs.readWhile(isDigit).c_str());
880 EXPECT_STREQ("world", curs.readWhile(isAlpha).c_str());
881 EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
882 EXPECT_TRUE(curs.isAtEnd());
885 // The same, but also use skipWhile()
887 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
888 Appender app(chain.get(), 0);
889 app.push(StringPiece("hello123world456"));
891 Cursor curs(chain.get());
892 EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
893 curs.skipWhile(isDigit);
894 curs.skipWhile(isAlpha);
895 EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
896 EXPECT_TRUE(curs.isAtEnd());
899 // Test readWhile() using data split across multiple buffers,
900 // including some empty buffers in the middle of the chain.
902 std::unique_ptr<IOBuf> chain;
904 // First element in the chain has "he"
905 auto buf = IOBuf::create(40);
906 Appender app(buf.get(), 0);
907 app.push(StringPiece("he"));
908 chain = std::move(buf);
910 // The second element has "ll", after 10 bytes of headroom
911 buf = IOBuf::create(40);
913 app = Appender{buf.get(), 0};
914 app.push(StringPiece("ll"));
915 chain->prependChain(std::move(buf));
917 // The third element is empty
918 buf = IOBuf::create(40);
920 chain->prependChain(std::move(buf));
922 // The fourth element has "o12"
923 buf = IOBuf::create(40);
925 app = Appender{buf.get(), 0};
926 app.push(StringPiece("o12"));
927 chain->prependChain(std::move(buf));
929 // The fifth element has "3"
930 buf = IOBuf::create(40);
931 app = Appender{buf.get(), 0};
932 app.push(StringPiece("3"));
933 chain->prependChain(std::move(buf));
935 // The sixth element is empty
936 buf = IOBuf::create(40);
937 chain->prependChain(std::move(buf));
939 // The seventh element has "world456"
940 buf = IOBuf::create(40);
941 app = Appender{buf.get(), 0};
942 app.push(StringPiece("world456"));
943 chain->prependChain(std::move(buf));
945 // The eighth element is empty
946 buf = IOBuf::create(40);
947 chain->prependChain(std::move(buf));
949 Cursor curs(chain.get());
950 EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
951 EXPECT_STREQ("123", curs.readWhile(isDigit).c_str());
952 EXPECT_STREQ("world", curs.readWhile(isAlpha).c_str());
953 EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
954 EXPECT_TRUE(curs.isAtEnd());
958 TEST(IOBuf, TestAdvanceToEndSingle) {
959 std::unique_ptr<IOBuf> chain(IOBuf::create(10));
962 Cursor curs(chain.get());
964 EXPECT_TRUE(curs.isAtEnd());
965 EXPECT_EQ(curs - chain.get(), 10);
968 TEST(IOBuf, TestAdvanceToEndMulti) {
969 std::unique_ptr<IOBuf> chain(IOBuf::create(10));
972 std::unique_ptr<IOBuf> buf(IOBuf::create(5));
974 chain->prependChain(std::move(buf));
976 buf = IOBuf::create(20);
978 chain->prependChain(std::move(buf));
980 Cursor curs(chain.get());
982 EXPECT_TRUE(curs.isAtEnd());
983 EXPECT_EQ(curs - chain.get(), 35);
985 curs.reset(chain.get());
988 EXPECT_TRUE(curs.isAtEnd());
991 TEST(IOBuf, TestRetreatSingle) {
992 std::unique_ptr<IOBuf> chain(IOBuf::create(20));
995 Cursor curs(chain.get());
996 EXPECT_EQ(curs.retreatAtMost(0), 0);
997 EXPECT_EQ(curs.totalLength(), 20);
998 EXPECT_EQ(curs.retreatAtMost(5), 0);
999 EXPECT_EQ(curs.totalLength(), 20);
1000 EXPECT_EQ(curs.retreatAtMost(25), 0);
1001 EXPECT_EQ(curs.totalLength(), 20);
1004 EXPECT_THROW(curs.retreat(5), std::out_of_range);
1005 curs.reset(chain.get());
1006 EXPECT_THROW(curs.retreat(25), std::out_of_range);
1007 curs.reset(chain.get());
1009 curs.advanceToEnd();
1011 EXPECT_EQ(curs.totalLength(), 5);
1013 EXPECT_EQ(curs.totalLength(), 15);
1014 EXPECT_THROW(curs.retreat(10), std::out_of_range);
1016 curs.reset(chain.get());
1017 curs.advanceToEnd();
1018 EXPECT_EQ(curs.retreatAtMost(5), 5);
1019 EXPECT_EQ(curs.totalLength(), 5);
1020 EXPECT_EQ(curs.retreatAtMost(10), 10);
1021 EXPECT_EQ(curs.totalLength(), 15);
1022 EXPECT_EQ(curs.retreatAtMost(10), 5);
1023 EXPECT_EQ(curs.totalLength(), 20);
1026 TEST(IOBuf, TestRetreatMulti) {
1027 std::unique_ptr<IOBuf> chain(IOBuf::create(10));
1030 std::unique_ptr<IOBuf> buf(IOBuf::create(5));
1032 chain->prependChain(std::move(buf));
1034 buf = IOBuf::create(20);
1036 chain->prependChain(std::move(buf));
1038 Cursor curs(chain.get());
1039 EXPECT_EQ(curs.retreatAtMost(10), 0);
1040 EXPECT_THROW(curs.retreat(10), std::out_of_range);
1041 curs.reset(chain.get());
1043 curs.advanceToEnd();
1045 EXPECT_EQ(curs.totalLength(), 20);
1046 EXPECT_EQ(curs.length(), 20);
1048 EXPECT_EQ(curs.totalLength(), 21);
1049 EXPECT_EQ(curs.length(), 1);
1050 EXPECT_EQ(curs.retreatAtMost(50), 14);
1051 EXPECT_EQ(curs.totalLength(), 35);
1053 curs.advanceToEnd();
1055 EXPECT_EQ(curs.totalLength(), 30);
1058 TEST(IOBuf, TestRetreatOperators) {
1059 std::unique_ptr<IOBuf> chain(IOBuf::create(20));
1062 Cursor curs(chain.get());
1063 curs.advanceToEnd();
1065 EXPECT_EQ(curs.totalLength(), 5);
1067 curs.advanceToEnd();
1068 auto retreated = curs - 5;
1069 EXPECT_EQ(retreated.totalLength(), 5);
1070 EXPECT_EQ(curs.totalLength(), 0);
1073 TEST(IOBuf, tryRead) {
1074 unique_ptr<IOBuf> iobuf1(IOBuf::create(6));
1076 unique_ptr<IOBuf> iobuf2(IOBuf::create(24));
1079 iobuf1->prependChain(std::move(iobuf2));
1081 EXPECT_TRUE(iobuf1->isChained());
1083 RWPrivateCursor wcursor(iobuf1.get());
1084 Cursor rcursor(iobuf1.get());
1085 wcursor.writeLE((uint32_t)1);
1086 wcursor.writeLE((uint64_t)1);
1087 wcursor.writeLE((uint64_t)1);
1088 wcursor.writeLE((uint64_t)1);
1089 wcursor.writeLE((uint16_t)1);
1090 EXPECT_EQ(0, wcursor.totalLength());
1092 EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1094 EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1095 EXPECT_EQ(0u, rcursor.readLE<uint32_t>());
1097 EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1101 EXPECT_TRUE(rcursor.tryRead(val));
1103 EXPECT_TRUE(rcursor.tryRead(val));
1106 EXPECT_FALSE(rcursor.tryRead(val));
1109 TEST(IOBuf, tryReadLE) {
1110 IOBuf buf{IOBuf::CREATE, 4};
1113 RWPrivateCursor wcursor(&buf);
1114 Cursor rcursor(&buf);
1116 const uint32_t expected = 0x01020304;
1117 wcursor.writeLE(expected);
1119 EXPECT_TRUE(rcursor.tryReadLE(actual));
1120 EXPECT_EQ(expected, actual);
1123 TEST(IOBuf, tryReadBE) {
1124 IOBuf buf{IOBuf::CREATE, 4};
1127 RWPrivateCursor wcursor(&buf);
1128 Cursor rcursor(&buf);
1130 const uint32_t expected = 0x01020304;
1131 wcursor.writeBE(expected);
1133 EXPECT_TRUE(rcursor.tryReadBE(actual));
1134 EXPECT_EQ(expected, actual);
1137 TEST(IOBuf, tryReadConsumesAllInputOnFailure) {
1138 IOBuf buf{IOBuf::CREATE, 2};
1141 Cursor rcursor(&buf);
1143 EXPECT_FALSE(rcursor.tryRead(val));
1144 EXPECT_EQ(0, rcursor.totalLength());
1147 TEST(IOBuf, readConsumesAllInputOnFailure) {
1148 IOBuf buf{IOBuf::CREATE, 2};
1151 Cursor rcursor(&buf);
1152 EXPECT_THROW(rcursor.read<uint32_t>(), std::out_of_range);
1153 EXPECT_EQ(0, rcursor.totalLength());
1156 TEST(IOBuf, pushEmptyByteRange) {
1157 // Test pushing an empty ByteRange. This mainly tests that we do not
1158 // trigger UBSAN warnings by calling memcpy() with an null source pointer,
1159 // which is undefined behavior even if the length is 0.
1160 IOBuf buf{IOBuf::CREATE, 2};
1161 ByteRange emptyBytes;
1163 // Test calling Cursor::push()
1164 RWPrivateCursor wcursor(&buf);
1165 wcursor.push(emptyBytes);
1166 EXPECT_EQ(0, buf.computeChainDataLength());
1168 // Test calling Appender::push()
1169 Appender app(&buf, 16);
1170 app.push(emptyBytes);
1171 EXPECT_EQ(0, buf.computeChainDataLength());
1174 TEST(IOBuf, positionTracking) {
1175 unique_ptr<IOBuf> iobuf1(IOBuf::create(6));
1177 unique_ptr<IOBuf> iobuf2(IOBuf::create(24));
1179 iobuf1->prependChain(std::move(iobuf2));
1181 Cursor cursor(iobuf1.get());
1183 EXPECT_EQ(0, cursor.getCurrentPosition());
1184 EXPECT_EQ(6, cursor.length());
1187 EXPECT_EQ(3, cursor.getCurrentPosition());
1188 EXPECT_EQ(3, cursor.length());
1190 // Test that we properly handle advancing to the next chunk.
1192 EXPECT_EQ(7, cursor.getCurrentPosition());
1193 EXPECT_EQ(23, cursor.length());
1195 // Test that we properly handle doing to the previous chunk.
1197 EXPECT_EQ(5, cursor.getCurrentPosition());
1198 EXPECT_EQ(1, cursor.length());
1200 // Test that we properly handle advanceToEnd
1201 cursor.advanceToEnd();
1202 EXPECT_EQ(30, cursor.getCurrentPosition());
1203 EXPECT_EQ(0, cursor.totalLength());
1206 cursor.reset(iobuf1.get());
1207 EXPECT_EQ(0, cursor.getCurrentPosition());
1208 EXPECT_EQ(30, cursor.totalLength());