aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDedicatedTest/include/protobuf/map_field_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'NorthstarDedicatedTest/include/protobuf/map_field_test.cc')
-rw-r--r--NorthstarDedicatedTest/include/protobuf/map_field_test.cc527
1 files changed, 527 insertions, 0 deletions
diff --git a/NorthstarDedicatedTest/include/protobuf/map_field_test.cc b/NorthstarDedicatedTest/include/protobuf/map_field_test.cc
new file mode 100644
index 00000000..6db44a2b
--- /dev/null
+++ b/NorthstarDedicatedTest/include/protobuf/map_field_test.cc
@@ -0,0 +1,527 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <map>
+#include <memory>
+#include <unordered_map>
+
+#include <stubs/logging.h>
+#include <stubs/common.h>
+#include <arena_test_util.h>
+#include <map_test_util.h>
+#include <map_unittest.pb.h>
+#include <unittest.pb.h>
+#include <arena.h>
+#include <map.h>
+#include <map_field_inl.h>
+#include <message.h>
+#include <repeated_field.h>
+#include <gtest/gtest.h>
+
+// Must be included last.
+#include <port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+using unittest::TestAllTypes;
+
+class MapFieldBaseStub : public MapFieldBase {
+ public:
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
+ MapFieldBaseStub() {}
+ explicit MapFieldBaseStub(Arena* arena) : MapFieldBase(arena) {}
+ // Get underlined repeated field without synchronizing map.
+ RepeatedPtrField<Message>* InternalRepeatedField() { return repeated_field_; }
+ bool IsMapClean() {
+ return state_.load(std::memory_order_relaxed) != STATE_MODIFIED_MAP;
+ }
+ bool IsRepeatedClean() {
+ return state_.load(std::memory_order_relaxed) != STATE_MODIFIED_REPEATED;
+ }
+ void SetMapDirty() {
+ state_.store(STATE_MODIFIED_MAP, std::memory_order_relaxed);
+ }
+ void SetRepeatedDirty() {
+ state_.store(STATE_MODIFIED_REPEATED, std::memory_order_relaxed);
+ }
+ bool ContainsMapKey(const MapKey& map_key) const override { return false; }
+ bool InsertOrLookupMapValue(const MapKey& map_key,
+ MapValueRef* val) override {
+ return false;
+ }
+ bool LookupMapValue(const MapKey& map_key,
+ MapValueConstRef* val) const override {
+ return false;
+ }
+ bool DeleteMapValue(const MapKey& map_key) override { return false; }
+ bool EqualIterator(const MapIterator& a,
+ const MapIterator& b) const override {
+ return false;
+ }
+ int size() const override { return 0; }
+ void Clear() override {}
+ void MapBegin(MapIterator* map_iter) const override {}
+ void MapEnd(MapIterator* map_iter) const override {}
+ void MergeFrom(const MapFieldBase& other) override {}
+ void Swap(MapFieldBase* other) override {}
+ void InitializeIterator(MapIterator* map_iter) const override {}
+ void DeleteIterator(MapIterator* map_iter) const override {}
+ void CopyIterator(MapIterator* this_iterator,
+ const MapIterator& other_iterator) const override {}
+ void IncreaseIterator(MapIterator* map_iter) const override {}
+
+ Arena* GetArenaForInternalRepeatedField() {
+ auto* repeated_field = MutableRepeatedField();
+ return repeated_field->GetArena();
+ }
+};
+
+class MapFieldBasePrimitiveTest : public testing::TestWithParam<bool> {
+ protected:
+ typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType;
+ typedef MapField<EntryType, int32, int32, WireFormatLite::TYPE_INT32,
+ WireFormatLite::TYPE_INT32>
+ MapFieldType;
+
+ MapFieldBasePrimitiveTest()
+ : arena_(GetParam() ? new Arena() : nullptr),
+ map_field_(arena_.get()),
+ map_field_base_(map_field_.get()) {
+ // Get descriptors
+ map_descriptor_ = unittest::TestMap::descriptor()
+ ->FindFieldByName("map_int32_int32")
+ ->message_type();
+ key_descriptor_ = map_descriptor_->map_key();
+ value_descriptor_ = map_descriptor_->map_value();
+
+ // Build map field
+ map_field_base_ = map_field_.get();
+ map_ = map_field_->MutableMap();
+ initial_value_map_[0] = 100;
+ initial_value_map_[1] = 101;
+ map_->insert(initial_value_map_.begin(), initial_value_map_.end());
+ EXPECT_EQ(2, map_->size());
+ }
+
+ std::unique_ptr<Arena> arena_;
+ ArenaHolder<MapFieldType> map_field_;
+ MapFieldBase* map_field_base_;
+ Map<int32, int32>* map_;
+ const Descriptor* map_descriptor_;
+ const FieldDescriptor* key_descriptor_;
+ const FieldDescriptor* value_descriptor_;
+ std::map<int32, int32> initial_value_map_; // copy of initial values inserted
+};
+
+INSTANTIATE_TEST_SUITE_P(MapFieldBasePrimitiveTestInstance,
+ MapFieldBasePrimitiveTest,
+ testing::Values(true, false));
+
+TEST_P(MapFieldBasePrimitiveTest, SpaceUsedExcludingSelf) {
+ EXPECT_LT(0, map_field_base_->SpaceUsedExcludingSelf());
+}
+
+TEST_P(MapFieldBasePrimitiveTest, GetRepeatedField) {
+ const RepeatedPtrField<Message>& repeated =
+ reinterpret_cast<const RepeatedPtrField<Message>&>(
+ map_field_base_->GetRepeatedField());
+ EXPECT_EQ(2, repeated.size());
+ for (int i = 0; i < repeated.size(); i++) {
+ const Message& message = repeated.Get(i);
+ int key = message.GetReflection()->GetInt32(message, key_descriptor_);
+ int value = message.GetReflection()->GetInt32(message, value_descriptor_);
+ EXPECT_EQ(value, initial_value_map_[key]);
+ }
+}
+
+TEST_P(MapFieldBasePrimitiveTest, MutableRepeatedField) {
+ RepeatedPtrField<Message>* repeated =
+ reinterpret_cast<RepeatedPtrField<Message>*>(
+ map_field_base_->MutableRepeatedField());
+ EXPECT_EQ(2, repeated->size());
+ for (int i = 0; i < repeated->size(); i++) {
+ const Message& message = repeated->Get(i);
+ int key = message.GetReflection()->GetInt32(message, key_descriptor_);
+ int value = message.GetReflection()->GetInt32(message, value_descriptor_);
+ EXPECT_EQ(value, initial_value_map_[key]);
+ }
+}
+
+TEST_P(MapFieldBasePrimitiveTest, Arena) {
+ // Allocate a large initial block to avoid mallocs during hooked test.
+ std::vector<char> arena_block(128 * 1024);
+ ArenaOptions options;
+ options.initial_block = &arena_block[0];
+ options.initial_block_size = arena_block.size();
+ Arena arena(options);
+
+ {
+ // TODO(liujisi): Re-write the test to ensure the memory for the map and
+ // repeated fields are allocated from arenas.
+ // NoHeapChecker no_heap;
+
+ MapFieldType* map_field = Arena::CreateMessage<MapFieldType>(&arena);
+
+ // Set content in map
+ (*map_field->MutableMap())[100] = 101;
+
+ // Trigger conversion to repeated field.
+ map_field->GetRepeatedField();
+ }
+
+ {
+ // TODO(liujisi): Re-write the test to ensure the memory for the map and
+ // repeated fields are allocated from arenas.
+ // NoHeapChecker no_heap;
+
+ MapFieldBaseStub* map_field =
+ Arena::CreateMessage<MapFieldBaseStub>(&arena);
+
+ // Trigger conversion to repeated field.
+ EXPECT_TRUE(map_field->MutableRepeatedField() != nullptr);
+
+ EXPECT_EQ(map_field->GetArenaForInternalRepeatedField(), &arena);
+ }
+}
+
+TEST_P(MapFieldBasePrimitiveTest, EnforceNoArena) {
+ std::unique_ptr<MapFieldBaseStub> map_field(
+ Arena::CreateMessage<MapFieldBaseStub>(nullptr));
+ EXPECT_EQ(map_field->GetArenaForInternalRepeatedField(), nullptr);
+}
+
+namespace {
+enum State { CLEAN, MAP_DIRTY, REPEATED_DIRTY };
+} // anonymous namespace
+
+class MapFieldStateTest
+ : public testing::TestWithParam<std::tuple<State, bool>> {
+ protected:
+ typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType;
+ typedef MapField<EntryType, int32, int32, WireFormatLite::TYPE_INT32,
+ WireFormatLite::TYPE_INT32>
+ MapFieldType;
+ MapFieldStateTest()
+ : arena_(std::get<1>(GetParam()) ? new Arena() : nullptr),
+ map_field_(arena_.get()),
+ map_field_base_(map_field_.get()),
+ state_(std::get<0>(GetParam())) {
+ // Build map field
+ Expect(map_field_.get(), MAP_DIRTY, 0, 0, true);
+ switch (state_) {
+ case CLEAN:
+ AddOneStillClean(map_field_.get());
+ break;
+ case MAP_DIRTY:
+ MakeMapDirty(map_field_.get());
+ break;
+ case REPEATED_DIRTY:
+ MakeRepeatedDirty(map_field_.get());
+ break;
+ default:
+ break;
+ }
+ }
+
+ void AddOneStillClean(MapFieldType* map_field) {
+ MapFieldBase* map_field_base = map_field;
+ Map<int32, int32>* map = map_field->MutableMap();
+ (*map)[0] = 0;
+ map_field_base->GetRepeatedField();
+ Expect(map_field, CLEAN, 1, 1, false);
+ }
+
+ void MakeMapDirty(MapFieldType* map_field) {
+ Map<int32, int32>* map = map_field->MutableMap();
+ (*map)[0] = 0;
+ Expect(map_field, MAP_DIRTY, 1, 0, true);
+ }
+
+ void MakeRepeatedDirty(MapFieldType* map_field) {
+ MakeMapDirty(map_field);
+ MapFieldBase* map_field_base = map_field;
+ map_field_base->MutableRepeatedField();
+ // We use MutableMap on impl_ because we don't want to disturb the syncing
+ Map<int32, int32>* map = map_field->impl_.MutableMap();
+ map->clear();
+
+ Expect(map_field, REPEATED_DIRTY, 0, 1, false);
+ }
+
+ void Expect(MapFieldType* map_field, State state, int map_size,
+ int repeated_size, bool is_repeated_null) {
+ MapFieldBase* map_field_base = map_field;
+ MapFieldBaseStub* stub =
+ reinterpret_cast<MapFieldBaseStub*>(map_field_base);
+
+ // We use MutableMap on impl_ because we don't want to disturb the syncing
+ Map<int32, int32>* map = map_field->impl_.MutableMap();
+ RepeatedPtrField<Message>* repeated_field = stub->InternalRepeatedField();
+
+ switch (state) {
+ case MAP_DIRTY:
+ EXPECT_FALSE(stub->IsMapClean());
+ EXPECT_TRUE(stub->IsRepeatedClean());
+ break;
+ case REPEATED_DIRTY:
+ EXPECT_TRUE(stub->IsMapClean());
+ EXPECT_FALSE(stub->IsRepeatedClean());
+ break;
+ case CLEAN:
+ EXPECT_TRUE(stub->IsMapClean());
+ EXPECT_TRUE(stub->IsRepeatedClean());
+ break;
+ default:
+ FAIL();
+ }
+
+ EXPECT_EQ(map_size, map->size());
+ if (is_repeated_null) {
+ EXPECT_TRUE(repeated_field == nullptr);
+ } else {
+ if (repeated_field == nullptr) {
+ EXPECT_EQ(repeated_size, 0);
+ } else {
+ EXPECT_EQ(repeated_size, repeated_field->size());
+ }
+ }
+ }
+
+ std::unique_ptr<Arena> arena_;
+ ArenaHolder<MapFieldType> map_field_;
+ MapFieldBase* map_field_base_;
+ State state_;
+};
+
+INSTANTIATE_TEST_SUITE_P(MapFieldStateTestInstance, MapFieldStateTest,
+ testing::Combine(testing::Values(CLEAN, MAP_DIRTY,
+ REPEATED_DIRTY),
+ testing::Values(true, false)));
+
+TEST_P(MapFieldStateTest, GetMap) {
+ map_field_->GetMap();
+ if (state_ != MAP_DIRTY) {
+ Expect(map_field_.get(), CLEAN, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ }
+}
+
+TEST_P(MapFieldStateTest, MutableMap) {
+ map_field_->MutableMap();
+ if (state_ != MAP_DIRTY) {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ }
+}
+
+TEST_P(MapFieldStateTest, MergeFromClean) {
+ ArenaHolder<MapFieldType> other(arena_.get());
+ AddOneStillClean(other.get());
+
+ map_field_->MergeFrom(*other);
+
+ if (state_ != MAP_DIRTY) {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ }
+
+ Expect(other.get(), CLEAN, 1, 1, false);
+}
+
+TEST_P(MapFieldStateTest, MergeFromMapDirty) {
+ ArenaHolder<MapFieldType> other(arena_.get());
+ MakeMapDirty(other.get());
+
+ map_field_->MergeFrom(*other);
+
+ if (state_ != MAP_DIRTY) {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ }
+
+ Expect(other.get(), MAP_DIRTY, 1, 0, true);
+}
+
+TEST_P(MapFieldStateTest, MergeFromRepeatedDirty) {
+ ArenaHolder<MapFieldType> other(arena_.get());
+ MakeRepeatedDirty(other.get());
+
+ map_field_->MergeFrom(*other);
+
+ if (state_ != MAP_DIRTY) {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ }
+
+ Expect(other.get(), CLEAN, 1, 1, false);
+}
+
+TEST_P(MapFieldStateTest, SwapClean) {
+ ArenaHolder<MapFieldType> other(arena_.get());
+ AddOneStillClean(other.get());
+
+ map_field_->Swap(other.get());
+
+ Expect(map_field_.get(), CLEAN, 1, 1, false);
+
+ switch (state_) {
+ case CLEAN:
+ Expect(other.get(), CLEAN, 1, 1, false);
+ break;
+ case MAP_DIRTY:
+ Expect(other.get(), MAP_DIRTY, 1, 0, true);
+ break;
+ case REPEATED_DIRTY:
+ Expect(other.get(), REPEATED_DIRTY, 0, 1, false);
+ break;
+ default:
+ break;
+ }
+}
+
+TEST_P(MapFieldStateTest, SwapMapDirty) {
+ ArenaHolder<MapFieldType> other(arena_.get());
+ MakeMapDirty(other.get());
+
+ map_field_->Swap(other.get());
+
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+
+ switch (state_) {
+ case CLEAN:
+ Expect(other.get(), CLEAN, 1, 1, false);
+ break;
+ case MAP_DIRTY:
+ Expect(other.get(), MAP_DIRTY, 1, 0, true);
+ break;
+ case REPEATED_DIRTY:
+ Expect(other.get(), REPEATED_DIRTY, 0, 1, false);
+ break;
+ default:
+ break;
+ }
+}
+
+TEST_P(MapFieldStateTest, SwapRepeatedDirty) {
+ ArenaHolder<MapFieldType> other(arena_.get());
+ MakeRepeatedDirty(other.get());
+
+ map_field_->Swap(other.get());
+
+ Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+
+ switch (state_) {
+ case CLEAN:
+ Expect(other.get(), CLEAN, 1, 1, false);
+ break;
+ case MAP_DIRTY:
+ Expect(other.get(), MAP_DIRTY, 1, 0, true);
+ break;
+ case REPEATED_DIRTY:
+ Expect(other.get(), REPEATED_DIRTY, 0, 1, false);
+ break;
+ default:
+ break;
+ }
+}
+
+TEST_P(MapFieldStateTest, Clear) {
+ map_field_->Clear();
+
+ Expect(map_field_.get(), MAP_DIRTY, 0, 0, false);
+}
+
+TEST_P(MapFieldStateTest, SpaceUsedExcludingSelf) {
+ map_field_base_->SpaceUsedExcludingSelf();
+
+ switch (state_) {
+ case CLEAN:
+ Expect(map_field_.get(), CLEAN, 1, 1, false);
+ break;
+ case MAP_DIRTY:
+ Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+ break;
+ case REPEATED_DIRTY:
+ Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+ break;
+ default:
+ break;
+ }
+}
+
+TEST_P(MapFieldStateTest, GetMapField) {
+ map_field_base_->GetRepeatedField();
+
+ if (state_ != REPEATED_DIRTY) {
+ Expect(map_field_.get(), CLEAN, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+ }
+}
+
+TEST_P(MapFieldStateTest, MutableMapField) {
+ map_field_base_->MutableRepeatedField();
+
+ if (state_ != REPEATED_DIRTY) {
+ Expect(map_field_.get(), REPEATED_DIRTY, 1, 1, false);
+ } else {
+ Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+ }
+}
+
+class MyMapField
+ : public MapField<unittest::TestMap_MapInt32Int32Entry_DoNotUse, int32,
+ int32, internal::WireFormatLite::TYPE_INT32,
+ internal::WireFormatLite::TYPE_INT32> {
+ public:
+ constexpr MyMapField()
+ : MyMapField::MapField(internal::ConstantInitialized{}) {}
+};
+
+TEST(MapFieldTest, ConstInit) {
+ // This tests that `MapField` and all its base classes can be constant
+ // initialized.
+ PROTOBUF_CONSTINIT static MyMapField field; // NOLINT
+ EXPECT_EQ(field.size(), 0);
+}
+
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google