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/Testing.h>
18 
19 #include <fmt/core.h>
20 #include <folly/lang/Exception.h>
21 #include <folly/portability/GTest.h>
22 #include <thrift/conformance/if/gen-cpp2/any_constants.h>
23 
24 namespace apache::thrift::conformance {
25 using type::getUniversalHashSize;
26 const Protocol Number1Serializer::kProtocol = Protocol(thriftType("Number1"));
27 const Protocol kFollyToStringProtocol = Protocol(thriftType("FollyToString"));
28 
thriftType(std::string_view type)29 std::string thriftType(std::string_view type) {
30   if (type.empty()) {
31     return {};
32   }
33   return fmt::format("facebook.com/thrift/{}", type);
34 }
35 
testThriftType(const std::string & shortName)36 ThriftTypeInfo testThriftType(const std::string& shortName) {
37   return testThriftType({shortName.c_str()});
38 }
39 
testThriftType(std::initializer_list<const char * > uris)40 ThriftTypeInfo testThriftType(std::initializer_list<const char*> uris) {
41   ThriftTypeInfo type;
42   type.set_typeHashBytes(0);
43   auto itr = uris.begin();
44   if (itr != uris.end()) {
45     type.set_uri(thriftType(*itr++));
46   }
47   while (itr != uris.end()) {
48     type.altUris_ref()->emplace(thriftType(*itr++));
49   }
50   return type;
51 }
52 
toString(const folly::IOBuf & buf)53 std::string toString(const folly::IOBuf& buf) {
54   std::string result;
55   folly::IOBufQueue queue;
56   queue.append(buf);
57   queue.appendToString(result);
58   return result;
59 }
60 
encode(any_ref value,folly::io::QueueAppender && appender) const61 void MultiSerializer::encode(
62     any_ref value, folly::io::QueueAppender&& appender) const {
63   if (value.type() == typeid(int)) {
64     ++intEncCount;
65     FollyToStringSerializer<int>().encode(value, std::move(appender));
66   } else if (value.type() == typeid(double)) {
67     ++dblEncCount;
68     FollyToStringSerializer<double>().encode(value, std::move(appender));
69   } else {
70     folly::throw_exception<std::bad_any_cast>();
71   }
72 }
73 
shortThriftType(int ordinal)74 ThriftTypeInfo shortThriftType(int ordinal) {
75   ThriftTypeInfo type;
76   type.set_uri(fmt::format("s.r/t/{}", ordinal));
77   assert(type.get_uri().size() <= kMinTypeHashBytes);
78   return type;
79 }
80 
longThriftType(int ordinal)81 ThriftTypeInfo longThriftType(int ordinal) {
82   ThriftTypeInfo type;
83   type.set_uri(
84       fmt::format("seriously.long.type/seriously/long/type/{}", ordinal));
85   assert(
86       type.get_uri().size() >
87       size_t(getUniversalHashSize(type::UniversalHashAlgorithm::Sha2_256)));
88   return type;
89 }
90 
decode(const std::type_info & typeInfo,folly::io::Cursor & cursor,any_ref value) const91 void MultiSerializer::decode(
92     const std::type_info& typeInfo,
93     folly::io::Cursor& cursor,
94     any_ref value) const {
95   if (value.type() == typeid(std::any)) {
96     // It is being decoded into an any.
97     ++anyDecCount;
98   }
99   if (typeInfo == typeid(int)) {
100     ++intDecCount;
101     FollyToStringSerializer<int>().decode(typeInfo, cursor, value);
102   } else if (typeInfo == typeid(double)) {
103     ++dblDecCount;
104     FollyToStringSerializer<double>().decode(typeInfo, cursor, value);
105   } else {
106     folly::throw_exception<std::bad_any_cast>();
107   }
108 }
109 
checkAndResetInt(size_t enc,size_t dec) const110 void MultiSerializer::checkAndResetInt(size_t enc, size_t dec) const {
111   EXPECT_EQ(intEncCount, enc);
112   EXPECT_EQ(intDecCount, dec);
113   intEncCount = 0;
114   intDecCount = 0;
115 }
checkAndResetDbl(size_t enc,size_t dec) const116 void MultiSerializer::checkAndResetDbl(size_t enc, size_t dec) const {
117   EXPECT_EQ(dblEncCount, enc);
118   EXPECT_EQ(dblDecCount, dec);
119   dblEncCount = 0;
120   dblDecCount = 0;
121 }
checkAndResetAny(size_t dec) const122 void MultiSerializer::checkAndResetAny(size_t dec) const {
123   EXPECT_EQ(anyDecCount, dec);
124   anyDecCount = 0;
125 }
checkAndResetAll() const126 void MultiSerializer::checkAndResetAll() const {
127   checkAndResetInt(0, 0);
128   checkAndResetDbl(0, 0);
129   checkAndResetAny(0);
130 }
checkAnyDec() const131 void MultiSerializer::checkAnyDec() const {
132   checkAndResetAny(1);
133   checkAndResetAll();
134 }
checkIntEnc() const135 void MultiSerializer::checkIntEnc() const {
136   checkAndResetInt(1, 0);
137   checkAndResetAll();
138 }
checkIntDec() const139 void MultiSerializer::checkIntDec() const {
140   checkAndResetInt(0, 1);
141   checkAndResetAll();
142 }
checkDblEnc() const143 void MultiSerializer::checkDblEnc() const {
144   checkAndResetDbl(1, 0);
145   checkAndResetAll();
146 }
checkDblDec() const147 void MultiSerializer::checkDblDec() const {
148   checkAndResetDbl(0, 1);
149   checkAndResetAll();
150 }
checkAnyIntDec() const151 void MultiSerializer::checkAnyIntDec() const {
152   checkAndResetAny(1);
153   checkAndResetInt(0, 1);
154   checkAndResetAll();
155 }
checkAnyDblDec() const156 void MultiSerializer::checkAnyDblDec() const {
157   checkAndResetAny(1);
158   checkAndResetDbl(0, 1);
159   checkAndResetAll();
160 }
161 
162 } // namespace apache::thrift::conformance
163