2 * Copyright 2015 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/io/IOBufQueue.h>
18 #include <folly/Range.h>
20 #include <gflags/gflags.h>
21 #include <gtest/gtest.h>
28 using folly::IOBufQueue;
29 using folly::StringPiece;
32 using std::unique_ptr;
34 // String Comma Length macro for string literals
35 #define SCL(x) (x), sizeof(x) - 1
39 IOBufQueue::Options clOptions;
42 clOptions.cacheChainLength = true;
45 Initializer initializer;
48 stringToIOBuf(const char* s, uint32_t len) {
49 unique_ptr<IOBuf> buf = IOBuf::create(len);
50 memcpy(buf->writableTail(), s, len);
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());
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());
72 queue.append(emptyString);
73 EXPECT_EQ(nullptr, queue.front());
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());
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());
110 TEST(IOBufQueue, AppendStringPiece) {
111 std::string s("Hello, World");
112 IOBufQueue queue(clOptions);
113 IOBufQueue queue2(clOptions);
114 queue.append(s.data(), s.length());
116 checkConsistency(queue);
117 checkConsistency(queue2);
118 const IOBuf* chain = queue.front();
119 const IOBuf* chain2 = queue2.front();
120 EXPECT_EQ(s.length(), chain->computeChainDataLength());
121 EXPECT_EQ(s.length(), chain2->computeChainDataLength());
122 EXPECT_EQ(0, memcmp(chain->data(), chain2->data(), s.length()));
125 TEST(IOBufQueue, Split) {
126 IOBufQueue queue(clOptions);
127 queue.append(stringToIOBuf(SCL("Hello")));
128 queue.append(stringToIOBuf(SCL(",")));
129 queue.append(stringToIOBuf(SCL(" ")));
130 queue.append(stringToIOBuf(SCL("")));
131 queue.append(stringToIOBuf(SCL("World")));
132 checkConsistency(queue);
133 EXPECT_EQ(12, queue.front()->computeChainDataLength());
135 unique_ptr<IOBuf> prefix(queue.split(1));
136 checkConsistency(queue);
137 EXPECT_EQ(1, prefix->computeChainDataLength());
138 EXPECT_EQ(11, queue.front()->computeChainDataLength());
139 prefix = queue.split(2);
140 checkConsistency(queue);
141 EXPECT_EQ(2, prefix->computeChainDataLength());
142 EXPECT_EQ(9, queue.front()->computeChainDataLength());
143 prefix = queue.split(3);
144 checkConsistency(queue);
145 EXPECT_EQ(3, prefix->computeChainDataLength());
146 EXPECT_EQ(6, queue.front()->computeChainDataLength());
147 prefix = queue.split(1);
148 checkConsistency(queue);
149 EXPECT_EQ(1, prefix->computeChainDataLength());
150 EXPECT_EQ(5, queue.front()->computeChainDataLength());
151 prefix = queue.split(5);
152 checkConsistency(queue);
153 EXPECT_EQ(5, prefix->computeChainDataLength());
154 EXPECT_EQ((IOBuf*)nullptr, queue.front());
156 queue.append(stringToIOBuf(SCL("Hello,")));
157 queue.append(stringToIOBuf(SCL(" World")));
158 checkConsistency(queue);
159 EXPECT_THROW({prefix = queue.split(13);}, std::underflow_error);
160 checkConsistency(queue);
163 TEST(IOBufQueue, Preallocate) {
164 IOBufQueue queue(clOptions);
165 queue.append(string("Hello"));
166 pair<void*,uint32_t> writable = queue.preallocate(2, 64, 64);
167 checkConsistency(queue);
168 EXPECT_NE((void*)nullptr, writable.first);
169 EXPECT_LE(2, writable.second);
170 EXPECT_GE(64, writable.second);
171 memcpy(writable.first, SCL(", "));
172 queue.postallocate(2);
173 checkConsistency(queue);
174 EXPECT_EQ(7, queue.front()->computeChainDataLength());
175 queue.append(SCL("World"));
176 checkConsistency(queue);
177 EXPECT_EQ(12, queue.front()->computeChainDataLength());
178 // There are not 2048 bytes available, this will alloc a new buf
179 writable = queue.preallocate(2048, 4096);
180 checkConsistency(queue);
181 EXPECT_LE(2048, writable.second);
182 // IOBuf allocates more than newAllocationSize, and we didn't cap it
183 EXPECT_GE(writable.second, 4096);
184 queue.postallocate(writable.second);
185 // queue has no empty space, make sure we allocate at least min, even if
186 // newAllocationSize < min
187 writable = queue.preallocate(1024, 1, 1024);
188 checkConsistency(queue);
189 EXPECT_EQ(1024, writable.second);
192 TEST(IOBufQueue, Wrap) {
193 IOBufQueue queue(clOptions);
194 const char* buf = "hello world goodbye";
195 size_t len = strlen(buf);
196 queue.wrapBuffer(buf, len, 6);
197 auto iob = queue.move();
198 EXPECT_EQ((len - 1) / 6 + 1, iob->countChainElements());
201 EXPECT_EQ(StringPiece(buf),
202 StringPiece(reinterpret_cast<const char*>(iob->data()),
206 TEST(IOBufQueue, Trim) {
207 IOBufQueue queue(clOptions);
208 unique_ptr<IOBuf> a = IOBuf::create(4);
210 queue.append(std::move(a));
211 checkConsistency(queue);
212 a = IOBuf::create(6);
214 queue.append(std::move(a));
215 checkConsistency(queue);
216 a = IOBuf::create(8);
218 queue.append(std::move(a));
219 checkConsistency(queue);
220 a = IOBuf::create(10);
222 queue.append(std::move(a));
223 checkConsistency(queue);
225 EXPECT_EQ(4, queue.front()->countChainElements());
226 EXPECT_EQ(28, queue.front()->computeChainDataLength());
227 EXPECT_EQ(4, queue.front()->length());
230 checkConsistency(queue);
231 EXPECT_EQ(4, queue.front()->countChainElements());
232 EXPECT_EQ(27, queue.front()->computeChainDataLength());
233 EXPECT_EQ(3, queue.front()->length());
236 checkConsistency(queue);
237 EXPECT_EQ(3, queue.front()->countChainElements());
238 EXPECT_EQ(22, queue.front()->computeChainDataLength());
239 EXPECT_EQ(4, queue.front()->length());
242 checkConsistency(queue);
243 EXPECT_EQ(3, queue.front()->countChainElements());
244 EXPECT_EQ(21, queue.front()->computeChainDataLength());
245 EXPECT_EQ(9, queue.front()->prev()->length());
248 checkConsistency(queue);
249 EXPECT_EQ(1, queue.front()->countChainElements());
250 EXPECT_EQ(1, queue.front()->computeChainDataLength());
251 EXPECT_EQ(1, queue.front()->prev()->length());
254 checkConsistency(queue);
255 EXPECT_EQ(nullptr, queue.front());
257 EXPECT_THROW(queue.trimStart(2), std::underflow_error);
258 checkConsistency(queue);
260 EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
261 checkConsistency(queue);
264 TEST(IOBufQueue, TrimPack) {
265 IOBufQueue queue(clOptions);
266 unique_ptr<IOBuf> a = IOBuf::create(64);
268 queue.append(std::move(a), true);
269 checkConsistency(queue);
270 a = IOBuf::create(6);
272 queue.append(std::move(a), true);
273 checkConsistency(queue);
274 a = IOBuf::create(8);
276 queue.append(std::move(a), true);
277 checkConsistency(queue);
278 a = IOBuf::create(10);
280 queue.append(std::move(a), true);
281 checkConsistency(queue);
283 EXPECT_EQ(1, queue.front()->countChainElements());
284 EXPECT_EQ(28, queue.front()->computeChainDataLength());
285 EXPECT_EQ(28, queue.front()->length());
288 checkConsistency(queue);
289 EXPECT_EQ(1, queue.front()->countChainElements());
290 EXPECT_EQ(27, queue.front()->computeChainDataLength());
291 EXPECT_EQ(27, queue.front()->length());
294 checkConsistency(queue);
295 EXPECT_EQ(1, queue.front()->countChainElements());
296 EXPECT_EQ(22, queue.front()->computeChainDataLength());
297 EXPECT_EQ(22, queue.front()->length());
300 checkConsistency(queue);
301 EXPECT_EQ(1, queue.front()->countChainElements());
302 EXPECT_EQ(21, queue.front()->computeChainDataLength());
303 EXPECT_EQ(21, queue.front()->prev()->length());
306 checkConsistency(queue);
307 EXPECT_EQ(1, queue.front()->countChainElements());
308 EXPECT_EQ(1, queue.front()->computeChainDataLength());
309 EXPECT_EQ(1, queue.front()->prev()->length());
312 checkConsistency(queue);
313 EXPECT_EQ(nullptr, queue.front());
315 EXPECT_THROW(queue.trimStart(2), std::underflow_error);
316 checkConsistency(queue);
318 EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
319 checkConsistency(queue);
322 TEST(IOBufQueue, Prepend) {
323 folly::IOBufQueue queue;
325 auto buf = folly::IOBuf::create(10);
327 queue.append(std::move(buf));
329 queue.append(SCL(" World"));
330 queue.prepend(SCL("Hello"));
332 EXPECT_THROW(queue.prepend(SCL("x")), std::overflow_error);
334 auto out = queue.move();
336 EXPECT_EQ("Hello World",
337 StringPiece(reinterpret_cast<const char*>(out->data()),
341 TEST(IOBufQueue, PopFirst) {
342 IOBufQueue queue(IOBufQueue::cacheChainLength());
343 const char * strings[] = {
351 const size_t numStrings=sizeof(strings)/sizeof(*strings);
352 size_t chainLength = 0;
353 for(size_t i = 0; i < numStrings; ++i) {
354 queue.append(stringToIOBuf(strings[i], strlen(strings[i])));
355 checkConsistency(queue);
356 chainLength += strlen(strings[i]);
359 unique_ptr<IOBuf> first;
360 for(size_t i = 0; i < numStrings; ++i) {
361 checkConsistency(queue);
362 EXPECT_EQ(chainLength, queue.front()->computeChainDataLength());
363 EXPECT_EQ(chainLength, queue.chainLength());
364 first = queue.pop_front();
365 chainLength-=strlen(strings[i]);
366 EXPECT_EQ(strlen(strings[i]), first->computeChainDataLength());
368 checkConsistency(queue);
369 EXPECT_EQ(chainLength, queue.chainLength());
371 EXPECT_EQ((IOBuf*)nullptr, queue.front());
372 first = queue.pop_front();
373 EXPECT_EQ((IOBuf*)nullptr, first.get());
375 checkConsistency(queue);
376 EXPECT_EQ((IOBuf*)nullptr, queue.front());
377 EXPECT_EQ(0, queue.chainLength());
380 TEST(IOBufQueue, AppendToString) {
382 queue.append("hello ", 6);
383 queue.append("world", 5);
385 queue.appendToString(s);
386 EXPECT_EQ("hello world", s);
389 int main(int argc, char** argv) {
390 testing::InitGoogleTest(&argc, argv);
391 gflags::ParseCommandLineFlags(&argc, &argv, true);
393 return RUN_ALL_TESTS();