Switch gflags to portability/GFlags.h
[folly.git] / folly / io / test / IOBufTest.cpp
1 /*
2  * Copyright 2016 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 #include <folly/io/TypedIOBuf.h>
19
20 #include <cstddef>
21
22 #include <boost/random.hpp>
23 #include <gtest/gtest.h>
24
25 #include <folly/Malloc.h>
26 #include <folly/Range.h>
27
28 using folly::fbstring;
29 using folly::fbvector;
30 using folly::IOBuf;
31 using folly::TypedIOBuf;
32 using folly::StringPiece;
33 using folly::ByteRange;
34 using std::unique_ptr;
35
36 void append(std::unique_ptr<IOBuf>& buf, StringPiece str) {
37   EXPECT_LE(str.size(), buf->tailroom());
38   memcpy(buf->writableData(), str.data(), str.size());
39   buf->append(str.size());
40 }
41
42 void prepend(std::unique_ptr<IOBuf>& buf, StringPiece str) {
43   EXPECT_LE(str.size(), buf->headroom());
44   memcpy(buf->writableData() - str.size(), str.data(), str.size());
45   buf->prepend(str.size());
46 }
47
48 TEST(IOBuf, Simple) {
49   unique_ptr<IOBuf> buf(IOBuf::create(100));
50   uint32_t cap = buf->capacity();
51   EXPECT_LE(100, cap);
52   EXPECT_EQ(0, buf->headroom());
53   EXPECT_EQ(0, buf->length());
54   EXPECT_EQ(cap, buf->tailroom());
55
56   append(buf, "world");
57   buf->advance(10);
58   EXPECT_EQ(10, buf->headroom());
59   EXPECT_EQ(5, buf->length());
60   EXPECT_EQ(cap - 15, buf->tailroom());
61
62   prepend(buf, "hello ");
63   EXPECT_EQ(4, buf->headroom());
64   EXPECT_EQ(11, buf->length());
65   EXPECT_EQ(cap - 15, buf->tailroom());
66
67   const char* p = reinterpret_cast<const char*>(buf->data());
68   EXPECT_EQ("hello world", std::string(p, buf->length()));
69
70   buf->clear();
71   EXPECT_EQ(0, buf->headroom());
72   EXPECT_EQ(0, buf->length());
73   EXPECT_EQ(cap, buf->tailroom());
74 }
75
76
77 void testAllocSize(uint32_t requestedCapacity) {
78   unique_ptr<IOBuf> iobuf(IOBuf::create(requestedCapacity));
79   EXPECT_GE(iobuf->capacity(), requestedCapacity);
80 }
81
82 TEST(IOBuf, AllocSizes) {
83   // Try with a small allocation size that should fit in the internal buffer
84   testAllocSize(28);
85
86   // Try with a large allocation size that will require an external buffer.
87   testAllocSize(9000);
88
89   // 220 bytes is currently the cutoff
90   // (It would be nice to use the IOBuf::kMaxInternalDataSize constant,
91   // but it's private and it doesn't seem worth making it public just for this
92   // test code.)
93   testAllocSize(220);
94   testAllocSize(219);
95   testAllocSize(221);
96 }
97
98 void deleteArrayBuffer(void *buf, void* arg) {
99   uint32_t* deleteCount = static_cast<uint32_t*>(arg);
100   ++(*deleteCount);
101   uint8_t* bufPtr = static_cast<uint8_t*>(buf);
102   delete[] bufPtr;
103 }
104
105 TEST(IOBuf, TakeOwnership) {
106   uint32_t size1 = 99;
107   uint8_t *buf1 = static_cast<uint8_t*>(malloc(size1));
108   unique_ptr<IOBuf> iobuf1(IOBuf::takeOwnership(buf1, size1));
109   EXPECT_EQ(buf1, iobuf1->data());
110   EXPECT_EQ(size1, iobuf1->length());
111   EXPECT_EQ(buf1, iobuf1->buffer());
112   EXPECT_EQ(size1, iobuf1->capacity());
113
114   uint32_t deleteCount = 0;
115   uint32_t size2 = 4321;
116   uint8_t *buf2 = new uint8_t[size2];
117   unique_ptr<IOBuf> iobuf2(IOBuf::takeOwnership(buf2, size2,
118                                                 deleteArrayBuffer,
119                                                 &deleteCount));
120   EXPECT_EQ(buf2, iobuf2->data());
121   EXPECT_EQ(size2, iobuf2->length());
122   EXPECT_EQ(buf2, iobuf2->buffer());
123   EXPECT_EQ(size2, iobuf2->capacity());
124   EXPECT_EQ(0, deleteCount);
125   iobuf2.reset();
126   EXPECT_EQ(1, deleteCount);
127
128   deleteCount = 0;
129   uint32_t size3 = 3456;
130   uint8_t *buf3 = new uint8_t[size3];
131   uint32_t length3 = 48;
132   unique_ptr<IOBuf> iobuf3(IOBuf::takeOwnership(buf3, size3, length3,
133                                                 deleteArrayBuffer,
134                                                 &deleteCount));
135   EXPECT_EQ(buf3, iobuf3->data());
136   EXPECT_EQ(length3, iobuf3->length());
137   EXPECT_EQ(buf3, iobuf3->buffer());
138   EXPECT_EQ(size3, iobuf3->capacity());
139   EXPECT_EQ(0, deleteCount);
140   iobuf3.reset();
141   EXPECT_EQ(1, deleteCount);
142
143   deleteCount = 0;
144   {
145     uint32_t size4 = 1234;
146     uint8_t *buf4 = new uint8_t[size4];
147     uint32_t length4 = 48;
148     IOBuf iobuf4(IOBuf::TAKE_OWNERSHIP, buf4, size4, length4,
149                  deleteArrayBuffer, &deleteCount);
150     EXPECT_EQ(buf4, iobuf4.data());
151     EXPECT_EQ(length4, iobuf4.length());
152     EXPECT_EQ(buf4, iobuf4.buffer());
153     EXPECT_EQ(size4, iobuf4.capacity());
154
155     IOBuf iobuf5 = std::move(iobuf4);
156     EXPECT_EQ(buf4, iobuf5.data());
157     EXPECT_EQ(length4, iobuf5.length());
158     EXPECT_EQ(buf4, iobuf5.buffer());
159     EXPECT_EQ(size4, iobuf5.capacity());
160     EXPECT_EQ(0, deleteCount);
161   }
162   EXPECT_EQ(1, deleteCount);
163 }
164
165 TEST(IOBuf, WrapBuffer) {
166   const uint32_t size1 = 1234;
167   uint8_t buf1[size1];
168   unique_ptr<IOBuf> iobuf1(IOBuf::wrapBuffer(buf1, size1));
169   EXPECT_EQ(buf1, iobuf1->data());
170   EXPECT_EQ(size1, iobuf1->length());
171   EXPECT_EQ(buf1, iobuf1->buffer());
172   EXPECT_EQ(size1, iobuf1->capacity());
173
174   uint32_t size2 = 0x1234;
175   unique_ptr<uint8_t[]> buf2(new uint8_t[size2]);
176   unique_ptr<IOBuf> iobuf2(IOBuf::wrapBuffer(buf2.get(), size2));
177   EXPECT_EQ(buf2.get(), iobuf2->data());
178   EXPECT_EQ(size2, iobuf2->length());
179   EXPECT_EQ(buf2.get(), iobuf2->buffer());
180   EXPECT_EQ(size2, iobuf2->capacity());
181
182   uint32_t size3 = 4321;
183   unique_ptr<uint8_t[]> buf3(new uint8_t[size3]);
184   IOBuf iobuf3(IOBuf::WRAP_BUFFER, buf3.get(), size3);
185   EXPECT_EQ(buf3.get(), iobuf3.data());
186   EXPECT_EQ(size3, iobuf3.length());
187   EXPECT_EQ(buf3.get(), iobuf3.buffer());
188   EXPECT_EQ(size3, iobuf3.capacity());
189 }
190
191 TEST(IOBuf, CreateCombined) {
192   // Create a combined IOBuf, then destroy it.
193   // The data buffer and IOBuf both become unused as part of the destruction
194   {
195     auto buf = IOBuf::createCombined(256);
196     EXPECT_FALSE(buf->isShared());
197   }
198
199   // Create a combined IOBuf, clone from it, and then destroy the original
200   // IOBuf.  The data buffer cannot be deleted until the clone is also
201   // destroyed.
202   {
203     auto bufA = IOBuf::createCombined(256);
204     EXPECT_FALSE(bufA->isShared());
205     auto bufB = bufA->clone();
206     EXPECT_TRUE(bufA->isShared());
207     EXPECT_TRUE(bufB->isShared());
208     bufA.reset();
209     EXPECT_FALSE(bufB->isShared());
210   }
211
212   // Create a combined IOBuf, then call reserve() to get a larger buffer.
213   // The IOBuf no longer points to the combined data buffer, but the
214   // overall memory segment cannot be deleted until the IOBuf is also
215   // destroyed.
216   {
217     auto buf = IOBuf::createCombined(256);
218     buf->reserve(0, buf->capacity() + 100);
219   }
220
221   // Create a combined IOBuf, clone from it, then call unshare() on the original
222   // buffer.  This creates a situation where bufB is pointing at the combined
223   // buffer associated with bufA, but bufA is now using a different buffer.
224   auto testSwap = [](bool resetAFirst) {
225     auto bufA = IOBuf::createCombined(256);
226     EXPECT_FALSE(bufA->isShared());
227     auto bufB = bufA->clone();
228     EXPECT_TRUE(bufA->isShared());
229     EXPECT_TRUE(bufB->isShared());
230     bufA->unshare();
231     EXPECT_FALSE(bufA->isShared());
232     EXPECT_FALSE(bufB->isShared());
233
234     if (resetAFirst) {
235       bufA.reset();
236       bufB.reset();
237     } else {
238       bufB.reset();
239       bufA.reset();
240     }
241   };
242   testSwap(true);
243   testSwap(false);
244 }
245
246 void fillBuf(uint8_t* buf, uint32_t length, boost::mt19937& gen) {
247   for (uint32_t n = 0; n < length; ++n) {
248     buf[n] = static_cast<uint8_t>(gen() & 0xff);
249   }
250 }
251
252 void fillBuf(IOBuf* buf, boost::mt19937& gen) {
253   buf->unshare();
254   fillBuf(buf->writableData(), buf->length(), gen);
255 }
256
257 void checkBuf(const uint8_t* buf, uint32_t length, boost::mt19937& gen) {
258   // Rather than using EXPECT_EQ() to check each character,
259   // count the number of differences and the first character that differs.
260   // This way on error we'll report just that information, rather than tons of
261   // failed checks for each byte in the buffer.
262   uint32_t numDifferences = 0;
263   uint32_t firstDiffIndex = 0;
264   uint8_t firstDiffExpected = 0;
265   for (uint32_t n = 0; n < length; ++n) {
266     uint8_t expected = static_cast<uint8_t>(gen() & 0xff);
267     if (buf[n] == expected) {
268       continue;
269     }
270
271     if (numDifferences == 0) {
272       firstDiffIndex = n;
273       firstDiffExpected = expected;
274     }
275     ++numDifferences;
276   }
277
278   EXPECT_EQ(0, numDifferences);
279   if (numDifferences > 0) {
280     // Cast to int so it will be printed numerically
281     // rather than as a char if the check fails
282     EXPECT_EQ(static_cast<int>(buf[firstDiffIndex]),
283               static_cast<int>(firstDiffExpected));
284   }
285 }
286
287 void checkBuf(IOBuf* buf, boost::mt19937& gen) {
288   checkBuf(buf->data(), buf->length(), gen);
289 }
290
291 void checkBuf(ByteRange buf, boost::mt19937& gen) {
292   checkBuf(buf.data(), buf.size(), gen);
293 }
294
295 void checkChain(IOBuf* buf, boost::mt19937& gen) {
296   IOBuf *current = buf;
297   do {
298     checkBuf(current->data(), current->length(), gen);
299     current = current->next();
300   } while (current != buf);
301 }
302
303 TEST(IOBuf, Chaining) {
304   uint32_t fillSeed = 0x12345678;
305   boost::mt19937 gen(fillSeed);
306
307   // An IOBuf with external storage
308   uint32_t headroom = 123;
309   unique_ptr<IOBuf> iob1(IOBuf::create(2048));
310   iob1->advance(headroom);
311   iob1->append(1500);
312   fillBuf(iob1.get(), gen);
313
314   // An IOBuf with internal storage
315   unique_ptr<IOBuf> iob2(IOBuf::create(20));
316   iob2->append(20);
317   fillBuf(iob2.get(), gen);
318
319   // An IOBuf around a buffer it doesn't own
320   uint8_t localbuf[1234];
321   fillBuf(localbuf, 1234, gen);
322   unique_ptr<IOBuf> iob3(IOBuf::wrapBuffer(localbuf, sizeof(localbuf)));
323
324   // An IOBuf taking ownership of a user-supplied buffer
325   uint32_t heapBufSize = 900;
326   uint8_t* heapBuf = static_cast<uint8_t*>(malloc(heapBufSize));
327   fillBuf(heapBuf, heapBufSize, gen);
328   unique_ptr<IOBuf> iob4(IOBuf::takeOwnership(heapBuf, heapBufSize));
329
330   // An IOBuf taking ownership of a user-supplied buffer with
331   // a custom free function
332   uint32_t arrayBufSize = 321;
333   uint8_t* arrayBuf = new uint8_t[arrayBufSize];
334   fillBuf(arrayBuf, arrayBufSize, gen);
335   uint32_t arrayBufFreeCount = 0;
336   unique_ptr<IOBuf> iob5(IOBuf::takeOwnership(arrayBuf, arrayBufSize,
337                                               deleteArrayBuffer,
338                                               &arrayBufFreeCount));
339
340   EXPECT_FALSE(iob1->isChained());
341   EXPECT_FALSE(iob2->isChained());
342   EXPECT_FALSE(iob3->isChained());
343   EXPECT_FALSE(iob4->isChained());
344   EXPECT_FALSE(iob5->isChained());
345
346   EXPECT_FALSE(iob1->isSharedOne());
347   EXPECT_FALSE(iob2->isSharedOne());
348   EXPECT_TRUE(iob3->isSharedOne()); // since we own the buffer
349   EXPECT_FALSE(iob4->isSharedOne());
350   EXPECT_FALSE(iob5->isSharedOne());
351
352   // Chain the buffers all together
353   // Since we are going to relinquish ownership of iob2-5 to the chain,
354   // store raw pointers to them so we can reference them later.
355   IOBuf* iob2ptr = iob2.get();
356   IOBuf* iob3ptr = iob3.get();
357   IOBuf* iob4ptr = iob4.get();
358   IOBuf* iob5ptr = iob5.get();
359
360   iob1->prependChain(std::move(iob2));
361   iob1->prependChain(std::move(iob4));
362   iob2ptr->appendChain(std::move(iob3));
363   iob1->prependChain(std::move(iob5));
364
365   EXPECT_EQ(iob2ptr, iob1->next());
366   EXPECT_EQ(iob3ptr, iob2ptr->next());
367   EXPECT_EQ(iob4ptr, iob3ptr->next());
368   EXPECT_EQ(iob5ptr, iob4ptr->next());
369   EXPECT_EQ(iob1.get(), iob5ptr->next());
370
371   EXPECT_EQ(iob5ptr, iob1->prev());
372   EXPECT_EQ(iob1.get(), iob2ptr->prev());
373   EXPECT_EQ(iob2ptr, iob3ptr->prev());
374   EXPECT_EQ(iob3ptr, iob4ptr->prev());
375   EXPECT_EQ(iob4ptr, iob5ptr->prev());
376
377   EXPECT_TRUE(iob1->isChained());
378   EXPECT_TRUE(iob2ptr->isChained());
379   EXPECT_TRUE(iob3ptr->isChained());
380   EXPECT_TRUE(iob4ptr->isChained());
381   EXPECT_TRUE(iob5ptr->isChained());
382
383   uint64_t fullLength = (iob1->length() + iob2ptr->length() +
384                          iob3ptr->length() + iob4ptr->length() +
385                         iob5ptr->length());
386   EXPECT_EQ(5, iob1->countChainElements());
387   EXPECT_EQ(fullLength, iob1->computeChainDataLength());
388
389   // Since iob3 is shared, the entire buffer should report itself as shared
390   EXPECT_TRUE(iob1->isShared());
391   // Unshare just iob3
392   iob3ptr->unshareOne();
393   EXPECT_FALSE(iob3ptr->isSharedOne());
394   // Now everything in the chain should be unshared.
395   // Check on all members of the chain just for good measure
396   EXPECT_FALSE(iob1->isShared());
397   EXPECT_FALSE(iob2ptr->isShared());
398   EXPECT_FALSE(iob3ptr->isShared());
399   EXPECT_FALSE(iob4ptr->isShared());
400   EXPECT_FALSE(iob5ptr->isShared());
401
402   // Check iteration
403   gen.seed(fillSeed);
404   size_t count = 0;
405   for (auto buf : *iob1) {
406     checkBuf(buf, gen);
407     ++count;
408   }
409   EXPECT_EQ(5, count);
410
411   // Clone one of the IOBufs in the chain
412   unique_ptr<IOBuf> iob4clone = iob4ptr->cloneOne();
413   gen.seed(fillSeed);
414   checkBuf(iob1.get(), gen);
415   checkBuf(iob2ptr, gen);
416   checkBuf(iob3ptr, gen);
417   checkBuf(iob4clone.get(), gen);
418   checkBuf(iob5ptr, gen);
419
420   EXPECT_TRUE(iob1->isShared());
421   EXPECT_TRUE(iob2ptr->isShared());
422   EXPECT_TRUE(iob3ptr->isShared());
423   EXPECT_TRUE(iob4ptr->isShared());
424   EXPECT_TRUE(iob5ptr->isShared());
425
426   EXPECT_FALSE(iob1->isSharedOne());
427   EXPECT_FALSE(iob2ptr->isSharedOne());
428   EXPECT_FALSE(iob3ptr->isSharedOne());
429   EXPECT_TRUE(iob4ptr->isSharedOne());
430   EXPECT_FALSE(iob5ptr->isSharedOne());
431
432   // Unshare that clone
433   EXPECT_TRUE(iob4clone->isSharedOne());
434   iob4clone->unshare();
435   EXPECT_FALSE(iob4clone->isSharedOne());
436   EXPECT_FALSE(iob4ptr->isSharedOne());
437   EXPECT_FALSE(iob1->isShared());
438   iob4clone.reset();
439
440
441   // Create a clone of a different IOBuf
442   EXPECT_FALSE(iob1->isShared());
443   EXPECT_FALSE(iob3ptr->isSharedOne());
444
445   unique_ptr<IOBuf> iob3clone = iob3ptr->cloneOne();
446   gen.seed(fillSeed);
447   checkBuf(iob1.get(), gen);
448   checkBuf(iob2ptr, gen);
449   checkBuf(iob3clone.get(), gen);
450   checkBuf(iob4ptr, gen);
451   checkBuf(iob5ptr, gen);
452
453   EXPECT_TRUE(iob1->isShared());
454   EXPECT_TRUE(iob3ptr->isSharedOne());
455   EXPECT_FALSE(iob1->isSharedOne());
456
457   // Delete the clone and make sure the original is unshared
458   iob3clone.reset();
459   EXPECT_FALSE(iob1->isShared());
460   EXPECT_FALSE(iob3ptr->isSharedOne());
461
462
463   // Clone the entire chain
464   unique_ptr<IOBuf> chainClone = iob1->clone();
465   // Verify that the data is correct.
466   EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
467   gen.seed(fillSeed);
468   checkChain(chainClone.get(), gen);
469
470   // Check that the buffers report sharing correctly
471   EXPECT_TRUE(chainClone->isShared());
472   EXPECT_TRUE(iob1->isShared());
473
474   EXPECT_TRUE(iob1->isSharedOne());
475   EXPECT_TRUE(iob2ptr->isSharedOne());
476   EXPECT_TRUE(iob3ptr->isSharedOne());
477   EXPECT_TRUE(iob4ptr->isSharedOne());
478   EXPECT_TRUE(iob5ptr->isSharedOne());
479
480   // Unshare the cloned chain
481   chainClone->unshare();
482   EXPECT_FALSE(chainClone->isShared());
483   EXPECT_FALSE(iob1->isShared());
484
485   // Make sure the unshared result still has the same data
486   EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
487   gen.seed(fillSeed);
488   checkChain(chainClone.get(), gen);
489
490   // Destroy this chain
491   chainClone.reset();
492
493
494   // Clone a new chain
495   EXPECT_FALSE(iob1->isShared());
496   chainClone = iob1->clone();
497   EXPECT_TRUE(iob1->isShared());
498   EXPECT_TRUE(chainClone->isShared());
499
500   // Delete the original chain
501   iob1.reset();
502   EXPECT_FALSE(chainClone->isShared());
503
504   // Coalesce the chain
505   //
506   // Coalescing this chain will create a new buffer and release the last
507   // refcount on the original buffers we created.  Also make sure
508   // that arrayBufFreeCount increases to one to indicate that arrayBuf was
509   // freed.
510   EXPECT_EQ(5, chainClone->countChainElements());
511   EXPECT_EQ(0, arrayBufFreeCount);
512
513   // Buffer lengths: 1500 20 1234 900 321
514   // Attempting to gather more data than available should fail
515   EXPECT_THROW(chainClone->gather(4000), std::overflow_error);
516   // Coalesce the first 3 buffers
517   chainClone->gather(1521);
518   EXPECT_EQ(3, chainClone->countChainElements());
519   EXPECT_EQ(0, arrayBufFreeCount);
520
521   // Make sure the data is still the same after coalescing
522   EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
523   gen.seed(fillSeed);
524   checkChain(chainClone.get(), gen);
525
526   // Coalesce the entire chain
527   chainClone->coalesce();
528   EXPECT_EQ(1, chainClone->countChainElements());
529   EXPECT_EQ(1, arrayBufFreeCount);
530
531   // Make sure the data is still the same after coalescing
532   EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
533   gen.seed(fillSeed);
534   checkChain(chainClone.get(), gen);
535
536   // Make a new chain to test the unlink and pop operations
537   iob1 = IOBuf::create(1);
538   iob1->append(1);
539   IOBuf *iob1ptr = iob1.get();
540   iob2 = IOBuf::create(3);
541   iob2->append(3);
542   iob2ptr = iob2.get();
543   iob3 = IOBuf::create(5);
544   iob3->append(5);
545   iob3ptr = iob3.get();
546   iob4 = IOBuf::create(7);
547   iob4->append(7);
548   iob4ptr = iob4.get();
549   iob1->appendChain(std::move(iob2));
550   iob1->prev()->appendChain(std::move(iob3));
551   iob1->prev()->appendChain(std::move(iob4));
552   EXPECT_EQ(4, iob1->countChainElements());
553   EXPECT_EQ(16, iob1->computeChainDataLength());
554
555   // Unlink from the middle of the chain
556   iob3 = iob3ptr->unlink();
557   EXPECT_TRUE(iob3.get() == iob3ptr);
558   EXPECT_EQ(3, iob1->countChainElements());
559   EXPECT_EQ(11, iob1->computeChainDataLength());
560
561   // Unlink from the end of the chain
562   iob4 = iob1->prev()->unlink();
563   EXPECT_TRUE(iob4.get() == iob4ptr);
564   EXPECT_EQ(2, iob1->countChainElements());
565   EXPECT_TRUE(iob1->next() == iob2ptr);
566   EXPECT_EQ(4, iob1->computeChainDataLength());
567
568   // Pop from the front of the chain
569   iob2 = iob1->pop();
570   EXPECT_TRUE(iob1.get() == iob1ptr);
571   EXPECT_EQ(1, iob1->countChainElements());
572   EXPECT_EQ(1, iob1->computeChainDataLength());
573   EXPECT_TRUE(iob2.get() == iob2ptr);
574   EXPECT_EQ(1, iob2->countChainElements());
575   EXPECT_EQ(3, iob2->computeChainDataLength());
576 }
577
578 void testFreeFn(void* buffer, void* ptr) {
579   uint32_t* freeCount = static_cast<uint32_t*>(ptr);;
580   delete[] static_cast<uint8_t*>(buffer);
581   if (freeCount) {
582     ++(*freeCount);
583   }
584 };
585
586 TEST(IOBuf, Reserve) {
587   uint32_t fillSeed = 0x23456789;
588   boost::mt19937 gen(fillSeed);
589
590   // Reserve does nothing if empty and doesn't have to grow the buffer
591   {
592     gen.seed(fillSeed);
593     unique_ptr<IOBuf> iob(IOBuf::create(2000));
594     EXPECT_EQ(0, iob->headroom());
595     const void* p1 = iob->buffer();
596     iob->reserve(5, 15);
597     EXPECT_LE(5, iob->headroom());
598     EXPECT_EQ(p1, iob->buffer());
599   }
600
601   // Reserve doesn't reallocate if we have enough total room
602   {
603     gen.seed(fillSeed);
604     unique_ptr<IOBuf> iob(IOBuf::create(2000));
605     iob->append(100);
606     fillBuf(iob.get(), gen);
607     EXPECT_EQ(0, iob->headroom());
608     EXPECT_EQ(100, iob->length());
609     const void* p1 = iob->buffer();
610     const uint8_t* d1 = iob->data();
611     iob->reserve(100, 1800);
612     EXPECT_LE(100, iob->headroom());
613     EXPECT_EQ(p1, iob->buffer());
614     EXPECT_EQ(d1 + 100, iob->data());
615     gen.seed(fillSeed);
616     checkBuf(iob.get(), gen);
617   }
618
619   // Reserve reallocates if we don't have enough total room.
620   // NOTE that, with jemalloc, we know that this won't reallocate in place
621   // as the size is less than jemallocMinInPlaceExpanadable
622   {
623     gen.seed(fillSeed);
624     unique_ptr<IOBuf> iob(IOBuf::create(2000));
625     iob->append(100);
626     fillBuf(iob.get(), gen);
627     EXPECT_EQ(0, iob->headroom());
628     EXPECT_EQ(100, iob->length());
629     const void* p1 = iob->buffer();
630     iob->reserve(100, 2512);  // allocation sizes are multiples of 256
631     EXPECT_LE(100, iob->headroom());
632     if (folly::usingJEMalloc()) {
633       EXPECT_NE(p1, iob->buffer());
634     }
635     gen.seed(fillSeed);
636     checkBuf(iob.get(), gen);
637   }
638
639   // Test reserve from internal buffer, this used to segfault
640   {
641     unique_ptr<IOBuf> iob(IOBuf::create(0));
642     iob->reserve(0, 2000);
643     EXPECT_EQ(0, iob->headroom());
644     EXPECT_LE(2000, iob->tailroom());
645   }
646
647   // Test reserving from a user-allocated buffer.
648   {
649     uint8_t* buf = static_cast<uint8_t*>(malloc(100));
650     auto iob = IOBuf::takeOwnership(buf, 100);
651     iob->reserve(0, 2000);
652     EXPECT_EQ(0, iob->headroom());
653     EXPECT_LE(2000, iob->tailroom());
654   }
655
656   // Test reserving from a user-allocated with a custom free function.
657   {
658     uint32_t freeCount{0};
659     uint8_t* buf = new uint8_t[100];
660     auto iob = IOBuf::takeOwnership(buf, 100, testFreeFn, &freeCount);
661     iob->reserve(0, 2000);
662     EXPECT_EQ(0, iob->headroom());
663     EXPECT_LE(2000, iob->tailroom());
664     EXPECT_EQ(1, freeCount);
665   }
666 }
667
668 TEST(IOBuf, copyBuffer) {
669   std::string s("hello");
670   auto buf = IOBuf::copyBuffer(s.data(), s.size(), 1, 2);
671   EXPECT_EQ(1, buf->headroom());
672   EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
673                            buf->length()));
674   EXPECT_LE(2, buf->tailroom());
675
676   buf = IOBuf::copyBuffer(s, 5, 7);
677   EXPECT_EQ(5, buf->headroom());
678   EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
679                            buf->length()));
680   EXPECT_LE(7, buf->tailroom());
681
682   std::string empty;
683   buf = IOBuf::copyBuffer(empty, 3, 6);
684   EXPECT_EQ(3, buf->headroom());
685   EXPECT_EQ(0, buf->length());
686   EXPECT_LE(6, buf->tailroom());
687
688   // A stack-allocated version
689   IOBuf stackBuf(IOBuf::COPY_BUFFER, s, 1, 2);
690   EXPECT_EQ(1, stackBuf.headroom());
691   EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(stackBuf.data()),
692                            stackBuf.length()));
693   EXPECT_LE(2, stackBuf.tailroom());
694 }
695
696 TEST(IOBuf, maybeCopyBuffer) {
697   std::string s("this is a test");
698   auto buf = IOBuf::maybeCopyBuffer(s, 1, 2);
699   EXPECT_EQ(1, buf->headroom());
700   EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
701                            buf->length()));
702   EXPECT_LE(2, buf->tailroom());
703
704   std::string empty;
705   buf = IOBuf::maybeCopyBuffer("", 5, 7);
706   EXPECT_EQ(nullptr, buf.get());
707
708   buf = IOBuf::maybeCopyBuffer("");
709   EXPECT_EQ(nullptr, buf.get());
710 }
711
712 namespace {
713
714 int customDeleterCount = 0;
715 int destructorCount = 0;
716 struct OwnershipTestClass {
717   explicit OwnershipTestClass(int v = 0) : val(v) { }
718   ~OwnershipTestClass() {
719     ++destructorCount;
720   }
721   int val;
722 };
723
724 typedef std::function<void(OwnershipTestClass*)> CustomDeleter;
725
726 void customDelete(OwnershipTestClass* p) {
727   ++customDeleterCount;
728   delete p;
729 }
730
731 void customDeleteArray(OwnershipTestClass* p) {
732   ++customDeleterCount;
733   delete[] p;
734 }
735
736 }  // namespace
737
738 TEST(IOBuf, takeOwnershipUniquePtr) {
739   destructorCount = 0;
740   {
741     std::unique_ptr<OwnershipTestClass> p(new OwnershipTestClass());
742   }
743   EXPECT_EQ(1, destructorCount);
744
745   destructorCount = 0;
746   {
747     std::unique_ptr<OwnershipTestClass[]> p(new OwnershipTestClass[2]);
748   }
749   EXPECT_EQ(2, destructorCount);
750
751   destructorCount = 0;
752   {
753     std::unique_ptr<OwnershipTestClass> p(new OwnershipTestClass());
754     std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p)));
755     EXPECT_EQ(sizeof(OwnershipTestClass), buf->length());
756     EXPECT_EQ(0, destructorCount);
757   }
758   EXPECT_EQ(1, destructorCount);
759
760   destructorCount = 0;
761   {
762     std::unique_ptr<OwnershipTestClass[]> p(new OwnershipTestClass[2]);
763     std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p), 2));
764     EXPECT_EQ(2 * sizeof(OwnershipTestClass), buf->length());
765     EXPECT_EQ(0, destructorCount);
766   }
767   EXPECT_EQ(2, destructorCount);
768
769   customDeleterCount = 0;
770   destructorCount = 0;
771   {
772     std::unique_ptr<OwnershipTestClass, CustomDeleter>
773       p(new OwnershipTestClass(), customDelete);
774     std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p)));
775     EXPECT_EQ(sizeof(OwnershipTestClass), buf->length());
776     EXPECT_EQ(0, destructorCount);
777   }
778   EXPECT_EQ(1, destructorCount);
779   EXPECT_EQ(1, customDeleterCount);
780
781   customDeleterCount = 0;
782   destructorCount = 0;
783   {
784     std::unique_ptr<OwnershipTestClass[], CustomDeleter>
785       p(new OwnershipTestClass[2], CustomDeleter(customDeleteArray));
786     std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p), 2));
787     EXPECT_EQ(2 * sizeof(OwnershipTestClass), buf->length());
788     EXPECT_EQ(0, destructorCount);
789   }
790   EXPECT_EQ(2, destructorCount);
791   EXPECT_EQ(1, customDeleterCount);
792 }
793
794 TEST(IOBuf, Alignment) {
795   size_t alignment = alignof(std::max_align_t);
796
797   std::vector<size_t> sizes {0, 1, 64, 256, 1024, 1 << 10};
798   for (size_t size : sizes) {
799     auto buf = IOBuf::create(size);
800     uintptr_t p = reinterpret_cast<uintptr_t>(buf->data());
801     EXPECT_EQ(0, p & (alignment - 1)) << "size=" << size;
802   }
803 }
804
805 TEST(TypedIOBuf, Simple) {
806   auto buf = IOBuf::create(0);
807   TypedIOBuf<uint64_t> typed(buf.get());
808   const uint64_t n = 10000;
809   typed.reserve(0, n);
810   EXPECT_LE(n, typed.capacity());
811   for (uint64_t i = 0; i < n; i++) {
812     *typed.writableTail() = i;
813     typed.append(1);
814   }
815   EXPECT_EQ(n, typed.length());
816   for (uint64_t i = 0; i < n; i++) {
817     EXPECT_EQ(i, typed.data()[i]);
818   }
819 }
820 enum BufType {
821   CREATE,
822   TAKE_OWNERSHIP_MALLOC,
823   TAKE_OWNERSHIP_CUSTOM,
824   USER_OWNED,
825 };
826
827 // chain element size, number of elements in chain, shared
828 class MoveToFbStringTest
829   : public ::testing::TestWithParam<std::tr1::tuple<int, int, bool, BufType>> {
830  protected:
831   void SetUp() override {
832     elementSize_ = std::tr1::get<0>(GetParam());
833     elementCount_ = std::tr1::get<1>(GetParam());
834     shared_ = std::tr1::get<2>(GetParam());
835     type_ = std::tr1::get<3>(GetParam());
836
837     buf_ = makeBuf();
838     for (int i = 0; i < elementCount_ - 1; ++i) {
839       buf_->prependChain(makeBuf());
840     }
841     EXPECT_EQ(elementCount_, buf_->countChainElements());
842     EXPECT_EQ(elementCount_ * elementSize_, buf_->computeChainDataLength());
843     if (shared_) {
844       buf2_ = buf_->clone();
845       EXPECT_EQ(elementCount_, buf2_->countChainElements());
846       EXPECT_EQ(elementCount_ * elementSize_, buf2_->computeChainDataLength());
847     }
848   }
849
850   std::unique_ptr<IOBuf> makeBuf() {
851     unique_ptr<IOBuf> buf;
852     switch (type_) {
853       case CREATE:
854         buf = IOBuf::create(elementSize_);
855         buf->append(elementSize_);
856         break;
857       case TAKE_OWNERSHIP_MALLOC: {
858         void* data = malloc(elementSize_);
859         if (!data) {
860           throw std::bad_alloc();
861         }
862         buf = IOBuf::takeOwnership(data, elementSize_);
863         break;
864       }
865       case TAKE_OWNERSHIP_CUSTOM: {
866         uint8_t* data = new uint8_t[elementSize_];
867         buf = IOBuf::takeOwnership(data, elementSize_, testFreeFn);
868         break;
869       }
870       case USER_OWNED: {
871         unique_ptr<uint8_t[]> data(new uint8_t[elementSize_]);
872         buf = IOBuf::wrapBuffer(data.get(), elementSize_);
873         ownedBuffers_.emplace_back(std::move(data));
874         break;
875       }
876       default:
877         throw std::invalid_argument("unexpected buffer type parameter");
878         break;
879     }
880     memset(buf->writableData(), 'x', elementSize_);
881     return buf;
882   }
883
884   void check(std::unique_ptr<IOBuf>& buf) {
885     fbstring str = buf->moveToFbString();
886     EXPECT_EQ(elementCount_ * elementSize_, str.size());
887     EXPECT_EQ(elementCount_ * elementSize_, strspn(str.c_str(), "x"));
888     EXPECT_EQ(0, buf->length());
889     EXPECT_EQ(1, buf->countChainElements());
890     EXPECT_EQ(0, buf->computeChainDataLength());
891     EXPECT_FALSE(buf->isChained());
892   }
893
894   int elementSize_;
895   int elementCount_;
896   bool shared_;
897   BufType type_;
898   std::unique_ptr<IOBuf> buf_;
899   std::unique_ptr<IOBuf> buf2_;
900   std::vector<std::unique_ptr<uint8_t[]>> ownedBuffers_;
901 };
902
903 TEST_P(MoveToFbStringTest, Simple) {
904   check(buf_);
905   if (shared_) {
906     check(buf2_);
907   }
908 }
909
910 INSTANTIATE_TEST_CASE_P(
911     MoveToFbString,
912     MoveToFbStringTest,
913     ::testing::Combine(
914         ::testing::Values(0, 1, 24, 256, 1 << 10, 1 << 20),  // element size
915         ::testing::Values(1, 2, 10),                         // element count
916         ::testing::Bool(),                                   // shared
917         ::testing::Values(CREATE, TAKE_OWNERSHIP_MALLOC,
918                           TAKE_OWNERSHIP_CUSTOM, USER_OWNED)));
919
920 TEST(IOBuf, getIov) {
921   uint32_t fillSeed = 0xdeadbeef;
922   boost::mt19937 gen(fillSeed);
923
924   size_t len = 4096;
925   size_t count = 32;
926   auto buf = IOBuf::create(len + 1);
927   buf->append(rand() % len + 1);
928   fillBuf(buf.get(), gen);
929
930   for (size_t i = 0; i < count - 1; i++) {
931     auto buf2 = IOBuf::create(len + 1);
932     buf2->append(rand() % len + 1);
933     fillBuf(buf2.get(), gen);
934     buf->prependChain(std::move(buf2));
935   }
936   EXPECT_EQ(count, buf->countChainElements());
937
938   auto iov = buf->getIov();
939   EXPECT_EQ(count, iov.size());
940
941   IOBuf const* p = buf.get();
942   for (size_t i = 0; i < count; i++, p = p->next()) {
943     EXPECT_EQ(p->data(), iov[i].iov_base);
944     EXPECT_EQ(p->length(), iov[i].iov_len);
945   }
946
947   // an empty buf should be skipped in the iov.
948   buf->next()->clear();
949   iov = buf->getIov();
950   EXPECT_EQ(count - 1, iov.size());
951   EXPECT_EQ(buf->next()->next()->data(), iov[1].iov_base);
952
953   // same for the first one being empty
954   buf->clear();
955   iov = buf->getIov();
956   EXPECT_EQ(count - 2, iov.size());
957   EXPECT_EQ(buf->next()->next()->data(), iov[0].iov_base);
958
959   // and the last one
960   buf->prev()->clear();
961   iov = buf->getIov();
962   EXPECT_EQ(count - 3, iov.size());
963
964   // test appending to an existing iovec array
965   iov.clear();
966   const char localBuf[] = "hello";
967   iov.push_back({(void*)localBuf, sizeof(localBuf)});
968   iov.push_back({(void*)localBuf, sizeof(localBuf)});
969   buf->appendToIov(&iov);
970   EXPECT_EQ(count - 1, iov.size());
971   EXPECT_EQ(localBuf, iov[0].iov_base);
972   EXPECT_EQ(localBuf, iov[1].iov_base);
973   // The first two IOBufs were cleared, so the next iov entry
974   // should be the third IOBuf in the chain.
975   EXPECT_EQ(buf->next()->next()->data(), iov[2].iov_base);
976 }
977
978 TEST(IOBuf, move) {
979   // Default allocate an IOBuf on the stack
980   IOBuf outerBuf;
981   char data[] = "foobar";
982   uint32_t length = sizeof(data);
983   uint32_t actualCapacity{0};
984   const void* ptr{nullptr};
985
986   {
987     // Create a small IOBuf on the stack.
988     // Note that IOBufs created on the stack always use an external buffer.
989     IOBuf b1(IOBuf::CREATE, 10);
990     actualCapacity = b1.capacity();
991     EXPECT_GE(actualCapacity, 10);
992     EXPECT_EQ(0, b1.length());
993     EXPECT_FALSE(b1.isShared());
994     ptr = b1.data();
995     ASSERT_TRUE(ptr != nullptr);
996     memcpy(b1.writableTail(), data, length);
997     b1.append(length);
998     EXPECT_EQ(length, b1.length());
999
1000     // Use the move constructor
1001     IOBuf b2(std::move(b1));
1002     EXPECT_EQ(ptr, b2.data());
1003     EXPECT_EQ(length, b2.length());
1004     EXPECT_EQ(actualCapacity, b2.capacity());
1005     EXPECT_FALSE(b2.isShared());
1006
1007     // Use the move assignment operator
1008     outerBuf = std::move(b2);
1009     // Close scope, destroying b1 and b2
1010     // (which are both be invalid now anyway after moving out of them)
1011   }
1012
1013   EXPECT_EQ(ptr, outerBuf.data());
1014   EXPECT_EQ(length, outerBuf.length());
1015   EXPECT_EQ(actualCapacity, outerBuf.capacity());
1016   EXPECT_FALSE(outerBuf.isShared());
1017 }
1018
1019 namespace {
1020 std::unique_ptr<IOBuf> fromStr(StringPiece sp) {
1021   return IOBuf::copyBuffer(ByteRange(sp));
1022 }
1023 }  // namespace
1024
1025 TEST(IOBuf, HashAndEqual) {
1026   folly::IOBufEqual eq;
1027   folly::IOBufHash hash;
1028
1029   EXPECT_TRUE(eq(nullptr, nullptr));
1030   EXPECT_EQ(0, hash(nullptr));
1031
1032   auto empty = IOBuf::create(0);
1033
1034   EXPECT_TRUE(eq(*empty, *empty));
1035   EXPECT_TRUE(eq(empty, empty));
1036
1037   EXPECT_FALSE(eq(nullptr, empty));
1038   EXPECT_FALSE(eq(empty, nullptr));
1039
1040   EXPECT_EQ(hash(*empty), hash(empty));
1041   EXPECT_NE(0, hash(empty));
1042
1043   auto a = fromStr("hello");
1044
1045   EXPECT_TRUE(eq(*a, *a));
1046   EXPECT_TRUE(eq(a, a));
1047
1048   EXPECT_FALSE(eq(nullptr, a));
1049   EXPECT_FALSE(eq(a, nullptr));
1050
1051   EXPECT_EQ(hash(*a), hash(a));
1052   EXPECT_NE(0, hash(a));
1053
1054   auto b = fromStr("hello");
1055
1056   EXPECT_TRUE(eq(*a, *b));
1057   EXPECT_TRUE(eq(a, b));
1058
1059   EXPECT_EQ(hash(a), hash(b));
1060
1061   auto c = fromStr("hellow");
1062
1063   EXPECT_FALSE(eq(a, c));
1064   EXPECT_NE(hash(a), hash(c));
1065
1066   auto d = fromStr("world");
1067
1068   EXPECT_FALSE(eq(a, d));
1069   EXPECT_NE(hash(a), hash(d));
1070
1071   auto e = fromStr("helloworld");
1072   auto f = fromStr("hello");
1073   f->prependChain(fromStr("wo"));
1074   f->prependChain(fromStr("rld"));
1075
1076   EXPECT_TRUE(eq(e, f));
1077   EXPECT_EQ(hash(e), hash(f));
1078 }
1079
1080 // reserveSlow() had a bug when reallocating the buffer in place. It would
1081 // preserve old headroom if it's not too much (heuristically) but wouldn't
1082 // adjust the requested amount of memory to account for that; the end result
1083 // would be that reserve() would return with less tailroom than requested.
1084 TEST(IOBuf, ReserveWithHeadroom) {
1085   // This is assuming jemalloc, where we know that 4096 and 8192 bytes are
1086   // valid (and consecutive) allocation sizes. We're hoping that our
1087   // 4096-byte buffer can be expanded in place to 8192 (in practice, this
1088   // usually happens).
1089   const char data[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit";
1090   constexpr size_t reservedSize = 24;  // sizeof(SharedInfo)
1091   // chosen carefully so that the buffer is exactly 4096 bytes
1092   IOBuf buf(IOBuf::CREATE, 4096 - reservedSize);
1093   buf.advance(10);
1094   memcpy(buf.writableData(), data, sizeof(data));
1095   buf.append(sizeof(data));
1096   EXPECT_EQ(sizeof(data), buf.length());
1097
1098   // Grow the buffer (hopefully in place); this would incorrectly reserve
1099   // the 10 bytes of headroom, giving us 10 bytes less than requested.
1100   size_t tailroom = 8192 - reservedSize - sizeof(data);
1101   buf.reserve(0, tailroom);
1102   EXPECT_LE(tailroom, buf.tailroom());
1103   EXPECT_EQ(sizeof(data), buf.length());
1104   EXPECT_EQ(0, memcmp(data, buf.data(), sizeof(data)));
1105 }
1106
1107 TEST(IOBuf, CopyConstructorAndAssignmentOperator) {
1108   auto buf = IOBuf::create(4096);
1109   append(buf, "hello world");
1110   auto buf2 = IOBuf::create(4096);
1111   append(buf2, " goodbye");
1112   buf->prependChain(std::move(buf2));
1113   EXPECT_FALSE(buf->isShared());
1114
1115   {
1116     auto copy = *buf;
1117     EXPECT_TRUE(buf->isShared());
1118     EXPECT_TRUE(copy.isShared());
1119     EXPECT_EQ((void*)buf->data(), (void*)copy.data());
1120     EXPECT_NE(buf->next(), copy.next());  // actually different buffers
1121
1122     auto copy2 = *buf;
1123     copy2.coalesce();
1124     EXPECT_TRUE(buf->isShared());
1125     EXPECT_TRUE(copy.isShared());
1126     EXPECT_FALSE(copy2.isShared());
1127
1128     auto p = reinterpret_cast<const char*>(copy2.data());
1129     EXPECT_EQ("hello world goodbye", std::string(p, copy2.length()));
1130   }
1131
1132   EXPECT_FALSE(buf->isShared());
1133
1134   {
1135     folly::IOBuf newBuf(folly::IOBuf::CREATE, 4096);
1136     EXPECT_FALSE(newBuf.isShared());
1137
1138     auto newBufCopy = newBuf;
1139     EXPECT_TRUE(newBuf.isShared());
1140     EXPECT_TRUE(newBufCopy.isShared());
1141
1142     newBufCopy = *buf;
1143     EXPECT_TRUE(buf->isShared());
1144     EXPECT_FALSE(newBuf.isShared());
1145     EXPECT_TRUE(newBufCopy.isShared());
1146   }
1147
1148   EXPECT_FALSE(buf->isShared());
1149 }
1150
1151 TEST(IOBuf, CloneAsValue) {
1152   auto buf = IOBuf::create(4096);
1153   append(buf, "hello world");
1154   {
1155     auto buf2 = IOBuf::create(4096);
1156     append(buf2, " goodbye");
1157     buf->prependChain(std::move(buf2));
1158     EXPECT_FALSE(buf->isShared());
1159   }
1160
1161   {
1162     auto copy = buf->cloneOneAsValue();
1163     EXPECT_TRUE(buf->isShared());
1164     EXPECT_TRUE(copy.isShared());
1165     EXPECT_EQ((void*)buf->data(), (void*)copy.data());
1166     EXPECT_TRUE(buf->isChained());
1167     EXPECT_FALSE(copy.isChained());
1168
1169     auto copy2 = buf->cloneAsValue();
1170     EXPECT_TRUE(buf->isShared());
1171     EXPECT_TRUE(copy.isShared());
1172     EXPECT_TRUE(copy2.isShared());
1173     EXPECT_TRUE(buf->isChained());
1174     EXPECT_TRUE(copy2.isChained());
1175
1176     copy.unshareOne();
1177     EXPECT_TRUE(buf->isShared());
1178     EXPECT_FALSE(copy.isShared());
1179     EXPECT_NE((void*)buf->data(), (void*)copy.data());
1180     EXPECT_TRUE(copy2.isShared());
1181
1182     auto p = reinterpret_cast<const char*>(copy.data());
1183     EXPECT_EQ("hello world", std::string(p, copy.length()));
1184
1185     copy2.coalesce();
1186     EXPECT_FALSE(buf->isShared());
1187     EXPECT_FALSE(copy.isShared());
1188     EXPECT_FALSE(copy2.isShared());
1189     EXPECT_FALSE(copy2.isChained());
1190
1191     auto p2 = reinterpret_cast<const char*>(copy2.data());
1192     EXPECT_EQ("hello world goodbye", std::string(p2, copy2.length()));
1193   }
1194
1195   EXPECT_FALSE(buf->isShared());
1196 }
1197
1198 namespace {
1199 // Use with string literals only
1200 std::unique_ptr<IOBuf> wrap(const char* str) {
1201   return IOBuf::wrapBuffer(str, strlen(str));
1202 }
1203
1204 std::unique_ptr<IOBuf> copy(const char* str) {
1205   // At least 1KiB of tailroom, to ensure an external buffer
1206   return IOBuf::copyBuffer(str, strlen(str), 0, 1024);
1207 }
1208
1209 std::string toString(const folly::IOBuf& buf) {
1210   std::string result;
1211   result.reserve(buf.computeChainDataLength());
1212   for (auto& b : buf) {
1213     result.append(reinterpret_cast<const char*>(b.data()), b.size());
1214   }
1215   return result;
1216 }
1217
1218 char* writableStr(folly::IOBuf& buf) {
1219   return reinterpret_cast<char*>(buf.writableData());
1220 }
1221
1222 }  // namespace
1223
1224 TEST(IOBuf, Managed) {
1225   auto hello = "hello";
1226   auto buf1UP = wrap(hello);
1227   auto buf1 = buf1UP.get();
1228   EXPECT_FALSE(buf1->isManagedOne());
1229   auto buf2UP = copy("world");
1230   auto buf2 = buf2UP.get();
1231   EXPECT_TRUE(buf2->isManagedOne());
1232   auto buf3UP = wrap(hello);
1233   auto buf3 = buf3UP.get();
1234   auto buf4UP = buf2->clone();
1235   auto buf4 = buf4UP.get();
1236
1237   // buf1 and buf3 share the same memory (but are unmanaged)
1238   EXPECT_FALSE(buf1->isManagedOne());
1239   EXPECT_FALSE(buf3->isManagedOne());
1240   EXPECT_TRUE(buf1->isSharedOne());
1241   EXPECT_TRUE(buf3->isSharedOne());
1242   EXPECT_EQ(buf1->data(), buf3->data());
1243
1244   // buf2 and buf4 share the same memory (but are managed)
1245   EXPECT_TRUE(buf2->isManagedOne());
1246   EXPECT_TRUE(buf4->isManagedOne());
1247   EXPECT_TRUE(buf2->isSharedOne());
1248   EXPECT_TRUE(buf4->isSharedOne());
1249   EXPECT_EQ(buf2->data(), buf4->data());
1250
1251   buf1->prependChain(std::move(buf2UP));
1252   buf1->prependChain(std::move(buf3UP));
1253   buf1->prependChain(std::move(buf4UP));
1254
1255   EXPECT_EQ("helloworldhelloworld", toString(*buf1));
1256   EXPECT_FALSE(buf1->isManaged());
1257
1258   buf1->makeManaged();
1259   EXPECT_TRUE(buf1->isManaged());
1260
1261   // buf1 and buf3 are now unshared (because they were unmanaged)
1262   EXPECT_TRUE(buf1->isManagedOne());
1263   EXPECT_TRUE(buf3->isManagedOne());
1264   EXPECT_FALSE(buf1->isSharedOne());
1265   EXPECT_FALSE(buf3->isSharedOne());
1266   EXPECT_NE(buf1->data(), buf3->data());
1267
1268   // buf2 and buf4 are still shared
1269   EXPECT_TRUE(buf2->isManagedOne());
1270   EXPECT_TRUE(buf4->isManagedOne());
1271   EXPECT_TRUE(buf2->isSharedOne());
1272   EXPECT_TRUE(buf4->isSharedOne());
1273   EXPECT_EQ(buf2->data(), buf4->data());
1274
1275   // And verify that the truth is what we expect: modify a byte in buf1 and
1276   // buf2, see that the change from buf1 is *not* reflected in buf3, but the
1277   // change from buf2 is reflected in buf4.
1278   writableStr(*buf1)[0] = 'j';
1279   writableStr(*buf2)[0] = 'x';
1280   EXPECT_EQ("jelloxorldhelloxorld", toString(*buf1));
1281 }