2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <folly/experimental/bser/Bser.h>
17 #include <folly/String.h>
18 #include <folly/portability/GTest.h>
22 static const dynamic roundtrips[] = {
24 std::numeric_limits<int8_t>::max(),
25 std::numeric_limits<int16_t>::max(),
26 std::numeric_limits<int32_t>::max(),
27 std::numeric_limits<int64_t>::max(),
28 std::numeric_limits<int8_t>::min(),
29 std::numeric_limits<int16_t>::min(),
30 std::numeric_limits<int32_t>::min(),
31 std::numeric_limits<int64_t>::min(),
37 folly::dynamic::array(1, 2, 3),
38 dynamic::object("key", "value")("otherkey", "otherval"),
41 // Here's a blob from the watchman test suite
42 const uint8_t template_blob[] =
44 "\x0b\x00\x03\x02\x02\x03\x04\x6e\x61\x6d\x65\x02"
45 "\x03\x03\x61\x67\x65\x03\x03\x02\x03\x04\x66\x72"
46 "\x65\x64\x03\x14\x02\x03\x04\x70\x65\x74\x65\x03"
49 // and here's what it represents
50 static const dynamic template_dynamic = folly::dynamic::array(
51 dynamic::object("name", "fred")("age", 20),
52 dynamic::object("name", "pete")("age", 30),
53 dynamic::object("name", nullptr)("age", 25));
55 TEST(Bser, RoundTrip) {
56 dynamic decoded(nullptr);
59 for (const auto& dyn : roundtrips) {
61 str = folly::bser::toBser(dyn, folly::bser::serialization_opts());
62 decoded = folly::bser::parseBser(str);
64 EXPECT_EQ(decoded, dyn);
65 } catch (const std::exception& err) {
66 LOG(ERROR) << err.what() << "\nInput: " << dyn.typeName() << ": " << dyn
67 << " decoded back as " << decoded.typeName() << ": " << decoded
68 << "\n" << folly::hexDump(str.data(), str.size());
74 TEST(Bser, Template) {
75 dynamic decoded(nullptr);
77 // Decode the template value provided from elsewhere
78 decoded = folly::bser::parseBser(
79 folly::ByteRange(template_blob, sizeof(template_blob) - 1));
80 EXPECT_EQ(decoded, template_dynamic)
81 << "Didn't load template value."
82 "\nInput: " << template_dynamic.typeName() << ": " << template_dynamic
83 << " decoded back as " << decoded.typeName() << ": " << decoded << "\n"
84 << folly::hexDump(template_blob, sizeof(template_blob) - 1);
86 // Now check that we can generate this same data representation
87 folly::bser::serialization_opts opts;
88 folly::bser::serialization_opts::TemplateMap templates = {std::make_pair(
89 &decoded, folly::dynamic(folly::dynamic::array("name", "age")))};
90 opts.templates = templates;
92 str = folly::bser::toBser(decoded, opts);
93 EXPECT_EQ(folly::ByteRange((const uint8_t*)str.data(), str.size()),
94 folly::ByteRange(template_blob, sizeof(template_blob) - 1))
96 << folly::hexDump(template_blob, sizeof(template_blob) - 1) << "\nGot:\n"
97 << folly::hexDump(str.data(), str.size());
100 TEST(Bser, PduLength) {
102 // Try to decode PDU for a short buffer that doesn't even have the
103 // complete length available
104 auto buf = folly::IOBuf::wrapBuffer(template_blob, 3);
105 auto len = folly::bser::decodePduLength(&*buf);
106 LOG(ERROR) << "managed to return a length, but only had 3 bytes";
107 }(), std::out_of_range);
109 auto buf = folly::IOBuf::wrapBuffer(template_blob, sizeof(template_blob));
110 auto len = folly::bser::decodePduLength(&*buf);
111 EXPECT_EQ(len, 44) << "PduLength should be 44, got " << len;