Make most implicit integer truncations and sign conversions explicit
[folly.git] / folly / io / test / IOBufCursorTest.cpp
1 /*
2  * Copyright 2017 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
17 #include <folly/io/IOBuf.h>
18
19 #include <folly/Format.h>
20 #include <folly/Range.h>
21 #include <folly/io/Cursor.h>
22 #include <folly/portability/GTest.h>
23
24 using folly::ByteRange;
25 using folly::format;
26 using folly::IOBuf;
27 using folly::StringPiece;
28 using std::unique_ptr;
29 using namespace folly::io;
30
31 TEST(IOBuf, RWCursor) {
32   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
33   iobuf1->append(20);
34   unique_ptr<IOBuf> iobuf2(IOBuf::create(20));
35   iobuf2->append(20);
36
37   iobuf2.get();
38   iobuf1->prependChain(std::move(iobuf2));
39
40   EXPECT_TRUE(iobuf1->isChained());
41
42   RWPrivateCursor wcursor(iobuf1.get());
43   Cursor rcursor(iobuf1.get());
44   wcursor.writeLE((uint64_t)1);
45   wcursor.writeLE((uint64_t)1);
46   wcursor.writeLE((uint64_t)1);
47   wcursor.write((uint8_t)1);
48
49   EXPECT_EQ(1u, rcursor.readLE<uint64_t>());
50   rcursor.skip(8);
51   EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
52   rcursor.skip(0);
53   EXPECT_EQ(0u, rcursor.read<uint8_t>());
54   EXPECT_EQ(0u, rcursor.read<uint8_t>());
55   EXPECT_EQ(0u, rcursor.read<uint8_t>());
56   EXPECT_EQ(0u, rcursor.read<uint8_t>());
57   EXPECT_EQ(1u, rcursor.read<uint8_t>());
58 }
59
60 TEST(IOBuf, skip) {
61   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
62   iobuf1->append(20);
63   RWPrivateCursor wcursor(iobuf1.get());
64   wcursor.write((uint8_t)1);
65   wcursor.write((uint8_t)2);
66   Cursor cursor(iobuf1.get());
67   cursor.skip(1);
68   EXPECT_EQ(2, cursor.read<uint8_t>());
69 }
70
71 TEST(IOBuf, reset) {
72   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
73   iobuf1->append(20);
74   RWPrivateCursor wcursor(iobuf1.get());
75   wcursor.write((uint8_t)1);
76   wcursor.write((uint8_t)2);
77   wcursor.reset(iobuf1.get());
78   EXPECT_EQ(1, wcursor.read<uint8_t>());
79 }
80
81 TEST(IOBuf, copy_assign_convert) {
82   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
83   iobuf1->append(20);
84   RWPrivateCursor wcursor(iobuf1.get());
85   RWPrivateCursor cursor2(wcursor);
86   RWPrivateCursor cursor3(iobuf1.get());
87
88   wcursor.write((uint8_t)1);
89   cursor3 = wcursor;
90   wcursor.write((uint8_t)2);
91   Cursor cursor4(wcursor);
92   RWPrivateCursor cursor5(wcursor);
93   wcursor.write((uint8_t)3);
94
95   EXPECT_EQ(1, cursor2.read<uint8_t>());
96   EXPECT_EQ(2, cursor3.read<uint8_t>());
97   EXPECT_EQ(3, cursor4.read<uint8_t>());
98 }
99
100 TEST(IOBuf, arithmetic) {
101   IOBuf iobuf1(IOBuf::CREATE, 20);
102   iobuf1.append(20);
103   RWPrivateCursor wcursor(&iobuf1);
104   wcursor += 1;
105   wcursor.write((uint8_t)1);
106   Cursor cursor(&iobuf1);
107   cursor += 1;
108   EXPECT_EQ(1, cursor.read<uint8_t>());
109
110   Cursor start(&iobuf1);
111   Cursor cursor2 = start + 9;
112   EXPECT_EQ(7, cursor2 - cursor);
113   EXPECT_NE(cursor, cursor2);
114   cursor += 8;
115   cursor2 = cursor2 + 1;
116   EXPECT_EQ(cursor, cursor2);
117 }
118
119 TEST(IOBuf, endian) {
120   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
121   iobuf1->append(20);
122   RWPrivateCursor wcursor(iobuf1.get());
123   Cursor rcursor(iobuf1.get());
124   uint16_t v = 1;
125   int16_t vu = -1;
126   wcursor.writeBE(v);
127   wcursor.writeBE(vu);
128   // Try a couple combinations to ensure they were generated correctly
129   wcursor.writeBE(vu);
130   wcursor.writeLE(vu);
131   wcursor.writeLE(vu);
132   wcursor.writeLE(v);
133   EXPECT_EQ(v, rcursor.readBE<uint16_t>());
134 }
135
136 TEST(IOBuf, Cursor) {
137   unique_ptr<IOBuf> iobuf1(IOBuf::create(1));
138   iobuf1->append(1);
139   RWPrivateCursor c(iobuf1.get());
140   c.write((uint8_t)40); // OK
141   try {
142     c.write((uint8_t)10); // Bad write, checked should except.
143     EXPECT_EQ(true, false);
144   } catch (...) {
145   }
146 }
147
148 TEST(IOBuf, UnshareCursor) {
149   uint8_t buf = 0;
150   unique_ptr<IOBuf> iobuf1(IOBuf::wrapBuffer(&buf, 1));
151   unique_ptr<IOBuf> iobuf2(IOBuf::wrapBuffer(&buf, 1));
152   RWUnshareCursor c1(iobuf1.get());
153   RWUnshareCursor c2(iobuf2.get());
154
155   c1.write((uint8_t)10); // This should duplicate the two buffers.
156   uint8_t t = c2.read<uint8_t>();
157   EXPECT_EQ(0, t);
158
159   iobuf1 = IOBuf::wrapBuffer(&buf, 1);
160   iobuf2 = IOBuf::wrapBuffer(&buf, 1);
161   RWPrivateCursor c3(iobuf1.get());
162   RWPrivateCursor c4(iobuf2.get());
163
164   c3.write((uint8_t)10); // This should _not_ duplicate the two buffers.
165   t = c4.read<uint8_t>();
166   EXPECT_EQ(10, t);
167 }
168
169 namespace {
170 void append(std::unique_ptr<IOBuf>& buf, folly::StringPiece data) {
171   EXPECT_LE(data.size(), buf->tailroom());
172   memcpy(buf->writableData(), data.data(), data.size());
173   buf->append(data.size());
174 }
175
176 void append(Appender& appender, StringPiece data) {
177   appender.push(ByteRange(data));
178 }
179
180 std::string toString(const IOBuf& buf) {
181   std::string str;
182   Cursor cursor(&buf);
183   ByteRange b;
184   while (!(b = cursor.peekBytes()).empty()) {
185     str.append(reinterpret_cast<const char*>(b.data()), b.size());
186     cursor.skip(b.size());
187   }
188   return str;
189 }
190
191 }  // namespace
192
193 TEST(IOBuf, PullAndPeek) {
194   std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
195   append(iobuf1, "he");
196   std::unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
197   append(iobuf2, "llo ");
198   std::unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
199   append(iobuf3, "world");
200   iobuf1->prependChain(std::move(iobuf2));
201   iobuf1->prependChain(std::move(iobuf3));
202   EXPECT_EQ(3, iobuf1->countChainElements());
203   EXPECT_EQ(11, iobuf1->computeChainDataLength());
204
205   char buf[12];
206   memset(buf, 0, sizeof(buf));
207   Cursor(iobuf1.get()).pull(buf, 11);
208   EXPECT_EQ("hello world", std::string(buf));
209
210   memset(buf, 0, sizeof(buf));
211   EXPECT_EQ(11, Cursor(iobuf1.get()).pullAtMost(buf, 20));
212   EXPECT_EQ("hello world", std::string(buf));
213
214   EXPECT_THROW({Cursor(iobuf1.get()).pull(buf, 20);},
215                std::out_of_range);
216
217   {
218     RWPrivateCursor cursor(iobuf1.get());
219     auto b = cursor.peekBytes();
220     EXPECT_EQ("he", StringPiece(b));
221     cursor.skip(b.size());
222     b = cursor.peekBytes();
223     EXPECT_EQ("llo ", StringPiece(b));
224     cursor.skip(b.size());
225     b = cursor.peekBytes();
226     EXPECT_EQ("world", StringPiece(b));
227     cursor.skip(b.size());
228     EXPECT_EQ(3, iobuf1->countChainElements());
229     EXPECT_EQ(11, iobuf1->computeChainDataLength());
230   }
231
232   {
233     RWPrivateCursor cursor(iobuf1.get());
234     cursor.gather(11);
235     auto b = cursor.peekBytes();
236     EXPECT_EQ("hello world", StringPiece(b));
237     EXPECT_EQ(1, iobuf1->countChainElements());
238     EXPECT_EQ(11, iobuf1->computeChainDataLength());
239   }
240 }
241
242 TEST(IOBuf, pushCursorData) {
243   unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
244   iobuf1->append(15);
245   iobuf1->trimStart(5);
246   unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
247   unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
248   iobuf3->append(10);
249
250   iobuf1->prependChain(std::move(iobuf2));
251   iobuf1->prependChain(std::move(iobuf3));
252   EXPECT_TRUE(iobuf1->isChained());
253
254   //write 20 bytes to the buffer chain
255   RWPrivateCursor wcursor(iobuf1.get());
256   EXPECT_FALSE(wcursor.isAtEnd());
257   wcursor.writeBE<uint64_t>(1);
258   wcursor.writeBE<uint64_t>(10);
259   wcursor.writeBE<uint32_t>(20);
260   EXPECT_TRUE(wcursor.isAtEnd());
261
262   // create a read buffer for the buffer chain
263   Cursor rcursor(iobuf1.get());
264   EXPECT_EQ(1, rcursor.readBE<uint64_t>());
265   EXPECT_EQ(10, rcursor.readBE<uint64_t>());
266   EXPECT_EQ(20, rcursor.readBE<uint32_t>());
267   EXPECT_EQ(0, rcursor.totalLength());
268   rcursor.reset(iobuf1.get());
269   EXPECT_EQ(20, rcursor.totalLength());
270
271   // create another write buffer
272   unique_ptr<IOBuf> iobuf4(IOBuf::create(30));
273   iobuf4->append(30);
274   RWPrivateCursor wcursor2(iobuf4.get());
275   // write buffer chain data into it, now wcursor2 should only
276   // have 10 bytes writable space
277   wcursor2.push(rcursor, 20);
278   EXPECT_EQ(wcursor2.totalLength(), 10);
279   // write again with not enough space in rcursor
280   EXPECT_THROW(wcursor2.push(rcursor, 20), std::out_of_range);
281
282   // create a read cursor to check iobuf3 data back
283   Cursor rcursor2(iobuf4.get());
284   EXPECT_EQ(1, rcursor2.readBE<uint64_t>());
285   EXPECT_EQ(10, rcursor2.readBE<uint64_t>());
286   EXPECT_EQ(20, rcursor2.readBE<uint32_t>());
287
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(7, iobuf1->countChainElements());
372     EXPECT_EQ(14, iobuf1->computeChainDataLength());
373     // Check that nextBuf got set correctly to the buffer with 1 byte left
374     EXPECT_EQ(1, cursor.peekBytes().size());
375     cursor.read<uint8_t>();
376   }
377
378   {
379     // Check that inserting at the end doesn't create empty buf
380     RWPrivateCursor cursor(iobuf1.get());
381     Cursor(iobuf1.get()).clone(cloned, 1);
382     EXPECT_EQ(1, cloned->countChainElements());
383     EXPECT_EQ(1, cloned->computeChainDataLength());
384
385     cursor.skip(1);
386
387     cursor.insert(std::move(cloned));
388     EXPECT_EQ(8, iobuf1->countChainElements());
389     EXPECT_EQ(15, iobuf1->computeChainDataLength());
390     // Check that nextBuf got set correctly
391     cursor.read<uint8_t>();
392   }
393   {
394     // Check that inserting at the beginning doesn't create empty buf
395     RWPrivateCursor cursor(iobuf1.get());
396     Cursor(iobuf1.get()).clone(cloned, 1);
397     EXPECT_EQ(1, cloned->countChainElements());
398     EXPECT_EQ(1, cloned->computeChainDataLength());
399
400     cursor.insert(std::move(cloned));
401     EXPECT_EQ(9, iobuf1->countChainElements());
402     EXPECT_EQ(16, iobuf1->computeChainDataLength());
403     // Check that nextBuf got set correctly
404     cursor.read<uint8_t>();
405   }
406 }
407
408 TEST(IOBuf, cloneWithEmptyBufAtStart) {
409   folly::IOBufEqual eq;
410   auto empty = IOBuf::create(0);
411   auto hel = IOBuf::create(3);
412   append(hel, "hel");
413   auto lo = IOBuf::create(2);
414   append(lo, "lo");
415
416   auto iobuf = empty->clone();
417   iobuf->prependChain(hel->clone());
418   iobuf->prependChain(lo->clone());
419   iobuf->prependChain(empty->clone());
420   iobuf->prependChain(hel->clone());
421   iobuf->prependChain(lo->clone());
422   iobuf->prependChain(empty->clone());
423   iobuf->prependChain(lo->clone());
424   iobuf->prependChain(hel->clone());
425   iobuf->prependChain(lo->clone());
426   iobuf->prependChain(lo->clone());
427
428   Cursor cursor(iobuf.get());
429   std::unique_ptr<IOBuf> cloned;
430   char data[3];
431   cursor.pull(&data, 3);
432   cursor.clone(cloned, 2);
433   EXPECT_EQ(1, cloned->countChainElements());
434   EXPECT_EQ(2, cloned->length());
435   EXPECT_TRUE(eq(lo, cloned));
436
437   cursor.pull(&data, 3);
438   EXPECT_EQ("hel", std::string(data, sizeof(data)));
439
440   cursor.skip(2);
441   cursor.clone(cloned, 2);
442   EXPECT_TRUE(eq(lo, cloned));
443
444   std::string hello = cursor.readFixedString(5);
445   cursor.clone(cloned, 2);
446   EXPECT_TRUE(eq(lo, cloned));
447 }
448
449 TEST(IOBuf, Appender) {
450   std::unique_ptr<IOBuf> head(IOBuf::create(10));
451   append(head, "hello");
452
453   Appender app(head.get(), 10);
454   uint32_t cap = head->capacity();
455   uint32_t len1 = app.length();
456   EXPECT_EQ(cap - 5, len1);
457   app.ensure(len1);  // won't grow
458   EXPECT_EQ(len1, app.length());
459   app.ensure(len1 + 1);  // will grow
460   EXPECT_LE(len1 + 1, app.length());
461
462   append(app, " world");
463   EXPECT_EQ("hello world", toString(*head));
464 }
465
466 TEST(IOBuf, Printf) {
467   IOBuf head(IOBuf::CREATE, 24);
468   Appender app(&head, 32);
469
470   app.printf("%s", "test");
471   EXPECT_EQ(head.length(), 4);
472   EXPECT_EQ(0, memcmp(head.data(), "test\0", 5));
473
474   app.printf("%d%s %s%s %#x", 32, "this string is",
475              "longer than our original allocation size,",
476              "and will therefore require a new allocation", 0x12345678);
477   // The tailroom should start with a nul byte now.
478   EXPECT_GE(head.prev()->tailroom(), 1u);
479   EXPECT_EQ(0, *head.prev()->tail());
480
481   EXPECT_EQ("test32this string is longer than our original "
482             "allocation size,and will therefore require a "
483             "new allocation 0x12345678",
484             head.moveToFbString().toStdString());
485 }
486
487 TEST(IOBuf, Format) {
488   IOBuf head(IOBuf::CREATE, 24);
489   Appender app(&head, 32);
490
491   format("{}", "test")(app);
492   EXPECT_EQ(head.length(), 4);
493   EXPECT_EQ(0, memcmp(head.data(), "test", 4));
494
495   auto fmt = format("{}{} {}{} {:#x}",
496                     32, "this string is",
497                     "longer than our original allocation size,",
498                     "and will therefore require a new allocation",
499                     0x12345678);
500   fmt(app);
501   EXPECT_EQ("test32this string is longer than our original "
502             "allocation size,and will therefore require a "
503             "new allocation 0x12345678",
504             head.moveToFbString().toStdString());
505 }
506
507 TEST(IOBuf, QueueAppender) {
508   folly::IOBufQueue queue;
509
510   // Allocate 100 bytes at once, but don't grow past 1024
511   QueueAppender app(&queue, 100);
512   size_t n = 1024 / sizeof(uint32_t);
513   for (uint32_t i = 0; i < n; ++i) {
514     app.writeBE(i);
515   }
516
517   // There must be a goodMallocSize between 100 and 1024...
518   EXPECT_LT(1u, queue.front()->countChainElements());
519   const IOBuf* buf = queue.front();
520   do {
521     EXPECT_LE(100u, buf->capacity());
522     buf = buf->next();
523   } while (buf != queue.front());
524
525   Cursor cursor(queue.front());
526   for (uint32_t i = 0; i < n; ++i) {
527     EXPECT_EQ(i, cursor.readBE<uint32_t>());
528   }
529
530   EXPECT_THROW({cursor.readBE<uint32_t>();}, std::out_of_range);
531 }
532
533 TEST(IOBuf, CursorOperators) {
534   // Test operators on a single-item chain
535   {
536     std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
537     chain1->append(10);
538
539     Cursor curs1(chain1.get());
540     EXPECT_EQ(0, curs1 - chain1.get());
541     EXPECT_FALSE(curs1.isAtEnd());
542     curs1.skip(3);
543     EXPECT_EQ(3, curs1 - chain1.get());
544     EXPECT_FALSE(curs1.isAtEnd());
545     curs1.skip(7);
546     EXPECT_EQ(10, curs1 - chain1.get());
547     EXPECT_TRUE(curs1.isAtEnd());
548
549     Cursor curs2(chain1.get());
550     EXPECT_EQ(0, curs2 - chain1.get());
551     EXPECT_EQ(10, curs1 - curs2);
552     EXPECT_THROW(curs2 - curs1, std::out_of_range);
553   }
554
555   // Test cross-chain operations
556   {
557     std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
558     chain1->append(10);
559     std::unique_ptr<IOBuf> chain2 = chain1->clone();
560
561     Cursor curs1(chain1.get());
562     Cursor curs2(chain2.get());
563     EXPECT_THROW(curs1 - curs2, std::out_of_range);
564     EXPECT_THROW(curs1 - chain2.get(), std::out_of_range);
565   }
566
567   // Test operations on multi-item chains
568   {
569     std::unique_ptr<IOBuf> chain(IOBuf::create(20));
570     chain->append(10);
571     chain->appendChain(chain->clone());
572     EXPECT_EQ(20, chain->computeChainDataLength());
573
574     Cursor curs1(chain.get());
575     curs1.skip(5);
576     Cursor curs2(chain.get());
577     curs2.skip(3);
578     EXPECT_EQ(2, curs1 - curs2);
579     EXPECT_EQ(5, curs1 - chain.get());
580     EXPECT_THROW(curs2 - curs1, std::out_of_range);
581
582     curs1.skip(7);
583     EXPECT_EQ(9, curs1 - curs2);
584     EXPECT_EQ(12, curs1 - chain.get());
585     EXPECT_THROW(curs2 - curs1, std::out_of_range);
586
587     curs2.skip(7);
588     EXPECT_EQ(2, curs1 - curs2);
589     EXPECT_THROW(curs2 - curs1, std::out_of_range);
590   }
591
592   // Test isAtEnd() with empty buffers at the end of a chain
593   {
594     auto iobuf1 = IOBuf::create(20);
595     iobuf1->append(15);
596     iobuf1->trimStart(5);
597
598     Cursor c(iobuf1.get());
599     EXPECT_FALSE(c.isAtEnd());
600     c.skip(10);
601     EXPECT_TRUE(c.isAtEnd());
602
603     iobuf1->prependChain(IOBuf::create(10));
604     iobuf1->prependChain(IOBuf::create(10));
605     EXPECT_TRUE(c.isAtEnd());
606     iobuf1->prev()->append(5);
607     EXPECT_FALSE(c.isAtEnd());
608     c.skip(5);
609     EXPECT_TRUE(c.isAtEnd());
610   }
611
612   // Test canAdvance with a chain of items
613   {
614     auto chain = IOBuf::create(10);
615     chain->append(10);
616     chain->appendChain(chain->clone());
617     EXPECT_EQ(2, chain->countChainElements());
618     EXPECT_EQ(20, chain->computeChainDataLength());
619
620     Cursor c(chain.get());
621     for (size_t i = 0; i <= 20; ++i) {
622       EXPECT_TRUE(c.canAdvance(i));
623     }
624     EXPECT_FALSE(c.canAdvance(21));
625     c.skip(10);
626     EXPECT_TRUE(c.canAdvance(10));
627     EXPECT_FALSE(c.canAdvance(11));
628   }
629 }
630
631 TEST(IOBuf, StringOperations) {
632   // Test a single buffer with two null-terminated strings and an extra uint8_t
633   // at the end
634   {
635     std::unique_ptr<IOBuf> chain(IOBuf::create(16));
636     Appender app(chain.get(), 0);
637     app.push(reinterpret_cast<const uint8_t*>("hello\0world\0\x01"), 13);
638
639     Cursor curs(chain.get());
640     EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
641     EXPECT_STREQ("world", curs.readTerminatedString().c_str());
642     EXPECT_EQ(1, curs.read<uint8_t>());
643   }
644
645   // Test multiple buffers where the first is empty and the string starts in
646   // the second buffer.
647   {
648     std::unique_ptr<IOBuf> chain(IOBuf::create(8));
649     chain->prependChain(IOBuf::create(12));
650     Appender app(chain.get(), 0);
651     app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
652
653     Cursor curs(chain.get());
654     EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
655   }
656
657   // Test multiple buffers with a single null-terminated string spanning them
658   {
659     std::unique_ptr<IOBuf> chain(IOBuf::create(8));
660     chain->prependChain(IOBuf::create(8));
661     chain->append(8);
662     chain->next()->append(4);
663     RWPrivateCursor rwc(chain.get());
664     rwc.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
665
666     Cursor curs(chain.get());
667     EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
668   }
669
670   // Test a reading a null-terminated string that's longer than the maximum
671   // allowable length
672   {
673     std::unique_ptr<IOBuf> chain(IOBuf::create(16));
674     Appender app(chain.get(), 0);
675     app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
676
677     Cursor curs(chain.get());
678     EXPECT_THROW(curs.readTerminatedString('\0', 5), std::length_error);
679   }
680
681   // Test reading a null-terminated string from a chain with an empty buffer at
682   // the front
683   {
684     std::unique_ptr<IOBuf> buf(IOBuf::create(8));
685     Appender app(buf.get(), 0);
686     app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
687     std::unique_ptr<IOBuf> chain(IOBuf::create(8));
688     chain->prependChain(std::move(buf));
689
690     Cursor curs(chain.get());
691     EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
692   }
693
694   // Test reading a null-terminated string from a chain that doesn't contain the
695   // terminator
696   {
697     std::unique_ptr<IOBuf> buf(IOBuf::create(8));
698     Appender app(buf.get(), 0);
699     app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
700     std::unique_ptr<IOBuf> chain(IOBuf::create(8));
701     chain->prependChain(std::move(buf));
702
703     Cursor curs(chain.get());
704     EXPECT_THROW(curs.readTerminatedString(),
705                  std::out_of_range);
706   }
707
708   // Test reading a null-terminated string past the maximum length
709   {
710     std::unique_ptr<IOBuf> buf(IOBuf::create(8));
711     Appender app(buf.get(), 0);
712     app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
713     std::unique_ptr<IOBuf> chain(IOBuf::create(8));
714     chain->prependChain(std::move(buf));
715
716     Cursor curs(chain.get());
717     EXPECT_THROW(curs.readTerminatedString('\0', 3),
718                  std::length_error);
719   }
720
721   // Test reading a two fixed-length strings from a single buffer with an extra
722   // uint8_t at the end
723   {
724     std::unique_ptr<IOBuf> chain(IOBuf::create(16));
725     Appender app(chain.get(), 0);
726     app.push(reinterpret_cast<const uint8_t*>("helloworld\x01"), 11);
727
728     Cursor curs(chain.get());
729     EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
730     EXPECT_STREQ("world", curs.readFixedString(5).c_str());
731     EXPECT_EQ(1, curs.read<uint8_t>());
732   }
733
734   // Test multiple buffers where the first is empty and a fixed-length string
735   // starts in the second buffer.
736   {
737     std::unique_ptr<IOBuf> chain(IOBuf::create(8));
738     chain->prependChain(IOBuf::create(16));
739     Appender app(chain.get(), 0);
740     app.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
741
742     Cursor curs(chain.get());
743     EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
744   }
745
746   // Test multiple buffers with a single fixed-length string spanning them
747   {
748     std::unique_ptr<IOBuf> chain(IOBuf::create(8));
749     chain->prependChain(IOBuf::create(8));
750     chain->append(7);
751     chain->next()->append(4);
752     RWPrivateCursor rwc(chain.get());
753     rwc.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
754
755     Cursor curs(chain.get());
756     EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
757   }
758
759   // Test reading a fixed-length string from a chain with an empty buffer at
760   // the front
761   {
762     std::unique_ptr<IOBuf> buf(IOBuf::create(8));
763     Appender app(buf.get(), 0);
764     app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
765     std::unique_ptr<IOBuf> chain(IOBuf::create(8));
766     chain->prependChain(std::move(buf));
767
768     Cursor curs(chain.get());
769     EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
770   }
771 }
772
773 TEST(IOBuf, ReadWhileTrue) {
774   auto isAlpha = [](uint8_t ch) {
775     return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
776   };
777   auto isDigit = [](uint8_t ch) { return (ch >= '0' && ch <= '9'); };
778
779   // Test reading alternating alphabetic and numeric strings
780   {
781     std::unique_ptr<IOBuf> chain(IOBuf::create(32));
782     Appender app(chain.get(), 0);
783     app.push(StringPiece("hello123world456"));
784
785     Cursor curs(chain.get());
786     EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
787     EXPECT_STREQ("123", curs.readWhile(isDigit).c_str());
788     EXPECT_STREQ("world", curs.readWhile(isAlpha).c_str());
789     EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
790     EXPECT_TRUE(curs.isAtEnd());
791   }
792
793   // The same, but also use skipWhile()
794   {
795     std::unique_ptr<IOBuf> chain(IOBuf::create(16));
796     Appender app(chain.get(), 0);
797     app.push(StringPiece("hello123world456"));
798
799     Cursor curs(chain.get());
800     EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
801     curs.skipWhile(isDigit);
802     curs.skipWhile(isAlpha);
803     EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
804     EXPECT_TRUE(curs.isAtEnd());
805   }
806
807   // Test readWhile() using data split across multiple buffers,
808   // including some empty buffers in the middle of the chain.
809   {
810     std::unique_ptr<IOBuf> chain;
811
812     // First element in the chain has "he"
813     auto buf = IOBuf::create(40);
814     Appender app(buf.get(), 0);
815     app.push(StringPiece("he"));
816     chain = std::move(buf);
817
818     // The second element has "ll", after 10 bytes of headroom
819     buf = IOBuf::create(40);
820     buf->advance(10);
821     app = Appender{buf.get(), 0};
822     app.push(StringPiece("ll"));
823     chain->prependChain(std::move(buf));
824
825     // The third element is empty
826     buf = IOBuf::create(40);
827     buf->advance(15);
828     chain->prependChain(std::move(buf));
829
830     // The fourth element has "o12"
831     buf = IOBuf::create(40);
832     buf->advance(37);
833     app = Appender{buf.get(), 0};
834     app.push(StringPiece("o12"));
835     chain->prependChain(std::move(buf));
836
837     // The fifth element has "3"
838     buf = IOBuf::create(40);
839     app = Appender{buf.get(), 0};
840     app.push(StringPiece("3"));
841     chain->prependChain(std::move(buf));
842
843     // The sixth element is empty
844     buf = IOBuf::create(40);
845     chain->prependChain(std::move(buf));
846
847     // The seventh element has "world456"
848     buf = IOBuf::create(40);
849     app = Appender{buf.get(), 0};
850     app.push(StringPiece("world456"));
851     chain->prependChain(std::move(buf));
852
853     // The eighth element is empty
854     buf = IOBuf::create(40);
855     chain->prependChain(std::move(buf));
856
857     Cursor curs(chain.get());
858     EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
859     EXPECT_STREQ("123", curs.readWhile(isDigit).c_str());
860     EXPECT_STREQ("world", curs.readWhile(isAlpha).c_str());
861     EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
862     EXPECT_TRUE(curs.isAtEnd());
863   }
864 }
865
866 TEST(IOBuf, TestAdvanceToEndSingle) {
867   std::unique_ptr<IOBuf> chain(IOBuf::create(10));
868   chain->append(10);
869
870   Cursor curs(chain.get());
871   curs.advanceToEnd();
872   EXPECT_TRUE(curs.isAtEnd());
873   EXPECT_EQ(curs - chain.get(), 10);
874 }
875
876 TEST(IOBuf, TestAdvanceToEndMulti) {
877   std::unique_ptr<IOBuf> chain(IOBuf::create(10));
878   chain->append(10);
879
880   std::unique_ptr<IOBuf> buf(IOBuf::create(5));
881   buf->append(5);
882   chain->prependChain(std::move(buf));
883
884   buf = IOBuf::create(20);
885   buf->append(20);
886   chain->prependChain(std::move(buf));
887
888   Cursor curs(chain.get());
889   curs.advanceToEnd();
890   EXPECT_TRUE(curs.isAtEnd());
891   EXPECT_EQ(curs - chain.get(), 35);
892
893   curs.reset(chain.get());
894   curs.skip(12);
895   curs.advanceToEnd();
896   EXPECT_TRUE(curs.isAtEnd());
897 }
898
899 TEST(IOBuf, TestRetreatSingle) {
900   std::unique_ptr<IOBuf> chain(IOBuf::create(20));
901   chain->append(20);
902
903   Cursor curs(chain.get());
904   EXPECT_EQ(curs.retreatAtMost(0), 0);
905   EXPECT_EQ(curs.totalLength(), 20);
906   EXPECT_EQ(curs.retreatAtMost(5), 0);
907   EXPECT_EQ(curs.totalLength(), 20);
908   EXPECT_EQ(curs.retreatAtMost(25), 0);
909   EXPECT_EQ(curs.totalLength(), 20);
910
911   curs.retreat(0);
912   EXPECT_THROW(curs.retreat(5), std::out_of_range);
913   curs.reset(chain.get());
914   EXPECT_THROW(curs.retreat(25), std::out_of_range);
915   curs.reset(chain.get());
916
917   curs.advanceToEnd();
918   curs.retreat(5);
919   EXPECT_EQ(curs.totalLength(), 5);
920   curs.retreat(10);
921   EXPECT_EQ(curs.totalLength(), 15);
922   EXPECT_THROW(curs.retreat(10), std::out_of_range);
923
924   curs.reset(chain.get());
925   curs.advanceToEnd();
926   EXPECT_EQ(curs.retreatAtMost(5), 5);
927   EXPECT_EQ(curs.totalLength(), 5);
928   EXPECT_EQ(curs.retreatAtMost(10), 10);
929   EXPECT_EQ(curs.totalLength(), 15);
930   EXPECT_EQ(curs.retreatAtMost(10), 5);
931   EXPECT_EQ(curs.totalLength(), 20);
932 }
933
934 TEST(IOBuf, TestRetreatMulti) {
935   std::unique_ptr<IOBuf> chain(IOBuf::create(10));
936   chain->append(10);
937
938   std::unique_ptr<IOBuf> buf(IOBuf::create(5));
939   buf->append(5);
940   chain->prependChain(std::move(buf));
941
942   buf = IOBuf::create(20);
943   buf->append(20);
944   chain->prependChain(std::move(buf));
945
946   Cursor curs(chain.get());
947   EXPECT_EQ(curs.retreatAtMost(10), 0);
948   EXPECT_THROW(curs.retreat(10), std::out_of_range);
949   curs.reset(chain.get());
950
951   curs.advanceToEnd();
952   curs.retreat(20);
953   EXPECT_EQ(curs.totalLength(), 20);
954   EXPECT_EQ(curs.length(), 20);
955   curs.retreat(1);
956   EXPECT_EQ(curs.totalLength(), 21);
957   EXPECT_EQ(curs.length(), 1);
958   EXPECT_EQ(curs.retreatAtMost(50), 14);
959   EXPECT_EQ(curs.totalLength(), 35);
960
961   curs.advanceToEnd();
962   curs.retreat(30);
963   EXPECT_EQ(curs.totalLength(), 30);
964 }
965
966 TEST(IOBuf, TestRetreatOperators) {
967   std::unique_ptr<IOBuf> chain(IOBuf::create(20));
968   chain->append(20);
969
970   Cursor curs(chain.get());
971   curs.advanceToEnd();
972   curs -= 5;
973   EXPECT_EQ(curs.totalLength(), 5);
974
975   curs.advanceToEnd();
976   auto retreated = curs - 5;
977   EXPECT_EQ(retreated.totalLength(), 5);
978   EXPECT_EQ(curs.totalLength(), 0);
979 }