NULL -> nullptr
[folly.git] / folly / io / test / IOBufQueueTest.cpp
1 /*
2  * Copyright 2014 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/IOBufQueue.h"
18 #include "folly/Range.h"
19
20 #include <gflags/gflags.h>
21 #include <gtest/gtest.h>
22
23 #include <iostream>
24 #include <stdexcept>
25 #include <string.h>
26
27 using folly::IOBuf;
28 using folly::IOBufQueue;
29 using folly::StringPiece;
30 using std::pair;
31 using std::string;
32 using std::unique_ptr;
33
34 // String Comma Length macro for string literals
35 #define SCL(x) (x), sizeof(x) - 1
36
37 namespace {
38
39 IOBufQueue::Options clOptions;
40 struct Initializer {
41   Initializer() {
42     clOptions.cacheChainLength = true;
43   }
44 };
45 Initializer initializer;
46
47 unique_ptr<IOBuf>
48 stringToIOBuf(const char* s, uint32_t len) {
49   unique_ptr<IOBuf> buf = IOBuf::create(len);
50   memcpy(buf->writableTail(), s, len);
51   buf->append(len);
52   return std::move(buf);
53 }
54
55 void checkConsistency(const IOBufQueue& queue) {
56   if (queue.options().cacheChainLength) {
57     size_t len = queue.front() ? queue.front()->computeChainDataLength() : 0;
58     EXPECT_EQ(len, queue.chainLength());
59   }
60 }
61
62 }
63
64 TEST(IOBufQueue, Simple) {
65   IOBufQueue queue(clOptions);
66   EXPECT_EQ(nullptr, queue.front());
67   queue.append(SCL(""));
68   EXPECT_EQ(nullptr, queue.front());
69   queue.append(unique_ptr<IOBuf>());
70   EXPECT_EQ(nullptr, queue.front());
71   string emptyString;
72   queue.append(emptyString);
73   EXPECT_EQ(nullptr, queue.front());
74 }
75
76 TEST(IOBufQueue, Append) {
77   IOBufQueue queue(clOptions);
78   queue.append(SCL("Hello"));
79   IOBufQueue queue2(clOptions);
80   queue2.append(SCL(", "));
81   queue2.append(SCL("World"));
82   checkConsistency(queue);
83   checkConsistency(queue2);
84   queue.append(queue2.move());
85   checkConsistency(queue);
86   checkConsistency(queue2);
87   const IOBuf* chain = queue.front();
88   EXPECT_NE((IOBuf*)nullptr, chain);
89   EXPECT_EQ(12, chain->computeChainDataLength());
90   EXPECT_EQ(nullptr, queue2.front());
91 }
92
93 TEST(IOBufQueue, Append2) {
94   IOBufQueue queue(clOptions);
95   queue.append(SCL("Hello"));
96   IOBufQueue queue2(clOptions);
97   queue2.append(SCL(", "));
98   queue2.append(SCL("World"));
99   checkConsistency(queue);
100   checkConsistency(queue2);
101   queue.append(queue2);
102   checkConsistency(queue);
103   checkConsistency(queue2);
104   const IOBuf* chain = queue.front();
105   EXPECT_NE((IOBuf*)nullptr, chain);
106   EXPECT_EQ(12, chain->computeChainDataLength());
107   EXPECT_EQ(nullptr, queue2.front());
108 }
109
110 TEST(IOBufQueue, Split) {
111   IOBufQueue queue(clOptions);
112   queue.append(stringToIOBuf(SCL("Hello")));
113   queue.append(stringToIOBuf(SCL(",")));
114   queue.append(stringToIOBuf(SCL(" ")));
115   queue.append(stringToIOBuf(SCL("")));
116   queue.append(stringToIOBuf(SCL("World")));
117   checkConsistency(queue);
118   EXPECT_EQ(12, queue.front()->computeChainDataLength());
119
120   unique_ptr<IOBuf> prefix(queue.split(1));
121   checkConsistency(queue);
122   EXPECT_EQ(1, prefix->computeChainDataLength());
123   EXPECT_EQ(11, queue.front()->computeChainDataLength());
124   prefix = queue.split(2);
125   checkConsistency(queue);
126   EXPECT_EQ(2, prefix->computeChainDataLength());
127   EXPECT_EQ(9, queue.front()->computeChainDataLength());
128   prefix = queue.split(3);
129   checkConsistency(queue);
130   EXPECT_EQ(3, prefix->computeChainDataLength());
131   EXPECT_EQ(6, queue.front()->computeChainDataLength());
132   prefix = queue.split(1);
133   checkConsistency(queue);
134   EXPECT_EQ(1, prefix->computeChainDataLength());
135   EXPECT_EQ(5, queue.front()->computeChainDataLength());
136   prefix = queue.split(5);
137   checkConsistency(queue);
138   EXPECT_EQ(5, prefix->computeChainDataLength());
139   EXPECT_EQ((IOBuf*)nullptr, queue.front());
140
141   queue.append(stringToIOBuf(SCL("Hello,")));
142   queue.append(stringToIOBuf(SCL(" World")));
143   checkConsistency(queue);
144   bool exceptionFired = false;
145   EXPECT_THROW({prefix = queue.split(13);}, std::underflow_error);
146   checkConsistency(queue);
147 }
148
149 TEST(IOBufQueue, Preallocate) {
150   IOBufQueue queue(clOptions);
151   queue.append(string("Hello"));
152   pair<void*,uint32_t> writable = queue.preallocate(2, 64, 64);
153   checkConsistency(queue);
154   EXPECT_NE((void*)nullptr, writable.first);
155   EXPECT_LE(2, writable.second);
156   EXPECT_GE(64, writable.second);
157   memcpy(writable.first, SCL(", "));
158   queue.postallocate(2);
159   checkConsistency(queue);
160   EXPECT_EQ(7, queue.front()->computeChainDataLength());
161   queue.append(SCL("World"));
162   checkConsistency(queue);
163   EXPECT_EQ(12, queue.front()->computeChainDataLength());
164   // There are not 2048 bytes available, this will alloc a new buf
165   writable = queue.preallocate(2048, 4096);
166   checkConsistency(queue);
167   EXPECT_LE(2048, writable.second);
168   // IOBuf allocates more than newAllocationSize, and we didn't cap it
169   EXPECT_GE(writable.second, 4096);
170   queue.postallocate(writable.second);
171   // queue has no empty space, make sure we allocate at least min, even if
172   // newAllocationSize < min
173   writable = queue.preallocate(1024, 1, 1024);
174   checkConsistency(queue);
175   EXPECT_EQ(1024, writable.second);
176 }
177
178 TEST(IOBufQueue, Wrap) {
179   IOBufQueue queue(clOptions);
180   const char* buf = "hello world goodbye";
181   size_t len = strlen(buf);
182   queue.wrapBuffer(buf, len, 6);
183   auto iob = queue.move();
184   EXPECT_EQ((len - 1) / 6 + 1, iob->countChainElements());
185   iob->unshare();
186   iob->coalesce();
187   EXPECT_EQ(StringPiece(buf),
188             StringPiece(reinterpret_cast<const char*>(iob->data()),
189                         iob->length()));
190 }
191
192 TEST(IOBufQueue, Trim) {
193   IOBufQueue queue(clOptions);
194   unique_ptr<IOBuf> a = IOBuf::create(4);
195   a->append(4);
196   queue.append(std::move(a));
197   checkConsistency(queue);
198   a = IOBuf::create(6);
199   a->append(6);
200   queue.append(std::move(a));
201   checkConsistency(queue);
202   a = IOBuf::create(8);
203   a->append(8);
204   queue.append(std::move(a));
205   checkConsistency(queue);
206   a = IOBuf::create(10);
207   a->append(10);
208   queue.append(std::move(a));
209   checkConsistency(queue);
210
211   EXPECT_EQ(4, queue.front()->countChainElements());
212   EXPECT_EQ(28, queue.front()->computeChainDataLength());
213   EXPECT_EQ(4, queue.front()->length());
214
215   queue.trimStart(1);
216   checkConsistency(queue);
217   EXPECT_EQ(4, queue.front()->countChainElements());
218   EXPECT_EQ(27, queue.front()->computeChainDataLength());
219   EXPECT_EQ(3, queue.front()->length());
220
221   queue.trimStart(5);
222   checkConsistency(queue);
223   EXPECT_EQ(3, queue.front()->countChainElements());
224   EXPECT_EQ(22, queue.front()->computeChainDataLength());
225   EXPECT_EQ(4, queue.front()->length());
226
227   queue.trimEnd(1);
228   checkConsistency(queue);
229   EXPECT_EQ(3, queue.front()->countChainElements());
230   EXPECT_EQ(21, queue.front()->computeChainDataLength());
231   EXPECT_EQ(9, queue.front()->prev()->length());
232
233   queue.trimEnd(20);
234   checkConsistency(queue);
235   EXPECT_EQ(1, queue.front()->countChainElements());
236   EXPECT_EQ(1, queue.front()->computeChainDataLength());
237   EXPECT_EQ(1, queue.front()->prev()->length());
238
239   queue.trimEnd(1);
240   checkConsistency(queue);
241   EXPECT_EQ(nullptr, queue.front());
242
243   EXPECT_THROW(queue.trimStart(2), std::underflow_error);
244   checkConsistency(queue);
245
246   EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
247   checkConsistency(queue);
248 }
249
250 TEST(IOBufQueue, TrimPack) {
251   IOBufQueue queue(clOptions);
252   unique_ptr<IOBuf> a = IOBuf::create(64);
253   a->append(4);
254   queue.append(std::move(a), true);
255   checkConsistency(queue);
256   a = IOBuf::create(6);
257   a->append(6);
258   queue.append(std::move(a), true);
259   checkConsistency(queue);
260   a = IOBuf::create(8);
261   a->append(8);
262   queue.append(std::move(a), true);
263   checkConsistency(queue);
264   a = IOBuf::create(10);
265   a->append(10);
266   queue.append(std::move(a), true);
267   checkConsistency(queue);
268
269   EXPECT_EQ(1, queue.front()->countChainElements());
270   EXPECT_EQ(28, queue.front()->computeChainDataLength());
271   EXPECT_EQ(28, queue.front()->length());
272
273   queue.trimStart(1);
274   checkConsistency(queue);
275   EXPECT_EQ(1, queue.front()->countChainElements());
276   EXPECT_EQ(27, queue.front()->computeChainDataLength());
277   EXPECT_EQ(27, queue.front()->length());
278
279   queue.trimStart(5);
280   checkConsistency(queue);
281   EXPECT_EQ(1, queue.front()->countChainElements());
282   EXPECT_EQ(22, queue.front()->computeChainDataLength());
283   EXPECT_EQ(22, queue.front()->length());
284
285   queue.trimEnd(1);
286   checkConsistency(queue);
287   EXPECT_EQ(1, queue.front()->countChainElements());
288   EXPECT_EQ(21, queue.front()->computeChainDataLength());
289   EXPECT_EQ(21, queue.front()->prev()->length());
290
291   queue.trimEnd(20);
292   checkConsistency(queue);
293   EXPECT_EQ(1, queue.front()->countChainElements());
294   EXPECT_EQ(1, queue.front()->computeChainDataLength());
295   EXPECT_EQ(1, queue.front()->prev()->length());
296
297   queue.trimEnd(1);
298   checkConsistency(queue);
299   EXPECT_EQ(nullptr, queue.front());
300
301   EXPECT_THROW(queue.trimStart(2), std::underflow_error);
302   checkConsistency(queue);
303
304   EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
305   checkConsistency(queue);
306 }
307
308 TEST(IOBufQueue, Prepend) {
309   folly::IOBufQueue queue;
310
311   auto buf = folly::IOBuf::create(10);
312   buf->advance(5);
313   queue.append(std::move(buf));
314
315   queue.append(SCL(" World"));
316   queue.prepend(SCL("Hello"));
317
318   EXPECT_THROW(queue.prepend(SCL("x")), std::overflow_error);
319
320   auto out = queue.move();
321   out->coalesce();
322   EXPECT_EQ("Hello World",
323             StringPiece(reinterpret_cast<const char*>(out->data()),
324                         out->length()));
325 }
326
327 TEST(IOBufQueue, PopFirst) {
328   IOBufQueue queue(IOBufQueue::cacheChainLength());
329   const char * strings[] = {
330     "Hello",
331     ",",
332     " ",
333     "",
334     "World"
335   };
336
337   const size_t numStrings=sizeof(strings)/sizeof(*strings);
338   size_t chainLength = 0;
339   for(ssize_t i=0; i<numStrings; ++i) {
340     queue.append(stringToIOBuf(strings[i], strlen(strings[i])));
341     checkConsistency(queue);
342     chainLength += strlen(strings[i]);
343   }
344
345   unique_ptr<IOBuf> first;
346   for(ssize_t i=0; i<numStrings; ++i) {
347     checkConsistency(queue);
348     EXPECT_EQ(chainLength, queue.front()->computeChainDataLength());
349     EXPECT_EQ(chainLength, queue.chainLength());
350     first = queue.pop_front();
351     chainLength-=strlen(strings[i]);
352     EXPECT_EQ(strlen(strings[i]), first->computeChainDataLength());
353   }
354   checkConsistency(queue);
355   EXPECT_EQ(chainLength, queue.chainLength());
356
357   EXPECT_EQ((IOBuf*)nullptr, queue.front());
358   first = queue.pop_front();
359   EXPECT_EQ((IOBuf*)nullptr, first.get());
360
361   checkConsistency(queue);
362   EXPECT_EQ((IOBuf*)nullptr, queue.front());
363   EXPECT_EQ(0, queue.chainLength());
364 }
365
366 int main(int argc, char** argv) {
367   testing::InitGoogleTest(&argc, argv);
368   google::ParseCommandLineFlags(&argc, &argv, true);
369
370   return RUN_ALL_TESTS();
371 }