2 * Copyright 2013 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);
52 return std::move(buf);
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(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());
72 queue.append(emptyString);
73 EXPECT_EQ(NULL, 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*)NULL, chain);
89 EXPECT_EQ(12, chain->computeChainDataLength());
90 EXPECT_EQ(NULL, 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*)NULL, chain);
106 EXPECT_EQ(12, chain->computeChainDataLength());
107 EXPECT_EQ(NULL, queue2.front());
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());
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());
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);
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);
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());
187 EXPECT_EQ(StringPiece(buf),
188 StringPiece(reinterpret_cast<const char*>(iob->data()),
192 TEST(IOBufQueue, trim) {
193 IOBufQueue queue(clOptions);
194 unique_ptr<IOBuf> a = IOBuf::create(4);
196 queue.append(std::move(a));
197 checkConsistency(queue);
198 a = IOBuf::create(6);
200 queue.append(std::move(a));
201 checkConsistency(queue);
202 a = IOBuf::create(8);
204 queue.append(std::move(a));
205 checkConsistency(queue);
206 a = IOBuf::create(10);
208 queue.append(std::move(a));
209 checkConsistency(queue);
211 EXPECT_EQ(4, queue.front()->countChainElements());
212 EXPECT_EQ(28, queue.front()->computeChainDataLength());
213 EXPECT_EQ(4, queue.front()->length());
216 checkConsistency(queue);
217 EXPECT_EQ(4, queue.front()->countChainElements());
218 EXPECT_EQ(27, queue.front()->computeChainDataLength());
219 EXPECT_EQ(3, queue.front()->length());
222 checkConsistency(queue);
223 EXPECT_EQ(3, queue.front()->countChainElements());
224 EXPECT_EQ(22, queue.front()->computeChainDataLength());
225 EXPECT_EQ(4, queue.front()->length());
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());
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());
240 checkConsistency(queue);
241 EXPECT_EQ(NULL, queue.front());
243 EXPECT_THROW(queue.trimStart(2), std::underflow_error);
244 checkConsistency(queue);
246 EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
247 checkConsistency(queue);
250 TEST(IOBufQueue, Prepend) {
251 folly::IOBufQueue queue;
253 auto buf = folly::IOBuf::create(10);
255 queue.append(std::move(buf));
257 queue.append(SCL(" World"));
258 queue.prepend(SCL("Hello"));
260 EXPECT_THROW(queue.prepend(SCL("x")), std::overflow_error);
262 auto out = queue.move();
264 EXPECT_EQ("Hello World",
265 StringPiece(reinterpret_cast<const char*>(out->data()),
269 int main(int argc, char** argv) {
270 testing::InitGoogleTest(&argc, argv);
271 google::ParseCommandLineFlags(&argc, &argv, true);
273 return RUN_ALL_TESTS();