/* * 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 #include namespace apache::thrift::op { namespace { using conformance::data::ValueGenerator; using test::IsEmpty; using test::IsEqualTo; using test::IsIdenticalTo; using ::testing::Not; // A test suite that check ops work correctly for a given test case. template class TypedOpTest : public testing::Test {}; // Helpers for defining test cases. template > struct BaseTestCase { using type_tag = Tag; using type = T; }; template > struct BaseDefaultTestCase : BaseTestCase { const static inline T default_ = {}; }; template > struct NumericTestCase : BaseDefaultTestCase { constexpr static T one = 1; constexpr static T otherOne = 1; constexpr static std::array many = {2, static_cast(-4)}; }; template > struct StringTestCase : BaseTestCase { const static inline T default_ = StringTraits::fromStringLiteral(""); const static inline T one = StringTraits::fromStringLiteral("one"); const static inline T otherOne = StringTraits::fromStringLiteral("one"); const static inline std::array many = { StringTraits::fromStringLiteral("two"), StringTraits::fromStringLiteral("three")}; }; template < typename VTagCase, typename T = type::standard_type>> struct ListTestCase : BaseDefaultTestCase, T> { const static inline T one = {VTagCase::many.begin(), VTagCase::many.end()}; const static inline T otherOne = { VTagCase::many.begin(), VTagCase::many.end()}; const static inline std::array many = { T{VTagCase::many.rbegin(), VTagCase::many.rend()}, T{VTagCase::one}, T{VTagCase::default_}, }; }; template < typename KTagCase, typename T = type::standard_type>> struct SetTestCase : BaseDefaultTestCase, T> { const static inline T one = {KTagCase::many.begin(), KTagCase::many.end()}; const static inline T otherOne = { KTagCase::many.rbegin(), KTagCase::many.rend()}; const static inline std::array many = { T{KTagCase::default_}, T{KTagCase::default_, KTagCase::one}, T{KTagCase::one}, }; }; template using map_type_tag = type::map; template < typename KTagCase, typename VTagCase, typename T = type::standard_type>> struct MapTestCase : BaseDefaultTestCase, T> { const static inline T one = { {KTagCase::one, VTagCase::one}, {KTagCase::default_, VTagCase::one}}; const static inline T otherOne = { {KTagCase::default_, VTagCase::one}, {KTagCase::one, VTagCase::one}}; const static inline std::array many = { T{{KTagCase::one, VTagCase::one}}, T{{KTagCase::default_, VTagCase::one}}, T{{KTagCase::one, VTagCase::default_}}, }; }; // The tests cases to run. using OpTestCases = ::testing::Types< NumericTestCase, NumericTestCase, // TODO(dokwon): Add support to cpp_type // NumericTestCase, NumericTestCase, // TODO(dokwon): Add support to cpp_type // NumericTestCase, NumericTestCase, // TODO(dokwon): Add support to cpp_type // NumericTestCase, NumericTestCase, NumericTestCase, StringTestCase, // TODO(dokwon): Add support to cpp_type // StringTestCase, StringTestCase, // TODO(afuller): Fix 'copyability' for this type, so we can test this case. // StringTestCase>, ListTestCase>, ListTestCase>, // TODO(afuller): Consider supporting non-default standard types in // the paramaterized types, for these tests. // ListTestCase>, SetTestCase>, MapTestCase, NumericTestCase>>; TYPED_TEST_SUITE(TypedOpTest, OpTestCases); TYPED_TEST(TypedOpTest, Equal) { using Tag = typename TypeParam::type_tag; EXPECT_THAT(TypeParam::default_, IsEqualTo(TypeParam::default_)); EXPECT_THAT(TypeParam::one, IsEqualTo(TypeParam::one)); EXPECT_THAT(TypeParam::one, IsEqualTo(TypeParam::otherOne)); EXPECT_THAT(TypeParam::default_, Not(IsEqualTo(TypeParam::one))); EXPECT_THAT(TypeParam::one, Not(IsEqualTo(TypeParam::default_))); for (const auto& other : TypeParam::many) { EXPECT_THAT(TypeParam::one, Not(IsEqualTo(other))); EXPECT_THAT(other, Not(IsEqualTo(TypeParam::one))); } } TYPED_TEST(TypedOpTest, Empty) { using Tag = typename TypeParam::type_tag; EXPECT_THAT(TypeParam::default_, IsEmpty()); EXPECT_THAT(TypeParam::one, Not(IsEmpty())); for (const auto& other : TypeParam::many) { EXPECT_THAT(other, Not(IsEmpty())); } } TYPED_TEST(TypedOpTest, Clear) { using T = typename TypeParam::type; using Tag = typename TypeParam::type_tag; T value = TypeParam::one; EXPECT_THAT(value, Not(IsEmpty())); EXPECT_THAT(value, Not(IsIdenticalTo(TypeParam::default_))); EXPECT_THAT(value, IsIdenticalTo(TypeParam::one)); clear(value); EXPECT_THAT(value, IsEmpty()); EXPECT_THAT(value, IsIdenticalTo(TypeParam::default_)); EXPECT_THAT(value, Not(IsIdenticalTo(TypeParam::one))); } TYPED_TEST(TypedOpTest, Hash) { using Tag = typename TypeParam::type_tag; EXPECT_NE(op::hash(TypeParam::default_), op::hash(TypeParam::one)); } TYPED_TEST(TypedOpTest, HashQuality) { using Tag = typename TypeParam::type_tag; std::set seen; // All the 'interesting' key values should not collide. for (const auto& val : ValueGenerator::getKeyValues()) { EXPECT_TRUE(seen.insert(op::hash(val.value)).second) << val.name; } } } // namespace } // namespace apache::thrift::op