Alex Vakulenko | b6513a1 | 2014-05-05 17:23:40 -0700 | [diff] [blame] | 1 | // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include <algorithm> |
| 6 | #include <functional> |
| 7 | #include <string> |
| 8 | #include <vector> |
| 9 | |
| 10 | #include <gtest/gtest.h> |
| 11 | |
| 12 | #include "buffet/any.h" |
| 13 | |
| 14 | using buffet::Any; |
| 15 | |
| 16 | TEST(Any, Empty) { |
| 17 | Any val; |
| 18 | EXPECT_TRUE(val.IsEmpty()); |
| 19 | |
| 20 | Any val2 = val; |
| 21 | EXPECT_TRUE(val.IsEmpty()); |
| 22 | EXPECT_TRUE(val2.IsEmpty()); |
| 23 | } |
| 24 | |
| 25 | TEST(Any, SimpleTypes) { |
| 26 | Any val(20); |
| 27 | EXPECT_FALSE(val.IsEmpty()); |
| 28 | EXPECT_TRUE(val.IsTypeCompatible<int>()); |
| 29 | EXPECT_EQ(20, val.Get<int>()); |
| 30 | |
| 31 | Any val2(3.1415926); |
| 32 | EXPECT_FALSE(val2.IsEmpty()); |
| 33 | EXPECT_TRUE(val2.IsTypeCompatible<double>()); |
| 34 | EXPECT_FALSE(val2.IsTypeCompatible<int>()); |
| 35 | EXPECT_DOUBLE_EQ(3.1415926, val2.Get<double>()); |
| 36 | |
| 37 | Any val3(std::string("blah")); |
| 38 | EXPECT_TRUE(val3.IsTypeCompatible<std::string>()); |
| 39 | EXPECT_EQ("blah", val3.Get<std::string>()); |
| 40 | } |
| 41 | |
| 42 | TEST(Any, Clear) { |
| 43 | Any val('x'); |
| 44 | EXPECT_FALSE(val.IsEmpty()); |
| 45 | EXPECT_EQ('x', val.Get<char>()); |
| 46 | |
| 47 | val.Clear(); |
| 48 | EXPECT_TRUE(val.IsEmpty()); |
| 49 | } |
| 50 | |
| 51 | TEST(Any, Assignments) { |
| 52 | Any val(20); |
| 53 | EXPECT_EQ(20, val.Get<int>()); |
| 54 | |
| 55 | val = 3.1415926; |
| 56 | EXPECT_FALSE(val.IsEmpty()); |
| 57 | EXPECT_TRUE(val.IsTypeCompatible<double>()); |
| 58 | EXPECT_DOUBLE_EQ(3.1415926, val.Get<double>()); |
| 59 | |
| 60 | val = std::string("blah"); |
| 61 | EXPECT_EQ("blah", val.Get<std::string>()); |
| 62 | |
| 63 | Any val2; |
| 64 | EXPECT_TRUE(val2.IsEmpty()); |
| 65 | val2 = val; |
| 66 | EXPECT_FALSE(val.IsEmpty()); |
| 67 | EXPECT_FALSE(val2.IsEmpty()); |
| 68 | EXPECT_EQ("blah", val.Get<std::string>()); |
| 69 | EXPECT_EQ("blah", val2.Get<std::string>()); |
| 70 | val.Clear(); |
| 71 | EXPECT_TRUE(val.IsEmpty()); |
| 72 | EXPECT_EQ("blah", val2.Get<std::string>()); |
| 73 | val2.Clear(); |
| 74 | EXPECT_TRUE(val2.IsEmpty()); |
| 75 | |
Alex Vakulenko | a0424dd | 2014-06-13 16:10:17 -0700 | [diff] [blame] | 76 | val = std::vector<int>{100, 20, 3}; |
Alex Vakulenko | b6513a1 | 2014-05-05 17:23:40 -0700 | [diff] [blame] | 77 | auto v = val.Get<std::vector<int>>(); |
| 78 | EXPECT_EQ(100, v[0]); |
| 79 | EXPECT_EQ(20, v[1]); |
| 80 | EXPECT_EQ(3, v[2]); |
| 81 | } |
| 82 | |
| 83 | TEST(Any, Enums) { |
| 84 | enum class Dummy { foo, bar, baz }; |
| 85 | Any val(Dummy::bar); |
| 86 | EXPECT_FALSE(val.IsEmpty()); |
| 87 | EXPECT_TRUE(val.IsConvertibleToInteger()); |
| 88 | EXPECT_EQ(Dummy::bar, val.Get<Dummy>()); |
| 89 | EXPECT_EQ(1, val.GetAsInteger()); |
| 90 | |
| 91 | val = Dummy::baz; |
| 92 | EXPECT_EQ(2, val.GetAsInteger()); |
| 93 | |
| 94 | val = Dummy::foo; |
| 95 | EXPECT_EQ(0, val.GetAsInteger()); |
| 96 | } |
| 97 | |
| 98 | TEST(Any, Integers) { |
| 99 | Any val(14); |
| 100 | EXPECT_TRUE(val.IsConvertibleToInteger()); |
| 101 | EXPECT_EQ(14, val.Get<int>()); |
| 102 | EXPECT_EQ(14, val.GetAsInteger()); |
| 103 | |
| 104 | val = '\x40'; |
| 105 | EXPECT_TRUE(val.IsConvertibleToInteger()); |
| 106 | EXPECT_EQ(64, val.Get<char>()); |
| 107 | EXPECT_EQ(64, val.GetAsInteger()); |
| 108 | |
| 109 | val = static_cast<uint16_t>(65535); |
| 110 | EXPECT_TRUE(val.IsConvertibleToInteger()); |
| 111 | EXPECT_EQ(65535, val.Get<uint16_t>()); |
| 112 | EXPECT_EQ(65535, val.GetAsInteger()); |
| 113 | |
| 114 | val = static_cast<uint64_t>(0xFFFFFFFFFFFFFFFFULL); |
| 115 | EXPECT_TRUE(val.IsConvertibleToInteger()); |
| 116 | EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, val.Get<uint64_t>()); |
| 117 | EXPECT_EQ(-1, val.GetAsInteger()); |
| 118 | |
| 119 | val = "abc"; |
| 120 | EXPECT_FALSE(val.IsConvertibleToInteger()); |
| 121 | |
| 122 | int a = 5; |
| 123 | val = &a; |
| 124 | EXPECT_FALSE(val.IsConvertibleToInteger()); |
| 125 | } |
| 126 | |
| 127 | TEST(Any, Pointers) { |
| 128 | Any val("abc"); // const char* |
| 129 | EXPECT_FALSE(val.IsTypeCompatible<char*>()); |
| 130 | EXPECT_TRUE(val.IsTypeCompatible<const char*>()); |
| 131 | EXPECT_FALSE(val.IsTypeCompatible<volatile char*>()); |
| 132 | EXPECT_TRUE(val.IsTypeCompatible<volatile const char*>()); |
| 133 | EXPECT_STREQ("abc", val.Get<const char*>()); |
| 134 | |
| 135 | int a = 10; |
| 136 | val = &a; |
| 137 | EXPECT_TRUE(val.IsTypeCompatible<int*>()); |
| 138 | EXPECT_TRUE(val.IsTypeCompatible<const int*>()); |
| 139 | EXPECT_TRUE(val.IsTypeCompatible<volatile int*>()); |
| 140 | EXPECT_TRUE(val.IsTypeCompatible<volatile const int*>()); |
| 141 | EXPECT_EQ(10, *val.Get<const int*>()); |
| 142 | *val.Get<int*>() = 3; |
| 143 | EXPECT_EQ(3, a); |
| 144 | } |
| 145 | |
| 146 | TEST(Any, Arrays) { |
| 147 | // The following test are here to validate the array-to-pointer decay rules. |
| 148 | // Since Any does not store the contents of a C-style array, just a pointer |
| 149 | // to the data, putting array data into Any could be dangerous. |
| 150 | // Make sure the array's lifetime exceeds that of an Any containing the |
| 151 | // pointer to the array data. |
| 152 | // If you want to store the array with data, use corresponding value types |
| 153 | // such as std::vector or a struct containing C-style array as a member. |
| 154 | |
| 155 | int int_array[] = {1, 2, 3}; // int* |
| 156 | Any val = int_array; |
| 157 | EXPECT_TRUE(val.IsTypeCompatible<int*>()); |
| 158 | EXPECT_TRUE(val.IsTypeCompatible<const int*>()); |
| 159 | EXPECT_TRUE(val.IsTypeCompatible<int[]>()); |
| 160 | EXPECT_TRUE(val.IsTypeCompatible<const int[]>()); |
| 161 | EXPECT_EQ(3, val.Get<int*>()[2]); |
| 162 | |
| 163 | const int const_int_array[] = {10, 20, 30}; // const int* |
| 164 | val = const_int_array; |
| 165 | EXPECT_FALSE(val.IsTypeCompatible<int*>()); |
| 166 | EXPECT_TRUE(val.IsTypeCompatible<const int*>()); |
| 167 | EXPECT_FALSE(val.IsTypeCompatible<int[]>()); |
| 168 | EXPECT_TRUE(val.IsTypeCompatible<const int[]>()); |
| 169 | EXPECT_EQ(30, val.Get<const int*>()[2]); |
| 170 | } |
| 171 | |
| 172 | TEST(Any, References) { |
| 173 | // Passing references to object via Any might be error-prone or the |
| 174 | // semantics could be unfamiliar to other developers. In many cases, |
| 175 | // using pointers instead of references are more conventional and easier |
| 176 | // to understand. Even though the cases of passing references are quite |
| 177 | // explicit on both storing and retrieving ends, you might want to |
| 178 | // use pointers instead anyway. |
| 179 | |
| 180 | int a = 5; |
| 181 | Any val(std::ref(a)); // int& |
| 182 | EXPECT_EQ(5, val.Get<std::reference_wrapper<int>>().get()); |
| 183 | val.Get<std::reference_wrapper<int>>().get() = 7; |
| 184 | EXPECT_EQ(7, val.Get<std::reference_wrapper<int>>().get()); |
| 185 | EXPECT_EQ(7, a); |
| 186 | |
| 187 | Any val2(std::cref(a)); // const int& |
| 188 | EXPECT_EQ(7, val2.Get<std::reference_wrapper<const int>>().get()); |
| 189 | |
| 190 | a = 10; |
| 191 | EXPECT_EQ(10, val.Get<std::reference_wrapper<int>>().get()); |
| 192 | EXPECT_EQ(10, val2.Get<std::reference_wrapper<const int>>().get()); |
| 193 | } |
| 194 | |
| 195 | TEST(Any, CustomTypes) { |
| 196 | struct Person { |
| 197 | std::string name; |
| 198 | int age; |
| 199 | }; |
Alex Vakulenko | a0424dd | 2014-06-13 16:10:17 -0700 | [diff] [blame] | 200 | Any val(Person{"Jack", 40}); |
Alex Vakulenko | b6513a1 | 2014-05-05 17:23:40 -0700 | [diff] [blame] | 201 | Any val2 = val; |
| 202 | EXPECT_EQ("Jack", val.Get<Person>().name); |
| 203 | val.GetPtr<Person>()->name = "Joe"; |
| 204 | val.GetPtr<Person>()->age /= 2; |
| 205 | EXPECT_EQ("Joe", val.Get<Person>().name); |
| 206 | EXPECT_EQ(20, val.Get<Person>().age); |
| 207 | EXPECT_EQ("Jack", val2.Get<Person>().name); |
| 208 | EXPECT_EQ(40, val2.Get<Person>().age); |
| 209 | } |
| 210 | |
| 211 | TEST(Any, Swap) { |
| 212 | Any val(12); |
| 213 | Any val2(2.7); |
| 214 | EXPECT_EQ(12, val.Get<int>()); |
| 215 | EXPECT_EQ(2.7, val2.Get<double>()); |
| 216 | |
| 217 | val.Swap(val2); |
| 218 | EXPECT_EQ(2.7, val.Get<double>()); |
| 219 | EXPECT_EQ(12, val2.Get<int>()); |
| 220 | |
| 221 | std::swap(val, val2); |
| 222 | EXPECT_EQ(12, val.Get<int>()); |
| 223 | EXPECT_EQ(2.7, val2.Get<double>()); |
| 224 | } |
| 225 | |
| 226 | TEST(Any, TypeMismatch) { |
| 227 | Any val(12); |
| 228 | EXPECT_DEATH(val.Get<double>(), |
| 229 | "Requesting value of type \\w+ from variant containing \\w+"); |
| 230 | |
| 231 | val = std::string("123"); |
| 232 | EXPECT_DEATH(val.GetAsInteger(), |
| 233 | "Unable to convert value of type \\w+ to integer"); |
| 234 | |
| 235 | Any empty; |
| 236 | EXPECT_DEATH(empty.GetAsInteger(), "Must not be called on an empty Any"); |
| 237 | } |
| 238 | |
| 239 | TEST(Any, TryGet) { |
| 240 | Any val(12); |
| 241 | Any empty; |
| 242 | EXPECT_EQ("dummy", val.TryGet<std::string>("dummy")); |
| 243 | EXPECT_EQ(12, val.TryGet<int>(17)); |
| 244 | EXPECT_EQ(17, empty.TryGet<int>(17)); |
| 245 | } |