2 * Copyright 2016 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/io/Cursor-defs.h>
24 #include <gtest/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(1, rcursor.readLE<uint64_t>());
53 EXPECT_EQ(1, rcursor.readLE<uint32_t>());
55 EXPECT_EQ(0, rcursor.read<uint8_t>());
56 EXPECT_EQ(0, rcursor.read<uint8_t>());
57 EXPECT_EQ(0, rcursor.read<uint8_t>());
58 EXPECT_EQ(0, rcursor.read<uint8_t>());
59 EXPECT_EQ(1, 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.
145 EXPECT_EQ(true, false);
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 uint32_t cap = head->capacity();
457 uint32_t 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(), 1);
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(1, queue.front()->countChainElements());
521 const IOBuf* buf = queue.front();
523 EXPECT_LE(100, 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, CursorOperators) {
536 // Test operators on a single-item chain
538 std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
541 Cursor curs1(chain1.get());
542 EXPECT_EQ(0, curs1 - chain1.get());
543 EXPECT_FALSE(curs1.isAtEnd());
545 EXPECT_EQ(3, curs1 - chain1.get());
546 EXPECT_FALSE(curs1.isAtEnd());
548 EXPECT_EQ(10, curs1 - chain1.get());
549 EXPECT_TRUE(curs1.isAtEnd());
551 Cursor curs2(chain1.get());
552 EXPECT_EQ(0, curs2 - chain1.get());
553 EXPECT_EQ(10, curs1 - curs2);
554 EXPECT_THROW(curs2 - curs1, std::out_of_range);
557 // Test cross-chain operations
559 std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
561 std::unique_ptr<IOBuf> chain2 = chain1->clone();
563 Cursor curs1(chain1.get());
564 Cursor curs2(chain2.get());
565 EXPECT_THROW(curs1 - curs2, std::out_of_range);
566 EXPECT_THROW(curs1 - chain2.get(), std::out_of_range);
569 // Test operations on multi-item chains
571 std::unique_ptr<IOBuf> chain(IOBuf::create(20));
573 chain->appendChain(chain->clone());
574 EXPECT_EQ(20, chain->computeChainDataLength());
576 Cursor curs1(chain.get());
578 Cursor curs2(chain.get());
580 EXPECT_EQ(2, curs1 - curs2);
581 EXPECT_EQ(5, curs1 - chain.get());
582 EXPECT_THROW(curs2 - curs1, std::out_of_range);
585 EXPECT_EQ(9, curs1 - curs2);
586 EXPECT_EQ(12, curs1 - chain.get());
587 EXPECT_THROW(curs2 - curs1, std::out_of_range);
590 EXPECT_EQ(2, curs1 - curs2);
591 EXPECT_THROW(curs2 - curs1, std::out_of_range);
594 // Test isAtEnd() with empty buffers at the end of a chain
596 auto iobuf1 = IOBuf::create(20);
598 iobuf1->trimStart(5);
600 Cursor c(iobuf1.get());
601 EXPECT_FALSE(c.isAtEnd());
603 EXPECT_TRUE(c.isAtEnd());
605 iobuf1->prependChain(IOBuf::create(10));
606 iobuf1->prependChain(IOBuf::create(10));
607 EXPECT_TRUE(c.isAtEnd());
608 iobuf1->prev()->append(5);
609 EXPECT_FALSE(c.isAtEnd());
611 EXPECT_TRUE(c.isAtEnd());
614 // Test canAdvance with a chain of items
616 auto chain = IOBuf::create(10);
618 chain->appendChain(chain->clone());
619 EXPECT_EQ(2, chain->countChainElements());
620 EXPECT_EQ(20, chain->computeChainDataLength());
622 Cursor c(chain.get());
623 for (size_t i = 0; i <= 20; ++i) {
624 EXPECT_TRUE(c.canAdvance(i));
626 EXPECT_FALSE(c.canAdvance(21));
628 EXPECT_TRUE(c.canAdvance(10));
629 EXPECT_FALSE(c.canAdvance(11));
633 TEST(IOBuf, StringOperations) {
634 // Test a single buffer with two null-terminated strings and an extra uint8_t
637 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
638 Appender app(chain.get(), 0);
639 app.push(reinterpret_cast<const uint8_t*>("hello\0world\0\x01"), 13);
641 Cursor curs(chain.get());
642 EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
643 EXPECT_STREQ("world", curs.readTerminatedString().c_str());
644 EXPECT_EQ(1, curs.read<uint8_t>());
647 // Test multiple buffers where the first is empty and the string starts in
648 // the second buffer.
650 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
651 chain->prependChain(IOBuf::create(12));
652 Appender app(chain.get(), 0);
653 app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
655 Cursor curs(chain.get());
656 EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
659 // Test multiple buffers with a single null-terminated string spanning them
661 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
662 chain->prependChain(IOBuf::create(8));
664 chain->next()->append(4);
665 RWPrivateCursor rwc(chain.get());
666 rwc.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
668 Cursor curs(chain.get());
669 EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
672 // Test a reading a null-terminated string that's longer than the maximum
675 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
676 Appender app(chain.get(), 0);
677 app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
679 Cursor curs(chain.get());
680 EXPECT_THROW(curs.readTerminatedString('\0', 5), std::length_error);
683 // Test reading a null-terminated string from a chain with an empty buffer at
686 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
687 Appender app(buf.get(), 0);
688 app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
689 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
690 chain->prependChain(std::move(buf));
692 Cursor curs(chain.get());
693 EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
696 // Test reading a null-terminated string from a chain that doesn't contain the
699 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
700 Appender app(buf.get(), 0);
701 app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
702 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
703 chain->prependChain(std::move(buf));
705 Cursor curs(chain.get());
706 EXPECT_THROW(curs.readTerminatedString(),
710 // Test reading a null-terminated string past the maximum length
712 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
713 Appender app(buf.get(), 0);
714 app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
715 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
716 chain->prependChain(std::move(buf));
718 Cursor curs(chain.get());
719 EXPECT_THROW(curs.readTerminatedString('\0', 3),
723 // Test reading a two fixed-length strings from a single buffer with an extra
724 // uint8_t at the end
726 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
727 Appender app(chain.get(), 0);
728 app.push(reinterpret_cast<const uint8_t*>("helloworld\x01"), 11);
730 Cursor curs(chain.get());
731 EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
732 EXPECT_STREQ("world", curs.readFixedString(5).c_str());
733 EXPECT_EQ(1, curs.read<uint8_t>());
736 // Test multiple buffers where the first is empty and a fixed-length string
737 // starts in the second buffer.
739 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
740 chain->prependChain(IOBuf::create(16));
741 Appender app(chain.get(), 0);
742 app.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
744 Cursor curs(chain.get());
745 EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
748 // Test multiple buffers with a single fixed-length string spanning them
750 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
751 chain->prependChain(IOBuf::create(8));
753 chain->next()->append(4);
754 RWPrivateCursor rwc(chain.get());
755 rwc.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
757 Cursor curs(chain.get());
758 EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
761 // Test reading a fixed-length string from a chain with an empty buffer at
764 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
765 Appender app(buf.get(), 0);
766 app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
767 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
768 chain->prependChain(std::move(buf));
770 Cursor curs(chain.get());
771 EXPECT_STREQ("hello", curs.readFixedString(5).c_str());