]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/test/beast/core/test_buffer.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / beast / test / beast / core / test_buffer.hpp
1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9
10 #ifndef BOOST_BEAST_TEST_BUFFER_HPP
11 #define BOOST_BEAST_TEST_BUFFER_HPP
12
13 #include <boost/beast/core/detail/config.hpp>
14 #include <boost/beast/_experimental/unit_test/suite.hpp>
15 #include <boost/beast/core/buffer_traits.hpp>
16 #include <boost/beast/core/buffers_to_string.hpp>
17 #include <boost/beast/core/string.hpp>
18 #include <boost/beast/core/detail/type_traits.hpp>
19 #include <boost/asio/buffer.hpp>
20 #include <boost/assert.hpp>
21 #include <algorithm>
22 #include <string>
23 #include <type_traits>
24
25 namespace boost {
26 namespace beast {
27
28 /** A MutableBufferSequence for tests, where length is always 3.
29 */
30 class buffers_triple
31 {
32 net::mutable_buffer b_[3];
33
34 public:
35 using value_type = net::mutable_buffer;
36 using const_iterator = net::mutable_buffer const*;
37
38 buffers_triple(
39 buffers_triple const&) = default;
40
41 buffers_triple& operator=(
42 buffers_triple const&) = default;
43
44 buffers_triple(char* data, std::size_t size)
45 {
46 b_[0] = {data, size/6};
47 data += b_[0].size();
48 size -= b_[0].size();
49
50 b_[1] = {data, 2*size/5};
51 data += b_[1].size();
52 size -= b_[1].size();
53
54 b_[2] = {data, size};
55
56 BOOST_ASSERT(b_[0].size() > 0);
57 BOOST_ASSERT(b_[1].size() > 0);
58 BOOST_ASSERT(b_[2].size() > 0);
59 }
60
61 bool
62 operator==(buffers_triple const& rhs) const noexcept
63 {
64 return
65 b_[0].data() == rhs.b_[0].data() &&
66 b_[0].size() == rhs.b_[0].size() &&
67 b_[1].data() == rhs.b_[1].data() &&
68 b_[1].size() == rhs.b_[1].size() &&
69 b_[2].data() == rhs.b_[2].data() &&
70 b_[2].size() == rhs.b_[2].size();
71 }
72
73 bool
74 operator!=(buffers_triple const& rhs) const noexcept
75 {
76 return !(*this == rhs);
77 }
78
79 const_iterator
80 begin() const noexcept
81 {
82 return &b_[0];
83 }
84
85 const_iterator
86 end() const noexcept
87 {
88 return &b_[3];
89 }
90 };
91
92 template<class ConstBufferSequence>
93 std::size_t
94 buffers_length(
95 ConstBufferSequence const& buffers)
96 {
97 return std::distance(
98 net::buffer_sequence_begin(buffers),
99 net::buffer_sequence_end(buffers));
100 }
101
102 //------------------------------------------------------------------------------
103
104 namespace detail {
105
106 template<class MutableBufferSequence>
107 void test_mutable_buffers(
108 MutableBufferSequence const&,
109 net::const_buffer)
110 {
111 }
112
113 template<class MutableBufferSequence>
114 void test_mutable_buffers(
115 MutableBufferSequence const& b,
116 net::mutable_buffer)
117 {
118 string_view src = "Hello, world!";
119 BOOST_ASSERT(buffer_bytes(b) <= src.size());
120 if(src.size() > buffer_bytes(b))
121 src = {src.data(), buffer_bytes(b)};
122 net::buffer_copy(b, net::const_buffer(
123 src.data(), src.size()));
124 BEAST_EXPECT(beast::buffers_to_string(b) == src);
125 }
126
127 } // detail
128
129 /** Test an instance of a constant or mutable buffer sequence.
130 */
131 template<class ConstBufferSequence>
132 void
133 test_buffer_sequence(
134 ConstBufferSequence const& buffers)
135 {
136 BOOST_STATIC_ASSERT(
137 net::is_const_buffer_sequence<
138 ConstBufferSequence>::value);
139
140 using iterator = decltype(
141 net::buffer_sequence_begin(buffers));
142 BEAST_EXPECT(sizeof(iterator) > 0);
143
144 auto const size = buffer_bytes(buffers);
145 BEAST_EXPECT(size > 0 );
146
147 // begin, end
148 auto const length = std::distance(
149 net::buffer_sequence_begin(buffers),
150 net::buffer_sequence_end(buffers));
151 BEAST_EXPECT(length > 0);
152 BEAST_EXPECT(
153 net::buffer_sequence_begin(buffers) !=
154 net::buffer_sequence_end(buffers));
155
156 // copy construction
157 ConstBufferSequence b1(buffers);
158 BEAST_EXPECT(buffer_bytes(b1) == size);
159
160 // copy assignment
161 ConstBufferSequence b2(buffers);
162 b2 = b1;
163 BEAST_EXPECT(buffer_bytes(b2) == size);
164
165 // iterators
166 {
167 iterator it1{};
168 iterator it2{};
169 iterator it3 =
170 net::buffer_sequence_begin(buffers);
171 iterator it4 =
172 net::buffer_sequence_end(buffers);
173 BEAST_EXPECT(it1 == it2);
174 BEAST_EXPECT(it1 != it3);
175 BEAST_EXPECT(it3 != it1);
176 BEAST_EXPECT(it1 != it4);
177 BEAST_EXPECT(it4 != it1);
178 }
179
180 // bidirectional
181 {
182 auto const first =
183 net::buffer_sequence_begin(buffers);
184 auto const last =
185 net::buffer_sequence_end(buffers);
186 std::size_t n, m;
187 iterator it;
188
189 // pre-increment
190 m = 0;
191 n = length;
192 for(it = first; n--; ++it)
193 m += buffer_bytes(*it);
194 BEAST_EXPECT(it == last);
195 BEAST_EXPECT(m == size);
196
197 // post-increment
198 m = 0;
199 n = length;
200 for(it = first; n--;)
201 m += buffer_bytes(*it++);
202 BEAST_EXPECT(it == last);
203 BEAST_EXPECT(m == size);
204
205 // pre-decrement
206 m = 0;
207 n = length;
208 for(it = last; n--;)
209 m += buffer_bytes(*--it);
210 BEAST_EXPECT(it == first);
211 BEAST_EXPECT(m == size);
212
213 // post-decrement
214 m = 0;
215 n = length;
216 for(it = last; n--;)
217 {
218 it--;
219 m += buffer_bytes(*it);
220 }
221 BEAST_EXPECT(it == first);
222 BEAST_EXPECT(m == size);
223 }
224
225 detail::test_mutable_buffers(buffers,
226 buffers_type<ConstBufferSequence>{});
227 }
228
229 //------------------------------------------------------------------------------
230
231 /** Metafunction to determine if a type meets the requirements of MutableDynamicBuffer
232 */
233 /* @{ */
234 // VFALCO This trait needs tests
235 template<class T, class = void>
236 struct is_mutable_dynamic_buffer
237 : std::false_type
238 {
239 };
240
241 template<class T>
242 struct is_mutable_dynamic_buffer<T, detail::void_t<decltype(
243 std::declval<typename T::const_buffers_type&>() =
244 std::declval<T const&>().data(),
245 std::declval<typename T::const_buffers_type&>() =
246 std::declval<T&>().cdata(),
247 std::declval<typename T::mutable_data_type&>() =
248 std::declval<T&>().data()
249 ) > > : net::is_dynamic_buffer<T>
250 {
251 };
252 /** @} */
253
254 namespace detail {
255
256 template<class MutableBufferSequence>
257 void
258 buffers_fill(
259 MutableBufferSequence const& buffers,
260 char c)
261 {
262 auto const end =
263 net::buffer_sequence_end(buffers);
264 for(auto it = net::buffer_sequence_begin(buffers);
265 it != end; ++it)
266 {
267 net::mutable_buffer b(*it);
268 std::fill(
269 static_cast<char*>(b.data()),
270 static_cast<char*>(b.data()) + b.size(), c);
271 }
272 }
273
274 template<class MutableDynamicBuffer>
275 void
276 test_mutable_dynamic_buffer(
277 MutableDynamicBuffer const&,
278 std::false_type)
279 {
280 }
281
282 template<class MutableDynamicBuffer>
283 void
284 test_mutable_dynamic_buffer(
285 MutableDynamicBuffer const& b0,
286 std::true_type)
287 {
288 BOOST_STATIC_ASSERT(
289 net::is_mutable_buffer_sequence<typename
290 MutableDynamicBuffer::mutable_data_type>::value);
291
292 BOOST_STATIC_ASSERT(
293 std::is_convertible<
294 typename MutableDynamicBuffer::mutable_data_type,
295 typename MutableDynamicBuffer::const_buffers_type>::value);
296
297 string_view src = "Hello, world!";
298 if(src.size() > b0.max_size())
299 src = {src.data(), b0.max_size()};
300
301 // modify readable bytes
302 {
303 MutableDynamicBuffer b(b0);
304 auto const mb = b.prepare(src.size());
305 BEAST_EXPECT(buffer_bytes(mb) == src.size());
306 buffers_fill(mb, '*');
307 b.commit(src.size());
308 BEAST_EXPECT(b.size() == src.size());
309 BEAST_EXPECT(
310 beast::buffers_to_string(b.data()) ==
311 std::string(src.size(), '*'));
312 BEAST_EXPECT(
313 beast::buffers_to_string(b.cdata()) ==
314 std::string(src.size(), '*'));
315 auto const n = net::buffer_copy(
316 b.data(), net::const_buffer(
317 src.data(), src.size()));
318 BEAST_EXPECT(n == src.size());
319 BEAST_EXPECT(
320 beast::buffers_to_string(b.data()) == src);
321 BEAST_EXPECT(
322 beast::buffers_to_string(b.cdata()) == src);
323 }
324
325 // mutable to const sequence conversion
326 {
327 MutableDynamicBuffer b(b0);
328 b.commit(net::buffer_copy(
329 b.prepare(src.size()),
330 net::const_buffer(src.data(), src.size())));
331 auto mb = b.data();
332 auto cb = static_cast<
333 MutableDynamicBuffer const&>(b).data();
334 auto cbc = b.cdata();
335 BEAST_EXPECT(
336 beast::buffers_to_string(b.data()) == src);
337 BEAST_EXPECT(
338 beast::buffers_to_string(b.cdata()) == src);
339 beast::test_buffer_sequence(cb);
340 beast::test_buffer_sequence(cbc);
341 beast::test_buffer_sequence(mb);
342 {
343 decltype(mb) mb2(mb);
344 mb = mb2;
345 decltype(cb) cb2(cb);
346 cb = cb2;
347 decltype(cbc) cbc2(cbc);
348 cbc = cbc2;
349 }
350 {
351 decltype(cb) cb2(mb);
352 decltype(cbc) cbc2(mb);
353 cb2 = mb;
354 cbc2 = mb;
355 }
356 }
357 }
358
359 } // detail
360
361 /** Test an instance of a dynamic buffer or mutable dynamic buffer.
362 */
363 template<class DynamicBuffer>
364 void
365 test_dynamic_buffer(
366 DynamicBuffer const& b0)
367 {
368 BOOST_STATIC_ASSERT(
369 net::is_dynamic_buffer<DynamicBuffer>::value);
370
371 BOOST_STATIC_ASSERT(
372 net::is_const_buffer_sequence<typename
373 DynamicBuffer::const_buffers_type>::value);
374
375 BOOST_STATIC_ASSERT(
376 net::is_mutable_buffer_sequence<typename
377 DynamicBuffer::mutable_buffers_type>::value);
378
379 BEAST_EXPECT(b0.size() == 0);
380 BEAST_EXPECT(buffer_bytes(b0.data()) == 0);
381
382 // members
383 {
384 string_view src = "Hello, world!";
385
386 DynamicBuffer b1(b0);
387 auto const mb = b1.prepare(src.size());
388 b1.commit(net::buffer_copy(mb,
389 net::const_buffer(src.data(), src.size())));
390
391 // copy constructor
392 {
393 DynamicBuffer b2(b1);
394 BEAST_EXPECT(b2.size() == b1.size());
395 BEAST_EXPECT(
396 buffers_to_string(b1.data()) ==
397 buffers_to_string(b2.data()));
398
399 // https://github.com/boostorg/beast/issues/1621
400 b2.consume(1);
401 DynamicBuffer b3(b2);
402 BEAST_EXPECT(b3.size() == b2.size());
403 BEAST_EXPECT(
404 buffers_to_string(b2.data()) ==
405 buffers_to_string(b3.data()));
406 }
407
408 // move constructor
409 {
410 DynamicBuffer b2(b1);
411 DynamicBuffer b3(std::move(b2));
412 BEAST_EXPECT(b3.size() == b1.size());
413 BEAST_EXPECT(
414 buffers_to_string(b3.data()) ==
415 buffers_to_string(b1.data()));
416 }
417
418 // copy assignment
419 {
420 DynamicBuffer b2(b0);
421 b2 = b1;
422 BEAST_EXPECT(b2.size() == b1.size());
423 BEAST_EXPECT(
424 buffers_to_string(b1.data()) ==
425 buffers_to_string(b2.data()));
426
427 // self assignment
428 b2 = *&b2;
429 BEAST_EXPECT(b2.size() == b1.size());
430 BEAST_EXPECT(
431 buffers_to_string(b2.data()) ==
432 buffers_to_string(b1.data()));
433
434 // https://github.com/boostorg/beast/issues/1621
435 b2.consume(1);
436 DynamicBuffer b3(b2);
437 BEAST_EXPECT(b3.size() == b2.size());
438 BEAST_EXPECT(
439 buffers_to_string(b2.data()) ==
440 buffers_to_string(b3.data()));
441
442 }
443
444 // move assignment
445 {
446 DynamicBuffer b2(b1);
447 DynamicBuffer b3(b0);
448 b3 = std::move(b2);
449 BEAST_EXPECT(b3.size() == b1.size());
450 BEAST_EXPECT(
451 buffers_to_string(b3.data()) ==
452 buffers_to_string(b1.data()));
453
454 // self move
455 b3 = std::move(b3);
456 BEAST_EXPECT(b3.size() == b1.size());
457 BEAST_EXPECT(
458 buffers_to_string(b3.data()) ==
459 buffers_to_string(b1.data()));
460 }
461
462 // swap
463 {
464 DynamicBuffer b2(b1);
465 DynamicBuffer b3(b0);
466 BEAST_EXPECT(b2.size() == b1.size());
467 BEAST_EXPECT(b3.size() == b0.size());
468 using std::swap;
469 swap(b2, b3);
470 BEAST_EXPECT(b2.size() == b0.size());
471 BEAST_EXPECT(b3.size() == b1.size());
472 BEAST_EXPECT(
473 buffers_to_string(b3.data()) ==
474 buffers_to_string(b1.data()));
475 }
476 }
477
478 // n == 0
479 {
480 DynamicBuffer b(b0);
481 b.commit(1);
482 BEAST_EXPECT(b.size() == 0);
483 BEAST_EXPECT(buffer_bytes(b.prepare(0)) == 0);
484 b.commit(0);
485 BEAST_EXPECT(b.size() == 0);
486 b.commit(1);
487 BEAST_EXPECT(b.size() == 0);
488 b.commit(b.max_size() + 1);
489 BEAST_EXPECT(b.size() == 0);
490 b.consume(0);
491 BEAST_EXPECT(b.size() == 0);
492 b.consume(1);
493 BEAST_EXPECT(b.size() == 0);
494 b.consume(b.max_size() + 1);
495 BEAST_EXPECT(b.size() == 0);
496 }
497
498 // max_size
499 {
500 DynamicBuffer b(b0);
501 if(BEAST_EXPECT(
502 b.max_size() + 1 > b.max_size()))
503 {
504 try
505 {
506 b.prepare(b.max_size() + 1);
507 BEAST_FAIL();
508 }
509 catch(std::length_error const&)
510 {
511 BEAST_PASS();
512 }
513 catch(...)
514 {
515 BEAST_FAIL();
516 }
517 }
518 }
519
520 // setup source buffer
521 char buf[13];
522 unsigned char k0 = 0;
523 string_view src(buf, sizeof(buf));
524 if(src.size() > b0.max_size())
525 src = {src.data(), b0.max_size()};
526 BEAST_EXPECT(b0.max_size() >= src.size());
527 BEAST_EXPECT(b0.size() == 0);
528 BEAST_EXPECT(buffer_bytes(b0.data()) == 0);
529 auto const make_new_src =
530 [&buf, &k0, &src]
531 {
532 auto k = k0++;
533 for(std::size_t i = 0; i < src.size(); ++i)
534 buf[i] = k++;
535 };
536
537 // readable / writable buffer sequence tests
538 {
539 make_new_src();
540 DynamicBuffer b(b0);
541 auto const& bc(b);
542 auto const mb = b.prepare(src.size());
543 BEAST_EXPECT(buffer_bytes(mb) == src.size());
544 beast::test_buffer_sequence(mb);
545 b.commit(net::buffer_copy(mb,
546 net::const_buffer(src.data(), src.size())));
547 BEAST_EXPECT(
548 buffer_bytes(bc.data()) == src.size());
549 beast::test_buffer_sequence(bc.data());
550 }
551
552 // h = in size
553 // i = prepare size
554 // j = commit size
555 // k = consume size
556 for(std::size_t h = 1; h <= src.size(); ++h)
557 {
558 string_view in(src.data(), h);
559 for(std::size_t i = 1; i <= in.size(); ++i) {
560 for(std::size_t j = 1; j <= i + 1; ++j) {
561 for(std::size_t k = 1; k <= in.size(); ++k) {
562 {
563 make_new_src();
564
565 DynamicBuffer b(b0);
566 auto const& bc(b);
567 net::const_buffer cb(in.data(), in.size());
568 while(cb.size() > 0)
569 {
570 auto const mb = b.prepare(
571 std::min<std::size_t>(i,
572 b.max_size() - b.size()));
573 auto const n = net::buffer_copy(mb,
574 net::const_buffer(cb.data(),
575 std::min<std::size_t>(j, cb.size())));
576 b.commit(n);
577 cb += n;
578 }
579 BEAST_EXPECT(b.size() == in.size());
580 BEAST_EXPECT(
581 buffer_bytes(bc.data()) == in.size());
582 BEAST_EXPECT(beast::buffers_to_string(
583 bc.data()) == in);
584 while(b.size() > 0)
585 b.consume(k);
586 BEAST_EXPECT(buffer_bytes(bc.data()) == 0);
587 }
588 } } }
589 }
590
591 // MutableDynamicBuffer refinement
592 detail::test_mutable_dynamic_buffer(b0,
593 is_mutable_dynamic_buffer<DynamicBuffer>{});
594 }
595
596 } // beast
597 } // boost
598
599 #endif