/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include namespace apache::thrift::op { namespace { using namespace type; // Helpers for encoding/decoding using string. template std::string encode(const Serializer& serializer, T&& value) { folly::IOBufQueue queue(folly::IOBufQueue::cacheChainLength()); // Allocate 16KB at a time; leave some room for the IOBuf overhead constexpr size_t kDesiredGrowth = (1 << 14) - 64; serializer.encode( std::forward(value), folly::io::QueueAppender(&queue, kDesiredGrowth)); std::string result; queue.appendToString(result); return result; } template native_type decode(const Serializer& serializer, std::string_view data) { folly::IOBuf buf(folly::IOBuf::WRAP_BUFFER, data.data(), data.size()); folly::io::Cursor cursor{&buf}; return serializer.decode(cursor); } template native_type decodeViaAnyRef( const Serializer& serializer, std::string_view data) { folly::IOBuf buf(folly::IOBuf::WRAP_BUFFER, data.data(), data.size()); folly::io::Cursor cursor{&buf}; native_type value; serializer.decode(cursor, AnyRef(value)); return value; } AnyValue decode( const Serializer& serializer, const Type& type, std::string_view data) { folly::IOBuf buf(folly::IOBuf::WRAP_BUFFER, data.data(), data.size()); folly::io::Cursor cursor{&buf}; AnyValue result; serializer.decode(type, cursor, result); return result; } TEST(SerializerTest, TagSerializer) { test::FollyToStringSerializer intCodec; int i = 1; auto ri = Ref::to(i); EXPECT_EQ(encode(intCodec, ri), "1"); EXPECT_EQ(decode(intCodec, "1"), 1); double d = 2.5; auto rd = Ref::to(d); Serializer& anyCodec(intCodec); EXPECT_EQ(encode(anyCodec, ri), "1"); EXPECT_EQ(encode(anyCodec, AnyValue::create(2)), "2"); EXPECT_THROW(encode(anyCodec, rd), std::bad_any_cast); EXPECT_THROW( encode(anyCodec, AnyValue::create(2.5)), folly::BadPolyCast); EXPECT_EQ(decode(anyCodec, "1"), 1); EXPECT_EQ(decodeViaAnyRef(anyCodec, "1"), 1); EXPECT_EQ(decode(anyCodec, type::i32_t{}, "1").as(), 1); EXPECT_THROW(decode(anyCodec, "1.0"), std::bad_any_cast); EXPECT_THROW(decode(anyCodec, type::double_t{}, "1.0"), std::bad_any_cast); EXPECT_THROW( decodeViaAnyRef(anyCodec, "1.0"), std::bad_any_cast); } TEST(SerializerTest, MultiSerializer) { int i = 1; auto ri = Ref::to(i); test::MultiSerializer multiSerializer; const Serializer& serializer = multiSerializer; FBTHRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAll()); // Can handle int refs. EXPECT_EQ(encode(serializer, ri), "1"); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkIntEnc()); EXPECT_EQ(decode(serializer, "1"), 1); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkIntDec()); // Can handle int AnyValue. AnyValue any = decode(serializer, type::i32_t{}, "1"); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkAnyIntDec()); EXPECT_EQ(any.as(), 1); EXPECT_EQ(encode(serializer, any), "1"); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkIntEnc()); double d = 2.5; auto rd = Ref::to(d); // Can handle doubles. EXPECT_EQ(encode(serializer, rd), "2.5"); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkDblEnc()); EXPECT_EQ(decode(serializer, "0.5"), 0.5); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkDblDec()); // Can handle double AnyValue. any = decode(serializer, type::double_t{}, "1"); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkAnyDblDec()); EXPECT_EQ(any.as(), 1.0); EXPECT_EQ(encode(serializer, any), "1"); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkDblEnc()); // Cannot handle float. float f = 1.5f; auto rf = Ref::to(f); EXPECT_THROW(encode(serializer, rf), std::bad_any_cast); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAll()); EXPECT_THROW(decode(serializer, "1"), std::bad_any_cast); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAll()); // Cannot handle std::any(float). any = AnyValue::create(1.5f); EXPECT_THROW(decode(serializer, type::float_t{}, "1"), std::bad_any_cast); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAny(1)); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAll()); EXPECT_THROW(encode(serializer, any), std::bad_any_cast); FBTHRIFT_SCOPED_CHECK(multiSerializer.checkAndResetAll()); } } // namespace } // namespace apache::thrift::op