|  | // 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 <gtest/gtest.h> | 
|  |  | 
|  | #include "buffet/any.h" | 
|  |  | 
|  | using buffet::Any; | 
|  |  | 
|  | TEST(Any, Empty) { | 
|  | Any val; | 
|  | EXPECT_TRUE(val.IsEmpty()); | 
|  |  | 
|  | Any val2 = val; | 
|  | EXPECT_TRUE(val.IsEmpty()); | 
|  | EXPECT_TRUE(val2.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]); | 
|  | } | 
|  |  | 
|  | 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 \\w+ from variant containing \\w+"); | 
|  |  | 
|  | val = std::string("123"); | 
|  | EXPECT_DEATH(val.GetAsInteger(), | 
|  | "Unable to convert value of type \\w+ 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)); | 
|  | } |