1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "variant_map.h"
18 #include "gtest/gtest.h"
19 
20 #define EXPECT_NULL(expected) EXPECT_EQ(reinterpret_cast<const void*>(expected), \
21                                         static_cast<void*>(nullptr));
22 
23 namespace art {
24 
25 namespace {
26 template <typename TValue>
27 struct FruitMapKey : VariantMapKey<TValue> {
FruitMapKeyart::__anon08c9e08c0111::FruitMapKey28   FruitMapKey() {}
29 };
30 
31 struct FruitMap : VariantMap<FruitMap, FruitMapKey> {
32   // This 'using' line is necessary to inherit the variadic constructor.
33   using VariantMap<FruitMap, FruitMapKey>::VariantMap;
34 
35   // Make the next '4' usages of Key slightly shorter to type.
36   template <typename TValue>
37   using Key = FruitMapKey<TValue>;
38 
39   static const Key<int> Apple;
40   static const Key<double> Orange;
41   static const Key<std::string> Label;
42 };
43 
44 const FruitMap::Key<int> FruitMap::Apple;
45 const FruitMap::Key<double> FruitMap::Orange;
46 const FruitMap::Key<std::string> FruitMap::Label;
47 }  // namespace
48 
TEST(VariantMaps,BasicReadWrite)49 TEST(VariantMaps, BasicReadWrite) {
50   FruitMap fm;
51 
52   EXPECT_NULL(fm.Get(FruitMap::Apple));
53   EXPECT_FALSE(fm.Exists(FruitMap::Apple));
54   EXPECT_NULL(fm.Get(FruitMap::Orange));
55   EXPECT_FALSE(fm.Exists(FruitMap::Orange));
56 
57   fm.Set(FruitMap::Apple, 1);
58   EXPECT_NULL(fm.Get(FruitMap::Orange));
59   EXPECT_EQ(1, *fm.Get(FruitMap::Apple));
60   EXPECT_TRUE(fm.Exists(FruitMap::Apple));
61 
62   fm.Set(FruitMap::Apple, 5);
63   EXPECT_NULL(fm.Get(FruitMap::Orange));
64   EXPECT_EQ(5, *fm.Get(FruitMap::Apple));
65   EXPECT_TRUE(fm.Exists(FruitMap::Apple));
66 
67   fm.Set(FruitMap::Orange, 555.0);
68   EXPECT_EQ(5, *fm.Get(FruitMap::Apple));
69   EXPECT_DOUBLE_EQ(555.0, *fm.Get(FruitMap::Orange));
70   EXPECT_EQ(size_t(2), fm.Size());
71 
72   // Simple remove
73   fm.Remove(FruitMap::Apple);
74   EXPECT_FALSE(fm.Exists(FruitMap::Apple));
75 
76   fm.Clear();
77   EXPECT_EQ(size_t(0), fm.Size());
78   EXPECT_FALSE(fm.Exists(FruitMap::Orange));
79 }
80 
TEST(VariantMaps,SetPreviousValue)81 TEST(VariantMaps, SetPreviousValue) {
82   FruitMap fm;
83 
84   // Indirect remove by setting yourself again
85   fm.Set(FruitMap::Label, std::string("hello_world"));
86   auto* ptr = fm.Get(FruitMap::Label);
87   ASSERT_TRUE(ptr != nullptr);
88   *ptr = "foobar";
89 
90   // Set the value to the same exact pointer which we got out of the map.
91   // This should cleanly 'just work' and not try to delete the value too early.
92   fm.Set(FruitMap::Label, *ptr);
93 
94   auto* new_ptr = fm.Get(FruitMap::Label);
95   ASSERT_TRUE(ptr != nullptr);
96   EXPECT_EQ(std::string("foobar"), *new_ptr);
97 }
98 
TEST(VariantMaps,RuleOfFive)99 TEST(VariantMaps, RuleOfFive) {
100   // Test empty constructor
101   FruitMap fmEmpty;
102   EXPECT_EQ(size_t(0), fmEmpty.Size());
103 
104   // Test empty constructor
105   FruitMap fmFilled;
106   fmFilled.Set(FruitMap::Apple, 1);
107   fmFilled.Set(FruitMap::Orange, 555.0);
108   EXPECT_EQ(size_t(2), fmFilled.Size());
109 
110   // Test copy constructor
111   FruitMap fmEmptyCopy(fmEmpty);  // NOLINT
112   EXPECT_EQ(size_t(0), fmEmptyCopy.Size());
113 
114   // Test copy constructor
115   FruitMap fmFilledCopy(fmFilled);
116   EXPECT_EQ(size_t(2), fmFilledCopy.Size());
117   EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmFilledCopy.Get(FruitMap::Apple));
118   EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmFilledCopy.Get(FruitMap::Orange));
119 
120   // Test operator=
121   FruitMap fmFilledCopy2;
122   fmFilledCopy2 = fmFilled;
123   EXPECT_EQ(size_t(2), fmFilledCopy2.Size());
124   EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmFilledCopy2.Get(FruitMap::Apple));
125   EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmFilledCopy2.Get(FruitMap::Orange));
126 
127   // Test move constructor
128   FruitMap fmMoved(std::move(fmFilledCopy));
129   EXPECT_EQ(size_t(0), fmFilledCopy.Size());
130   EXPECT_EQ(size_t(2), fmMoved.Size());
131   EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmMoved.Get(FruitMap::Apple));
132   EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmMoved.Get(FruitMap::Orange));
133 
134   // Test operator= move
135   FruitMap fmMoved2;
136   fmMoved2.Set(FruitMap::Apple, 12345);  // This value will be clobbered after the move
137 
138   fmMoved2 = std::move(fmFilledCopy2);
139   EXPECT_EQ(size_t(0), fmFilledCopy2.Size());
140   EXPECT_EQ(size_t(2), fmMoved2.Size());
141   EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmMoved2.Get(FruitMap::Apple));
142   EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmMoved2.Get(FruitMap::Orange));
143 }
144 
TEST(VariantMaps,VariadicConstructors)145 TEST(VariantMaps, VariadicConstructors) {
146   // Variadic constructor, 1 kv/pair
147   FruitMap fmApple(FruitMap::Apple, 12345);
148   EXPECT_EQ(size_t(1), fmApple.Size());
149   EXPECT_EQ(12345, *fmApple.Get(FruitMap::Apple));
150 
151   // Variadic constructor, 2 kv/pair
152   FruitMap fmAppleAndOrange(FruitMap::Apple,   12345,
153                             FruitMap::Orange,  100.0);
154   EXPECT_EQ(size_t(2), fmAppleAndOrange.Size());
155   EXPECT_EQ(12345, *fmAppleAndOrange.Get(FruitMap::Apple));
156   EXPECT_DOUBLE_EQ(100.0, *fmAppleAndOrange.Get(FruitMap::Orange));
157 }
158 
TEST(VariantMaps,ReleaseOrDefault)159 TEST(VariantMaps, ReleaseOrDefault) {
160   FruitMap fmAppleAndOrange(FruitMap::Apple,   12345,
161                             FruitMap::Orange,  100.0);
162 
163   int apple = fmAppleAndOrange.ReleaseOrDefault(FruitMap::Apple);
164   EXPECT_EQ(12345, apple);
165 
166   // Releasing will also remove the Apple key.
167   EXPECT_EQ(size_t(1), fmAppleAndOrange.Size());
168 
169   // Releasing again yields a default value.
170   int apple2 = fmAppleAndOrange.ReleaseOrDefault(FruitMap::Apple);
171   EXPECT_EQ(0, apple2);
172 }
173 
TEST(VariantMaps,GetOrDefault)174 TEST(VariantMaps, GetOrDefault) {
175   FruitMap fm(FruitMap::Apple,   12345);
176 
177   // Apple gives the expected value we set.
178   int apple = fm.GetOrDefault(FruitMap::Apple);
179   EXPECT_EQ(12345, apple);
180 
181   // Map is still 1.
182   EXPECT_EQ(size_t(1), fm.Size());
183 
184   // Orange gives back a default value, since it's not in the map.
185   double orange = fm.GetOrDefault(FruitMap::Orange);
186   EXPECT_DOUBLE_EQ(0.0, orange);
187 }
188 
189 }  // namespace art
190