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