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
23namespace art {
24
25namespace {
26template <typename TValue>
27struct FruitMapKey : VariantMapKey<TValue> {
28  FruitMapKey() {}
29};
30
31struct 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
44const FruitMap::Key<int> FruitMap::Apple;
45const FruitMap::Key<double> FruitMap::Orange;
46const FruitMap::Key<std::string> FruitMap::Label;
47}  // namespace
48
49TEST(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
81TEST(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
99TEST(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);
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
145TEST(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
159TEST(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
174TEST(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