Properly handle appending to the tail of the chain
[folly.git] / folly / io / test / IOBufCursorTest.cpp
1 /*
2  * Copyright 2013-present Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 #include <folly/io/IOBuf.h>
17
18 #include <folly/Format.h>
19 #include <folly/Range.h>
20 #include <folly/io/Cursor.h>
21 #include <folly/portability/GTest.h>
22 #include <numeric>
23 #include <vector>
24
25 using folly::ByteRange;
26 using folly::format;
27 using folly::IOBuf;
28 using folly::StringPiece;
29 using std::unique_ptr;
30 using namespace folly::io;
31
32 TEST(IOBuf, RWCursor) {
33   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
34   iobuf1->append(20);
35   unique_ptr<IOBuf> iobuf2(IOBuf::create(20));
36   iobuf2->append(20);
37
38   iobuf2.get();
39   iobuf1->prependChain(std::move(iobuf2));
40
41   EXPECT_TRUE(iobuf1->isChained());
42
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);
49
50   EXPECT_EQ(1u, rcursor.readLE<uint64_t>());
51   rcursor.skip(8);
52   EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
53   rcursor.skip(0);
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>());
59 }
60
61 TEST(IOBuf, skip) {
62   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
63   iobuf1->append(20);
64   RWPrivateCursor wcursor(iobuf1.get());
65   wcursor.write((uint8_t)1);
66   wcursor.write((uint8_t)2);
67   Cursor cursor(iobuf1.get());
68   cursor.skip(1);
69   EXPECT_EQ(2, cursor.read<uint8_t>());
70 }
71
72 TEST(IOBuf, reset) {
73   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
74   iobuf1->append(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>());
80 }
81
82 TEST(IOBuf, copy_assign_convert) {
83   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
84   iobuf1->append(20);
85   RWPrivateCursor wcursor(iobuf1.get());
86   RWPrivateCursor cursor2(wcursor);
87   RWPrivateCursor cursor3(iobuf1.get());
88
89   wcursor.write((uint8_t)1);
90   cursor3 = wcursor;
91   wcursor.write((uint8_t)2);
92   Cursor cursor4(wcursor);
93   RWPrivateCursor cursor5(wcursor);
94   wcursor.write((uint8_t)3);
95
96   EXPECT_EQ(1, cursor2.read<uint8_t>());
97   EXPECT_EQ(2, cursor3.read<uint8_t>());
98   EXPECT_EQ(3, cursor4.read<uint8_t>());
99 }
100
101 TEST(IOBuf, arithmetic) {
102   IOBuf iobuf1(IOBuf::CREATE, 20);
103   iobuf1.append(20);
104   RWPrivateCursor wcursor(&iobuf1);
105   wcursor += 1;
106   wcursor.write((uint8_t)1);
107   Cursor cursor(&iobuf1);
108   cursor += 1;
109   EXPECT_EQ(1, cursor.read<uint8_t>());
110
111   Cursor start(&iobuf1);
112   Cursor cursor2 = start + 9;
113   EXPECT_EQ(7, cursor2 - cursor);
114   EXPECT_NE(cursor, cursor2);
115   cursor += 8;
116   cursor2 = cursor2 + 1;
117   EXPECT_EQ(cursor, cursor2);
118 }
119
120 TEST(IOBuf, endian) {
121   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
122   iobuf1->append(20);
123   RWPrivateCursor wcursor(iobuf1.get());
124   Cursor rcursor(iobuf1.get());
125   uint16_t v = 1;
126   int16_t vu = -1;
127   wcursor.writeBE(v);
128   wcursor.writeBE(vu);
129   // Try a couple combinations to ensure they were generated correctly
130   wcursor.writeBE(vu);
131   wcursor.writeLE(vu);
132   wcursor.writeLE(vu);
133   wcursor.writeLE(v);
134   EXPECT_EQ(v, rcursor.readBE<uint16_t>());
135 }
136
137 TEST(IOBuf, Cursor) {
138   unique_ptr<IOBuf> iobuf1(IOBuf::create(1));
139   iobuf1->append(1);
140   RWPrivateCursor c(iobuf1.get());
141   c.write((uint8_t)40); // OK
142   try {
143     c.write((uint8_t)10); // Bad write, checked should except.
144     ADD_FAILURE();
145   } catch (...) {
146   }
147 }
148
149 TEST(IOBuf, UnshareCursor) {
150   uint8_t buf = 0;
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());
155
156   c1.write((uint8_t)10); // This should duplicate the two buffers.
157   uint8_t t = c2.read<uint8_t>();
158   EXPECT_EQ(0, t);
159
160   iobuf1 = IOBuf::wrapBuffer(&buf, 1);
161   iobuf2 = IOBuf::wrapBuffer(&buf, 1);
162   RWPrivateCursor c3(iobuf1.get());
163   RWPrivateCursor c4(iobuf2.get());
164
165   c3.write((uint8_t)10); // This should _not_ duplicate the two buffers.
166   t = c4.read<uint8_t>();
167   EXPECT_EQ(10, t);
168 }
169
170 namespace {
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());
175 }
176
177 void append(Appender& appender, StringPiece data) {
178   appender.push(ByteRange(data));
179 }
180
181 std::string toString(const IOBuf& buf) {
182   std::string str;
183   Cursor cursor(&buf);
184   ByteRange b;
185   while (!(b = cursor.peekBytes()).empty()) {
186     str.append(reinterpret_cast<const char*>(b.data()), b.size());
187     cursor.skip(b.size());
188   }
189   return str;
190 }
191
192 } // namespace
193
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());
205
206   char buf[12];
207   memset(buf, 0, sizeof(buf));
208   Cursor(iobuf1.get()).pull(buf, 11);
209   EXPECT_EQ("hello world", std::string(buf));
210
211   memset(buf, 0, sizeof(buf));
212   EXPECT_EQ(11, Cursor(iobuf1.get()).pullAtMost(buf, 20));
213   EXPECT_EQ("hello world", std::string(buf));
214
215   EXPECT_THROW({Cursor(iobuf1.get()).pull(buf, 20);},
216                std::out_of_range);
217
218   {
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());
231   }
232
233   {
234     RWPrivateCursor cursor(iobuf1.get());
235     cursor.gather(11);
236     auto b = cursor.peekBytes();
237     EXPECT_EQ("hello world", StringPiece(b));
238     EXPECT_EQ(1, iobuf1->countChainElements());
239     EXPECT_EQ(11, iobuf1->computeChainDataLength());
240   }
241 }
242
243 TEST(IOBuf, pushCursorData) {
244   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
245   iobuf1->append(15);
246   iobuf1->trimStart(5);
247   unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
248   unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
249   iobuf3->append(10);
250
251   iobuf1->prependChain(std::move(iobuf2));
252   iobuf1->prependChain(std::move(iobuf3));
253   EXPECT_TRUE(iobuf1->isChained());
254
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());
262
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());
271
272   // create another write buffer
273   unique_ptr<IOBuf> iobuf4(IOBuf::create(30));
274   iobuf4->append(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);
282
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>());
288 }
289
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());
301
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
307   cursor += 3;
308   EXPECT_THROW(cursor.gather(10), std::overflow_error);
309
310   // Calling gatherAtMost() should succeed, however, and just gather
311   // as much as it can
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()),
318                                cursor.length()));
319   EXPECT_EQ(2, iobuf1->countChainElements());
320   EXPECT_EQ(11, iobuf1->computeChainDataLength());
321
322   // Now try gather again on the chain head
323   cursor = RWPrivateCursor(iobuf1.get());
324   cursor.gather(5);
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());
331 }
332
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());
344
345   std::unique_ptr<IOBuf> cloned;
346
347   Cursor(iobuf1.get()).clone(cloned, 3);
348   EXPECT_EQ(2, cloned->countChainElements());
349   EXPECT_EQ(3, cloned->computeChainDataLength());
350
351
352   EXPECT_EQ(11, Cursor(iobuf1.get()).cloneAtMost(cloned, 20));
353   EXPECT_EQ(3, cloned->countChainElements());
354   EXPECT_EQ(11, cloned->computeChainDataLength());
355
356
357   EXPECT_THROW({Cursor(iobuf1.get()).clone(cloned, 20);},
358                std::out_of_range);
359
360   {
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());
366
367     cursor.skip(1);
368
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>();
377   }
378
379   {
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());
385
386     cursor.skip(1);
387
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>();
394   }
395   {
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());
402
403     cursor.skip(1);
404
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>();
412   }
413   {
414     // Check that inserting at the beginning of a chain DOES keep an empty
415     // buffer.
416     RWPrivateCursor cursor(iobuf1.get());
417     Cursor(iobuf1.get()).clone(cloned, 1);
418     EXPECT_EQ(1, cloned->countChainElements());
419     EXPECT_EQ(1, cloned->computeChainDataLength());
420
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>();
428   }
429   {
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());
435
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());
444   }
445 }
446
447 TEST(IOBuf, cloneWithEmptyBufAtStart) {
448   folly::IOBufEqual eq;
449   auto empty = IOBuf::create(0);
450   auto hel = IOBuf::create(3);
451   append(hel, "hel");
452   auto lo = IOBuf::create(2);
453   append(lo, "lo");
454
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());
466
467   Cursor cursor(iobuf.get());
468   std::unique_ptr<IOBuf> cloned;
469   char data[3];
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));
475
476   cursor.pull(&data, 3);
477   EXPECT_EQ("hel", std::string(data, sizeof(data)));
478
479   cursor.skip(2);
480   cursor.clone(cloned, 2);
481   EXPECT_TRUE(eq(lo, cloned));
482
483   std::string hello = cursor.readFixedString(5);
484   cursor.clone(cloned, 2);
485   EXPECT_TRUE(eq(lo, cloned));
486 }
487
488 TEST(IOBuf, Appender) {
489   std::unique_ptr<IOBuf> head(IOBuf::create(10));
490   append(head, "hello");
491
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());
500
501   append(app, " world");
502   EXPECT_EQ("hello world", toString(*head));
503 }
504
505 TEST(IOBuf, Printf) {
506   IOBuf head(IOBuf::CREATE, 24);
507   Appender app(&head, 32);
508
509   app.printf("%s", "test");
510   EXPECT_EQ(head.length(), 4);
511   EXPECT_EQ(0, memcmp(head.data(), "test\0", 5));
512
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());
519
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());
524 }
525
526 TEST(IOBuf, Format) {
527   IOBuf head(IOBuf::CREATE, 24);
528   Appender app(&head, 32);
529
530   format("{}", "test")(app);
531   EXPECT_EQ(head.length(), 4);
532   EXPECT_EQ(0, memcmp(head.data(), "test", 4));
533
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",
538                     0x12345678);
539   fmt(app);
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());
544 }
545
546 TEST(IOBuf, QueueAppender) {
547   folly::IOBufQueue queue;
548
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) {
553     app.writeBE(i);
554   }
555
556   // There must be a goodMallocSize between 100 and 1024...
557   EXPECT_LT(1u, queue.front()->countChainElements());
558   const IOBuf* buf = queue.front();
559   do {
560     EXPECT_LE(100u, buf->capacity());
561     buf = buf->next();
562   } while (buf != queue.front());
563
564   Cursor cursor(queue.front());
565   for (uint32_t i = 0; i < n; ++i) {
566     EXPECT_EQ(i, cursor.readBE<uint32_t>());
567   }
568
569   EXPECT_THROW({cursor.readBE<uint32_t>();}, std::out_of_range);
570 }
571
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;
577   data.resize(1000);
578   std::iota(data.begin(), data.end(), uint8_t(0));
579   // Add 100 byte
580   appender.pushAtMost(data.data(), 100);
581   // Add 900 bytes
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));
591 }
592
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));
598
599   std::vector<uint8_t> data;
600   data.resize(256);
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()));
608 }
609
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);
616   uint8_t x = 42;
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]);
623 }
624
625 TEST(IOBuf, CursorOperators) {
626   // Test operators on a single-item chain
627   {
628     std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
629     chain1->append(10);
630
631     Cursor curs1(chain1.get());
632     EXPECT_EQ(0, curs1 - chain1.get());
633     EXPECT_FALSE(curs1.isAtEnd());
634     curs1.skip(3);
635     EXPECT_EQ(3, curs1 - chain1.get());
636     EXPECT_FALSE(curs1.isAtEnd());
637     curs1.skip(7);
638     EXPECT_EQ(10, curs1 - chain1.get());
639     EXPECT_TRUE(curs1.isAtEnd());
640
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);
645   }
646
647   // Test cross-chain operations
648   {
649     std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
650     chain1->append(10);
651     std::unique_ptr<IOBuf> chain2 = chain1->clone();
652
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);
657   }
658
659   // Test operations on multi-item chains
660   {
661     std::unique_ptr<IOBuf> chain(IOBuf::create(20));
662     chain->append(10);
663     chain->appendChain(chain->clone());
664     EXPECT_EQ(20, chain->computeChainDataLength());
665
666     Cursor curs1(chain.get());
667     curs1.skip(5);
668     Cursor curs2(chain.get());
669     curs2.skip(3);
670     EXPECT_EQ(2, curs1 - curs2);
671     EXPECT_EQ(5, curs1 - chain.get());
672     EXPECT_THROW(curs2 - curs1, std::out_of_range);
673
674     curs1.skip(7);
675     EXPECT_EQ(9, curs1 - curs2);
676     EXPECT_EQ(12, curs1 - chain.get());
677     EXPECT_THROW(curs2 - curs1, std::out_of_range);
678
679     curs2.skip(7);
680     EXPECT_EQ(2, curs1 - curs2);
681     EXPECT_THROW(curs2 - curs1, std::out_of_range);
682   }
683
684   // Test isAtEnd() with empty buffers at the end of a chain
685   {
686     auto iobuf1 = IOBuf::create(20);
687     iobuf1->append(15);
688     iobuf1->trimStart(5);
689
690     Cursor c(iobuf1.get());
691     EXPECT_FALSE(c.isAtEnd());
692     c.skip(10);
693     EXPECT_TRUE(c.isAtEnd());
694
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());
700     c.skip(5);
701     EXPECT_TRUE(c.isAtEnd());
702   }
703
704   // Test canAdvance with a chain of items
705   {
706     auto chain = IOBuf::create(10);
707     chain->append(10);
708     chain->appendChain(chain->clone());
709     EXPECT_EQ(2, chain->countChainElements());
710     EXPECT_EQ(20, chain->computeChainDataLength());
711
712     Cursor c(chain.get());
713     for (size_t i = 0; i <= 20; ++i) {
714       EXPECT_TRUE(c.canAdvance(i));
715     }
716     EXPECT_FALSE(c.canAdvance(21));
717     c.skip(10);
718     EXPECT_TRUE(c.canAdvance(10));
719     EXPECT_FALSE(c.canAdvance(11));
720   }
721 }
722
723 TEST(IOBuf, StringOperations) {
724   // Test a single buffer with two null-terminated strings and an extra uint8_t
725   // at the end
726   {
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);
730
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>());
735   }
736
737   // Test multiple buffers where the first is empty and the string starts in
738   // the second buffer.
739   {
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);
744
745     Cursor curs(chain.get());
746     EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
747   }
748
749   // Test multiple buffers with a single null-terminated string spanning them
750   {
751     std::unique_ptr<IOBuf> chain(IOBuf::create(8));
752     chain->prependChain(IOBuf::create(8));
753     chain->append(8);
754     chain->next()->append(4);
755     RWPrivateCursor rwc(chain.get());
756     rwc.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
757
758     Cursor curs(chain.get());
759     EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
760   }
761
762   // Test a reading a null-terminated string that's longer than the maximum
763   // allowable length
764   {
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);
768
769     Cursor curs(chain.get());
770     EXPECT_THROW(curs.readTerminatedString('\0', 5), std::length_error);
771   }
772
773   // Test reading a null-terminated string from a chain with an empty buffer at
774   // the front
775   {
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));
781
782     Cursor curs(chain.get());
783     EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
784   }
785
786   // Test reading a null-terminated string from a chain that doesn't contain the
787   // terminator
788   {
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));
794
795     Cursor curs(chain.get());
796     EXPECT_THROW(curs.readTerminatedString(),
797                  std::out_of_range);
798   }
799
800   // Test reading a null-terminated string past the maximum length
801   {
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));
807
808     Cursor curs(chain.get());
809     EXPECT_THROW(curs.readTerminatedString('\0', 3),
810                  std::length_error);
811   }
812
813   // Test reading a two fixed-length strings from a single buffer with an extra
814   // uint8_t at the end
815   {
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);
819
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>());
824   }
825
826   // Test multiple buffers where the first is empty and a fixed-length string
827   // starts in the second buffer.
828   {
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);
833
834     Cursor curs(chain.get());
835     EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
836   }
837
838   // Test multiple buffers with a single fixed-length string spanning them
839   {
840     std::unique_ptr<IOBuf> chain(IOBuf::create(8));
841     chain->prependChain(IOBuf::create(8));
842     chain->append(7);
843     chain->next()->append(4);
844     RWPrivateCursor rwc(chain.get());
845     rwc.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
846
847     Cursor curs(chain.get());
848     EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
849   }
850
851   // Test reading a fixed-length string from a chain with an empty buffer at
852   // the front
853   {
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));
859
860     Cursor curs(chain.get());
861     EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
862   }
863 }
864
865 TEST(IOBuf, ReadWhileTrue) {
866   auto isAlpha = [](uint8_t ch) {
867     return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
868   };
869   auto isDigit = [](uint8_t ch) { return (ch >= '0' && ch <= '9'); };
870
871   // Test reading alternating alphabetic and numeric strings
872   {
873     std::unique_ptr<IOBuf> chain(IOBuf::create(32));
874     Appender app(chain.get(), 0);
875     app.push(StringPiece("hello123world456"));
876
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());
883   }
884
885   // The same, but also use skipWhile()
886   {
887     std::unique_ptr<IOBuf> chain(IOBuf::create(16));
888     Appender app(chain.get(), 0);
889     app.push(StringPiece("hello123world456"));
890
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());
897   }
898
899   // Test readWhile() using data split across multiple buffers,
900   // including some empty buffers in the middle of the chain.
901   {
902     std::unique_ptr<IOBuf> chain;
903
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);
909
910     // The second element has "ll", after 10 bytes of headroom
911     buf = IOBuf::create(40);
912     buf->advance(10);
913     app = Appender{buf.get(), 0};
914     app.push(StringPiece("ll"));
915     chain->prependChain(std::move(buf));
916
917     // The third element is empty
918     buf = IOBuf::create(40);
919     buf->advance(15);
920     chain->prependChain(std::move(buf));
921
922     // The fourth element has "o12"
923     buf = IOBuf::create(40);
924     buf->advance(37);
925     app = Appender{buf.get(), 0};
926     app.push(StringPiece("o12"));
927     chain->prependChain(std::move(buf));
928
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));
934
935     // The sixth element is empty
936     buf = IOBuf::create(40);
937     chain->prependChain(std::move(buf));
938
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));
944
945     // The eighth element is empty
946     buf = IOBuf::create(40);
947     chain->prependChain(std::move(buf));
948
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());
955   }
956 }
957
958 TEST(IOBuf, TestAdvanceToEndSingle) {
959   std::unique_ptr<IOBuf> chain(IOBuf::create(10));
960   chain->append(10);
961
962   Cursor curs(chain.get());
963   curs.advanceToEnd();
964   EXPECT_TRUE(curs.isAtEnd());
965   EXPECT_EQ(curs - chain.get(), 10);
966 }
967
968 TEST(IOBuf, TestAdvanceToEndMulti) {
969   std::unique_ptr<IOBuf> chain(IOBuf::create(10));
970   chain->append(10);
971
972   std::unique_ptr<IOBuf> buf(IOBuf::create(5));
973   buf->append(5);
974   chain->prependChain(std::move(buf));
975
976   buf = IOBuf::create(20);
977   buf->append(20);
978   chain->prependChain(std::move(buf));
979
980   Cursor curs(chain.get());
981   curs.advanceToEnd();
982   EXPECT_TRUE(curs.isAtEnd());
983   EXPECT_EQ(curs - chain.get(), 35);
984
985   curs.reset(chain.get());
986   curs.skip(12);
987   curs.advanceToEnd();
988   EXPECT_TRUE(curs.isAtEnd());
989 }
990
991 TEST(IOBuf, TestRetreatSingle) {
992   std::unique_ptr<IOBuf> chain(IOBuf::create(20));
993   chain->append(20);
994
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);
1002
1003   curs.retreat(0);
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());
1008
1009   curs.advanceToEnd();
1010   curs.retreat(5);
1011   EXPECT_EQ(curs.totalLength(), 5);
1012   curs.retreat(10);
1013   EXPECT_EQ(curs.totalLength(), 15);
1014   EXPECT_THROW(curs.retreat(10), std::out_of_range);
1015
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);
1024 }
1025
1026 TEST(IOBuf, TestRetreatMulti) {
1027   std::unique_ptr<IOBuf> chain(IOBuf::create(10));
1028   chain->append(10);
1029
1030   std::unique_ptr<IOBuf> buf(IOBuf::create(5));
1031   buf->append(5);
1032   chain->prependChain(std::move(buf));
1033
1034   buf = IOBuf::create(20);
1035   buf->append(20);
1036   chain->prependChain(std::move(buf));
1037
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());
1042
1043   curs.advanceToEnd();
1044   curs.retreat(20);
1045   EXPECT_EQ(curs.totalLength(), 20);
1046   EXPECT_EQ(curs.length(), 20);
1047   curs.retreat(1);
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);
1052
1053   curs.advanceToEnd();
1054   curs.retreat(30);
1055   EXPECT_EQ(curs.totalLength(), 30);
1056 }
1057
1058 TEST(IOBuf, TestRetreatOperators) {
1059   std::unique_ptr<IOBuf> chain(IOBuf::create(20));
1060   chain->append(20);
1061
1062   Cursor curs(chain.get());
1063   curs.advanceToEnd();
1064   curs -= 5;
1065   EXPECT_EQ(curs.totalLength(), 5);
1066
1067   curs.advanceToEnd();
1068   auto retreated = curs - 5;
1069   EXPECT_EQ(retreated.totalLength(), 5);
1070   EXPECT_EQ(curs.totalLength(), 0);
1071 }
1072
1073 TEST(IOBuf, tryRead) {
1074   unique_ptr<IOBuf> iobuf1(IOBuf::create(6));
1075   iobuf1->append(6);
1076   unique_ptr<IOBuf> iobuf2(IOBuf::create(24));
1077   iobuf2->append(24);
1078
1079   iobuf1->prependChain(std::move(iobuf2));
1080
1081   EXPECT_TRUE(iobuf1->isChained());
1082
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());
1091
1092   EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1093
1094   EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1095   EXPECT_EQ(0u, rcursor.readLE<uint32_t>());
1096
1097   EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1098   rcursor.skip(4);
1099
1100   uint32_t val;
1101   EXPECT_TRUE(rcursor.tryRead(val));
1102   EXPECT_EQ(1, val);
1103   EXPECT_TRUE(rcursor.tryRead(val));
1104
1105   EXPECT_EQ(0, val);
1106   EXPECT_FALSE(rcursor.tryRead(val));
1107 }
1108
1109 TEST(IOBuf, tryReadLE) {
1110   IOBuf buf{IOBuf::CREATE, 4};
1111   buf.append(4);
1112
1113   RWPrivateCursor wcursor(&buf);
1114   Cursor rcursor(&buf);
1115
1116   const uint32_t expected = 0x01020304;
1117   wcursor.writeLE(expected);
1118   uint32_t actual;
1119   EXPECT_TRUE(rcursor.tryReadLE(actual));
1120   EXPECT_EQ(expected, actual);
1121 }
1122
1123 TEST(IOBuf, tryReadBE) {
1124   IOBuf buf{IOBuf::CREATE, 4};
1125   buf.append(4);
1126
1127   RWPrivateCursor wcursor(&buf);
1128   Cursor rcursor(&buf);
1129
1130   const uint32_t expected = 0x01020304;
1131   wcursor.writeBE(expected);
1132   uint32_t actual;
1133   EXPECT_TRUE(rcursor.tryReadBE(actual));
1134   EXPECT_EQ(expected, actual);
1135 }
1136
1137 TEST(IOBuf, tryReadConsumesAllInputOnFailure) {
1138   IOBuf buf{IOBuf::CREATE, 2};
1139   buf.append(2);
1140
1141   Cursor rcursor(&buf);
1142   uint32_t val;
1143   EXPECT_FALSE(rcursor.tryRead(val));
1144   EXPECT_EQ(0, rcursor.totalLength());
1145 }
1146
1147 TEST(IOBuf, readConsumesAllInputOnFailure) {
1148   IOBuf buf{IOBuf::CREATE, 2};
1149   buf.append(2);
1150
1151   Cursor rcursor(&buf);
1152   EXPECT_THROW(rcursor.read<uint32_t>(), std::out_of_range);
1153   EXPECT_EQ(0, rcursor.totalLength());
1154 }
1155
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;
1162
1163   // Test calling Cursor::push()
1164   RWPrivateCursor wcursor(&buf);
1165   wcursor.push(emptyBytes);
1166   EXPECT_EQ(0, buf.computeChainDataLength());
1167
1168   // Test calling Appender::push()
1169   Appender app(&buf, 16);
1170   app.push(emptyBytes);
1171   EXPECT_EQ(0, buf.computeChainDataLength());
1172 }
1173
1174 TEST(IOBuf, positionTracking) {
1175   unique_ptr<IOBuf> iobuf1(IOBuf::create(6));
1176   iobuf1->append(6);
1177   unique_ptr<IOBuf> iobuf2(IOBuf::create(24));
1178   iobuf2->append(24);
1179   iobuf1->prependChain(std::move(iobuf2));
1180
1181   Cursor cursor(iobuf1.get());
1182
1183   EXPECT_EQ(0, cursor.getCurrentPosition());
1184   EXPECT_EQ(6, cursor.length());
1185
1186   cursor.skip(3);
1187   EXPECT_EQ(3, cursor.getCurrentPosition());
1188   EXPECT_EQ(3, cursor.length());
1189
1190   // Test that we properly handle advancing to the next chunk.
1191   cursor.skip(4);
1192   EXPECT_EQ(7, cursor.getCurrentPosition());
1193   EXPECT_EQ(23, cursor.length());
1194
1195   // Test that we properly handle doing to the previous chunk.
1196   cursor.retreat(2);
1197   EXPECT_EQ(5, cursor.getCurrentPosition());
1198   EXPECT_EQ(1, cursor.length());
1199
1200   // Test that we properly handle advanceToEnd
1201   cursor.advanceToEnd();
1202   EXPECT_EQ(30, cursor.getCurrentPosition());
1203   EXPECT_EQ(0, cursor.totalLength());
1204
1205   // Reset to 0.
1206   cursor.reset(iobuf1.get());
1207   EXPECT_EQ(0, cursor.getCurrentPosition());
1208   EXPECT_EQ(30, cursor.totalLength());
1209 }