1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/quic/iovector.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "net/test/gtest_util.h"
12 #include "testing/gtest/include/gtest/gtest.h"
20 const char* const test_data
[] = {
21 "test string 1, a medium size one.",
23 "test string 3, a looooooooooooong loooooooooooooooong string"
26 TEST(IOVectorTest
, CopyConstructor
) {
28 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
29 iov1
.Append(const_cast<char*>(test_data
[i
]), strlen(test_data
[i
]));
32 EXPECT_EQ(iov2
.Size(), iov1
.Size());
33 for (size_t i
= 0; i
< iov2
.Size(); ++i
) {
34 EXPECT_TRUE(iov2
.iovec()[i
].iov_base
== iov1
.iovec()[i
].iov_base
);
35 EXPECT_EQ(iov2
.iovec()[i
].iov_len
, iov1
.iovec()[i
].iov_len
);
37 EXPECT_EQ(iov2
.TotalBufferSize(), iov1
.TotalBufferSize());
40 TEST(IOVectorTest
, AssignmentOperator
) {
42 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
43 iov1
.Append(const_cast<char*>(test_data
[i
]), strlen(test_data
[i
]));
46 iov2
.Append(const_cast<char*>("ephemeral string"), 16);
47 // The following assignment results in a shallow copy;
48 // both IOVectors point to the same underlying data.
50 EXPECT_EQ(iov2
.Size(), iov1
.Size());
51 for (size_t i
= 0; i
< iov2
.Size(); ++i
) {
52 EXPECT_TRUE(iov2
.iovec()[i
].iov_base
== iov1
.iovec()[i
].iov_base
);
53 EXPECT_EQ(iov2
.iovec()[i
].iov_len
, iov1
.iovec()[i
].iov_len
);
55 EXPECT_EQ(iov2
.TotalBufferSize(), iov1
.TotalBufferSize());
58 TEST(IOVectorTest
, Append
) {
61 const struct iovec
* iov2
= iov
.iovec();
63 ASSERT_EQ(0u, iov
.Size());
64 ASSERT_TRUE(iov2
== nullptr);
65 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
66 const int str_len
= strlen(test_data
[i
]);
67 const int append_len
= str_len
/ 2;
68 // This should append a new block.
69 iov
.Append(const_cast<char*>(test_data
[i
]), append_len
);
71 ASSERT_EQ(i
+ 1, static_cast<size_t>(iov
.Size()));
72 ASSERT_TRUE(iov
.LastBlockEnd() == test_data
[i
] + append_len
);
73 // This should just lengthen the existing block.
74 iov
.Append(const_cast<char*>(test_data
[i
] + append_len
),
75 str_len
- append_len
);
76 length
+= (str_len
- append_len
);
77 ASSERT_EQ(i
+ 1, static_cast<size_t>(iov
.Size()));
78 ASSERT_TRUE(iov
.LastBlockEnd() == test_data
[i
] + str_len
);
82 ASSERT_TRUE(iov2
!= nullptr);
83 for (size_t i
= 0; i
< iov
.Size(); ++i
) {
84 ASSERT_TRUE(test_data
[i
] == iov2
[i
].iov_base
);
85 ASSERT_EQ(strlen(test_data
[i
]), iov2
[i
].iov_len
);
89 TEST(IOVectorTest
, AppendIovec
) {
91 const struct iovec test_iov
[] = {
92 {const_cast<char*>("foo"), 3},
93 {const_cast<char*>("bar"), 3},
94 {const_cast<char*>("buzzzz"), 6}
96 iov
.AppendIovec(test_iov
, arraysize(test_iov
));
97 for (size_t i
= 0; i
< arraysize(test_iov
); ++i
) {
98 EXPECT_EQ(test_iov
[i
].iov_base
, iov
.iovec()[i
].iov_base
);
99 EXPECT_EQ(test_iov
[i
].iov_len
, iov
.iovec()[i
].iov_len
);
102 // Test AppendIovecAtMostBytes.
104 // Stop in the middle of a block.
105 EXPECT_EQ(5u, iov
.AppendIovecAtMostBytes(test_iov
, arraysize(test_iov
), 5));
106 EXPECT_EQ(5u, iov
.TotalBufferSize());
107 iov
.Append(static_cast<char*>(test_iov
[1].iov_base
) + 2, 1);
108 // Make sure the boundary case, where max_bytes == size of block also works.
109 EXPECT_EQ(6u, iov
.AppendIovecAtMostBytes(&test_iov
[2], 1, 6));
110 ASSERT_LE(arraysize(test_iov
), static_cast<size_t>(iov
.Size()));
111 for (size_t i
= 0; i
< arraysize(test_iov
); ++i
) {
112 EXPECT_EQ(test_iov
[i
].iov_base
, iov
.iovec()[i
].iov_base
);
113 EXPECT_EQ(test_iov
[i
].iov_len
, iov
.iovec()[i
].iov_len
);
117 TEST(IOVectorTest
, ConsumeHalfBlocks
) {
121 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
122 const int str_len
= strlen(test_data
[i
]);
123 iov
.Append(const_cast<char*>(test_data
[i
]), str_len
);
126 const char* endp
= iov
.LastBlockEnd();
127 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
128 const struct iovec
* iov2
= iov
.iovec();
129 const size_t str_len
= strlen(test_data
[i
]);
130 size_t tmp
= str_len
/ 2;
132 ASSERT_TRUE(iov2
!= nullptr);
133 ASSERT_TRUE(iov2
[0].iov_base
== test_data
[i
]);
134 ASSERT_EQ(str_len
, iov2
[0].iov_len
);
136 // Consume half of the first block.
137 size_t consumed
= iov
.Consume(tmp
);
138 ASSERT_EQ(tmp
, consumed
);
139 ASSERT_EQ(arraysize(test_data
) - i
, static_cast<size_t>(iov
.Size()));
141 ASSERT_TRUE(iov2
!= nullptr);
142 ASSERT_TRUE(iov2
[0].iov_base
== test_data
[i
] + tmp
);
143 ASSERT_EQ(iov2
[0].iov_len
, str_len
- tmp
);
145 // Consume the rest of the first block.
146 consumed
= iov
.Consume(str_len
- tmp
);
147 ASSERT_EQ(str_len
- tmp
, consumed
);
148 ASSERT_EQ(arraysize(test_data
) - i
- 1, static_cast<size_t>(iov
.Size()));
150 if (iov
.Size() > 0) {
151 ASSERT_TRUE(iov2
!= nullptr);
152 ASSERT_TRUE(iov
.LastBlockEnd() == endp
);
154 ASSERT_TRUE(iov2
== nullptr);
155 ASSERT_TRUE(iov
.LastBlockEnd() == nullptr);
160 TEST(IOVectorTest
, ConsumeTwoAndHalfBlocks
) {
164 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
165 const int str_len
= strlen(test_data
[i
]);
166 iov
.Append(const_cast<char*>(test_data
[i
]), str_len
);
169 const size_t last_len
= strlen(test_data
[arraysize(test_data
) - 1]);
170 const size_t half_len
= last_len
/ 2;
172 const char* endp
= iov
.LastBlockEnd();
173 size_t consumed
= iov
.Consume(length
- half_len
);
174 ASSERT_EQ(length
- half_len
, consumed
);
175 const struct iovec
* iov2
= iov
.iovec();
176 ASSERT_TRUE(iov2
!= nullptr);
177 ASSERT_EQ(1u, iov
.Size());
178 ASSERT_TRUE(iov2
[0].iov_base
==
179 test_data
[arraysize(test_data
) - 1] + last_len
- half_len
);
180 ASSERT_EQ(half_len
, iov2
[0].iov_len
);
181 ASSERT_TRUE(iov
.LastBlockEnd() == endp
);
183 consumed
= iov
.Consume(half_len
);
184 ASSERT_EQ(half_len
, consumed
);
186 ASSERT_EQ(0u, iov
.Size());
187 ASSERT_TRUE(iov2
== nullptr);
188 ASSERT_TRUE(iov
.LastBlockEnd() == nullptr);
191 TEST(IOVectorTest
, ConsumeTooMuch
) {
195 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
196 const int str_len
= strlen(test_data
[i
]);
197 iov
.Append(const_cast<char*>(test_data
[i
]), str_len
);
203 {consumed
= iov
.Consume(length
+ 1);},
204 "Attempting to consume 1 non-existent bytes.");
205 ASSERT_EQ(length
, consumed
);
206 const struct iovec
* iov2
= iov
.iovec();
207 ASSERT_EQ(0u, iov
.Size());
208 ASSERT_TRUE(iov2
== nullptr);
209 ASSERT_TRUE(iov
.LastBlockEnd() == nullptr);
212 TEST(IOVectorTest
, ConsumeAndCopyHalfBlocks
) {
216 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
217 const int str_len
= strlen(test_data
[i
]);
218 iov
.Append(const_cast<char*>(test_data
[i
]), str_len
);
221 const char* endp
= iov
.LastBlockEnd();
222 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
223 const struct iovec
* iov2
= iov
.iovec();
224 const size_t str_len
= strlen(test_data
[i
]);
225 size_t tmp
= str_len
/ 2;
227 ASSERT_TRUE(iov2
!= nullptr);
228 ASSERT_TRUE(iov2
[0].iov_base
== test_data
[i
]);
229 ASSERT_EQ(str_len
, iov2
[0].iov_len
);
231 // Consume half of the first block.
232 scoped_ptr
<char[]> buffer(new char[str_len
]);
233 size_t consumed
= iov
.ConsumeAndCopy(tmp
, buffer
.get());
234 EXPECT_EQ(0, memcmp(test_data
[i
], buffer
.get(), tmp
));
235 ASSERT_EQ(tmp
, consumed
);
236 ASSERT_EQ(arraysize(test_data
) - i
, static_cast<size_t>(iov
.Size()));
238 ASSERT_TRUE(iov2
!= nullptr);
239 ASSERT_TRUE(iov2
[0].iov_base
== test_data
[i
] + tmp
);
240 ASSERT_EQ(iov2
[0].iov_len
, str_len
- tmp
);
242 // Consume the rest of the first block.
243 consumed
= iov
.ConsumeAndCopy(str_len
- tmp
, buffer
.get());
244 ASSERT_EQ(str_len
- tmp
, consumed
);
245 ASSERT_EQ(arraysize(test_data
) - i
- 1, static_cast<size_t>(iov
.Size()));
247 if (iov
.Size() > 0) {
248 ASSERT_TRUE(iov2
!= nullptr);
249 ASSERT_TRUE(iov
.LastBlockEnd() == endp
);
251 ASSERT_TRUE(iov2
== nullptr);
252 ASSERT_TRUE(iov
.LastBlockEnd() == nullptr);
257 TEST(IOVectorTest
, ConsumeAndCopyTwoAndHalfBlocks
) {
261 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
262 const int str_len
= strlen(test_data
[i
]);
263 iov
.Append(const_cast<char*>(test_data
[i
]), str_len
);
266 const size_t last_len
= strlen(test_data
[arraysize(test_data
) - 1]);
267 const size_t half_len
= last_len
/ 2;
269 const char* endp
= iov
.LastBlockEnd();
270 scoped_ptr
<char[]> buffer(new char[length
]);
271 size_t consumed
= iov
.ConsumeAndCopy(length
- half_len
, buffer
.get());
272 ASSERT_EQ(length
- half_len
, consumed
);
273 const struct iovec
* iov2
= iov
.iovec();
274 ASSERT_TRUE(iov2
!= nullptr);
275 ASSERT_EQ(1u, iov
.Size());
276 ASSERT_TRUE(iov2
[0].iov_base
==
277 test_data
[arraysize(test_data
) - 1] + last_len
- half_len
);
278 ASSERT_EQ(half_len
, iov2
[0].iov_len
);
279 ASSERT_TRUE(iov
.LastBlockEnd() == endp
);
281 consumed
= iov
.Consume(half_len
);
282 ASSERT_EQ(half_len
, consumed
);
284 ASSERT_EQ(0u, iov
.Size());
285 ASSERT_TRUE(iov2
== nullptr);
286 ASSERT_TRUE(iov
.LastBlockEnd() == nullptr);
289 TEST(IOVectorTest
, ConsumeAndCopyTooMuch
) {
293 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
294 const int str_len
= strlen(test_data
[i
]);
295 iov
.Append(const_cast<char*>(test_data
[i
]), str_len
);
300 scoped_ptr
<char[]> buffer(new char[length
+ 1]);
301 EXPECT_DFATAL({ consumed
= iov
.ConsumeAndCopy(length
+ 1, buffer
.get()); },
302 "Attempting to consume 1 non-existent bytes.");
303 ASSERT_EQ(length
, consumed
);
304 const struct iovec
* iov2
= iov
.iovec();
305 ASSERT_EQ(0u, iov
.Size());
306 ASSERT_TRUE(iov2
== nullptr);
307 ASSERT_TRUE(iov
.LastBlockEnd() == nullptr);
310 TEST(IOVectorTest
, Clear
) {
314 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
315 const int str_len
= strlen(test_data
[i
]);
316 iov
.Append(const_cast<char*>(test_data
[i
]), str_len
);
319 const struct iovec
* iov2
= iov
.iovec();
320 ASSERT_TRUE(iov2
!= nullptr);
321 ASSERT_EQ(arraysize(test_data
), static_cast<size_t>(iov
.Size()));
325 ASSERT_EQ(0u, iov
.Size());
326 ASSERT_TRUE(iov2
== nullptr);
329 TEST(IOVectorTest
, Capacity
) {
331 // Note: IOVector merges adjacent Appends() into a single iov.
332 // Therefore, if we expect final size of iov to be 3, we must insure
333 // that the items we are appending are not adjacent. To achieve that
334 // we use use an array (a[1] provides a buffer between a[0] and b[0],
335 // and makes them non-adjacent).
336 char a
[2], b
[2], c
[2];
337 iov
.Append(&a
[0], 1);
338 iov
.Append(&b
[0], 1);
339 iov
.Append(&c
[0], 1);
340 ASSERT_EQ(3u, iov
.Size());
341 size_t capacity
= iov
.Capacity();
342 EXPECT_LE(iov
.Size(), capacity
);
344 // The capacity should not have changed.
345 EXPECT_EQ(capacity
, iov
.Capacity());
348 TEST(IOVectorTest
, Swap
) {
350 // See IOVector merge comment above.
351 char a
[2], b
[2], c
[2], d
[2], e
[2];
352 iov1
.Append(&a
[0], 1);
353 iov1
.Append(&b
[0], 1);
355 iov2
.Append(&c
[0], 1);
356 iov2
.Append(&d
[0], 1);
357 iov2
.Append(&e
[0], 1);
360 ASSERT_EQ(3u, iov1
.Size());
361 EXPECT_EQ(&c
[0], iov1
.iovec()[0].iov_base
);
362 EXPECT_EQ(1u, iov1
.iovec()[0].iov_len
);
363 EXPECT_EQ(&d
[0], iov1
.iovec()[1].iov_base
);
364 EXPECT_EQ(1u, iov1
.iovec()[1].iov_len
);
365 EXPECT_EQ(&e
[0], iov1
.iovec()[2].iov_base
);
366 EXPECT_EQ(1u, iov1
.iovec()[2].iov_len
);
368 ASSERT_EQ(2u, iov2
.Size());
369 EXPECT_EQ(&a
[0], iov2
.iovec()[0].iov_base
);
370 EXPECT_EQ(1u, iov2
.iovec()[0].iov_len
);
371 EXPECT_EQ(&b
[0], iov2
.iovec()[1].iov_base
);
372 EXPECT_EQ(1u, iov2
.iovec()[1].iov_len
);