1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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 <thrift/conformance/cpp2/AnySerializer.h>
18 
19 #include <any>
20 
21 #include <folly/portability/GTest.h>
22 #include <thrift/conformance/cpp2/Testing.h>
23 
24 namespace apache::thrift::conformance {
25 
26 namespace {
27 
28 // Helpers for encoding/decoding using stirngs.
encode(const AnySerializer & serializer,any_ref value)29 std::string encode(const AnySerializer& serializer, any_ref value) {
30   folly::IOBufQueue queue(folly::IOBufQueue::cacheChainLength());
31   // Allocate 16KB at a time; leave some room for the IOBuf overhead
32   constexpr size_t kDesiredGrowth = (1 << 14) - 64;
33   serializer.encode(value, folly::io::QueueAppender(&queue, kDesiredGrowth));
34 
35   std::string result;
36   queue.appendToString(result);
37   return result;
38 }
39 
40 template <typename T>
decode(const AnySerializer & serializer,std::string_view data)41 T decode(const AnySerializer& serializer, std::string_view data) {
42   folly::IOBuf buf(folly::IOBuf::WRAP_BUFFER, data.data(), data.size());
43   folly::io::Cursor cursor{&buf};
44   return serializer.decode<T>(cursor);
45 }
46 
decode(const AnySerializer & serializer,const std::type_info & typeinfo,std::string_view data)47 std::any decode(
48     const AnySerializer& serializer,
49     const std::type_info& typeinfo,
50     std::string_view data) {
51   folly::IOBuf buf(folly::IOBuf::WRAP_BUFFER, data.data(), data.size());
52   folly::io::Cursor cursor{&buf};
53   std::any result;
54   serializer.decode(typeinfo, cursor, result);
55   return result;
56 }
57 
TEST(AnySerializerTest,TypedSerializer)58 TEST(AnySerializerTest, TypedSerializer) {
59   FollyToStringSerializer<int> intCodec;
60   EXPECT_EQ(encode(intCodec, 1), "1");
61   EXPECT_EQ(decode<int>(intCodec, "1"), 1);
62 
63   AnySerializer& anyCodec(intCodec);
64   EXPECT_EQ(encode(anyCodec, 1), "1");
65   EXPECT_EQ(encode(anyCodec, std::any(1)), "1");
66   EXPECT_THROW(encode(anyCodec, 2.5), std::bad_any_cast);
67   EXPECT_THROW(encode(anyCodec, std::any(2.5)), std::bad_any_cast);
68 
69   EXPECT_EQ(decode<int>(anyCodec, "1"), 1);
70   EXPECT_EQ(std::any_cast<int>(decode(anyCodec, typeid(int), "1")), 1);
71 
72   EXPECT_THROW(decode<double>(anyCodec, "1.0"), std::bad_any_cast);
73   EXPECT_THROW(decode(anyCodec, typeid(double), "1.0"), std::bad_any_cast);
74 }
75 
TEST(SerializerTest,MultiSerializer)76 TEST(SerializerTest, MultiSerializer) {
77   MultiSerializer multiSerializer;
78   const AnySerializer& serializer = multiSerializer;
79 
80   THRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAll());
81 
82   // Can handle ints.
83   EXPECT_EQ(encode(serializer, 1), "1");
84   THRIFT_SCOPED_CHECK(multiSerializer.checkIntEnc());
85   EXPECT_EQ(decode<int>(serializer, "1"), 1);
86   THRIFT_SCOPED_CHECK(multiSerializer.checkIntDec());
87 
88   // Can handle std::any(int).
89   std::any a = decode(serializer, typeid(int), "1");
90   THRIFT_SCOPED_CHECK(multiSerializer.checkAnyIntDec());
91   EXPECT_EQ(std::any_cast<int>(a), 1);
92   EXPECT_EQ(encode(serializer, a), "1");
93   THRIFT_SCOPED_CHECK(multiSerializer.checkIntEnc());
94 
95   // Can handle doubles.
96   EXPECT_EQ(encode(serializer, 2.5), "2.5");
97   THRIFT_SCOPED_CHECK(multiSerializer.checkDblEnc());
98   EXPECT_EQ(decode<double>(serializer, "0.5"), 0.5f);
99   THRIFT_SCOPED_CHECK(multiSerializer.checkDblDec());
100 
101   // Can handle std::any(double).
102   a = decode(serializer, typeid(double), "1");
103   THRIFT_SCOPED_CHECK(multiSerializer.checkAnyDblDec());
104   EXPECT_EQ(std::any_cast<double>(a), 1.0);
105   EXPECT_EQ(encode(serializer, a), "1");
106   THRIFT_SCOPED_CHECK(multiSerializer.checkDblEnc());
107 
108   // Cannot handle float.
109   EXPECT_THROW(encode(serializer, 1.0f), std::bad_any_cast);
110   THRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAll());
111   EXPECT_THROW(decode<float>(serializer, "1"), std::bad_any_cast);
112   THRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAll());
113 
114   // Cannot handle std::any(float).
115   a = 1.0f;
116   EXPECT_THROW(decode(serializer, typeid(float), "1"), std::bad_any_cast);
117   THRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAny(1));
118   THRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAll());
119   EXPECT_THROW(encode(serializer, a), std::bad_any_cast);
120   THRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAll());
121 }
122 
123 } // namespace
124 } // namespace apache::thrift::conformance
125