1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph distributed storage system
6 * Copyright (C) 2016 Red Hat
8 * Author: Sage Weil <sage@redhat.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
19 #include "global/global_init.h"
20 #include "common/ceph_argparse.h"
21 #include "global/global_context.h"
22 #include "gtest/gtest.h"
24 #include "include/denc.h"
29 void test_encode_decode(T v
) {
32 bufferlist::iterator p
= bl
.begin();
48 auto a
= bl
.get_contiguous_appender(s
);
51 ASSERT_LE(bl
.length(), s
);
56 auto bpi
= bl
.front().begin();
59 ASSERT_EQ(bpi
.get_pos(), bl
.c_str() + bl
.length());
62 test_encode_decode(v
);
66 void test_encode_decode_featured(T v
) {
69 bufferlist::iterator p
= bl
.begin();
76 void test_denc_featured(T v
) {
85 auto a
= bl
.get_contiguous_appender(s
);
88 ASSERT_LE(bl
.length(), s
);
93 auto bpi
= bl
.front().begin();
96 ASSERT_EQ(bpi
.get_pos(), bl
.c_str() + bl
.length());
99 test_encode_decode_featured(v
);
103 // hooks to count bound calls
106 int num_bound_encode
= 0;
110 num_bound_encode
= 0;
116 struct denc_counter_t
{
117 void bound_encode(size_t& p
) const {
118 ++counts
.num_bound_encode
;
119 ++p
; // denc.h does not like 0-length objects
121 void encode(buffer::list::contiguous_appender
& p
) const {
125 void decode(buffer::ptr::iterator
&p
) {
130 WRITE_CLASS_DENC(denc_counter_t
)
132 struct denc_counter_bounded_t
{
133 void bound_encode(size_t& p
) const {
134 ++counts
.num_bound_encode
;
135 ++p
; // denc.h does not like 0-length objects
137 void encode(buffer::list::contiguous_appender
& p
) const {
141 void decode(buffer::ptr::iterator
&p
) {
146 WRITE_CLASS_DENC_BOUNDED(denc_counter_bounded_t
)
148 TEST(denc
, denc_counter
)
150 denc_counter_t single
, single2
;
153 ::encode(single
, bl
);
154 ::decode(single2
, bl
);
156 ASSERT_EQ(counts
.num_bound_encode
, 1);
157 ASSERT_EQ(counts
.num_encode
, 1);
158 ASSERT_EQ(counts
.num_decode
, 1);
164 test_denc((uint8_t)4);
165 test_denc((int8_t)-5);
166 test_denc((uint16_t)6);
167 test_denc((int16_t)-7);
168 test_denc((uint32_t)8);
169 test_denc((int32_t)-9);
170 test_denc((uint64_t)10);
171 test_denc((int64_t)-11);
176 string a
, b("hi"), c("multi\nline\n");
184 void encode(bufferlist
& bl
) const {
187 void decode(bufferlist::iterator
& p
) {
191 legacy_t(int32_t i
) : a(i
) {}
192 friend bool operator<(const legacy_t
& l
, const legacy_t
& r
) {
195 friend bool operator==(const legacy_t
& l
, const legacy_t
& r
) {
199 WRITE_CLASS_ENCODER(legacy_t
)
201 template<template<class> class C
>
202 void test_common_veclist(const char* c
) {
204 cout
<< c
<< "<std::string>" << std::endl
;
213 cout
<< c
<< "<int32_t>" << std::endl
;
221 cout
<< c
<< "<legacy_t>" << std::endl
;
223 s
.push_back(legacy_t(1));
224 s
.push_back(legacy_t(2));
225 test_encode_decode(s
);
229 // We only care about specializing the type, all other template
230 // parameters should have the default values. (Like first-class
231 // functions, first-class templates do not bring their defaults.)
234 using default_vector
= std::vector
<T
>;
238 test_common_veclist
<default_vector
>("std::vector");
241 vector
<denc_counter_t
> v
, v2
;
248 ASSERT_EQ(counts
.num_bound_encode
, 100);
249 ASSERT_EQ(counts
.num_encode
, 100);
250 ASSERT_EQ(counts
.num_decode
, 100);
254 vector
<denc_counter_bounded_t
> v
, v2
;
261 ASSERT_EQ(counts
.num_bound_encode
, 1);
262 ASSERT_EQ(counts
.num_encode
, 100);
263 ASSERT_EQ(counts
.num_decode
, 100);
268 using default_list
= std::list
<T
>;
272 test_common_veclist
<default_list
>("std::list");
275 list
<denc_counter_bounded_t
> l
, l2
;
276 for (unsigned i
=0; i
<100; ++i
) {
277 l
.emplace_back(denc_counter_bounded_t());
284 ASSERT_EQ(counts
.num_bound_encode
, 1);
285 ASSERT_EQ(counts
.num_encode
, 100);
286 ASSERT_EQ(counts
.num_decode
, 100);
290 template<template<class> class C
>
291 void test_setlike(const char* c
) {
293 cout
<< c
<< "<std::string>" << std::endl
;
301 cout
<< c
<< "<int32_t>" << std::endl
;
309 cout
<< c
<< "<legacy_t>" << std::endl
;
311 s
.insert(legacy_t(1));
312 s
.insert(legacy_t(2));
313 test_encode_decode(s
);
318 using default_set
= std::set
<T
>;
322 test_setlike
<default_set
>("std::set");
326 using default_flat_set
= boost::container::flat_set
<T
>;
330 test_setlike
<default_flat_set
>("std::set");
344 friend bool operator==(const foo_t
& l
, const foo_t
& r
) {
345 return l
.a
== r
.a
&& l
.b
== r
.b
;
348 WRITE_CLASS_DENC_BOUNDED(foo_t
)
361 friend bool operator==(const foo2_t
& l
, const foo2_t
& r
) {
362 return l
.c
== r
.c
&& l
.d
== r
.d
;
365 WRITE_CLASS_DENC_BOUNDED(foo2_t
)
372 DENC_FEATURED(bar_t
, v
, p
, f
) {
377 friend bool operator==(const bar_t
& l
, const bar_t
& r
) {
378 return l
.a
== r
.a
&& l
.b
== r
.b
;
381 WRITE_CLASS_DENC_FEATURED_BOUNDED(bar_t
)
395 test_denc_featured(a
);
402 pair
<int32_t,std::string
> p
;
405 auto a
= bl
.get_contiguous_appender(1000);
410 pair
<int32_t,legacy_t
> lp
;
414 template<template<class, class> class C
>
415 void test_common_maplike(const char* c
) {
417 cout
<< c
<< "<std::string, foo_t>" << std::endl
;
425 cout
<< c
<< "<std::string, bar_t>" << std::endl
;
430 test_denc_featured(s
);
433 cout
<< c
<< "<std::string, legacy_t>" << std::endl
;
434 C
<std::string
, legacy_t
> s
;
435 s
["foo"] = legacy_t(1);
436 s
["bar"] = legacy_t(2);
437 test_encode_decode(s
);
441 template<typename U
, typename V
>
442 using default_map
= std::map
<U
, V
>;
446 test_common_maplike
<default_map
>("std::map");
449 template<typename U
, typename V
>
450 using default_flat_map
= boost::container::flat_map
<U
, V
>;
454 test_common_maplike
<default_flat_map
>("boost::container::flat_map");
457 TEST(denc
, bufferptr_shallow_and_deep
) {
460 bufferptr
p1("foo", 3);
463 auto a
= bl
.get_contiguous_appender(100);
468 cout
<< "bl is " << bl
<< std::endl
;
470 ASSERT_EQ(3u, bl
.get_num_buffers());
478 cout
<< "bl is " << bl
<< std::endl
;
480 auto p
= bl
.front().begin();
486 ASSERT_EQ(3u, op
.length());
487 ASSERT_EQ('f', op
[0]);
488 memset(bl
.c_str(), 0, bl
.length());
494 cout
<< "bl is " << bl2
<< std::endl
;
496 auto p
= bl2
.front().begin_deep();
502 ASSERT_EQ('f', op
[0]);
503 memset(bl2
.c_str(), 1, bl2
.length());
504 ASSERT_EQ('f', op
[0]);
511 cout
<< "std::array<std::string, 3>" << std::endl
;
512 std::array
<std::string
, 3> s
= { "foo", "bar", "baz" };
517 cout
<< "std::array<uint32_t, 3>" << std::endl
;
518 std::array
<uint32_t, 3> s
= { 1UL, 2UL, 3UL };
526 cout
<< "std::tuple<uint64_t, uint32_t>" << std::endl
;
527 std::tuple
<uint64_t, uint32_t> s(100ULL, 97UL);
532 cout
<< "std::tuple<std::string, uint3_t>" << std::endl
;
533 std::tuple
<std::string
, uint32_t> s("foo", 97);
537 cout
<< "std::tuple<std::string, std::set<uint32_t>>" << std::endl
;
538 std::tuple
<std::string
, std::set
<uint32_t>> s(
539 "bar", std::set
<uint32_t>{uint32_t(1), uint32_t(2), uint32_t(3)});
547 cout
<< "boost::optional<uint64_t>" << std::endl
;
548 boost::optional
<uint64_t> s
= 97, t
= boost::none
;
554 cout
<< "boost::optional<std::string>" << std::endl
;
555 boost::optional
<std::string
> s
= std::string("Meow"), t
= boost::none
;
562 denc(boost::none
, s
);
568 auto a
= bl
.get_contiguous_appender(s
);
569 denc(boost::none
, a
);
571 ASSERT_LE(bl
.length(), s
);
574 boost::optional
<uint32_t> out
= 5;
575 auto bpi
= bl
.front().begin();
578 ASSERT_EQ(bpi
.get_pos(), bl
.c_str() + bl
.length());