61f07f2b5193501e110ce53acb64f531dc431d05
[folly.git] / folly / experimental / bser / test / BserTest.cpp
1 /*
2  * Copyright 2016-present 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/bser/Bser.h>
18
19 #include <folly/String.h>
20 #include <folly/portability/GTest.h>
21
22 using folly::dynamic;
23
24 static const dynamic roundtrips[] = {
25     1,
26     std::numeric_limits<int8_t>::max(),
27     std::numeric_limits<int16_t>::max(),
28     std::numeric_limits<int32_t>::max(),
29     std::numeric_limits<int64_t>::max(),
30     std::numeric_limits<int8_t>::min(),
31     std::numeric_limits<int16_t>::min(),
32     std::numeric_limits<int32_t>::min(),
33     std::numeric_limits<int64_t>::min(),
34     bool(true),
35     bool(false),
36     nullptr,
37     1.5,
38     "hello",
39     folly::dynamic::array(1, 2, 3),
40     dynamic::object("key", "value")("otherkey", "otherval"),
41 };
42
43 // Here's a blob from the watchman test suite
44 const uint8_t template_blob[] =
45     "\x00\x01\x03\x28"
46     "\x0b\x00\x03\x02\x02\x03\x04\x6e\x61\x6d\x65\x02"
47     "\x03\x03\x61\x67\x65\x03\x03\x02\x03\x04\x66\x72"
48     "\x65\x64\x03\x14\x02\x03\x04\x70\x65\x74\x65\x03"
49     "\x1e\x0c\x03\x19";
50
51 // and here's what it represents
52 static const dynamic template_dynamic = folly::dynamic::array(
53     dynamic::object("name", "fred")("age", 20),
54     dynamic::object("name", "pete")("age", 30),
55     dynamic::object("name", nullptr)("age", 25));
56
57 TEST(Bser, RoundTrip) {
58   dynamic decoded(nullptr);
59   folly::fbstring str;
60
61   for (const auto& dyn : roundtrips) {
62     try {
63       str = folly::bser::toBser(dyn, folly::bser::serialization_opts());
64       decoded = folly::bser::parseBser(str);
65
66       EXPECT_EQ(decoded, dyn);
67     } catch (const std::exception& err) {
68       LOG(ERROR) << err.what() << "\nInput: " << dyn.typeName() << ": " << dyn
69                  << " decoded back as " << decoded.typeName() << ": " << decoded
70                  << "\n"
71                  << folly::hexDump(str.data(), str.size());
72       throw;
73     }
74   }
75 }
76
77 TEST(Bser, Template) {
78   dynamic decoded(nullptr);
79   folly::fbstring str;
80   // Decode the template value provided from elsewhere
81   decoded = folly::bser::parseBser(
82       folly::ByteRange(template_blob, sizeof(template_blob) - 1));
83   EXPECT_EQ(decoded, template_dynamic)
84       << "Didn't load template value.\n"
85       << "Input: " << template_dynamic.typeName() << ": " << template_dynamic
86       << " decoded back as " << decoded.typeName() << ": " << decoded << "\n"
87       << folly::hexDump(template_blob, sizeof(template_blob) - 1);
88
89   // Now check that we can generate this same data representation
90   folly::bser::serialization_opts opts;
91   folly::bser::serialization_opts::TemplateMap templates = {std::make_pair(
92       &decoded, folly::dynamic(folly::dynamic::array("name", "age")))};
93   opts.templates = templates;
94
95   str = folly::bser::toBser(decoded, opts);
96   EXPECT_EQ(
97       folly::ByteRange((const uint8_t*)str.data(), str.size()),
98       folly::ByteRange(template_blob, sizeof(template_blob) - 1))
99       << "Expected:\n"
100       << folly::hexDump(template_blob, sizeof(template_blob) - 1) << "\nGot:\n"
101       << folly::hexDump(str.data(), str.size());
102 }
103
104 TEST(Bser, PduLength) {
105   EXPECT_THROW(
106       [] {
107         // Try to decode PDU for a short buffer that doesn't even have the
108         // complete length available
109         auto buf = folly::IOBuf::wrapBuffer(template_blob, 3);
110         auto len = folly::bser::decodePduLength(&*buf);
111         (void)len;
112         LOG(ERROR) << "managed to return a length, but only had 3 bytes";
113       }(),
114       std::out_of_range);
115
116   auto buf = folly::IOBuf::wrapBuffer(template_blob, sizeof(template_blob));
117   auto len = folly::bser::decodePduLength(&*buf);
118   EXPECT_EQ(len, 44) << "PduLength should be 44, got " << len;
119 }
120
121 /* vim:ts=2:sw=2:et:
122  */