Add IOBufQueue::wrapBuffer, which handles buffers > 4GB.
[folly.git] / folly / experimental / io / test / IOBufQueueTest.cpp
1 /*
2  * Copyright 2012 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/experimental/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);
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   writable = queue.preallocate(1024, 4096);
165   checkConsistency(queue);
166   EXPECT_LE(1024, writable.second);
167   EXPECT_GE(4096, writable.second);
168 }
169
170 TEST(IOBufQueue, Wrap) {
171   IOBufQueue queue(clOptions);
172   const char* buf = "hello world goodbye";
173   size_t len = strlen(buf);
174   queue.wrapBuffer(buf, len, 6);
175   auto iob = queue.move();
176   EXPECT_EQ((len - 1) / 6 + 1, iob->countChainElements());
177   iob->unshare();
178   iob->coalesce();
179   EXPECT_EQ(StringPiece(buf),
180             StringPiece(reinterpret_cast<const char*>(iob->data()),
181                         iob->length()));
182 }
183
184 TEST(IOBufQueue, trim) {
185   IOBufQueue queue(clOptions);
186   unique_ptr<IOBuf> a = IOBuf::create(4);
187   a->append(4);
188   queue.append(std::move(a));
189   checkConsistency(queue);
190   a = IOBuf::create(6);
191   a->append(6);
192   queue.append(std::move(a));
193   checkConsistency(queue);
194   a = IOBuf::create(8);
195   a->append(8);
196   queue.append(std::move(a));
197   checkConsistency(queue);
198   a = IOBuf::create(10);
199   a->append(10);
200   queue.append(std::move(a));
201   checkConsistency(queue);
202
203   EXPECT_EQ(4, queue.front()->countChainElements());
204   EXPECT_EQ(28, queue.front()->computeChainDataLength());
205   EXPECT_EQ(4, queue.front()->length());
206
207   queue.trimStart(1);
208   checkConsistency(queue);
209   EXPECT_EQ(4, queue.front()->countChainElements());
210   EXPECT_EQ(27, queue.front()->computeChainDataLength());
211   EXPECT_EQ(3, queue.front()->length());
212
213   queue.trimStart(5);
214   checkConsistency(queue);
215   EXPECT_EQ(3, queue.front()->countChainElements());
216   EXPECT_EQ(22, queue.front()->computeChainDataLength());
217   EXPECT_EQ(4, queue.front()->length());
218
219   queue.trimEnd(1);
220   checkConsistency(queue);
221   EXPECT_EQ(3, queue.front()->countChainElements());
222   EXPECT_EQ(21, queue.front()->computeChainDataLength());
223   EXPECT_EQ(9, queue.front()->prev()->length());
224
225   queue.trimEnd(20);
226   checkConsistency(queue);
227   EXPECT_EQ(1, queue.front()->countChainElements());
228   EXPECT_EQ(1, queue.front()->computeChainDataLength());
229   EXPECT_EQ(1, queue.front()->prev()->length());
230
231   queue.trimEnd(1);
232   checkConsistency(queue);
233   EXPECT_EQ(NULL, queue.front());
234
235   EXPECT_THROW(queue.trimStart(2), std::underflow_error);
236   checkConsistency(queue);
237
238   EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
239   checkConsistency(queue);
240 }
241
242 int main(int argc, char** argv) {
243   testing::InitGoogleTest(&argc, argv);
244   google::ParseCommandLineFlags(&argc, &argv, true);
245
246   return RUN_ALL_TESTS();
247 }