| /* | |
| * Copyright (C) 2015 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "variant_map.h" | |
| #include "gtest/gtest.h" | |
| #define EXPECT_NULL(expected) EXPECT_EQ(reinterpret_cast<const void*>(expected), \ | |
| static_cast<void*>(nullptr)); | |
| namespace art { | |
| namespace { | |
| template <typename TValue> | |
| struct FruitMapKey : VariantMapKey<TValue> { | |
| FruitMapKey() {} | |
| }; | |
| struct FruitMap : VariantMap<FruitMap, FruitMapKey> { | |
| // This 'using' line is necessary to inherit the variadic constructor. | |
| using VariantMap<FruitMap, FruitMapKey>::VariantMap; | |
| // Make the next '4' usages of Key slightly shorter to type. | |
| template <typename TValue> | |
| using Key = FruitMapKey<TValue>; | |
| static const Key<int> Apple; | |
| static const Key<double> Orange; | |
| static const Key<std::string> Label; | |
| }; | |
| const FruitMap::Key<int> FruitMap::Apple; | |
| const FruitMap::Key<double> FruitMap::Orange; | |
| const FruitMap::Key<std::string> FruitMap::Label; | |
| } // namespace | |
| TEST(VariantMaps, BasicReadWrite) { | |
| FruitMap fm; | |
| EXPECT_NULL(fm.Get(FruitMap::Apple)); | |
| EXPECT_FALSE(fm.Exists(FruitMap::Apple)); | |
| EXPECT_NULL(fm.Get(FruitMap::Orange)); | |
| EXPECT_FALSE(fm.Exists(FruitMap::Orange)); | |
| fm.Set(FruitMap::Apple, 1); | |
| EXPECT_NULL(fm.Get(FruitMap::Orange)); | |
| EXPECT_EQ(1, *fm.Get(FruitMap::Apple)); | |
| EXPECT_TRUE(fm.Exists(FruitMap::Apple)); | |
| fm.Set(FruitMap::Apple, 5); | |
| EXPECT_NULL(fm.Get(FruitMap::Orange)); | |
| EXPECT_EQ(5, *fm.Get(FruitMap::Apple)); | |
| EXPECT_TRUE(fm.Exists(FruitMap::Apple)); | |
| fm.Set(FruitMap::Orange, 555.0); | |
| EXPECT_EQ(5, *fm.Get(FruitMap::Apple)); | |
| EXPECT_DOUBLE_EQ(555.0, *fm.Get(FruitMap::Orange)); | |
| EXPECT_EQ(size_t(2), fm.Size()); | |
| // Simple remove | |
| fm.Remove(FruitMap::Apple); | |
| EXPECT_FALSE(fm.Exists(FruitMap::Apple)); | |
| fm.Clear(); | |
| EXPECT_EQ(size_t(0), fm.Size()); | |
| EXPECT_FALSE(fm.Exists(FruitMap::Orange)); | |
| } | |
| TEST(VariantMaps, SetPreviousValue) { | |
| FruitMap fm; | |
| // Indirect remove by setting yourself again | |
| fm.Set(FruitMap::Label, std::string("hello_world")); | |
| auto* ptr = fm.Get(FruitMap::Label); | |
| ASSERT_TRUE(ptr != nullptr); | |
| *ptr = "foobar"; | |
| // Set the value to the same exact pointer which we got out of the map. | |
| // This should cleanly 'just work' and not try to delete the value too early. | |
| fm.Set(FruitMap::Label, *ptr); | |
| auto* new_ptr = fm.Get(FruitMap::Label); | |
| ASSERT_TRUE(ptr != nullptr); | |
| EXPECT_EQ(std::string("foobar"), *new_ptr); | |
| } | |
| TEST(VariantMaps, RuleOfFive) { | |
| // Test empty constructor | |
| FruitMap fmEmpty; | |
| EXPECT_EQ(size_t(0), fmEmpty.Size()); | |
| // Test empty constructor | |
| FruitMap fmFilled; | |
| fmFilled.Set(FruitMap::Apple, 1); | |
| fmFilled.Set(FruitMap::Orange, 555.0); | |
| EXPECT_EQ(size_t(2), fmFilled.Size()); | |
| // Test copy constructor | |
| FruitMap fmEmptyCopy(fmEmpty); // NOLINT | |
| EXPECT_EQ(size_t(0), fmEmptyCopy.Size()); | |
| // Test copy constructor | |
| FruitMap fmFilledCopy(fmFilled); | |
| EXPECT_EQ(size_t(2), fmFilledCopy.Size()); | |
| EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmFilledCopy.Get(FruitMap::Apple)); | |
| EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmFilledCopy.Get(FruitMap::Orange)); | |
| // Test operator= | |
| FruitMap fmFilledCopy2; | |
| fmFilledCopy2 = fmFilled; | |
| EXPECT_EQ(size_t(2), fmFilledCopy2.Size()); | |
| EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmFilledCopy2.Get(FruitMap::Apple)); | |
| EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmFilledCopy2.Get(FruitMap::Orange)); | |
| // Test move constructor | |
| FruitMap fmMoved(std::move(fmFilledCopy)); | |
| // NOLINTNEXTLINE - checking underlying storage has been freed | |
| EXPECT_EQ(size_t(0), fmFilledCopy.Size()); | |
| EXPECT_EQ(size_t(2), fmMoved.Size()); | |
| EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmMoved.Get(FruitMap::Apple)); | |
| EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmMoved.Get(FruitMap::Orange)); | |
| // Test operator= move | |
| FruitMap fmMoved2; | |
| fmMoved2.Set(FruitMap::Apple, 12345); // This value will be clobbered after the move | |
| fmMoved2 = std::move(fmFilledCopy2); | |
| // NOLINTNEXTLINE - checking underlying storage has been freed | |
| EXPECT_EQ(size_t(0), fmFilledCopy2.Size()); | |
| EXPECT_EQ(size_t(2), fmMoved2.Size()); | |
| EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmMoved2.Get(FruitMap::Apple)); | |
| EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmMoved2.Get(FruitMap::Orange)); | |
| } | |
| TEST(VariantMaps, VariadicConstructors) { | |
| // Variadic constructor, 1 kv/pair | |
| FruitMap fmApple(FruitMap::Apple, 12345); | |
| EXPECT_EQ(size_t(1), fmApple.Size()); | |
| EXPECT_EQ(12345, *fmApple.Get(FruitMap::Apple)); | |
| // Variadic constructor, 2 kv/pair | |
| FruitMap fmAppleAndOrange(FruitMap::Apple, 12345, | |
| FruitMap::Orange, 100.0); | |
| EXPECT_EQ(size_t(2), fmAppleAndOrange.Size()); | |
| EXPECT_EQ(12345, *fmAppleAndOrange.Get(FruitMap::Apple)); | |
| EXPECT_DOUBLE_EQ(100.0, *fmAppleAndOrange.Get(FruitMap::Orange)); | |
| } | |
| TEST(VariantMaps, ReleaseOrDefault) { | |
| FruitMap fmAppleAndOrange(FruitMap::Apple, 12345, | |
| FruitMap::Orange, 100.0); | |
| int apple = fmAppleAndOrange.ReleaseOrDefault(FruitMap::Apple); | |
| EXPECT_EQ(12345, apple); | |
| // Releasing will also remove the Apple key. | |
| EXPECT_EQ(size_t(1), fmAppleAndOrange.Size()); | |
| // Releasing again yields a default value. | |
| int apple2 = fmAppleAndOrange.ReleaseOrDefault(FruitMap::Apple); | |
| EXPECT_EQ(0, apple2); | |
| } | |
| TEST(VariantMaps, GetOrDefault) { | |
| FruitMap fm(FruitMap::Apple, 12345); | |
| // Apple gives the expected value we set. | |
| int apple = fm.GetOrDefault(FruitMap::Apple); | |
| EXPECT_EQ(12345, apple); | |
| // Map is still 1. | |
| EXPECT_EQ(size_t(1), fm.Size()); | |
| // Orange gives back a default value, since it's not in the map. | |
| double orange = fm.GetOrDefault(FruitMap::Orange); | |
| EXPECT_DOUBLE_EQ(0.0, orange); | |
| } | |
| } // namespace art |