1 #include "include/buffer.h"
2 #include "include/encoding.h"
4 #include "gtest/gtest.h"
8 template < typename T
>
9 static void test_encode_and_decode(const T
& src
)
11 bufferlist
bl(1000000);
16 ASSERT_EQ(src
, dst
) << "Encoding roundtrip changed the string: orig=" << src
<< ", but new=" << dst
;
19 TEST(EncodingRoundTrip
, StringSimple
) {
20 string
my_str("I am the very model of a modern major general");
21 test_encode_and_decode
< std::string
>(my_str
);
24 TEST(EncodingRoundTrip
, StringEmpty
) {
26 test_encode_and_decode
< std::string
>(my_str
);
29 TEST(EncodingRoundTrip
, StringNewline
) {
30 string
my_str("foo bar baz\n");
31 test_encode_and_decode
< std::string
>(my_str
);
34 template <typename Size
, typename T
>
35 static void test_encode_and_nohead_nohead(Size len
, const T
& src
)
37 bufferlist
bl(1000000);
39 encode_nohead(src
, bl
);
43 decode_nohead(len
, dst
, i
);
44 ASSERT_EQ(src
, dst
) << "Encoding roundtrip changed the string: orig=" << src
<< ", but new=" << dst
;
47 TEST(EncodingRoundTrip
, StringNoHead
) {
48 const string
str("The quick brown fox jumps over the lazy dog");
49 auto size
= str
.size();
50 test_encode_and_nohead_nohead(static_cast<int>(size
), str
);
51 test_encode_and_nohead_nohead(static_cast<unsigned>(size
), str
);
52 test_encode_and_nohead_nohead(static_cast<uint32_t>(size
), str
);
53 test_encode_and_nohead_nohead(static_cast<__u32
>(size
), str
);
54 test_encode_and_nohead_nohead(static_cast<size_t>(size
), str
);
57 TEST(EncodingRoundTrip
, BufferListNoHead
) {
59 bl
.append("is this a dagger which i see before me?");
60 auto size
= bl
.length();
61 test_encode_and_nohead_nohead(static_cast<int>(size
), bl
);
62 test_encode_and_nohead_nohead(static_cast<unsigned>(size
), bl
);
63 test_encode_and_nohead_nohead(static_cast<uint32_t>(size
), bl
);
64 test_encode_and_nohead_nohead(static_cast<__u32
>(size
), bl
);
65 test_encode_and_nohead_nohead(static_cast<size_t>(size
), bl
);
68 typedef std::multimap
< int, std::string
> multimap_t
;
69 typedef multimap_t::value_type my_val_ty
;
72 static std::ostream
& operator<<(std::ostream
& oss
, const multimap_t
&multimap
)
74 for (multimap_t::const_iterator m
= multimap
.begin();
78 oss
<< m
->first
<< "->" << m
->second
<< " ";
84 TEST(EncodingRoundTrip
, Multimap
) {
86 multimap
.insert( my_val_ty(1, "foo") );
87 multimap
.insert( my_val_ty(2, "bar") );
88 multimap
.insert( my_val_ty(2, "baz") );
89 multimap
.insert( my_val_ty(3, "lucky number 3") );
90 multimap
.insert( my_val_ty(10000, "large number") );
92 test_encode_and_decode
< multimap_t
>(multimap
);
97 ///////////////////////////////////////////////////////
99 ///////////////////////////////////////////////////////
100 template <typename T
>
101 class ConstructorCounter
104 ConstructorCounter() : data(0)
109 explicit ConstructorCounter(const T
& data_
)
115 ConstructorCounter(const ConstructorCounter
&rhs
)
121 ConstructorCounter
&operator=(const ConstructorCounter
&rhs
)
128 static void init(void)
136 static int get_default_ctor(void)
141 static int get_one_arg_ctor(void)
146 static int get_copy_ctor(void)
151 static int get_assigns(void)
156 bool operator<(const ConstructorCounter
&rhs
) const
158 return data
< rhs
.data
;
161 bool operator==(const ConstructorCounter
&rhs
) const
163 return data
== rhs
.data
;
166 friend void decode(ConstructorCounter
&s
, bufferlist::const_iterator
& p
)
171 friend void encode(const ConstructorCounter
&s
, bufferlist
& p
)
176 friend ostream
& operator<<(ostream
&oss
, const ConstructorCounter
&cc
)
184 static int default_ctor
;
185 static int one_arg_ctor
;
186 static int copy_ctor
;
190 template class ConstructorCounter
<int32_t>;
191 template class ConstructorCounter
<int16_t>;
193 typedef ConstructorCounter
<int32_t> my_key_t
;
194 typedef ConstructorCounter
<int16_t> my_val_t
;
195 typedef std::multimap
< my_key_t
, my_val_t
> multimap2_t
;
196 typedef multimap2_t::value_type val2_ty
;
198 template <class T
> int ConstructorCounter
<T
>::default_ctor
= 0;
199 template <class T
> int ConstructorCounter
<T
>::one_arg_ctor
= 0;
200 template <class T
> int ConstructorCounter
<T
>::copy_ctor
= 0;
201 template <class T
> int ConstructorCounter
<T
>::assigns
= 0;
203 static std::ostream
& operator<<(std::ostream
& oss
, const multimap2_t
&multimap
)
205 for (multimap2_t::const_iterator m
= multimap
.begin();
209 oss
<< m
->first
<< "->" << m
->second
<< " ";
214 TEST(EncodingRoundTrip
, MultimapConstructorCounter
) {
215 multimap2_t multimap2
;
216 multimap2
.insert( val2_ty(my_key_t(1), my_val_t(10)) );
217 multimap2
.insert( val2_ty(my_key_t(2), my_val_t(20)) );
218 multimap2
.insert( val2_ty(my_key_t(2), my_val_t(30)) );
219 multimap2
.insert( val2_ty(my_key_t(3), my_val_t(40)) );
220 multimap2
.insert( val2_ty(my_key_t(10000), my_val_t(1)) );
224 test_encode_and_decode
< multimap2_t
>(multimap2
);
226 EXPECT_EQ(my_key_t::get_default_ctor(), 5);
227 EXPECT_EQ(my_key_t::get_one_arg_ctor(), 0);
228 EXPECT_EQ(my_key_t::get_copy_ctor(), 5);
229 EXPECT_EQ(my_key_t::get_assigns(), 0);
231 EXPECT_EQ(my_val_t::get_default_ctor(), 5);
232 EXPECT_EQ(my_val_t::get_one_arg_ctor(), 0);
233 EXPECT_EQ(my_val_t::get_copy_ctor(), 5);
234 EXPECT_EQ(my_val_t::get_assigns(), 0);
238 // make sure that the legacy encode/decode methods are selected
239 // over the ones defined using templates. the later is likely to
240 // be slower, see also the definition of "WRITE_INT_DENC" in
243 void encode
<uint64_t, denc_traits
<uint64_t>>(const uint64_t&,
246 static_assert(denc_traits
<uint64_t>::supported
,
247 "should support new encoder");
248 static_assert(!denc_traits
<uint64_t>::featured
,
249 "should not be featured");
251 // make sure the test fails if i get called
256 void encode
<ceph_le64
, denc_traits
<ceph_le64
>>(const ceph_le64
&,
259 static_assert(denc_traits
<ceph_le64
>::supported
,
260 "should support new encoder");
261 static_assert(!denc_traits
<ceph_le64
>::featured
,
262 "should not be featured");
264 // make sure the test fails if i get called
270 // search `underlying_type` in denc.h for supported underlying types
271 enum class Colour
: int8_t { R
,G
,B
};
272 ostream
& operator<<(ostream
& os
, Colour c
) {
275 return os
<< "Colour::R";
277 return os
<< "Colour::G";
279 return os
<< "Colour::B";
281 return os
<< "Colour::???";
286 TEST(EncodingRoundTrip
, Integers
) {
290 test_encode_and_decode(i
);
294 test_encode_and_decode(i
);
298 test_encode_and_decode(b
);
302 test_encode_and_decode(b
);
308 test_encode_and_decode(i
);
312 test_encode_and_decode(Colour::R
);
313 // this should not build, as the size of unsigned is not the same on
314 // different archs, that's why denc_traits<> intentionally leaves
315 // `int` and `unsigned int` out of supported types.
317 // enum E { R, G, B };
318 // test_encode_and_decode(R);
322 const char* expected_what
[] = {
323 "buffer::malformed_input: void lame_decoder(int) no longer understand old encoding version 100 < 200",
324 "buffer::malformed_input: void lame_decoder(int) decode past end of struct encoding",
327 void lame_decoder(int which
) {
330 throw buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__
, 100, 200));
332 throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__
));
336 TEST(EncodingException
, Macros
) {
337 for (unsigned i
= 0; i
< sizeof(expected_what
)/sizeof(expected_what
[0]); i
++) {
340 } catch (const exception
& e
) {
341 ASSERT_EQ(string(expected_what
[i
]), string(e
.what()));
347 TEST(small_encoding
, varint
) {
349 /* value, varint bytes, signed varint bytes, signed varint bytes (neg) */
368 {0xff00001, 4, 5, 5},
369 {0x1ff00001, 5, 5, 5},
370 {0xffff0001, 5, 5, 5},
371 {0xffffffff, 5, 5, 5},
372 {1074790401, 5, 5, 5},
375 for (unsigned i
=0; v
[i
][1]; ++i
) {
379 auto app
= bl
.get_contiguous_appender(16, true);
380 denc_varint(v
[i
][0], app
);
382 cout
<< std::hex
<< v
[i
][0] << "\t" << v
[i
][1] << "\t";
383 bl
.hexdump(cout
, false);
385 ASSERT_EQ(bl
.length(), v
[i
][1]);
387 auto p
= bl
.begin().get_current_ptr().cbegin();
389 ASSERT_EQ(v
[i
][0], u
);
394 auto app
= bl
.get_contiguous_appender(16, true);
395 denc_signed_varint(v
[i
][0], app
);
397 cout
<< std::hex
<< v
[i
][0] << "\t" << v
[i
][2] << "\t";
398 bl
.hexdump(cout
, false);
400 ASSERT_EQ(bl
.length(), v
[i
][2]);
402 auto p
= bl
.begin().get_current_ptr().cbegin();
403 denc_signed_varint(u
, p
);
404 ASSERT_EQ((int32_t)v
[i
][0], u
);
408 int64_t x
= -(int64_t)v
[i
][0];
410 auto app
= bl
.get_contiguous_appender(16, true);
411 denc_signed_varint(x
, app
);
413 cout
<< std::dec
<< x
<< std::hex
<< "\t" << v
[i
][3] << "\t";
414 bl
.hexdump(cout
, false);
416 ASSERT_EQ(bl
.length(), v
[i
][3]);
418 auto p
= bl
.begin().get_current_ptr().cbegin();
419 denc_signed_varint(u
, p
);
425 TEST(small_encoding
, varint_lowz
) {
427 /* value, bytes encoded */
448 {0xffff0000, 4, 4, 4},
449 {0xffffffff, 5, 5, 5},
450 {0x41000000, 3, 4, 4},
453 for (unsigned i
=0; v
[i
][1]; ++i
) {
457 auto app
= bl
.get_contiguous_appender(16, true);
458 denc_varint_lowz(v
[i
][0], app
);
460 cout
<< std::hex
<< v
[i
][0] << "\t" << v
[i
][1] << "\t";
461 bl
.hexdump(cout
, false);
463 ASSERT_EQ(bl
.length(), v
[i
][1]);
465 auto p
= bl
.begin().get_current_ptr().cbegin();
466 denc_varint_lowz(u
, p
);
467 ASSERT_EQ(v
[i
][0], u
);
473 auto app
= bl
.get_contiguous_appender(16, true);
474 denc_signed_varint_lowz(x
, app
);
476 cout
<< std::hex
<< x
<< "\t" << v
[i
][1] << "\t";
477 bl
.hexdump(cout
, false);
479 ASSERT_EQ(bl
.length(), v
[i
][2]);
481 auto p
= bl
.begin().get_current_ptr().cbegin();
482 denc_signed_varint_lowz(u
, p
);
487 int64_t x
= -(int64_t)v
[i
][0];
489 auto app
= bl
.get_contiguous_appender(16, true);
490 denc_signed_varint_lowz(x
, app
);
492 cout
<< std::dec
<< x
<< "\t" << v
[i
][1] << "\t";
493 bl
.hexdump(cout
, false);
495 ASSERT_EQ(bl
.length(), v
[i
][3]);
497 auto p
= bl
.begin().get_current_ptr().cbegin();
498 denc_signed_varint_lowz(u
, p
);
504 TEST(small_encoding
, lba
) {
506 /* value, bytes encoded */
521 {0x1fffffff00000, 5},
525 for (unsigned i
=0; v
[i
][1]; ++i
) {
528 auto app
= bl
.get_contiguous_appender(16, true);
529 denc_lba(v
[i
][0], app
);
531 cout
<< std::hex
<< v
[i
][0] << "\t" << v
[i
][1] << "\t";
532 bl
.hexdump(cout
, false);
534 ASSERT_EQ(bl
.length(), v
[i
][1]);
536 auto p
= bl
.begin().get_current_ptr().cbegin();
538 ASSERT_EQ(v
[i
][0], u
);