// Copyright 2019 Google LLC // // 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 // // https://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 "dap/any.h" #include "dap/typeof.h" #include "dap/types.h" #include "gmock/gmock.h" #include "gtest/gtest.h" namespace dap { struct AnyTestObject { dap::integer i; dap::number n; }; DAP_STRUCT_TYPEINFO(AnyTestObject, "AnyTestObject", DAP_FIELD(i, "i"), DAP_FIELD(n, "n")); inline bool operator==(const AnyTestObject& a, const AnyTestObject& b) { return a.i == b.i && a.n == b.n; } } // namespace dap namespace { template struct TestValue {}; template <> struct TestValue { static const dap::null value; }; template <> struct TestValue { static const dap::integer value; }; template <> struct TestValue { static const dap::boolean value; }; template <> struct TestValue { static const dap::number value; }; template <> struct TestValue { static const dap::string value; }; template <> struct TestValue> { static const dap::array value; }; template <> struct TestValue { static const dap::AnyTestObject value; }; const dap::null TestValue::value = nullptr; const dap::integer TestValue::value = 20; const dap::boolean TestValue::value = true; const dap::number TestValue::value = 123.45; const dap::string TestValue::value = "hello world"; const dap::array TestValue>::value = { "one", "two", "three"}; const dap::AnyTestObject TestValue::value = {10, 20.30}; } // namespace TEST(Any, EmptyConstruct) { dap::any any; ASSERT_TRUE(any.is()); ASSERT_FALSE(any.is()); ASSERT_FALSE(any.is()); ASSERT_FALSE(any.is()); ASSERT_FALSE(any.is()); ASSERT_FALSE(any.is()); ASSERT_FALSE(any.is>()); ASSERT_FALSE(any.is()); } TEST(Any, Boolean) { dap::any any(dap::boolean(true)); ASSERT_TRUE(any.is()); ASSERT_EQ(any.get(), dap::boolean(true)); } TEST(Any, Integer) { dap::any any(dap::integer(10)); ASSERT_TRUE(any.is()); ASSERT_EQ(any.get(), dap::integer(10)); } TEST(Any, Number) { dap::any any(dap::number(123.0f)); ASSERT_TRUE(any.is()); ASSERT_EQ(any.get(), dap::number(123.0f)); } TEST(Any, String) { dap::any any(dap::string("hello world")); ASSERT_TRUE(any.is()); ASSERT_EQ(any.get(), dap::string("hello world")); } TEST(Any, Array) { using array = dap::array; dap::any any(array({10, 20, 30})); ASSERT_TRUE(any.is()); ASSERT_EQ(any.get(), array({10, 20, 30})); } TEST(Any, Object) { dap::object o; o["one"] = dap::integer(1); o["two"] = dap::integer(2); o["three"] = dap::integer(3); dap::any any(o); ASSERT_TRUE(any.is()); if (any.is()) { auto got = any.get(); ASSERT_EQ(got.size(), 3U); ASSERT_EQ(got.count("one"), 1U); ASSERT_EQ(got.count("two"), 1U); ASSERT_EQ(got.count("three"), 1U); ASSERT_TRUE(got["one"].is()); ASSERT_TRUE(got["two"].is()); ASSERT_TRUE(got["three"].is()); ASSERT_EQ(got["one"].get(), dap::integer(1)); ASSERT_EQ(got["two"].get(), dap::integer(2)); ASSERT_EQ(got["three"].get(), dap::integer(3)); } } TEST(Any, TestObject) { dap::any any(dap::AnyTestObject{5, 3.0}); ASSERT_TRUE(any.is()); ASSERT_EQ(any.get().i, 5); ASSERT_EQ(any.get().n, 3.0); } template class AnyT : public ::testing::Test { protected: template ::value && !std::is_same::value>> void check_val(const dap::any& any, const T0& expect) { ASSERT_EQ(any.is(), any.is()); ASSERT_EQ(any.get(), expect); } // Special case for Null assignment, as we can assign nullptr_t to any but // can't `get()` it template void check_val(const dap::any& any, const dap::null& expect) { ASSERT_EQ(nullptr, expect); ASSERT_TRUE(any.is()); } void check_type(const dap::any& any) { ASSERT_EQ(any.is(), (std::is_same::value)); ASSERT_EQ(any.is(), (std::is_same::value)); ASSERT_EQ(any.is(), (std::is_same::value)); ASSERT_EQ(any.is(), (std::is_same::value)); ASSERT_EQ(any.is(), (std::is_same::value)); ASSERT_EQ(any.is>(), (std::is_same>::value)); ASSERT_EQ(any.is(), (std::is_same::value)); } }; TYPED_TEST_SUITE_P(AnyT); TYPED_TEST_P(AnyT, CopyConstruct) { auto val = TestValue::value; dap::any any(val); this->check_type(any); this->check_val(any, val); } TYPED_TEST_P(AnyT, MoveConstruct) { auto val = TestValue::value; dap::any any(std::move(val)); this->check_type(any); this->check_val(any, val); } TYPED_TEST_P(AnyT, Assign) { auto val = TestValue::value; dap::any any; any = val; this->check_type(any); this->check_val(any, val); } TYPED_TEST_P(AnyT, MoveAssign) { auto val = TestValue::value; dap::any any; any = std::move(val); this->check_type(any); this->check_val(any, val); } TYPED_TEST_P(AnyT, RepeatedAssign) { dap::string str = "hello world"; auto val = TestValue::value; dap::any any; any = str; any = val; this->check_type(any); this->check_val(any, val); } TYPED_TEST_P(AnyT, RepeatedMoveAssign) { dap::string str = "hello world"; auto val = TestValue::value; dap::any any; any = std::move(str); any = std::move(val); this->check_type(any); this->check_val(any, val); } REGISTER_TYPED_TEST_SUITE_P(AnyT, CopyConstruct, MoveConstruct, Assign, MoveAssign, RepeatedAssign, RepeatedMoveAssign); using AnyTypes = ::testing::Types, dap::AnyTestObject>; INSTANTIATE_TYPED_TEST_SUITE_P(T, AnyT, AnyTypes); TEST(Any, Reset) { dap::any any(dap::integer(10)); ASSERT_TRUE(any.is()); any.reset(); ASSERT_FALSE(any.is()); }