proxygen
IOBufCursorTest.cpp
Go to the documentation of this file.
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>
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 
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 
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 
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); }, 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 TEST(IOBuf, Gather) {
290  std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
291  append(iobuf1, "he");
292  std::unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
293  append(iobuf2, "llo ");
294  std::unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
295  append(iobuf3, "world");
296  iobuf1->prependChain(std::move(iobuf2));
297  iobuf1->prependChain(std::move(iobuf3));
298  EXPECT_EQ(3, iobuf1->countChainElements());
299  EXPECT_EQ(11, iobuf1->computeChainDataLength());
300 
301  // Attempting to gather() more data than available in the chain should fail.
302  // Try from the very beginning of the chain.
303  RWPrivateCursor cursor(iobuf1.get());
304  EXPECT_THROW(cursor.gather(15), std::overflow_error);
305  // Now try from the middle of the chain
306  cursor += 3;
307  EXPECT_THROW(cursor.gather(10), std::overflow_error);
308 
309  // Calling gatherAtMost() should succeed, however, and just gather
310  // as much as it can
311  cursor.gatherAtMost(10);
312  EXPECT_EQ(8, cursor.length());
313  EXPECT_EQ(8, cursor.totalLength());
314  EXPECT_FALSE(cursor.isAtEnd());
315  EXPECT_EQ(
316  "lo world",
318  reinterpret_cast<const char*>(cursor.data()), 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  EXPECT_EQ(11, Cursor(iobuf1.get()).cloneAtMost(cloned, 20));
352  EXPECT_EQ(3, cloned->countChainElements());
353  EXPECT_EQ(11, cloned->computeChainDataLength());
354 
355  EXPECT_THROW({ Cursor(iobuf1.get()).clone(cloned, 20); }, std::out_of_range);
356 
357  {
358  // Check that inserting in the middle of an iobuf splits
359  RWPrivateCursor cursor(iobuf1.get());
360  Cursor(iobuf1.get()).clone(cloned, 3);
361  EXPECT_EQ(2, cloned->countChainElements());
362  EXPECT_EQ(3, cloned->computeChainDataLength());
363 
364  cursor.skip(1);
365 
366  cursor.insert(std::move(cloned));
367  cursor.insert(folly::IOBuf::create(0));
368  EXPECT_EQ(4, cursor.getCurrentPosition());
369  EXPECT_EQ(7, iobuf1->countChainElements());
370  EXPECT_EQ(14, iobuf1->computeChainDataLength());
371  // Check that nextBuf got set correctly to the buffer with 1 byte left
372  EXPECT_EQ(1, cursor.peekBytes().size());
373  cursor.read<uint8_t>();
374  }
375 
376  {
377  // Check that inserting at the end doesn't create empty buf
378  RWPrivateCursor cursor(iobuf1.get());
379  Cursor(iobuf1.get()).clone(cloned, 1);
380  EXPECT_EQ(1, cloned->countChainElements());
381  EXPECT_EQ(1, cloned->computeChainDataLength());
382 
383  cursor.skip(1);
384 
385  cursor.insert(std::move(cloned));
386  EXPECT_EQ(2, cursor.getCurrentPosition());
387  EXPECT_EQ(8, iobuf1->countChainElements());
388  EXPECT_EQ(15, iobuf1->computeChainDataLength());
389  // Check that nextBuf got set correctly
390  cursor.read<uint8_t>();
391  }
392  {
393  // Check that inserting at the beginning of a chunk (except first one)
394  // 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.skip(1);
401 
402  cursor.insert(std::move(cloned));
403  EXPECT_EQ(2, cursor.getCurrentPosition());
404  EXPECT_EQ(14, cursor.totalLength());
405  EXPECT_EQ(9, iobuf1->countChainElements());
406  EXPECT_EQ(16, iobuf1->computeChainDataLength());
407  // Check that nextBuf got set correctly
408  cursor.read<uint8_t>();
409  }
410  {
411  // Check that inserting at the beginning of a chain DOES keep an empty
412  // buffer.
413  RWPrivateCursor cursor(iobuf1.get());
414  Cursor(iobuf1.get()).clone(cloned, 1);
415  EXPECT_EQ(1, cloned->countChainElements());
416  EXPECT_EQ(1, cloned->computeChainDataLength());
417 
418  cursor.insert(std::move(cloned));
419  EXPECT_EQ(1, cursor.getCurrentPosition());
420  EXPECT_EQ(16, cursor.totalLength());
421  EXPECT_EQ(11, iobuf1->countChainElements());
422  EXPECT_EQ(17, iobuf1->computeChainDataLength());
423  // Check that nextBuf got set correctly
424  cursor.read<uint8_t>();
425  }
426  {
427  // Check that inserting at the end of the buffer keeps it at the end.
428  RWPrivateCursor cursor(iobuf1.get());
429  Cursor(iobuf1.get()).clone(cloned, 1);
430  EXPECT_EQ(1, cloned->countChainElements());
431  EXPECT_EQ(1, cloned->computeChainDataLength());
432 
433  cursor.advanceToEnd();
434  EXPECT_EQ(17, cursor.getCurrentPosition());
435  cursor.insert(std::move(cloned));
436  EXPECT_EQ(18, cursor.getCurrentPosition());
437  EXPECT_EQ(0, cursor.totalLength());
438  EXPECT_EQ(12, iobuf1->countChainElements());
439  EXPECT_EQ(18, iobuf1->computeChainDataLength());
440  EXPECT_TRUE(cursor.isAtEnd());
441  }
442 }
443 
444 TEST(IOBuf, cloneWithEmptyBufAtStart) {
446  auto empty = IOBuf::create(0);
447  auto hel = IOBuf::create(3);
448  append(hel, "hel");
449  auto lo = IOBuf::create(2);
450  append(lo, "lo");
451 
452  auto iobuf = empty->clone();
453  iobuf->prependChain(hel->clone());
454  iobuf->prependChain(lo->clone());
455  iobuf->prependChain(empty->clone());
456  iobuf->prependChain(hel->clone());
457  iobuf->prependChain(lo->clone());
458  iobuf->prependChain(empty->clone());
459  iobuf->prependChain(lo->clone());
460  iobuf->prependChain(hel->clone());
461  iobuf->prependChain(lo->clone());
462  iobuf->prependChain(lo->clone());
463 
464  Cursor cursor(iobuf.get());
465  std::unique_ptr<IOBuf> cloned;
466  char data[3];
467  cursor.pull(&data, 3);
468  cursor.clone(cloned, 2);
469  EXPECT_EQ(1, cloned->countChainElements());
470  EXPECT_EQ(2, cloned->length());
471  EXPECT_TRUE(eq(lo, cloned));
472 
473  cursor.pull(&data, 3);
474  EXPECT_EQ("hel", std::string(data, sizeof(data)));
475 
476  cursor.skip(2);
477  cursor.clone(cloned, 2);
478  EXPECT_TRUE(eq(lo, cloned));
479 
480  std::string hello = cursor.readFixedString(5);
481  cursor.clone(cloned, 2);
482  EXPECT_TRUE(eq(lo, cloned));
483 }
484 
486  std::unique_ptr<IOBuf> head(IOBuf::create(10));
487  append(head, "hello");
488 
489  Appender app(head.get(), 10);
490  auto cap = head->capacity();
491  auto len1 = app.length();
492  EXPECT_EQ(cap - 5, len1);
493  app.ensure(len1); // won't grow
494  EXPECT_EQ(len1, app.length());
495  app.ensure(len1 + 1); // will grow
496  EXPECT_LE(len1 + 1, app.length());
497 
498  append(app, " world");
499  EXPECT_EQ("hello world", toString(*head));
500 }
501 
502 TEST(IOBuf, Printf) {
503  IOBuf head(IOBuf::CREATE, 24);
504  Appender app(&head, 32);
505 
506  app.printf("%s", "test");
507  EXPECT_EQ(head.length(), 4);
508  EXPECT_EQ(0, memcmp(head.data(), "test\0", 5));
509 
510  app.printf(
511  "%d%s %s%s %#x",
512  32,
513  "this string is",
514  "longer than our original allocation size,",
515  "and will therefore require a new allocation",
516  0x12345678);
517  // The tailroom should start with a nul byte now.
518  EXPECT_GE(head.prev()->tailroom(), 1u);
519  EXPECT_EQ(0, *head.prev()->tail());
520 
521  EXPECT_EQ(
522  "test32this string is longer than our original "
523  "allocation size,and will therefore require a "
524  "new allocation 0x12345678",
525  head.moveToFbString().toStdString());
526 }
527 
528 TEST(IOBuf, Format) {
529  IOBuf head(IOBuf::CREATE, 24);
530  Appender app(&head, 32);
531 
532  format("{}", "test")(app);
533  EXPECT_EQ(head.length(), 4);
534  EXPECT_EQ(0, memcmp(head.data(), "test", 4));
535 
536  auto fmt = format(
537  "{}{} {}{} {:#x}",
538  32,
539  "this string is",
540  "longer than our original allocation size,",
541  "and will therefore require a new allocation",
542  0x12345678);
543  fmt(app);
544  EXPECT_EQ(
545  "test32this string is longer than our original "
546  "allocation size,and will therefore require a "
547  "new allocation 0x12345678",
548  head.moveToFbString().toStdString());
549 }
550 
552  folly::IOBufQueue queue;
553 
554  // Allocate 100 bytes at once, but don't grow past 1024
555  QueueAppender app(&queue, 100);
556  size_t n = 1024 / sizeof(uint32_t);
557  for (uint32_t i = 0; i < n; ++i) {
558  app.writeBE(i);
559  }
560 
561  // There must be a goodMallocSize between 100 and 1024...
562  EXPECT_LT(1u, queue.front()->countChainElements());
563  const IOBuf* buf = queue.front();
564  do {
565  EXPECT_LE(100u, buf->capacity());
566  buf = buf->next();
567  } while (buf != queue.front());
568 
569  Cursor cursor(queue.front());
570  for (uint32_t i = 0; i < n; ++i) {
571  EXPECT_EQ(i, cursor.readBE<uint32_t>());
572  }
573 
574  EXPECT_THROW({ cursor.readBE<uint32_t>(); }, std::out_of_range);
575 }
576 
577 TEST(IOBuf, QueueAppenderPushAtMostFillBuffer) {
578  folly::IOBufQueue queue;
579  // There should be a goodMallocSize between 125 and 1000
580  QueueAppender appender{&queue, 125};
581  std::vector<uint8_t> data;
582  data.resize(1000);
583  std::iota(data.begin(), data.end(), uint8_t(0));
584  // Add 100 byte
585  appender.pushAtMost(data.data(), 100);
586  // Add 900 bytes
587  appender.pushAtMost(data.data() + 100, data.size() - 100);
588  const auto buf = queue.front();
589  // Should fill the current buffer before adding another
590  EXPECT_LE(2, buf->countChainElements());
591  EXPECT_EQ(0, buf->tailroom());
592  EXPECT_LE(125, buf->length());
593  EXPECT_EQ(1000, buf->computeChainDataLength());
594  const StringPiece sp{(const char*)data.data(), data.size()};
595  EXPECT_EQ(sp, toString(*buf));
596 }
597 
598 TEST(IOBuf, QueueAppenderInsertOwn) {
599  auto buf = IOBuf::create(10);
600  folly::IOBufQueue queue;
601  QueueAppender appender{&queue, 128};
602  appender.insert(std::move(buf));
603 
604  std::vector<uint8_t> data;
605  data.resize(256);
606  std::iota(data.begin(), data.end(), 0);
607  appender.pushAtMost(folly::range(data));
608  // Buffer is owned, so we should write to it
609  EXPECT_LE(2, queue.front()->countChainElements());
610  EXPECT_EQ(0, queue.front()->tailroom());
611  const StringPiece sp{(const char*)data.data(), data.size()};
612  EXPECT_EQ(sp, toString(*queue.front()));
613 }
614 
615 TEST(IOBuf, QueueAppenderInsertClone) {
616  IOBuf buf{IOBuf::CREATE, 100};
617  folly::IOBufQueue queue;
618  QueueAppender appender{&queue, 100};
619  // Buffer is shared, so we create a new buffer to write to
620  appender.insert(buf);
621  uint8_t x = 42;
622  appender.pushAtMost(&x, 1);
623  EXPECT_EQ(2, queue.front()->countChainElements());
624  EXPECT_EQ(0, queue.front()->length());
625  EXPECT_LT(0, queue.front()->tailroom());
626  EXPECT_EQ(1, queue.front()->next()->length());
627  EXPECT_EQ(x, queue.front()->next()->data()[0]);
628 }
629 
630 TEST(IOBuf, CursorOperators) {
631  // Test operators on a single-item chain
632  {
633  std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
634  chain1->append(10);
635 
636  Cursor curs1(chain1.get());
637  EXPECT_EQ(0, curs1 - chain1.get());
638  EXPECT_FALSE(curs1.isAtEnd());
639  curs1.skip(3);
640  EXPECT_EQ(3, curs1 - chain1.get());
641  EXPECT_FALSE(curs1.isAtEnd());
642  curs1.skip(7);
643  EXPECT_EQ(10, curs1 - chain1.get());
644  EXPECT_TRUE(curs1.isAtEnd());
645 
646  Cursor curs2(chain1.get());
647  EXPECT_EQ(0, curs2 - chain1.get());
648  EXPECT_EQ(10, curs1 - curs2);
649  EXPECT_THROW(curs2 - curs1, std::out_of_range);
650  }
651 
652  // Test cross-chain operations
653  {
654  std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
655  chain1->append(10);
656  std::unique_ptr<IOBuf> chain2 = chain1->clone();
657 
658  Cursor curs1(chain1.get());
659  Cursor curs2(chain2.get());
660  EXPECT_THROW(curs1 - curs2, std::out_of_range);
661  EXPECT_THROW(curs1 - chain2.get(), std::out_of_range);
662  }
663 
664  // Test operations on multi-item chains
665  {
666  std::unique_ptr<IOBuf> chain(IOBuf::create(20));
667  chain->append(10);
668  chain->appendChain(chain->clone());
669  EXPECT_EQ(20, chain->computeChainDataLength());
670 
671  Cursor curs1(chain.get());
672  curs1.skip(5);
673  Cursor curs2(chain.get());
674  curs2.skip(3);
675  EXPECT_EQ(2, curs1 - curs2);
676  EXPECT_EQ(5, curs1 - chain.get());
677  EXPECT_THROW(curs2 - curs1, std::out_of_range);
678 
679  curs1.skip(7);
680  EXPECT_EQ(9, curs1 - curs2);
681  EXPECT_EQ(12, curs1 - chain.get());
682  EXPECT_THROW(curs2 - curs1, std::out_of_range);
683 
684  curs2.skip(7);
685  EXPECT_EQ(2, curs1 - curs2);
686  EXPECT_THROW(curs2 - curs1, std::out_of_range);
687  }
688 
689  // Test isAtEnd() with empty buffers at the end of a chain
690  {
691  auto iobuf1 = IOBuf::create(20);
692  iobuf1->append(15);
693  iobuf1->trimStart(5);
694 
695  Cursor c(iobuf1.get());
696  EXPECT_FALSE(c.isAtEnd());
697  c.skip(10);
698  EXPECT_TRUE(c.isAtEnd());
699 
700  iobuf1->prependChain(IOBuf::create(10));
701  iobuf1->prependChain(IOBuf::create(10));
702  EXPECT_TRUE(c.isAtEnd());
703  iobuf1->prev()->append(5);
704  EXPECT_FALSE(c.isAtEnd());
705  c.skip(5);
706  EXPECT_TRUE(c.isAtEnd());
707  }
708 
709  // Test canAdvance with a chain of items
710  {
711  auto chain = IOBuf::create(10);
712  chain->append(10);
713  chain->appendChain(chain->clone());
714  EXPECT_EQ(2, chain->countChainElements());
715  EXPECT_EQ(20, chain->computeChainDataLength());
716 
717  Cursor c(chain.get());
718  for (size_t i = 0; i <= 20; ++i) {
719  EXPECT_TRUE(c.canAdvance(i));
720  }
721  EXPECT_FALSE(c.canAdvance(21));
722  c.skip(10);
723  EXPECT_TRUE(c.canAdvance(10));
724  EXPECT_FALSE(c.canAdvance(11));
725  }
726 }
727 
728 TEST(IOBuf, StringOperations) {
729  // Test a single buffer with two null-terminated strings and an extra uint8_t
730  // at the end
731  {
732  std::unique_ptr<IOBuf> chain(IOBuf::create(16));
733  Appender app(chain.get(), 0);
734  app.push(reinterpret_cast<const uint8_t*>("hello\0world\0\x01"), 13);
735 
736  Cursor curs(chain.get());
737  EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
738  EXPECT_STREQ("world", curs.readTerminatedString().c_str());
739  EXPECT_EQ(1, curs.read<uint8_t>());
740  }
741 
742  // Test multiple buffers where the first is empty and the string starts in
743  // the second buffer.
744  {
745  std::unique_ptr<IOBuf> chain(IOBuf::create(8));
746  chain->prependChain(IOBuf::create(12));
747  Appender app(chain.get(), 0);
748  app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
749 
750  Cursor curs(chain.get());
751  EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
752  }
753 
754  // Test multiple buffers with a single null-terminated string spanning them
755  {
756  std::unique_ptr<IOBuf> chain(IOBuf::create(8));
757  chain->prependChain(IOBuf::create(8));
758  chain->append(8);
759  chain->next()->append(4);
760  RWPrivateCursor rwc(chain.get());
761  rwc.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
762 
763  Cursor curs(chain.get());
764  EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
765  }
766 
767  // Test a reading a null-terminated string that's longer than the maximum
768  // allowable length
769  {
770  std::unique_ptr<IOBuf> chain(IOBuf::create(16));
771  Appender app(chain.get(), 0);
772  app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
773 
774  Cursor curs(chain.get());
775  EXPECT_THROW(curs.readTerminatedString('\0', 5), std::length_error);
776  }
777 
778  // Test reading a null-terminated string from a chain with an empty buffer at
779  // the front
780  {
781  std::unique_ptr<IOBuf> buf(IOBuf::create(8));
782  Appender app(buf.get(), 0);
783  app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
784  std::unique_ptr<IOBuf> chain(IOBuf::create(8));
785  chain->prependChain(std::move(buf));
786 
787  Cursor curs(chain.get());
788  EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
789  }
790 
791  // Test reading a null-terminated string from a chain that doesn't contain the
792  // terminator
793  {
794  std::unique_ptr<IOBuf> buf(IOBuf::create(8));
795  Appender app(buf.get(), 0);
796  app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
797  std::unique_ptr<IOBuf> chain(IOBuf::create(8));
798  chain->prependChain(std::move(buf));
799 
800  Cursor curs(chain.get());
801  EXPECT_THROW(curs.readTerminatedString(), std::out_of_range);
802  }
803 
804  // Test reading a null-terminated string past the maximum length
805  {
806  std::unique_ptr<IOBuf> buf(IOBuf::create(8));
807  Appender app(buf.get(), 0);
808  app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
809  std::unique_ptr<IOBuf> chain(IOBuf::create(8));
810  chain->prependChain(std::move(buf));
811 
812  Cursor curs(chain.get());
813  EXPECT_THROW(curs.readTerminatedString('\0', 3), std::length_error);
814  }
815 
816  // Test reading a two fixed-length strings from a single buffer with an extra
817  // uint8_t at the end
818  {
819  std::unique_ptr<IOBuf> chain(IOBuf::create(16));
820  Appender app(chain.get(), 0);
821  app.push(reinterpret_cast<const uint8_t*>("helloworld\x01"), 11);
822 
823  Cursor curs(chain.get());
824  EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
825  EXPECT_STREQ("world", curs.readFixedString(5).c_str());
826  EXPECT_EQ(1, curs.read<uint8_t>());
827  }
828 
829  // Test multiple buffers where the first is empty and a fixed-length string
830  // starts in the second buffer.
831  {
832  std::unique_ptr<IOBuf> chain(IOBuf::create(8));
833  chain->prependChain(IOBuf::create(16));
834  Appender app(chain.get(), 0);
835  app.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
836 
837  Cursor curs(chain.get());
838  EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
839  }
840 
841  // Test multiple buffers with a single fixed-length string spanning them
842  {
843  std::unique_ptr<IOBuf> chain(IOBuf::create(8));
844  chain->prependChain(IOBuf::create(8));
845  chain->append(7);
846  chain->next()->append(4);
847  RWPrivateCursor rwc(chain.get());
848  rwc.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
849 
850  Cursor curs(chain.get());
851  EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
852  }
853 
854  // Test reading a fixed-length string from a chain with an empty buffer at
855  // the front
856  {
857  std::unique_ptr<IOBuf> buf(IOBuf::create(8));
858  Appender app(buf.get(), 0);
859  app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
860  std::unique_ptr<IOBuf> chain(IOBuf::create(8));
861  chain->prependChain(std::move(buf));
862 
863  Cursor curs(chain.get());
864  EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
865  }
866 }
867 
868 TEST(IOBuf, ReadWhileTrue) {
869  auto isAlpha = [](uint8_t ch) {
870  return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
871  };
872  auto isDigit = [](uint8_t ch) { return (ch >= '0' && ch <= '9'); };
873 
874  // Test reading alternating alphabetic and numeric strings
875  {
876  std::unique_ptr<IOBuf> chain(IOBuf::create(32));
877  Appender app(chain.get(), 0);
878  app.push(StringPiece("hello123world456"));
879 
880  Cursor curs(chain.get());
881  EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
882  EXPECT_STREQ("123", curs.readWhile(isDigit).c_str());
883  EXPECT_STREQ("world", curs.readWhile(isAlpha).c_str());
884  EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
885  EXPECT_TRUE(curs.isAtEnd());
886  }
887 
888  // The same, but also use skipWhile()
889  {
890  std::unique_ptr<IOBuf> chain(IOBuf::create(16));
891  Appender app(chain.get(), 0);
892  app.push(StringPiece("hello123world456"));
893 
894  Cursor curs(chain.get());
895  EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
896  curs.skipWhile(isDigit);
897  curs.skipWhile(isAlpha);
898  EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
899  EXPECT_TRUE(curs.isAtEnd());
900  }
901 
902  // Test readWhile() using data split across multiple buffers,
903  // including some empty buffers in the middle of the chain.
904  {
905  std::unique_ptr<IOBuf> chain;
906 
907  // First element in the chain has "he"
908  auto buf = IOBuf::create(40);
909  Appender app(buf.get(), 0);
910  app.push(StringPiece("he"));
911  chain = std::move(buf);
912 
913  // The second element has "ll", after 10 bytes of headroom
914  buf = IOBuf::create(40);
915  buf->advance(10);
916  app = Appender{buf.get(), 0};
917  app.push(StringPiece("ll"));
918  chain->prependChain(std::move(buf));
919 
920  // The third element is empty
921  buf = IOBuf::create(40);
922  buf->advance(15);
923  chain->prependChain(std::move(buf));
924 
925  // The fourth element has "o12"
926  buf = IOBuf::create(40);
927  buf->advance(37);
928  app = Appender{buf.get(), 0};
929  app.push(StringPiece("o12"));
930  chain->prependChain(std::move(buf));
931 
932  // The fifth element has "3"
933  buf = IOBuf::create(40);
934  app = Appender{buf.get(), 0};
935  app.push(StringPiece("3"));
936  chain->prependChain(std::move(buf));
937 
938  // The sixth element is empty
939  buf = IOBuf::create(40);
940  chain->prependChain(std::move(buf));
941 
942  // The seventh element has "world456"
943  buf = IOBuf::create(40);
944  app = Appender{buf.get(), 0};
945  app.push(StringPiece("world456"));
946  chain->prependChain(std::move(buf));
947 
948  // The eighth element is empty
949  buf = IOBuf::create(40);
950  chain->prependChain(std::move(buf));
951 
952  Cursor curs(chain.get());
953  EXPECT_STREQ("hello", curs.readWhile(isAlpha).c_str());
954  EXPECT_STREQ("123", curs.readWhile(isDigit).c_str());
955  EXPECT_STREQ("world", curs.readWhile(isAlpha).c_str());
956  EXPECT_STREQ("456", curs.readWhile(isDigit).c_str());
957  EXPECT_TRUE(curs.isAtEnd());
958  }
959 }
960 
961 TEST(IOBuf, TestAdvanceToEndSingle) {
962  std::unique_ptr<IOBuf> chain(IOBuf::create(10));
963  chain->append(10);
964 
965  Cursor curs(chain.get());
966  curs.advanceToEnd();
967  EXPECT_TRUE(curs.isAtEnd());
968  EXPECT_EQ(curs - chain.get(), 10);
969 }
970 
971 TEST(IOBuf, TestAdvanceToEndMulti) {
972  std::unique_ptr<IOBuf> chain(IOBuf::create(10));
973  chain->append(10);
974 
975  std::unique_ptr<IOBuf> buf(IOBuf::create(5));
976  buf->append(5);
977  chain->prependChain(std::move(buf));
978 
979  buf = IOBuf::create(20);
980  buf->append(20);
981  chain->prependChain(std::move(buf));
982 
983  Cursor curs(chain.get());
984  curs.advanceToEnd();
985  EXPECT_TRUE(curs.isAtEnd());
986  EXPECT_EQ(curs - chain.get(), 35);
987 
988  curs.reset(chain.get());
989  curs.skip(12);
990  curs.advanceToEnd();
991  EXPECT_TRUE(curs.isAtEnd());
992 }
993 
994 TEST(IOBuf, TestRetreatSingle) {
995  std::unique_ptr<IOBuf> chain(IOBuf::create(20));
996  chain->append(20);
997 
998  Cursor curs(chain.get());
999  EXPECT_EQ(curs.retreatAtMost(0), 0);
1000  EXPECT_EQ(curs.totalLength(), 20);
1001  EXPECT_EQ(curs.retreatAtMost(5), 0);
1002  EXPECT_EQ(curs.totalLength(), 20);
1003  EXPECT_EQ(curs.retreatAtMost(25), 0);
1004  EXPECT_EQ(curs.totalLength(), 20);
1005 
1006  curs.retreat(0);
1007  EXPECT_THROW(curs.retreat(5), std::out_of_range);
1008  curs.reset(chain.get());
1009  EXPECT_THROW(curs.retreat(25), std::out_of_range);
1010  curs.reset(chain.get());
1011 
1012  curs.advanceToEnd();
1013  curs.retreat(5);
1014  EXPECT_EQ(curs.totalLength(), 5);
1015  curs.retreat(10);
1016  EXPECT_EQ(curs.totalLength(), 15);
1017  EXPECT_THROW(curs.retreat(10), std::out_of_range);
1018 
1019  curs.reset(chain.get());
1020  curs.advanceToEnd();
1021  EXPECT_EQ(curs.retreatAtMost(5), 5);
1022  EXPECT_EQ(curs.totalLength(), 5);
1023  EXPECT_EQ(curs.retreatAtMost(10), 10);
1024  EXPECT_EQ(curs.totalLength(), 15);
1025  EXPECT_EQ(curs.retreatAtMost(10), 5);
1026  EXPECT_EQ(curs.totalLength(), 20);
1027 }
1028 
1029 TEST(IOBuf, TestRetreatMulti) {
1030  std::unique_ptr<IOBuf> chain(IOBuf::create(10));
1031  chain->append(10);
1032 
1033  std::unique_ptr<IOBuf> buf(IOBuf::create(5));
1034  buf->append(5);
1035  chain->prependChain(std::move(buf));
1036 
1037  buf = IOBuf::create(20);
1038  buf->append(20);
1039  chain->prependChain(std::move(buf));
1040 
1041  Cursor curs(chain.get());
1042  EXPECT_EQ(curs.retreatAtMost(10), 0);
1043  EXPECT_THROW(curs.retreat(10), std::out_of_range);
1044  curs.reset(chain.get());
1045 
1046  curs.advanceToEnd();
1047  curs.retreat(20);
1048  EXPECT_EQ(curs.totalLength(), 20);
1049  EXPECT_EQ(curs.length(), 20);
1050  curs.retreat(1);
1051  EXPECT_EQ(curs.totalLength(), 21);
1052  EXPECT_EQ(curs.length(), 1);
1053  EXPECT_EQ(curs.retreatAtMost(50), 14);
1054  EXPECT_EQ(curs.totalLength(), 35);
1055 
1056  curs.advanceToEnd();
1057  curs.retreat(30);
1058  EXPECT_EQ(curs.totalLength(), 30);
1059 }
1060 
1061 TEST(IOBuf, TestRetreatOperators) {
1062  std::unique_ptr<IOBuf> chain(IOBuf::create(20));
1063  chain->append(20);
1064 
1065  Cursor curs(chain.get());
1066  curs.advanceToEnd();
1067  curs -= 5;
1068  EXPECT_EQ(curs.totalLength(), 5);
1069 
1070  curs.advanceToEnd();
1071  auto retreated = curs - 5;
1072  EXPECT_EQ(retreated.totalLength(), 5);
1073  EXPECT_EQ(curs.totalLength(), 0);
1074 }
1075 
1076 TEST(IOBuf, tryRead) {
1077  unique_ptr<IOBuf> iobuf1(IOBuf::create(6));
1078  iobuf1->append(6);
1079  unique_ptr<IOBuf> iobuf2(IOBuf::create(24));
1080  iobuf2->append(24);
1081 
1082  iobuf1->prependChain(std::move(iobuf2));
1083 
1084  EXPECT_TRUE(iobuf1->isChained());
1085 
1086  RWPrivateCursor wcursor(iobuf1.get());
1087  Cursor rcursor(iobuf1.get());
1088  wcursor.writeLE((uint32_t)1);
1089  wcursor.writeLE((uint64_t)1);
1090  wcursor.writeLE((uint64_t)1);
1091  wcursor.writeLE((uint64_t)1);
1092  wcursor.writeLE((uint16_t)1);
1093  EXPECT_EQ(0, wcursor.totalLength());
1094 
1095  EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1096 
1097  EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1098  EXPECT_EQ(0u, rcursor.readLE<uint32_t>());
1099 
1100  EXPECT_EQ(1u, rcursor.readLE<uint32_t>());
1101  rcursor.skip(4);
1102 
1103  uint32_t val;
1104  EXPECT_TRUE(rcursor.tryRead(val));
1105  EXPECT_EQ(1, val);
1106  EXPECT_TRUE(rcursor.tryRead(val));
1107 
1108  EXPECT_EQ(0, val);
1109  EXPECT_FALSE(rcursor.tryRead(val));
1110 }
1111 
1112 TEST(IOBuf, tryReadLE) {
1113  IOBuf buf{IOBuf::CREATE, 4};
1114  buf.append(4);
1115 
1116  RWPrivateCursor wcursor(&buf);
1117  Cursor rcursor(&buf);
1118 
1119  const uint32_t expected = 0x01020304;
1120  wcursor.writeLE(expected);
1121  uint32_t actual;
1122  EXPECT_TRUE(rcursor.tryReadLE(actual));
1123  EXPECT_EQ(expected, actual);
1124 }
1125 
1126 TEST(IOBuf, tryReadBE) {
1127  IOBuf buf{IOBuf::CREATE, 4};
1128  buf.append(4);
1129 
1130  RWPrivateCursor wcursor(&buf);
1131  Cursor rcursor(&buf);
1132 
1133  const uint32_t expected = 0x01020304;
1134  wcursor.writeBE(expected);
1135  uint32_t actual;
1136  EXPECT_TRUE(rcursor.tryReadBE(actual));
1137  EXPECT_EQ(expected, actual);
1138 }
1139 
1140 TEST(IOBuf, tryReadConsumesAllInputOnFailure) {
1141  IOBuf buf{IOBuf::CREATE, 2};
1142  buf.append(2);
1143 
1144  Cursor rcursor(&buf);
1145  uint32_t val;
1146  EXPECT_FALSE(rcursor.tryRead(val));
1147  EXPECT_EQ(0, rcursor.totalLength());
1148 }
1149 
1150 TEST(IOBuf, readConsumesAllInputOnFailure) {
1151  IOBuf buf{IOBuf::CREATE, 2};
1152  buf.append(2);
1153 
1154  Cursor rcursor(&buf);
1155  EXPECT_THROW(rcursor.read<uint32_t>(), std::out_of_range);
1156  EXPECT_EQ(0, rcursor.totalLength());
1157 }
1158 
1159 TEST(IOBuf, pushEmptyByteRange) {
1160  // Test pushing an empty ByteRange. This mainly tests that we do not
1161  // trigger UBSAN warnings by calling memcpy() with an null source pointer,
1162  // which is undefined behavior even if the length is 0.
1163  IOBuf buf{IOBuf::CREATE, 2};
1164  ByteRange emptyBytes;
1165 
1166  // Test calling Cursor::push()
1167  RWPrivateCursor wcursor(&buf);
1168  wcursor.push(emptyBytes);
1169  EXPECT_EQ(0, buf.computeChainDataLength());
1170 
1171  // Test calling Appender::push()
1172  Appender app(&buf, 16);
1173  app.push(emptyBytes);
1174  EXPECT_EQ(0, buf.computeChainDataLength());
1175 }
1176 
1177 TEST(IOBuf, positionTracking) {
1178  unique_ptr<IOBuf> iobuf1(IOBuf::create(6));
1179  iobuf1->append(6);
1180  unique_ptr<IOBuf> iobuf2(IOBuf::create(24));
1181  iobuf2->append(24);
1182  iobuf1->prependChain(std::move(iobuf2));
1183 
1184  Cursor cursor(iobuf1.get());
1185 
1186  EXPECT_EQ(0, cursor.getCurrentPosition());
1187  EXPECT_EQ(6, cursor.length());
1188 
1189  cursor.skip(3);
1190  EXPECT_EQ(3, cursor.getCurrentPosition());
1191  EXPECT_EQ(3, cursor.length());
1192 
1193  // Test that we properly handle advancing to the next chunk.
1194  cursor.skip(4);
1195  EXPECT_EQ(7, cursor.getCurrentPosition());
1196  EXPECT_EQ(23, cursor.length());
1197 
1198  // Test that we properly handle doing to the previous chunk.
1199  cursor.retreat(2);
1200  EXPECT_EQ(5, cursor.getCurrentPosition());
1201  EXPECT_EQ(1, cursor.length());
1202 
1203  // Test that we properly handle advanceToEnd
1204  cursor.advanceToEnd();
1205  EXPECT_EQ(30, cursor.getCurrentPosition());
1206  EXPECT_EQ(0, cursor.totalLength());
1207 
1208  // Reset to 0.
1209  cursor.reset(iobuf1.get());
1210  EXPECT_EQ(0, cursor.getCurrentPosition());
1211  EXPECT_EQ(30, cursor.totalLength());
1212 }
#define EXPECT_LE(val1, val2)
Definition: gtest.h:1928
Definition: InvokeTest.cpp:58
const folly::IOBuf * front() const
Definition: IOBufQueue.h:476
folly::StringPiece toString(StateEnum state)
Definition: State.cpp:16
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
void printf(FOLLY_PRINTF_FORMAT const char *fmt,...) FOLLY_PRINTF_FORMAT_ATTR(2
Definition: Cursor.cpp:26
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
char b
static std::unique_ptr< IOBuf > wrapBuffer(const void *buf, std::size_t capacity)
Definition: IOBuf.cpp:353
std::enable_if< std::is_arithmetic< T >::value >::type write(T value)
Definition: Cursor.h:737
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
fbstring moveToFbString()
Definition: IOBuf.cpp:968
std::enable_if< std::is_arithmetic< T >::value, bool >::type tryRead(T &val)
Definition: Cursor.h:257
void appendChain(std::unique_ptr< IOBuf > &&iobuf)
Definition: IOBuf.h:827
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const uint8_t * tail() const
Definition: IOBuf.h:516
void append(std::unique_ptr< IOBuf > &buf, StringPiece str)
Definition: IOBufTest.cpp:37
constexpr size_type size() const
Definition: Range.h:431
double val
Definition: String.cpp:273
const uint8_t * data() const
Definition: IOBuf.h:499
void push(const uint8_t *buf, size_t len)
Definition: Cursor.h:755
bool isChained() const
Definition: IOBuf.h:760
std::unique_ptr< IOBuf > clone() const
Definition: IOBuf.cpp:527
size_t countChainElements() const
Definition: IOBuf.cpp:493
detail::Skip skip(size_t count)
Definition: Base-inl.h:2598
#define EXPECT_GE(val1, val2)
Definition: gtest.h:1932
std::size_t capacity() const
Definition: IOBuf.h:593
std::size_t tailroom() const
Definition: IOBuf.h:551
auto ch
void writeLE(T value)
Definition: Cursor.h:750
#define EXPECT_STREQ(s1, s2)
Definition: gtest.h:1995
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
uint8_t * writableData()
Definition: IOBuf.h:509
constexpr Iter data() const
Definition: Range.h:446
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
std::size_t length() const
Definition: IOBuf.h:533
std::basic_string< E, T, A > toStdString() const
Definition: FBString.h:1227
constexpr Range< Iter > range(Iter first, Iter last)
Definition: Range.h:1114
IOBuf * next()
Definition: IOBuf.h:600
auto start
RWCursor< CursorAccess::PRIVATE > RWPrivateCursor
Definition: Cursor.h:958
void prependChain(std::unique_ptr< IOBuf > &&iobuf)
Definition: IOBuf.cpp:509
IOBuf * prev()
Definition: IOBuf.h:610
std::size_t computeChainDataLength() const
Definition: IOBuf.cpp:501
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
void skip(size_t len)
Definition: Cursor.h:371
const char * string
Definition: Conv.cpp:212
Range< const unsigned char * > ByteRange
Definition: Range.h:1163
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
Formatter< false, Args... > format(StringPiece fmt, Args &&...args)
Definition: Format.h:271
void trimStart(std::size_t amount)
Definition: IOBuf.h:703
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
Range< const char * > StringPiece
#define EXPECT_LT(val1, val2)
Definition: gtest.h:1930
#define ADD_FAILURE()
Definition: gtest.h:1808
void gather(size_t n)
Definition: Cursor.h:831
char c
TEST(SequencedExecutor, CPUThreadPoolExecutor)
size_t totalLength() const
Definition: Cursor.h:126
void append(std::size_t amount)
Definition: IOBuf.h:689
void writeBE(T value)
Definition: Cursor.h:744