graduate IOBuf out of folly/experimental
[folly.git] / folly / io / test / IOBufQueueTest.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/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(NULL, queue.front());
67   queue.append(SCL(""));
68   EXPECT_EQ(NULL, queue.front());
69   queue.append(unique_ptr<IOBuf>());
70   EXPECT_EQ(NULL, queue.front());
71   string emptyString;
72   queue.append(emptyString);
73   EXPECT_EQ(NULL, 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*)NULL, chain);
89   EXPECT_EQ(12, chain->computeChainDataLength());
90   EXPECT_EQ(NULL, 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*)NULL, chain);
106   EXPECT_EQ(12, chain->computeChainDataLength());
107   EXPECT_EQ(NULL, 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*)NULL, 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*)NULL, 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(NULL, 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, Prepend) {
251   folly::IOBufQueue queue;
252
253   auto buf = folly::IOBuf::create(10);
254   buf->advance(5);
255   queue.append(std::move(buf));
256
257   queue.append(SCL(" World"));
258   queue.prepend(SCL("Hello"));
259
260   EXPECT_THROW(queue.prepend(SCL("x")), std::overflow_error);
261
262   auto out = queue.move();
263   out->coalesce();
264   EXPECT_EQ("Hello World",
265             StringPiece(reinterpret_cast<const char*>(out->data()),
266                         out->length()));
267 }
268
269 int main(int argc, char** argv) {
270   testing::InitGoogleTest(&argc, argv);
271   google::ParseCommandLineFlags(&argc, &argv, true);
272
273   return RUN_ALL_TESTS();
274 }