proxygen
BserTest.cpp
Go to the documentation of this file.
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 
18 
19 #include <folly/String.h>
21 
22 using folly::dynamic;
23 
24 static const dynamic roundtrips[] = {
25  1,
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
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
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 {
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(
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"
88 
89  // Now check that we can generate this same data representation
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()),
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
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 
117  auto len = folly::bser::decodePduLength(&*buf);
118  EXPECT_EQ(len, 44) << "PduLength should be 44, got " << len;
119 }
120 
121 TEST(Bser, CursorLength) {
123  std::string inputStr("hello there please break");
124 
125  // This test is exercising the decode logic for pathological
126  // fragmentation cases. We try a few permutations with the
127  // BSER header being fragmented to tickle boundary conditions
128 
129  auto longSerialized = folly::bser::toBser(inputStr, opts);
130  for (uint32_t i = 1; i < longSerialized.size(); ++i) {
132 
133  q.append(folly::IOBuf::wrapBuffer(longSerialized.data(), i));
134  uint32_t j = i;
135  while (j < longSerialized.size()) {
136  q.append(folly::IOBuf::wrapBuffer(&longSerialized[j], 1));
137  ++j;
138  }
139 
140  auto pdu_len = folly::bser::decodePduLength(q.front());
141  auto buf = q.split(pdu_len);
142 
143  auto hello = folly::bser::parseBser(buf.get());
144  EXPECT_EQ(inputStr, hello.asString());
145  }
146 }
147 
148 /* vim:ts=2:sw=2:et:
149  */
size_type size() const
Definition: FBString.h:1337
std::unique_ptr< folly::IOBuf > split(size_t n)
Definition: IOBufQueue.h:420
const folly::IOBuf * front() const
Definition: IOBufQueue.h:476
void * object
Definition: AtFork.cpp:32
void append(std::unique_ptr< folly::IOBuf > &&buf, bool pack=false)
Definition: IOBufQueue.cpp:143
static const dynamic roundtrips[]
Definition: BserTest.cpp:24
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
const char * typeName() const
Definition: dynamic.cpp:45
LogLevel max
Definition: LogLevel.cpp:31
static std::unique_ptr< IOBuf > wrapBuffer(const void *buf, std::size_t capacity)
Definition: IOBuf.cpp:353
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
size_t decodePduLength(const folly::IOBuf *)
Definition: Load.cpp:202
const uint8_t template_blob[]
Definition: BserTest.cpp:44
const value_type * data() const
Definition: FBString.h:1716
LogLevel min
Definition: LogLevel.cpp:30
void hexDump(const void *ptr, size_t size, OutIt out)
Definition: String-inl.h:645
static const dynamic template_dynamic
Definition: BserTest.cpp:52
const char * string
Definition: Conv.cpp:212
static void array(EmptyArrayTag)
Definition: dynamic-inl.h:233
folly::Optional< TemplateMap > templates
Definition: Bser.h:82
std::unordered_map< const folly::dynamic *, folly::dynamic > TemplateMap
Definition: Bser.h:81
folly::dynamic parseBser(folly::StringPiece)
Definition: Load.cpp:219
folly::fbstring toBser(folly::dynamic const &, const serialization_opts &)
Definition: Dump.cpp:246
TEST(Bser, RoundTrip)
Definition: BserTest.cpp:57