| // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <algorithm> |
| #include <functional> |
| #include <string> |
| #include <vector> |
| |
| #include <chromeos/any.h> |
| #include <gtest/gtest.h> |
| |
| using chromeos::Any; |
| |
| TEST(Any, Empty) { |
| Any val; |
| EXPECT_TRUE(val.IsEmpty()); |
| |
| Any val2 = val; |
| EXPECT_TRUE(val.IsEmpty()); |
| EXPECT_TRUE(val2.IsEmpty()); |
| |
| Any val3 = std::move(val); |
| EXPECT_TRUE(val.IsEmpty()); |
| EXPECT_TRUE(val3.IsEmpty()); |
| } |
| |
| TEST(Any, SimpleTypes) { |
| Any val(20); |
| EXPECT_FALSE(val.IsEmpty()); |
| EXPECT_TRUE(val.IsTypeCompatible<int>()); |
| EXPECT_EQ(20, val.Get<int>()); |
| |
| Any val2(3.1415926); |
| EXPECT_FALSE(val2.IsEmpty()); |
| EXPECT_TRUE(val2.IsTypeCompatible<double>()); |
| EXPECT_FALSE(val2.IsTypeCompatible<int>()); |
| EXPECT_DOUBLE_EQ(3.1415926, val2.Get<double>()); |
| |
| Any val3(std::string("blah")); |
| EXPECT_TRUE(val3.IsTypeCompatible<std::string>()); |
| EXPECT_EQ("blah", val3.Get<std::string>()); |
| } |
| |
| TEST(Any, Clear) { |
| Any val('x'); |
| EXPECT_FALSE(val.IsEmpty()); |
| EXPECT_EQ('x', val.Get<char>()); |
| |
| val.Clear(); |
| EXPECT_TRUE(val.IsEmpty()); |
| } |
| |
| TEST(Any, Assignments) { |
| Any val(20); |
| EXPECT_EQ(20, val.Get<int>()); |
| |
| val = 3.1415926; |
| EXPECT_FALSE(val.IsEmpty()); |
| EXPECT_TRUE(val.IsTypeCompatible<double>()); |
| EXPECT_DOUBLE_EQ(3.1415926, val.Get<double>()); |
| |
| val = std::string("blah"); |
| EXPECT_EQ("blah", val.Get<std::string>()); |
| |
| Any val2; |
| EXPECT_TRUE(val2.IsEmpty()); |
| val2 = val; |
| EXPECT_FALSE(val.IsEmpty()); |
| EXPECT_FALSE(val2.IsEmpty()); |
| EXPECT_EQ("blah", val.Get<std::string>()); |
| EXPECT_EQ("blah", val2.Get<std::string>()); |
| val.Clear(); |
| EXPECT_TRUE(val.IsEmpty()); |
| EXPECT_EQ("blah", val2.Get<std::string>()); |
| val2.Clear(); |
| EXPECT_TRUE(val2.IsEmpty()); |
| |
| val = std::vector<int>{100, 20, 3}; |
| auto v = val.Get<std::vector<int>>(); |
| EXPECT_EQ(100, v[0]); |
| EXPECT_EQ(20, v[1]); |
| EXPECT_EQ(3, v[2]); |
| |
| val2 = std::move(val); |
| EXPECT_TRUE(val.IsEmpty()); |
| EXPECT_TRUE(val2.IsTypeCompatible<std::vector<int>>()); |
| EXPECT_EQ(3, val2.Get<std::vector<int>>().size()); |
| |
| val = val2; |
| EXPECT_TRUE(val.IsTypeCompatible<std::vector<int>>()); |
| EXPECT_TRUE(val2.IsTypeCompatible<std::vector<int>>()); |
| EXPECT_EQ(3, val.Get<std::vector<int>>().size()); |
| EXPECT_EQ(3, val2.Get<std::vector<int>>().size()); |
| } |
| |
| TEST(Any, Enums) { |
| enum class Dummy { foo, bar, baz }; |
| Any val(Dummy::bar); |
| EXPECT_FALSE(val.IsEmpty()); |
| EXPECT_TRUE(val.IsConvertibleToInteger()); |
| EXPECT_EQ(Dummy::bar, val.Get<Dummy>()); |
| EXPECT_EQ(1, val.GetAsInteger()); |
| |
| val = Dummy::baz; |
| EXPECT_EQ(2, val.GetAsInteger()); |
| |
| val = Dummy::foo; |
| EXPECT_EQ(0, val.GetAsInteger()); |
| } |
| |
| TEST(Any, Integers) { |
| Any val(14); |
| EXPECT_TRUE(val.IsConvertibleToInteger()); |
| EXPECT_EQ(14, val.Get<int>()); |
| EXPECT_EQ(14, val.GetAsInteger()); |
| |
| val = '\x40'; |
| EXPECT_TRUE(val.IsConvertibleToInteger()); |
| EXPECT_EQ(64, val.Get<char>()); |
| EXPECT_EQ(64, val.GetAsInteger()); |
| |
| val = static_cast<uint16_t>(65535); |
| EXPECT_TRUE(val.IsConvertibleToInteger()); |
| EXPECT_EQ(65535, val.Get<uint16_t>()); |
| EXPECT_EQ(65535, val.GetAsInteger()); |
| |
| val = static_cast<uint64_t>(0xFFFFFFFFFFFFFFFFULL); |
| EXPECT_TRUE(val.IsConvertibleToInteger()); |
| EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, val.Get<uint64_t>()); |
| EXPECT_EQ(-1, val.GetAsInteger()); |
| |
| val = "abc"; |
| EXPECT_FALSE(val.IsConvertibleToInteger()); |
| |
| int a = 5; |
| val = &a; |
| EXPECT_FALSE(val.IsConvertibleToInteger()); |
| } |
| |
| TEST(Any, Pointers) { |
| Any val("abc"); // const char* |
| EXPECT_FALSE(val.IsTypeCompatible<char*>()); |
| EXPECT_TRUE(val.IsTypeCompatible<const char*>()); |
| EXPECT_FALSE(val.IsTypeCompatible<volatile char*>()); |
| EXPECT_TRUE(val.IsTypeCompatible<volatile const char*>()); |
| EXPECT_STREQ("abc", val.Get<const char*>()); |
| |
| int a = 10; |
| val = &a; |
| EXPECT_TRUE(val.IsTypeCompatible<int*>()); |
| EXPECT_TRUE(val.IsTypeCompatible<const int*>()); |
| EXPECT_TRUE(val.IsTypeCompatible<volatile int*>()); |
| EXPECT_TRUE(val.IsTypeCompatible<volatile const int*>()); |
| EXPECT_EQ(10, *val.Get<const int*>()); |
| *val.Get<int*>() = 3; |
| EXPECT_EQ(3, a); |
| } |
| |
| TEST(Any, Arrays) { |
| // The following test are here to validate the array-to-pointer decay rules. |
| // Since Any does not store the contents of a C-style array, just a pointer |
| // to the data, putting array data into Any could be dangerous. |
| // Make sure the array's lifetime exceeds that of an Any containing the |
| // pointer to the array data. |
| // If you want to store the array with data, use corresponding value types |
| // such as std::vector or a struct containing C-style array as a member. |
| |
| int int_array[] = {1, 2, 3}; // int* |
| Any val = int_array; |
| EXPECT_TRUE(val.IsTypeCompatible<int*>()); |
| EXPECT_TRUE(val.IsTypeCompatible<const int*>()); |
| EXPECT_TRUE(val.IsTypeCompatible<int[]>()); |
| EXPECT_TRUE(val.IsTypeCompatible<const int[]>()); |
| EXPECT_EQ(3, val.Get<int*>()[2]); |
| |
| const int const_int_array[] = {10, 20, 30}; // const int* |
| val = const_int_array; |
| EXPECT_FALSE(val.IsTypeCompatible<int*>()); |
| EXPECT_TRUE(val.IsTypeCompatible<const int*>()); |
| EXPECT_FALSE(val.IsTypeCompatible<int[]>()); |
| EXPECT_TRUE(val.IsTypeCompatible<const int[]>()); |
| EXPECT_EQ(30, val.Get<const int*>()[2]); |
| } |
| |
| TEST(Any, References) { |
| // Passing references to object via Any might be error-prone or the |
| // semantics could be unfamiliar to other developers. In many cases, |
| // using pointers instead of references are more conventional and easier |
| // to understand. Even though the cases of passing references are quite |
| // explicit on both storing and retrieving ends, you might want to |
| // use pointers instead anyway. |
| |
| int a = 5; |
| Any val(std::ref(a)); // int& |
| EXPECT_EQ(5, val.Get<std::reference_wrapper<int>>().get()); |
| val.Get<std::reference_wrapper<int>>().get() = 7; |
| EXPECT_EQ(7, val.Get<std::reference_wrapper<int>>().get()); |
| EXPECT_EQ(7, a); |
| |
| Any val2(std::cref(a)); // const int& |
| EXPECT_EQ(7, val2.Get<std::reference_wrapper<const int>>().get()); |
| |
| a = 10; |
| EXPECT_EQ(10, val.Get<std::reference_wrapper<int>>().get()); |
| EXPECT_EQ(10, val2.Get<std::reference_wrapper<const int>>().get()); |
| } |
| |
| TEST(Any, CustomTypes) { |
| struct Person { |
| std::string name; |
| int age; |
| }; |
| Any val(Person{"Jack", 40}); |
| Any val2 = val; |
| EXPECT_EQ("Jack", val.Get<Person>().name); |
| val.GetPtr<Person>()->name = "Joe"; |
| val.GetPtr<Person>()->age /= 2; |
| EXPECT_EQ("Joe", val.Get<Person>().name); |
| EXPECT_EQ(20, val.Get<Person>().age); |
| EXPECT_EQ("Jack", val2.Get<Person>().name); |
| EXPECT_EQ(40, val2.Get<Person>().age); |
| } |
| |
| TEST(Any, Swap) { |
| Any val(12); |
| Any val2(2.7); |
| EXPECT_EQ(12, val.Get<int>()); |
| EXPECT_EQ(2.7, val2.Get<double>()); |
| |
| val.Swap(val2); |
| EXPECT_EQ(2.7, val.Get<double>()); |
| EXPECT_EQ(12, val2.Get<int>()); |
| |
| std::swap(val, val2); |
| EXPECT_EQ(12, val.Get<int>()); |
| EXPECT_EQ(2.7, val2.Get<double>()); |
| } |
| |
| TEST(Any, TypeMismatch) { |
| Any val(12); |
| EXPECT_DEATH(val.Get<double>(), |
| "Requesting value of type 'double' from variant containing " |
| "'int'"); |
| |
| val = std::string("123"); |
| EXPECT_DEATH(val.GetAsInteger(), |
| "Unable to convert value of type 'std::string' to integer"); |
| |
| Any empty; |
| EXPECT_DEATH(empty.GetAsInteger(), "Must not be called on an empty Any"); |
| } |
| |
| TEST(Any, TryGet) { |
| Any val(12); |
| Any empty; |
| EXPECT_EQ("dummy", val.TryGet<std::string>("dummy")); |
| EXPECT_EQ(12, val.TryGet<int>(17)); |
| EXPECT_EQ(17, empty.TryGet<int>(17)); |
| } |
| |
| TEST(Any, Compare_Int) { |
| Any int1{12}; |
| Any int2{12}; |
| Any int3{20}; |
| EXPECT_EQ(int1, int2); |
| EXPECT_NE(int2, int3); |
| } |
| |
| TEST(Any, Compare_String) { |
| Any str1{std::string{"foo"}}; |
| Any str2{std::string{"foo"}}; |
| Any str3{std::string{"bar"}}; |
| EXPECT_EQ(str1, str2); |
| EXPECT_NE(str2, str3); |
| } |
| |
| TEST(Any, Compare_Array) { |
| Any vec1{std::vector<int>{1, 2}}; |
| Any vec2{std::vector<int>{1, 2}}; |
| Any vec3{std::vector<int>{1, 2, 3}}; |
| EXPECT_EQ(vec1, vec2); |
| EXPECT_NE(vec2, vec3); |
| } |
| |
| TEST(Any, Compare_Empty) { |
| Any empty1; |
| Any empty2; |
| Any int1{1}; |
| EXPECT_EQ(empty1, empty2); |
| EXPECT_NE(int1, empty1); |
| EXPECT_NE(empty2, int1); |
| } |
| |
| TEST(Any, Compare_NonComparable) { |
| struct Person { |
| std::string name; |
| int age; |
| }; |
| Any person1(Person{"Jack", 40}); |
| Any person2 = person1; |
| Any person3(Person{"Jill", 20}); |
| EXPECT_NE(person1, person2); |
| EXPECT_NE(person1, person3); |
| EXPECT_NE(person2, person3); |
| } |