b16511a4d90d3229b1dc20f3981f221549e53023
[folly.git] / folly / experimental / io / test / IOBufTest.cpp
1 /*
2  * Copyright 2012 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/experimental/io/IOBuf.h"
18 #include "folly/experimental/io/TypedIOBuf.h"
19
20 // googletest requires std::tr1::tuple, not std::tuple
21 #include <tr1/tuple>
22
23 #include <gflags/gflags.h>
24 #include <boost/random.hpp>
25 #include <gtest/gtest.h>
26
27 #include "folly/Malloc.h"
28 #include "folly/Range.h"
29
30 using folly::fbstring;
31 using folly::IOBuf;
32 using folly::TypedIOBuf;
33 using folly::StringPiece;
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
144 }
145
146 TEST(IOBuf, WrapBuffer) {
147   const uint32_t size1 = 1234;
148   uint8_t buf1[size1];
149   unique_ptr<IOBuf> iobuf1(IOBuf::wrapBuffer(buf1, size1));
150   EXPECT_EQ(buf1, iobuf1->data());
151   EXPECT_EQ(size1, iobuf1->length());
152   EXPECT_EQ(buf1, iobuf1->buffer());
153   EXPECT_EQ(size1, iobuf1->capacity());
154
155   uint32_t size2 = 0x1234;
156   unique_ptr<uint8_t[]> buf2(new uint8_t[size2]);
157   unique_ptr<IOBuf> iobuf2(IOBuf::wrapBuffer(buf2.get(), size2));
158   EXPECT_EQ(buf2.get(), iobuf2->data());
159   EXPECT_EQ(size2, iobuf2->length());
160   EXPECT_EQ(buf2.get(), iobuf2->buffer());
161   EXPECT_EQ(size2, iobuf2->capacity());
162 }
163
164 void fillBuf(uint8_t* buf, uint32_t length, boost::mt19937& gen) {
165   for (uint32_t n = 0; n < length; ++n) {
166     buf[n] = static_cast<uint8_t>(gen() & 0xff);
167   }
168 }
169
170 void fillBuf(IOBuf* buf, boost::mt19937& gen) {
171   buf->unshare();
172   fillBuf(buf->writableData(), buf->length(), gen);
173 }
174
175 void checkBuf(const uint8_t* buf, uint32_t length, boost::mt19937& gen) {
176   // Rather than using EXPECT_EQ() to check each character,
177   // count the number of differences and the first character that differs.
178   // This way on error we'll report just that information, rather than tons of
179   // failed checks for each byte in the buffer.
180   uint32_t numDifferences = 0;
181   uint32_t firstDiffIndex = 0;
182   uint8_t firstDiffExpected = 0;
183   for (uint32_t n = 0; n < length; ++n) {
184     uint8_t expected = static_cast<uint8_t>(gen() & 0xff);
185     if (buf[n] == expected) {
186       continue;
187     }
188
189     if (numDifferences == 0) {
190       firstDiffIndex = n;
191       firstDiffExpected = expected;
192     }
193     ++numDifferences;
194   }
195
196   EXPECT_EQ(0, numDifferences);
197   if (numDifferences > 0) {
198     // Cast to int so it will be printed numerically
199     // rather than as a char if the check fails
200     EXPECT_EQ(static_cast<int>(buf[firstDiffIndex]),
201               static_cast<int>(firstDiffExpected));
202   }
203 }
204
205 void checkBuf(IOBuf* buf, boost::mt19937& gen) {
206   checkBuf(buf->data(), buf->length(), gen);
207 }
208
209 void checkChain(IOBuf* buf, boost::mt19937& gen) {
210   IOBuf *current = buf;
211   do {
212     checkBuf(current->data(), current->length(), gen);
213     current = current->next();
214   } while (current != buf);
215 }
216
217 TEST(IOBuf, Chaining) {
218   uint32_t fillSeed = 0x12345678;
219   boost::mt19937 gen(fillSeed);
220
221   // An IOBuf with external storage
222   uint32_t headroom = 123;
223   unique_ptr<IOBuf> iob1(IOBuf::create(2048));
224   iob1->advance(headroom);
225   iob1->append(1500);
226   fillBuf(iob1.get(), gen);
227
228   // An IOBuf with internal storage
229   unique_ptr<IOBuf> iob2(IOBuf::create(20));
230   iob2->append(20);
231   fillBuf(iob2.get(), gen);
232
233   // An IOBuf around a buffer it doesn't own
234   uint8_t localbuf[1234];
235   fillBuf(localbuf, 1234, gen);
236   unique_ptr<IOBuf> iob3(IOBuf::wrapBuffer(localbuf, sizeof(localbuf)));
237
238   // An IOBuf taking ownership of a user-supplied buffer
239   uint32_t heapBufSize = 900;
240   uint8_t* heapBuf = static_cast<uint8_t*>(malloc(heapBufSize));
241   fillBuf(heapBuf, heapBufSize, gen);
242   unique_ptr<IOBuf> iob4(IOBuf::takeOwnership(heapBuf, heapBufSize));
243
244   // An IOBuf taking ownership of a user-supplied buffer with
245   // a custom free function
246   uint32_t arrayBufSize = 321;
247   uint8_t* arrayBuf = new uint8_t[arrayBufSize];
248   fillBuf(arrayBuf, arrayBufSize, gen);
249   uint32_t arrayBufFreeCount = 0;
250   unique_ptr<IOBuf> iob5(IOBuf::takeOwnership(arrayBuf, arrayBufSize,
251                                               deleteArrayBuffer,
252                                               &arrayBufFreeCount));
253
254   EXPECT_FALSE(iob1->isChained());
255   EXPECT_FALSE(iob2->isChained());
256   EXPECT_FALSE(iob3->isChained());
257   EXPECT_FALSE(iob4->isChained());
258   EXPECT_FALSE(iob5->isChained());
259
260   EXPECT_FALSE(iob1->isSharedOne());
261   EXPECT_FALSE(iob2->isSharedOne());
262   EXPECT_TRUE(iob3->isSharedOne()); // since we own the buffer
263   EXPECT_FALSE(iob4->isSharedOne());
264   EXPECT_FALSE(iob5->isSharedOne());
265
266   // Chain the buffers all together
267   // Since we are going to relinquish ownership of iob2-5 to the chain,
268   // store raw pointers to them so we can reference them later.
269   IOBuf* iob2ptr = iob2.get();
270   IOBuf* iob3ptr = iob3.get();
271   IOBuf* iob4ptr = iob4.get();
272   IOBuf* iob5ptr = iob5.get();
273
274   iob1->prependChain(std::move(iob2));
275   iob1->prependChain(std::move(iob4));
276   iob2ptr->appendChain(std::move(iob3));
277   iob1->prependChain(std::move(iob5));
278
279   EXPECT_EQ(iob2ptr, iob1->next());
280   EXPECT_EQ(iob3ptr, iob2ptr->next());
281   EXPECT_EQ(iob4ptr, iob3ptr->next());
282   EXPECT_EQ(iob5ptr, iob4ptr->next());
283   EXPECT_EQ(iob1.get(), iob5ptr->next());
284
285   EXPECT_EQ(iob5ptr, iob1->prev());
286   EXPECT_EQ(iob1.get(), iob2ptr->prev());
287   EXPECT_EQ(iob2ptr, iob3ptr->prev());
288   EXPECT_EQ(iob3ptr, iob4ptr->prev());
289   EXPECT_EQ(iob4ptr, iob5ptr->prev());
290
291   EXPECT_TRUE(iob1->isChained());
292   EXPECT_TRUE(iob2ptr->isChained());
293   EXPECT_TRUE(iob3ptr->isChained());
294   EXPECT_TRUE(iob4ptr->isChained());
295   EXPECT_TRUE(iob5ptr->isChained());
296
297   uint64_t fullLength = (iob1->length() + iob2ptr->length() +
298                          iob3ptr->length() + iob4ptr->length() +
299                          iob5ptr->length());
300   EXPECT_EQ(5, iob1->countChainElements());
301   EXPECT_EQ(fullLength, iob1->computeChainDataLength());
302
303   // Since iob3 is shared, the entire buffer should report itself as shared
304   EXPECT_TRUE(iob1->isShared());
305   // Unshare just iob3
306   iob3ptr->unshareOne();
307   EXPECT_FALSE(iob3ptr->isSharedOne());
308   // Now everything in the chain should be unshared.
309   // Check on all members of the chain just for good measure
310   EXPECT_FALSE(iob1->isShared());
311   EXPECT_FALSE(iob2ptr->isShared());
312   EXPECT_FALSE(iob3ptr->isShared());
313   EXPECT_FALSE(iob4ptr->isShared());
314   EXPECT_FALSE(iob5ptr->isShared());
315
316
317   // Clone one of the IOBufs in the chain
318   unique_ptr<IOBuf> iob4clone = iob4ptr->cloneOne();
319   gen.seed(fillSeed);
320   checkBuf(iob1.get(), gen);
321   checkBuf(iob2ptr, gen);
322   checkBuf(iob3ptr, gen);
323   checkBuf(iob4clone.get(), gen);
324   checkBuf(iob5ptr, gen);
325
326   EXPECT_TRUE(iob1->isShared());
327   EXPECT_TRUE(iob2ptr->isShared());
328   EXPECT_TRUE(iob3ptr->isShared());
329   EXPECT_TRUE(iob4ptr->isShared());
330   EXPECT_TRUE(iob5ptr->isShared());
331
332   EXPECT_FALSE(iob1->isSharedOne());
333   EXPECT_FALSE(iob2ptr->isSharedOne());
334   EXPECT_FALSE(iob3ptr->isSharedOne());
335   EXPECT_TRUE(iob4ptr->isSharedOne());
336   EXPECT_FALSE(iob5ptr->isSharedOne());
337
338   // Unshare that clone
339   EXPECT_TRUE(iob4clone->isSharedOne());
340   iob4clone->unshare();
341   EXPECT_FALSE(iob4clone->isSharedOne());
342   EXPECT_FALSE(iob4ptr->isSharedOne());
343   EXPECT_FALSE(iob1->isShared());
344   iob4clone.reset();
345
346
347   // Create a clone of a different IOBuf
348   EXPECT_FALSE(iob1->isShared());
349   EXPECT_FALSE(iob3ptr->isSharedOne());
350
351   unique_ptr<IOBuf> iob3clone = iob3ptr->cloneOne();
352   gen.seed(fillSeed);
353   checkBuf(iob1.get(), gen);
354   checkBuf(iob2ptr, gen);
355   checkBuf(iob3clone.get(), gen);
356   checkBuf(iob4ptr, gen);
357   checkBuf(iob5ptr, gen);
358
359   EXPECT_TRUE(iob1->isShared());
360   EXPECT_TRUE(iob3ptr->isSharedOne());
361   EXPECT_FALSE(iob1->isSharedOne());
362
363   // Delete the clone and make sure the original is unshared
364   iob3clone.reset();
365   EXPECT_FALSE(iob1->isShared());
366   EXPECT_FALSE(iob3ptr->isSharedOne());
367
368
369   // Clone the entire chain
370   unique_ptr<IOBuf> chainClone = iob1->clone();
371   // Verify that the data is correct.
372   EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
373   gen.seed(fillSeed);
374   checkChain(chainClone.get(), gen);
375
376   // Check that the buffers report sharing correctly
377   EXPECT_TRUE(chainClone->isShared());
378   EXPECT_TRUE(iob1->isShared());
379
380   EXPECT_TRUE(iob1->isSharedOne());
381   // since iob2 has a small internal buffer, it will never be shared
382   EXPECT_FALSE(iob2ptr->isSharedOne());
383   EXPECT_TRUE(iob3ptr->isSharedOne());
384   EXPECT_TRUE(iob4ptr->isSharedOne());
385   EXPECT_TRUE(iob5ptr->isSharedOne());
386
387   // Unshare the cloned chain
388   chainClone->unshare();
389   EXPECT_FALSE(chainClone->isShared());
390   EXPECT_FALSE(iob1->isShared());
391
392   // Make sure the unshared result still has the same data
393   EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
394   gen.seed(fillSeed);
395   checkChain(chainClone.get(), gen);
396
397   // Destroy this chain
398   chainClone.reset();
399
400
401   // Clone a new chain
402   EXPECT_FALSE(iob1->isShared());
403   chainClone = iob1->clone();
404   EXPECT_TRUE(iob1->isShared());
405   EXPECT_TRUE(chainClone->isShared());
406
407   // Delete the original chain
408   iob1.reset();
409   EXPECT_FALSE(chainClone->isShared());
410
411   // Coalesce the chain
412   //
413   // Coalescing this chain will create a new buffer and release the last
414   // refcount on the original buffers we created.  Also make sure
415   // that arrayBufFreeCount increases to one to indicate that arrayBuf was
416   // freed.
417   EXPECT_EQ(5, chainClone->countChainElements());
418   EXPECT_EQ(0, arrayBufFreeCount);
419
420   // Buffer lengths: 1500 20 1234 900 321
421   // Coalesce the first 3 buffers
422   chainClone->gather(1521);
423   EXPECT_EQ(3, chainClone->countChainElements());
424   EXPECT_EQ(0, arrayBufFreeCount);
425
426   // Make sure the data is still the same after coalescing
427   EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
428   gen.seed(fillSeed);
429   checkChain(chainClone.get(), gen);
430
431   // Coalesce the entire chain
432   chainClone->coalesce();
433   EXPECT_EQ(1, chainClone->countChainElements());
434   EXPECT_EQ(1, arrayBufFreeCount);
435
436   // Make sure the data is still the same after coalescing
437   EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
438   gen.seed(fillSeed);
439   checkChain(chainClone.get(), gen);
440
441   // Make a new chain to test the unlink and pop operations
442   iob1 = IOBuf::create(1);
443   iob1->append(1);
444   IOBuf *iob1ptr = iob1.get();
445   iob2 = IOBuf::create(3);
446   iob2->append(3);
447   iob2ptr = iob2.get();
448   iob3 = IOBuf::create(5);
449   iob3->append(5);
450   iob3ptr = iob3.get();
451   iob4 = IOBuf::create(7);
452   iob4->append(7);
453   iob4ptr = iob4.get();
454   iob1->appendChain(std::move(iob2));
455   iob1->prev()->appendChain(std::move(iob3));
456   iob1->prev()->appendChain(std::move(iob4));
457   EXPECT_EQ(4, iob1->countChainElements());
458   EXPECT_EQ(16, iob1->computeChainDataLength());
459
460   // Unlink from the middle of the chain
461   iob3 = iob3ptr->unlink();
462   EXPECT_TRUE(iob3.get() == iob3ptr);
463   EXPECT_EQ(3, iob1->countChainElements());
464   EXPECT_EQ(11, iob1->computeChainDataLength());
465
466   // Unlink from the end of the chain
467   iob4 = iob1->prev()->unlink();
468   EXPECT_TRUE(iob4.get() == iob4ptr);
469   EXPECT_EQ(2, iob1->countChainElements());
470   EXPECT_TRUE(iob1->next() == iob2ptr);
471   EXPECT_EQ(4, iob1->computeChainDataLength());
472
473   // Pop from the front of the chain
474   iob2 = iob1->pop();
475   EXPECT_TRUE(iob1.get() == iob1ptr);
476   EXPECT_EQ(1, iob1->countChainElements());
477   EXPECT_EQ(1, iob1->computeChainDataLength());
478   EXPECT_TRUE(iob2.get() == iob2ptr);
479   EXPECT_EQ(1, iob2->countChainElements());
480   EXPECT_EQ(3, iob2->computeChainDataLength());
481 }
482
483 TEST(IOBuf, Reserve) {
484   uint32_t fillSeed = 0x23456789;
485   boost::mt19937 gen(fillSeed);
486
487   // Reserve does nothing if empty and doesn't have to grow the buffer
488   {
489     gen.seed(fillSeed);
490     unique_ptr<IOBuf> iob(IOBuf::create(2000));
491     EXPECT_EQ(0, iob->headroom());
492     const void* p1 = iob->buffer();
493     iob->reserve(5, 15);
494     EXPECT_LE(5, iob->headroom());
495     EXPECT_EQ(p1, iob->buffer());
496   }
497
498   // Reserve doesn't reallocate if we have enough total room
499   {
500     gen.seed(fillSeed);
501     unique_ptr<IOBuf> iob(IOBuf::create(2000));
502     iob->append(100);
503     fillBuf(iob.get(), gen);
504     EXPECT_EQ(0, iob->headroom());
505     EXPECT_EQ(100, iob->length());
506     const void* p1 = iob->buffer();
507     const uint8_t* d1 = iob->data();
508     iob->reserve(100, 1800);
509     EXPECT_LE(100, iob->headroom());
510     EXPECT_EQ(p1, iob->buffer());
511     EXPECT_EQ(d1 + 100, iob->data());
512     gen.seed(fillSeed);
513     checkBuf(iob.get(), gen);
514   }
515
516   // Reserve reallocates if we don't have enough total room.
517   // NOTE that, with jemalloc, we know that this won't reallocate in place
518   // as the size is less than jemallocMinInPlaceExpanadable
519   {
520     gen.seed(fillSeed);
521     unique_ptr<IOBuf> iob(IOBuf::create(2000));
522     iob->append(100);
523     fillBuf(iob.get(), gen);
524     EXPECT_EQ(0, iob->headroom());
525     EXPECT_EQ(100, iob->length());
526     const void* p1 = iob->buffer();
527     const uint8_t* d1 = iob->data();
528     iob->reserve(100, 2512);  // allocation sizes are multiples of 256
529     EXPECT_LE(100, iob->headroom());
530     if (folly::usingJEMalloc()) {
531       EXPECT_NE(p1, iob->buffer());
532     }
533     gen.seed(fillSeed);
534     checkBuf(iob.get(), gen);
535   }
536
537   // Test reserve from internal buffer, this used to segfault
538   {
539     unique_ptr<IOBuf> iob(IOBuf::create(0));
540     iob->reserve(0, 2000);
541     EXPECT_EQ(0, iob->headroom());
542     EXPECT_LE(2000, iob->tailroom());
543   }
544 }
545
546 TEST(IOBuf, copyBuffer) {
547   std::string s("hello");
548   auto buf = IOBuf::copyBuffer(s.data(), s.size(), 1, 2);
549   EXPECT_EQ(1, buf->headroom());
550   EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
551                            buf->length()));
552   EXPECT_LE(2, buf->tailroom());
553 }
554
555 namespace {
556
557 int customDeleterCount = 0;
558 int destructorCount = 0;
559 struct OwnershipTestClass {
560   explicit OwnershipTestClass(int v = 0) : val(v) { }
561   ~OwnershipTestClass() {
562     ++destructorCount;
563   }
564   int val;
565 };
566
567 typedef std::function<void(OwnershipTestClass*)> CustomDeleter;
568
569 void customDelete(OwnershipTestClass* p) {
570   ++customDeleterCount;
571   delete p;
572 }
573
574 void customDeleteArray(OwnershipTestClass* p) {
575   ++customDeleterCount;
576   delete[] p;
577 }
578
579 }  // namespace
580
581 TEST(IOBuf, takeOwnershipUniquePtr) {
582   destructorCount = 0;
583   {
584     std::unique_ptr<OwnershipTestClass> p(new OwnershipTestClass());
585   }
586   EXPECT_EQ(1, destructorCount);
587
588   destructorCount = 0;
589   {
590     std::unique_ptr<OwnershipTestClass[]> p(new OwnershipTestClass[2]);
591   }
592   EXPECT_EQ(2, destructorCount);
593
594   destructorCount = 0;
595   {
596     std::unique_ptr<OwnershipTestClass> p(new OwnershipTestClass());
597     std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p)));
598     EXPECT_EQ(sizeof(OwnershipTestClass), buf->length());
599     EXPECT_EQ(0, destructorCount);
600   }
601   EXPECT_EQ(1, destructorCount);
602
603   destructorCount = 0;
604   {
605     std::unique_ptr<OwnershipTestClass[]> p(new OwnershipTestClass[2]);
606     std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p), 2));
607     EXPECT_EQ(2 * sizeof(OwnershipTestClass), buf->length());
608     EXPECT_EQ(0, destructorCount);
609   }
610   EXPECT_EQ(2, destructorCount);
611
612   customDeleterCount = 0;
613   destructorCount = 0;
614   {
615     std::unique_ptr<OwnershipTestClass, CustomDeleter>
616       p(new OwnershipTestClass(), customDelete);
617     std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p)));
618     EXPECT_EQ(sizeof(OwnershipTestClass), buf->length());
619     EXPECT_EQ(0, destructorCount);
620   }
621   EXPECT_EQ(1, destructorCount);
622   EXPECT_EQ(1, customDeleterCount);
623
624   customDeleterCount = 0;
625   destructorCount = 0;
626   {
627     std::unique_ptr<OwnershipTestClass[], CustomDeleter>
628       p(new OwnershipTestClass[2], customDeleteArray);
629     std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p), 2));
630     EXPECT_EQ(2 * sizeof(OwnershipTestClass), buf->length());
631     EXPECT_EQ(0, destructorCount);
632   }
633   EXPECT_EQ(2, destructorCount);
634   EXPECT_EQ(1, customDeleterCount);
635 }
636
637 TEST(IOBuf, Alignment) {
638   // max_align_t doesn't exist in gcc 4.6.2
639   struct MaxAlign {
640     char c;
641   } __attribute__((aligned));
642   size_t alignment = alignof(MaxAlign);
643
644   std::vector<size_t> sizes {0, 1, 64, 256, 1024, 1 << 10};
645   for (size_t size : sizes) {
646     auto buf = IOBuf::create(size);
647     uintptr_t p = reinterpret_cast<uintptr_t>(buf->data());
648     EXPECT_EQ(0, p & (alignment - 1)) << "size=" << size;
649   }
650 }
651
652 TEST(TypedIOBuf, Simple) {
653   auto buf = IOBuf::create(0);
654   TypedIOBuf<uint64_t> typed(buf.get());
655   const uint64_t n = 10000;
656   typed.reserve(0, n);
657   EXPECT_LE(n, typed.capacity());
658   for (uint64_t i = 0; i < n; i++) {
659     *typed.writableTail() = i;
660     typed.append(1);
661   }
662   EXPECT_EQ(n, typed.length());
663   for (uint64_t i = 0; i < n; i++) {
664     EXPECT_EQ(i, typed.data()[i]);
665   }
666 }
667
668 // chain element size, number of elements in chain, shared
669 class MoveToFbStringTest
670   : public ::testing::TestWithParam<std::tr1::tuple<int, int, bool>> {
671  protected:
672   void SetUp() {
673     std::tr1::tie(elementSize_, elementCount_, shared_) = GetParam();
674     buf_ = makeBuf();
675     for (int i = 0; i < elementCount_ - 1; ++i) {
676       buf_->prependChain(makeBuf());
677     }
678     EXPECT_EQ(elementCount_, buf_->countChainElements());
679     EXPECT_EQ(elementCount_ * elementSize_, buf_->computeChainDataLength());
680     if (shared_) {
681       buf2_ = buf_->clone();
682       EXPECT_EQ(elementCount_, buf2_->countChainElements());
683       EXPECT_EQ(elementCount_ * elementSize_, buf2_->computeChainDataLength());
684     }
685   }
686
687   std::unique_ptr<IOBuf> makeBuf() {
688     auto buf = IOBuf::create(elementSize_);
689     memset(buf->writableTail(), 'x', elementSize_);
690     buf->append(elementSize_);
691     return buf;
692   }
693
694   void check(std::unique_ptr<IOBuf>& buf) {
695     fbstring str = buf->moveToFbString();
696     EXPECT_EQ(elementCount_ * elementSize_, str.size());
697     EXPECT_EQ(elementCount_ * elementSize_, strspn(str.c_str(), "x"));
698     EXPECT_EQ(0, buf->length());
699     EXPECT_EQ(1, buf->countChainElements());
700     EXPECT_EQ(0, buf->computeChainDataLength());
701     EXPECT_FALSE(buf->isChained());
702   }
703
704   int elementSize_;
705   int elementCount_;
706   bool shared_;
707   std::unique_ptr<IOBuf> buf_;
708   std::unique_ptr<IOBuf> buf2_;
709 };
710
711 TEST_P(MoveToFbStringTest, Simple) {
712   check(buf_);
713   if (shared_) {
714     check(buf2_);
715   }
716 }
717
718 INSTANTIATE_TEST_CASE_P(
719     MoveToFbString,
720     MoveToFbStringTest,
721     ::testing::Combine(
722         ::testing::Values(0, 1, 24, 256, 1 << 10, 1 << 20),  // element size
723         ::testing::Values(1, 2, 10),                         // element count
724         ::testing::Bool()));                                 // shared
725
726 int main(int argc, char** argv) {
727   testing::InitGoogleTest(&argc, argv);
728   google::ParseCommandLineFlags(&argc, &argv, true);
729
730   return RUN_ALL_TESTS();
731 }