2 * Copyright 2017 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.
17 #include <folly/io/IOBuf.h>
19 #include <folly/Format.h>
20 #include <folly/Range.h>
21 #include <folly/io/Cursor.h>
22 #include <folly/portability/GTest.h>
26 using folly::ByteRange;
29 using folly::StringPiece;
30 using std::unique_ptr;
31 using namespace folly::io;
33 TEST(IOBuf, RWCursor) {
34 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
36 unique_ptr<IOBuf> iobuf2(IOBuf::create(20));
40 iobuf1->prependChain(std::move(iobuf2));
42 EXPECT_TRUE(iobuf1->isChained());
44 RWPrivateCursor wcursor(iobuf1.get());
45 Cursor rcursor(iobuf1.get());
46 wcursor.writeLE((uint64_t)1);
47 wcursor.writeLE((uint64_t)1);
48 wcursor.writeLE((uint64_t)1);
49 wcursor.write((uint8_t)1);
51 EXPECT_EQ(1u, rcursor.readLE<uint64_t>());
53 EXPECT_EQ(1u, rcursor.readLE<uint32_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(0u, rcursor.read<uint8_t>());
59 EXPECT_EQ(1u, rcursor.read<uint8_t>());
63 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
65 RWPrivateCursor wcursor(iobuf1.get());
66 wcursor.write((uint8_t)1);
67 wcursor.write((uint8_t)2);
68 Cursor cursor(iobuf1.get());
70 EXPECT_EQ(2, cursor.read<uint8_t>());
74 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
76 RWPrivateCursor wcursor(iobuf1.get());
77 wcursor.write((uint8_t)1);
78 wcursor.write((uint8_t)2);
79 wcursor.reset(iobuf1.get());
80 EXPECT_EQ(1, wcursor.read<uint8_t>());
83 TEST(IOBuf, copy_assign_convert) {
84 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
86 RWPrivateCursor wcursor(iobuf1.get());
87 RWPrivateCursor cursor2(wcursor);
88 RWPrivateCursor cursor3(iobuf1.get());
90 wcursor.write((uint8_t)1);
92 wcursor.write((uint8_t)2);
93 Cursor cursor4(wcursor);
94 RWPrivateCursor cursor5(wcursor);
95 wcursor.write((uint8_t)3);
97 EXPECT_EQ(1, cursor2.read<uint8_t>());
98 EXPECT_EQ(2, cursor3.read<uint8_t>());
99 EXPECT_EQ(3, cursor4.read<uint8_t>());
102 TEST(IOBuf, arithmetic) {
103 IOBuf iobuf1(IOBuf::CREATE, 20);
105 RWPrivateCursor wcursor(&iobuf1);
107 wcursor.write((uint8_t)1);
108 Cursor cursor(&iobuf1);
110 EXPECT_EQ(1, cursor.read<uint8_t>());
112 Cursor start(&iobuf1);
113 Cursor cursor2 = start + 9;
114 EXPECT_EQ(7, cursor2 - cursor);
115 EXPECT_NE(cursor, cursor2);
117 cursor2 = cursor2 + 1;
118 EXPECT_EQ(cursor, cursor2);
121 TEST(IOBuf, endian) {
122 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
124 RWPrivateCursor wcursor(iobuf1.get());
125 Cursor rcursor(iobuf1.get());
130 // Try a couple combinations to ensure they were generated correctly
135 EXPECT_EQ(v, rcursor.readBE<uint16_t>());
138 TEST(IOBuf, Cursor) {
139 unique_ptr<IOBuf> iobuf1(IOBuf::create(1));
141 RWPrivateCursor c(iobuf1.get());
142 c.write((uint8_t)40); // OK
144 c.write((uint8_t)10); // Bad write, checked should except.
150 TEST(IOBuf, UnshareCursor) {
152 unique_ptr<IOBuf> iobuf1(IOBuf::wrapBuffer(&buf, 1));
153 unique_ptr<IOBuf> iobuf2(IOBuf::wrapBuffer(&buf, 1));
154 RWUnshareCursor c1(iobuf1.get());
155 RWUnshareCursor c2(iobuf2.get());
157 c1.write((uint8_t)10); // This should duplicate the two buffers.
158 uint8_t t = c2.read<uint8_t>();
161 iobuf1 = IOBuf::wrapBuffer(&buf, 1);
162 iobuf2 = IOBuf::wrapBuffer(&buf, 1);
163 RWPrivateCursor c3(iobuf1.get());
164 RWPrivateCursor c4(iobuf2.get());
166 c3.write((uint8_t)10); // This should _not_ duplicate the two buffers.
167 t = c4.read<uint8_t>();
172 void append(std::unique_ptr<IOBuf>& buf, folly::StringPiece data) {
173 EXPECT_LE(data.size(), buf->tailroom());
174 memcpy(buf->writableData(), data.data(), data.size());
175 buf->append(data.size());
178 void append(Appender& appender, StringPiece data) {
179 appender.push(ByteRange(data));
182 std::string toString(const IOBuf& buf) {
186 while (!(b = cursor.peekBytes()).empty()) {
187 str.append(reinterpret_cast<const char*>(b.data()), b.size());
188 cursor.skip(b.size());
195 TEST(IOBuf, PullAndPeek) {
196 std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
197 append(iobuf1, "he");
198 std::unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
199 append(iobuf2, "llo ");
200 std::unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
201 append(iobuf3, "world");
202 iobuf1->prependChain(std::move(iobuf2));
203 iobuf1->prependChain(std::move(iobuf3));
204 EXPECT_EQ(3, iobuf1->countChainElements());
205 EXPECT_EQ(11, iobuf1->computeChainDataLength());
208 memset(buf, 0, sizeof(buf));
209 Cursor(iobuf1.get()).pull(buf, 11);
210 EXPECT_EQ("hello world", std::string(buf));
212 memset(buf, 0, sizeof(buf));
213 EXPECT_EQ(11, Cursor(iobuf1.get()).pullAtMost(buf, 20));
214 EXPECT_EQ("hello world", std::string(buf));
216 EXPECT_THROW({Cursor(iobuf1.get()).pull(buf, 20);},
220 RWPrivateCursor cursor(iobuf1.get());
221 auto b = cursor.peekBytes();
222 EXPECT_EQ("he", StringPiece(b));
223 cursor.skip(b.size());
224 b = cursor.peekBytes();
225 EXPECT_EQ("llo ", StringPiece(b));
226 cursor.skip(b.size());
227 b = cursor.peekBytes();
228 EXPECT_EQ("world", StringPiece(b));
229 cursor.skip(b.size());
230 EXPECT_EQ(3, iobuf1->countChainElements());
231 EXPECT_EQ(11, iobuf1->computeChainDataLength());
235 RWPrivateCursor cursor(iobuf1.get());
237 auto b = cursor.peekBytes();
238 EXPECT_EQ("hello world", StringPiece(b));
239 EXPECT_EQ(1, iobuf1->countChainElements());
240 EXPECT_EQ(11, iobuf1->computeChainDataLength());
244 TEST(IOBuf, pushCursorData) {
245 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
247 iobuf1->trimStart(5);
248 unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
249 unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
252 iobuf1->prependChain(std::move(iobuf2));
253 iobuf1->prependChain(std::move(iobuf3));
254 EXPECT_TRUE(iobuf1->isChained());
256 //write 20 bytes to the buffer chain
257 RWPrivateCursor wcursor(iobuf1.get());
258 EXPECT_FALSE(wcursor.isAtEnd());
259 wcursor.writeBE<uint64_t>(1);
260 wcursor.writeBE<uint64_t>(10);
261 wcursor.writeBE<uint32_t>(20);
262 EXPECT_TRUE(wcursor.isAtEnd());
264 // create a read buffer for the buffer chain
265 Cursor rcursor(iobuf1.get());
266 EXPECT_EQ(1, rcursor.readBE<uint64_t>());
267 EXPECT_EQ(10, rcursor.readBE<uint64_t>());
268 EXPECT_EQ(20, rcursor.readBE<uint32_t>());
269 EXPECT_EQ(0, rcursor.totalLength());
270 rcursor.reset(iobuf1.get());
271 EXPECT_EQ(20, rcursor.totalLength());
273 // create another write buffer
274 unique_ptr<IOBuf> iobuf4(IOBuf::create(30));
276 RWPrivateCursor wcursor2(iobuf4.get());
277 // write buffer chain data into it, now wcursor2 should only
278 // have 10 bytes writable space
279 wcursor2.push(rcursor, 20);
280 EXPECT_EQ(wcursor2.totalLength(), 10);
281 // write again with not enough space in rcursor
282 EXPECT_THROW(wcursor2.push(rcursor, 20), std::out_of_range);
284 // create a read cursor to check iobuf3 data back
285 Cursor rcursor2(iobuf4.get());
286 EXPECT_EQ(1, rcursor2.readBE<uint64_t>());
287 EXPECT_EQ(10, rcursor2.readBE<uint64_t>());
288 EXPECT_EQ(20, rcursor2.readBE<uint32_t>());
292 TEST(IOBuf, Gather) {
293 std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
294 append(iobuf1, "he");
295 std::unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
296 append(iobuf2, "llo ");
297 std::unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
298 append(iobuf3, "world");
299 iobuf1->prependChain(std::move(iobuf2));
300 iobuf1->prependChain(std::move(iobuf3));
301 EXPECT_EQ(3, iobuf1->countChainElements());
302 EXPECT_EQ(11, iobuf1->computeChainDataLength());
304 // Attempting to gather() more data than available in the chain should fail.
305 // Try from the very beginning of the chain.
306 RWPrivateCursor cursor(iobuf1.get());
307 EXPECT_THROW(cursor.gather(15), std::overflow_error);
308 // Now try from the middle of the chain
310 EXPECT_THROW(cursor.gather(10), std::overflow_error);
312 // Calling gatherAtMost() should succeed, however, and just gather
314 cursor.gatherAtMost(10);
315 EXPECT_EQ(8, cursor.length());
316 EXPECT_EQ(8, cursor.totalLength());
317 EXPECT_FALSE(cursor.isAtEnd());
318 EXPECT_EQ("lo world",
319 folly::StringPiece(reinterpret_cast<const char*>(cursor.data()),
321 EXPECT_EQ(2, iobuf1->countChainElements());
322 EXPECT_EQ(11, iobuf1->computeChainDataLength());
324 // Now try gather again on the chain head
325 cursor = RWPrivateCursor(iobuf1.get());
327 // Since gather() doesn't split buffers, everything should be collapsed into
328 // a single buffer now.
329 EXPECT_EQ(1, iobuf1->countChainElements());
330 EXPECT_EQ(11, iobuf1->computeChainDataLength());
331 EXPECT_EQ(11, cursor.length());
332 EXPECT_EQ(11, cursor.totalLength());
335 TEST(IOBuf, cloneAndInsert) {
336 std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
337 append(iobuf1, "he");
338 std::unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
339 append(iobuf2, "llo ");
340 std::unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
341 append(iobuf3, "world");
342 iobuf1->prependChain(std::move(iobuf2));
343 iobuf1->prependChain(std::move(iobuf3));
344 EXPECT_EQ(3, iobuf1->countChainElements());
345 EXPECT_EQ(11, iobuf1->computeChainDataLength());
347 std::unique_ptr<IOBuf> cloned;
349 Cursor(iobuf1.get()).clone(cloned, 3);
350 EXPECT_EQ(2, cloned->countChainElements());
351 EXPECT_EQ(3, cloned->computeChainDataLength());
354 EXPECT_EQ(11, Cursor(iobuf1.get()).cloneAtMost(cloned, 20));
355 EXPECT_EQ(3, cloned->countChainElements());
356 EXPECT_EQ(11, cloned->computeChainDataLength());
359 EXPECT_THROW({Cursor(iobuf1.get()).clone(cloned, 20);},
363 // Check that inserting in the middle of an iobuf splits
364 RWPrivateCursor cursor(iobuf1.get());
365 Cursor(iobuf1.get()).clone(cloned, 3);
366 EXPECT_EQ(2, cloned->countChainElements());
367 EXPECT_EQ(3, cloned->computeChainDataLength());
371 cursor.insert(std::move(cloned));
372 cursor.insert(folly::IOBuf::create(0));
373 EXPECT_EQ(7, iobuf1->countChainElements());
374 EXPECT_EQ(14, iobuf1->computeChainDataLength());
375 // Check that nextBuf got set correctly to the buffer with 1 byte left
376 EXPECT_EQ(1, cursor.peekBytes().size());
377 cursor.read<uint8_t>();
381 // Check that inserting at the end doesn't create empty buf
382 RWPrivateCursor cursor(iobuf1.get());
383 Cursor(iobuf1.get()).clone(cloned, 1);
384 EXPECT_EQ(1, cloned->countChainElements());
385 EXPECT_EQ(1, cloned->computeChainDataLength());
389 cursor.insert(std::move(cloned));
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 doesn't create empty buf
397 RWPrivateCursor cursor(iobuf1.get());
398 Cursor(iobuf1.get()).clone(cloned, 1);
399 EXPECT_EQ(1, cloned->countChainElements());
400 EXPECT_EQ(1, cloned->computeChainDataLength());
402 cursor.insert(std::move(cloned));
403 EXPECT_EQ(9, iobuf1->countChainElements());
404 EXPECT_EQ(16, iobuf1->computeChainDataLength());
405 // Check that nextBuf got set correctly
406 cursor.read<uint8_t>();
410 TEST(IOBuf, cloneWithEmptyBufAtStart) {
411 folly::IOBufEqual eq;
412 auto empty = IOBuf::create(0);
413 auto hel = IOBuf::create(3);
415 auto lo = IOBuf::create(2);
418 auto iobuf = empty->clone();
419 iobuf->prependChain(hel->clone());
420 iobuf->prependChain(lo->clone());
421 iobuf->prependChain(empty->clone());
422 iobuf->prependChain(hel->clone());
423 iobuf->prependChain(lo->clone());
424 iobuf->prependChain(empty->clone());
425 iobuf->prependChain(lo->clone());
426 iobuf->prependChain(hel->clone());
427 iobuf->prependChain(lo->clone());
428 iobuf->prependChain(lo->clone());
430 Cursor cursor(iobuf.get());
431 std::unique_ptr<IOBuf> cloned;
433 cursor.pull(&data, 3);
434 cursor.clone(cloned, 2);
435 EXPECT_EQ(1, cloned->countChainElements());
436 EXPECT_EQ(2, cloned->length());
437 EXPECT_TRUE(eq(lo, cloned));
439 cursor.pull(&data, 3);
440 EXPECT_EQ("hel", std::string(data, sizeof(data)));
443 cursor.clone(cloned, 2);
444 EXPECT_TRUE(eq(lo, cloned));
446 std::string hello = cursor.readFixedString(5);
447 cursor.clone(cloned, 2);
448 EXPECT_TRUE(eq(lo, cloned));
451 TEST(IOBuf, Appender) {
452 std::unique_ptr<IOBuf> head(IOBuf::create(10));
453 append(head, "hello");
455 Appender app(head.get(), 10);
456 auto cap = head->capacity();
457 auto len1 = app.length();
458 EXPECT_EQ(cap - 5, len1);
459 app.ensure(len1); // won't grow
460 EXPECT_EQ(len1, app.length());
461 app.ensure(len1 + 1); // will grow
462 EXPECT_LE(len1 + 1, app.length());
464 append(app, " world");
465 EXPECT_EQ("hello world", toString(*head));
468 TEST(IOBuf, Printf) {
469 IOBuf head(IOBuf::CREATE, 24);
470 Appender app(&head, 32);
472 app.printf("%s", "test");
473 EXPECT_EQ(head.length(), 4);
474 EXPECT_EQ(0, memcmp(head.data(), "test\0", 5));
476 app.printf("%d%s %s%s %#x", 32, "this string is",
477 "longer than our original allocation size,",
478 "and will therefore require a new allocation", 0x12345678);
479 // The tailroom should start with a nul byte now.
480 EXPECT_GE(head.prev()->tailroom(), 1u);
481 EXPECT_EQ(0, *head.prev()->tail());
483 EXPECT_EQ("test32this string is longer than our original "
484 "allocation size,and will therefore require a "
485 "new allocation 0x12345678",
486 head.moveToFbString().toStdString());
489 TEST(IOBuf, Format) {
490 IOBuf head(IOBuf::CREATE, 24);
491 Appender app(&head, 32);
493 format("{}", "test")(app);
494 EXPECT_EQ(head.length(), 4);
495 EXPECT_EQ(0, memcmp(head.data(), "test", 4));
497 auto fmt = format("{}{} {}{} {:#x}",
498 32, "this string is",
499 "longer than our original allocation size,",
500 "and will therefore require a new allocation",
503 EXPECT_EQ("test32this string is longer than our original "
504 "allocation size,and will therefore require a "
505 "new allocation 0x12345678",
506 head.moveToFbString().toStdString());
509 TEST(IOBuf, QueueAppender) {
510 folly::IOBufQueue queue;
512 // Allocate 100 bytes at once, but don't grow past 1024
513 QueueAppender app(&queue, 100);
514 size_t n = 1024 / sizeof(uint32_t);
515 for (uint32_t i = 0; i < n; ++i) {
519 // There must be a goodMallocSize between 100 and 1024...
520 EXPECT_LT(1u, queue.front()->countChainElements());
521 const IOBuf* buf = queue.front();
523 EXPECT_LE(100u, buf->capacity());
525 } while (buf != queue.front());
527 Cursor cursor(queue.front());
528 for (uint32_t i = 0; i < n; ++i) {
529 EXPECT_EQ(i, cursor.readBE<uint32_t>());
532 EXPECT_THROW({cursor.readBE<uint32_t>();}, std::out_of_range);
535 TEST(IOBuf, QueueAppenderPushAtMostFillBuffer) {
536 folly::IOBufQueue queue;
537 // There should be a goodMallocSize between 125 and 1000
538 QueueAppender appender{&queue, 125};
539 std::vector<uint8_t> data;
541 std::iota(data.begin(), data.end(), 0);
543 appender.pushAtMost(data.data(), 100);
545 appender.pushAtMost(data.data() + 100, data.size() - 100);
546 const auto buf = queue.front();
547 // Should fill the current buffer before adding another
548 EXPECT_LE(2, buf->countChainElements());
549 EXPECT_EQ(0, buf->tailroom());
550 EXPECT_LE(125, buf->length());
551 EXPECT_EQ(1000, buf->computeChainDataLength());
552 const StringPiece sp{(const char*)data.data(), data.size()};
553 EXPECT_EQ(sp, toString(*buf));
556 TEST(IOBuf, QueueAppenderInsertOwn) {
557 auto buf = IOBuf::create(10);
558 folly::IOBufQueue queue;
559 QueueAppender appender{&queue, 128};
560 appender.insert(std::move(buf));
562 std::vector<uint8_t> data;
564 std::iota(data.begin(), data.end(), 0);
565 appender.pushAtMost(folly::range(data));
566 // Buffer is owned, so we should write to it
567 EXPECT_LE(2, queue.front()->countChainElements());
568 EXPECT_EQ(0, queue.front()->tailroom());
569 const StringPiece sp{(const char*)data.data(), data.size()};
570 EXPECT_EQ(sp, toString(*queue.front()));
573 TEST(IOBuf, QueueAppenderInsertClone) {
574 IOBuf buf{IOBuf::CREATE, 100};
575 folly::IOBufQueue queue;
576 QueueAppender appender{&queue, 100};
577 // Buffer is shared, so we create a new buffer to write to
578 appender.insert(buf);
580 appender.pushAtMost(&x, 1);
581 EXPECT_EQ(2, queue.front()->countChainElements());
582 EXPECT_EQ(0, queue.front()->length());
583 EXPECT_LT(0, queue.front()->tailroom());
584 EXPECT_EQ(1, queue.front()->next()->length());
585 EXPECT_EQ(x, queue.front()->next()->data()[0]);
588 TEST(IOBuf, CursorOperators) {
589 // Test operators on a single-item chain
591 std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
594 Cursor curs1(chain1.get());
595 EXPECT_EQ(0, curs1 - chain1.get());
596 EXPECT_FALSE(curs1.isAtEnd());
598 EXPECT_EQ(3, curs1 - chain1.get());
599 EXPECT_FALSE(curs1.isAtEnd());
601 EXPECT_EQ(10, curs1 - chain1.get());
602 EXPECT_TRUE(curs1.isAtEnd());
604 Cursor curs2(chain1.get());
605 EXPECT_EQ(0, curs2 - chain1.get());
606 EXPECT_EQ(10, curs1 - curs2);
607 EXPECT_THROW(curs2 - curs1, std::out_of_range);
610 // Test cross-chain operations
612 std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
614 std::unique_ptr<IOBuf> chain2 = chain1->clone();
616 Cursor curs1(chain1.get());
617 Cursor curs2(chain2.get());
618 EXPECT_THROW(curs1 - curs2, std::out_of_range);
619 EXPECT_THROW(curs1 - chain2.get(), std::out_of_range);
622 // Test operations on multi-item chains
624 std::unique_ptr<IOBuf> chain(IOBuf::create(20));
626 chain->appendChain(chain->clone());
627 EXPECT_EQ(20, chain->computeChainDataLength());
629 Cursor curs1(chain.get());
631 Cursor curs2(chain.get());
633 EXPECT_EQ(2, curs1 - curs2);
634 EXPECT_EQ(5, curs1 - chain.get());
635 EXPECT_THROW(curs2 - curs1, std::out_of_range);
638 EXPECT_EQ(9, curs1 - curs2);
639 EXPECT_EQ(12, curs1 - chain.get());
640 EXPECT_THROW(curs2 - curs1, std::out_of_range);
643 EXPECT_EQ(2, curs1 - curs2);
644 EXPECT_THROW(curs2 - curs1, std::out_of_range);
647 // Test isAtEnd() with empty buffers at the end of a chain
649 auto iobuf1 = IOBuf::create(20);
651 iobuf1->trimStart(5);
653 Cursor c(iobuf1.get());
654 EXPECT_FALSE(c.isAtEnd());
656 EXPECT_TRUE(c.isAtEnd());
658 iobuf1->prependChain(IOBuf::create(10));
659 iobuf1->prependChain(IOBuf::create(10));
660 EXPECT_TRUE(c.isAtEnd());
661 iobuf1->prev()->append(5);
662 EXPECT_FALSE(c.isAtEnd());
664 EXPECT_TRUE(c.isAtEnd());
667 // Test canAdvance with a chain of items
669 auto chain = IOBuf::create(10);
671 chain->appendChain(chain->clone());
672 EXPECT_EQ(2, chain->countChainElements());
673 EXPECT_EQ(20, chain->computeChainDataLength());
675 Cursor c(chain.get());
676 for (size_t i = 0; i <= 20; ++i) {
677 EXPECT_TRUE(c.canAdvance(i));
679 EXPECT_FALSE(c.canAdvance(21));
681 EXPECT_TRUE(c.canAdvance(10));
682 EXPECT_FALSE(c.canAdvance(11));
686 TEST(IOBuf, StringOperations) {
687 // Test a single buffer with two null-terminated strings and an extra uint8_t
690 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
691 Appender app(chain.get(), 0);
692 app.push(reinterpret_cast<const uint8_t*>("hello\0world\0\x01"), 13);
694 Cursor curs(chain.get());
695 EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
696 EXPECT_STREQ("world", curs.readTerminatedString().c_str());
697 EXPECT_EQ(1, curs.read<uint8_t>());
700 // Test multiple buffers where the first is empty and the string starts in
701 // the second buffer.
703 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
704 chain->prependChain(IOBuf::create(12));
705 Appender app(chain.get(), 0);
706 app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
708 Cursor curs(chain.get());
709 EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
712 // Test multiple buffers with a single null-terminated string spanning them
714 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
715 chain->prependChain(IOBuf::create(8));
717 chain->next()->append(4);
718 RWPrivateCursor rwc(chain.get());
719 rwc.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
721 Cursor curs(chain.get());
722 EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
725 // Test a reading a null-terminated string that's longer than the maximum
728 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
729 Appender app(chain.get(), 0);
730 app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
732 Cursor curs(chain.get());
733 EXPECT_THROW(curs.readTerminatedString('\0', 5), std::length_error);
736 // Test reading a null-terminated string from a chain with an empty buffer at
739 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
740 Appender app(buf.get(), 0);
741 app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
742 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
743 chain->prependChain(std::move(buf));
745 Cursor curs(chain.get());
746 EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
749 // Test reading a null-terminated string from a chain that doesn't contain the
752 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
753 Appender app(buf.get(), 0);
754 app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
755 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
756 chain->prependChain(std::move(buf));
758 Cursor curs(chain.get());
759 EXPECT_THROW(curs.readTerminatedString(),
763 // Test reading a null-terminated string past the maximum length
765 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
766 Appender app(buf.get(), 0);
767 app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
768 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
769 chain->prependChain(std::move(buf));
771 Cursor curs(chain.get());
772 EXPECT_THROW(curs.readTerminatedString('\0', 3),
776 // Test reading a two fixed-length strings from a single buffer with an extra
777 // uint8_t at the end
779 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
780 Appender app(chain.get(), 0);
781 app.push(reinterpret_cast<const uint8_t*>("helloworld\x01"), 11);
783 Cursor curs(chain.get());
784 EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
785 EXPECT_STREQ("world", curs.readFixedString(5).c_str());
786 EXPECT_EQ(1, curs.read<uint8_t>());
789 // Test multiple buffers where the first is empty and a fixed-length string
790 // starts in the second buffer.
792 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
793 chain->prependChain(IOBuf::create(16));
794 Appender app(chain.get(), 0);
795 app.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
797 Cursor curs(chain.get());
798 EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
801 // Test multiple buffers with a single fixed-length string spanning them
803 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
804 chain->prependChain(IOBuf::create(8));
806 chain->next()->append(4);
807 RWPrivateCursor rwc(chain.get());
808 rwc.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
810 Cursor curs(chain.get());
811 EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
814 // Test reading a fixed-length string from a chain with an empty buffer at
817 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
818 Appender app(buf.get(), 0);
819 app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
820 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
821 chain->prependChain(std::move(buf));
823 Cursor curs(chain.get());
824 EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
828 TEST(IOBuf, ReadWhileTrue) {
829 auto isAlpha = [](uint8_t ch) {
830 return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
832 auto isDigit = [](uint8_t ch) { return (ch >= '0' && ch <= '9'); };
834 // Test reading alternating alphabetic and numeric strings
836 std::unique_ptr<IOBuf> chain(IOBuf::create(32));
837 Appender app(chain.get(), 0);
838 app.push(StringPiece("hello123world456"));
840 Cursor curs(chain.get());
841 EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
842 EXPECT_STREQ("123", curs.readWhile(isDigit).c_str());
843 EXPECT_STREQ("world", curs.readWhile(isAlpha).c_str());
844 EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
845 EXPECT_TRUE(curs.isAtEnd());
848 // The same, but also use skipWhile()
850 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
851 Appender app(chain.get(), 0);
852 app.push(StringPiece("hello123world456"));
854 Cursor curs(chain.get());
855 EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
856 curs.skipWhile(isDigit);
857 curs.skipWhile(isAlpha);
858 EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
859 EXPECT_TRUE(curs.isAtEnd());
862 // Test readWhile() using data split across multiple buffers,
863 // including some empty buffers in the middle of the chain.
865 std::unique_ptr<IOBuf> chain;
867 // First element in the chain has "he"
868 auto buf = IOBuf::create(40);
869 Appender app(buf.get(), 0);
870 app.push(StringPiece("he"));
871 chain = std::move(buf);
873 // The second element has "ll", after 10 bytes of headroom
874 buf = IOBuf::create(40);
876 app = Appender{buf.get(), 0};
877 app.push(StringPiece("ll"));
878 chain->prependChain(std::move(buf));
880 // The third element is empty
881 buf = IOBuf::create(40);
883 chain->prependChain(std::move(buf));
885 // The fourth element has "o12"
886 buf = IOBuf::create(40);
888 app = Appender{buf.get(), 0};
889 app.push(StringPiece("o12"));
890 chain->prependChain(std::move(buf));
892 // The fifth element has "3"
893 buf = IOBuf::create(40);
894 app = Appender{buf.get(), 0};
895 app.push(StringPiece("3"));
896 chain->prependChain(std::move(buf));
898 // The sixth element is empty
899 buf = IOBuf::create(40);
900 chain->prependChain(std::move(buf));
902 // The seventh element has "world456"
903 buf = IOBuf::create(40);
904 app = Appender{buf.get(), 0};
905 app.push(StringPiece("world456"));
906 chain->prependChain(std::move(buf));
908 // The eighth element is empty
909 buf = IOBuf::create(40);
910 chain->prependChain(std::move(buf));
912 Cursor curs(chain.get());
913 EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
914 EXPECT_STREQ("123", curs.readWhile(isDigit).c_str());
915 EXPECT_STREQ("world", curs.readWhile(isAlpha).c_str());
916 EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
917 EXPECT_TRUE(curs.isAtEnd());
921 TEST(IOBuf, TestAdvanceToEndSingle) {
922 std::unique_ptr<IOBuf> chain(IOBuf::create(10));
925 Cursor curs(chain.get());
927 EXPECT_TRUE(curs.isAtEnd());
928 EXPECT_EQ(curs - chain.get(), 10);
931 TEST(IOBuf, TestAdvanceToEndMulti) {
932 std::unique_ptr<IOBuf> chain(IOBuf::create(10));
935 std::unique_ptr<IOBuf> buf(IOBuf::create(5));
937 chain->prependChain(std::move(buf));
939 buf = IOBuf::create(20);
941 chain->prependChain(std::move(buf));
943 Cursor curs(chain.get());
945 EXPECT_TRUE(curs.isAtEnd());
946 EXPECT_EQ(curs - chain.get(), 35);
948 curs.reset(chain.get());
951 EXPECT_TRUE(curs.isAtEnd());
954 TEST(IOBuf, TestRetreatSingle) {
955 std::unique_ptr<IOBuf> chain(IOBuf::create(20));
958 Cursor curs(chain.get());
959 EXPECT_EQ(curs.retreatAtMost(0), 0);
960 EXPECT_EQ(curs.totalLength(), 20);
961 EXPECT_EQ(curs.retreatAtMost(5), 0);
962 EXPECT_EQ(curs.totalLength(), 20);
963 EXPECT_EQ(curs.retreatAtMost(25), 0);
964 EXPECT_EQ(curs.totalLength(), 20);
967 EXPECT_THROW(curs.retreat(5), std::out_of_range);
968 curs.reset(chain.get());
969 EXPECT_THROW(curs.retreat(25), std::out_of_range);
970 curs.reset(chain.get());
974 EXPECT_EQ(curs.totalLength(), 5);
976 EXPECT_EQ(curs.totalLength(), 15);
977 EXPECT_THROW(curs.retreat(10), std::out_of_range);
979 curs.reset(chain.get());
981 EXPECT_EQ(curs.retreatAtMost(5), 5);
982 EXPECT_EQ(curs.totalLength(), 5);
983 EXPECT_EQ(curs.retreatAtMost(10), 10);
984 EXPECT_EQ(curs.totalLength(), 15);
985 EXPECT_EQ(curs.retreatAtMost(10), 5);
986 EXPECT_EQ(curs.totalLength(), 20);
989 TEST(IOBuf, TestRetreatMulti) {
990 std::unique_ptr<IOBuf> chain(IOBuf::create(10));
993 std::unique_ptr<IOBuf> buf(IOBuf::create(5));
995 chain->prependChain(std::move(buf));
997 buf = IOBuf::create(20);
999 chain->prependChain(std::move(buf));
1001 Cursor curs(chain.get());
1002 EXPECT_EQ(curs.retreatAtMost(10), 0);
1003 EXPECT_THROW(curs.retreat(10), std::out_of_range);
1004 curs.reset(chain.get());
1006 curs.advanceToEnd();
1008 EXPECT_EQ(curs.totalLength(), 20);
1009 EXPECT_EQ(curs.length(), 20);
1011 EXPECT_EQ(curs.totalLength(), 21);
1012 EXPECT_EQ(curs.length(), 1);
1013 EXPECT_EQ(curs.retreatAtMost(50), 14);
1014 EXPECT_EQ(curs.totalLength(), 35);
1016 curs.advanceToEnd();
1018 EXPECT_EQ(curs.totalLength(), 30);
1021 TEST(IOBuf, TestRetreatOperators) {
1022 std::unique_ptr<IOBuf> chain(IOBuf::create(20));
1025 Cursor curs(chain.get());
1026 curs.advanceToEnd();
1028 EXPECT_EQ(curs.totalLength(), 5);
1030 curs.advanceToEnd();
1031 auto retreated = curs - 5;
1032 EXPECT_EQ(retreated.totalLength(), 5);
1033 EXPECT_EQ(curs.totalLength(), 0);
1036 TEST(IOBuf, tryRead) {
1037 unique_ptr<IOBuf> iobuf1(IOBuf::create(6));
1039 unique_ptr<IOBuf> iobuf2(IOBuf::create(24));
1042 iobuf1->prependChain(std::move(iobuf2));
1044 EXPECT_TRUE(iobuf1->isChained());
1046 RWPrivateCursor wcursor(iobuf1.get());
1047 Cursor rcursor(iobuf1.get());
1048 wcursor.writeLE((uint32_t)1);
1049 wcursor.writeLE((uint64_t)1);
1050 wcursor.writeLE((uint64_t)1);
1051 wcursor.writeLE((uint64_t)1);
1052 wcursor.writeLE((uint16_t)1);
1053 EXPECT_EQ(0, wcursor.totalLength());
1055 EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1057 EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1058 EXPECT_EQ(0u, rcursor.readLE<uint32_t>());
1060 EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1064 EXPECT_TRUE(rcursor.tryRead(val));
1066 EXPECT_TRUE(rcursor.tryRead(val));
1069 EXPECT_FALSE(rcursor.tryRead(val));
1072 TEST(IOBuf, tryReadLE) {
1073 IOBuf buf{IOBuf::CREATE, 4};
1076 RWPrivateCursor wcursor(&buf);
1077 Cursor rcursor(&buf);
1079 const uint32_t expected = 0x01020304;
1080 wcursor.writeLE(expected);
1082 EXPECT_TRUE(rcursor.tryReadLE(actual));
1083 EXPECT_EQ(expected, actual);
1086 TEST(IOBuf, tryReadBE) {
1087 IOBuf buf{IOBuf::CREATE, 4};
1090 RWPrivateCursor wcursor(&buf);
1091 Cursor rcursor(&buf);
1093 const uint32_t expected = 0x01020304;
1094 wcursor.writeBE(expected);
1096 EXPECT_TRUE(rcursor.tryReadBE(actual));
1097 EXPECT_EQ(expected, actual);
1100 TEST(IOBuf, tryReadConsumesAllInputOnFailure) {
1101 IOBuf buf{IOBuf::CREATE, 2};
1104 Cursor rcursor(&buf);
1106 EXPECT_FALSE(rcursor.tryRead(val));
1107 EXPECT_EQ(0, rcursor.totalLength());
1110 TEST(IOBuf, readConsumesAllInputOnFailure) {
1111 IOBuf buf{IOBuf::CREATE, 2};
1114 Cursor rcursor(&buf);
1115 EXPECT_THROW(rcursor.read<uint32_t>(), std::out_of_range);
1116 EXPECT_EQ(0, rcursor.totalLength());