Index: mojo/public/cpp/bindings/tests/map_unittest.cc |
diff --git a/mojo/public/cpp/bindings/tests/map_unittest.cc b/mojo/public/cpp/bindings/tests/map_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..dd4ff071b82faf334b6667dadf95e15e39e1048e |
--- /dev/null |
+++ b/mojo/public/cpp/bindings/tests/map_unittest.cc |
@@ -0,0 +1,240 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "mojo/public/cpp/bindings/array.h" |
+#include "mojo/public/cpp/bindings/lib/array_serialization.h" |
+#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" |
+#include "mojo/public/cpp/bindings/map.h" |
+#include "mojo/public/cpp/bindings/string.h" |
+#include "mojo/public/cpp/environment/environment.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace mojo { |
+namespace test { |
+ |
+namespace { |
+ |
+struct StringIntData { |
+ const char* string_data; |
+ int int_data; |
+} kStringIntData[] = { |
+ { "one", 1 }, |
+ { "two", 2 }, |
+ { "three", 3 }, |
+ { "four", 4 }, |
+}; |
+ |
+const size_t kStringIntDataSize = 4; |
+ |
+class CopyableType { |
+ public: |
+ CopyableType() : copied_(false), ptr_(this) { num_instances_++; } |
+ CopyableType(const CopyableType& other) : copied_(true), ptr_(other.ptr()) { |
+ num_instances_++; |
+ } |
+ CopyableType& operator=(const CopyableType& other) { |
+ copied_ = true; |
+ ptr_ = other.ptr(); |
+ return *this; |
+ } |
+ ~CopyableType() { num_instances_--; } |
+ |
+ bool copied() const { return copied_; } |
+ static size_t num_instances() { return num_instances_; } |
+ CopyableType* ptr() const { return ptr_; } |
+ void ResetCopied() { copied_ = false; } |
+ |
+ private: |
+ bool copied_; |
+ static size_t num_instances_; |
+ CopyableType* ptr_; |
+}; |
+ |
+size_t CopyableType::num_instances_ = 0; |
+ |
+class MoveOnlyType { |
+ MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(MoveOnlyType, RValue) |
+ public: |
+ typedef MoveOnlyType Data_; |
+ MoveOnlyType() : moved_(false), ptr_(this) { num_instances_++; } |
+ MoveOnlyType(RValue other) : moved_(true), ptr_(other.object->ptr()) { |
+ num_instances_++; |
+ } |
+ MoveOnlyType& operator=(RValue other) { |
+ moved_ = true; |
+ ptr_ = other.object->ptr(); |
+ return *this; |
+ } |
+ ~MoveOnlyType() { num_instances_--; } |
+ |
+ bool moved() const { return moved_; } |
+ static size_t num_instances() { return num_instances_; } |
+ MoveOnlyType* ptr() const { return ptr_; } |
+ void ResetMoved() { moved_ = false; } |
+ |
+ private: |
+ bool moved_; |
+ static size_t num_instances_; |
+ MoveOnlyType* ptr_; |
+}; |
+ |
+size_t MoveOnlyType::num_instances_ = 0; |
+ |
+class MapTest : public testing::Test { |
+ public: |
+ virtual ~MapTest() {} |
+ |
+ private: |
+ Environment env_; |
+}; |
+ |
+// Tests that basic Map operations work. |
+TEST_F(MapTest, InsertWorks) { |
+ Map<String, int> map; |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) |
+ map.insert(kStringIntData[i].string_data, kStringIntData[i].int_data); |
+ |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) { |
+ EXPECT_EQ(kStringIntData[i].int_data, |
+ map.at(kStringIntData[i].string_data)); |
+ } |
+} |
+ |
+TEST_F(MapTest, ConstructedFromArray) { |
+ Array<String> keys(kStringIntDataSize); |
+ Array<int> values(kStringIntDataSize); |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) { |
+ keys[i] = kStringIntData[i].string_data; |
+ values[i] = kStringIntData[i].int_data; |
+ } |
+ |
+ Map<String, int> map(keys.Pass(), values.Pass()); |
+ |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) { |
+ EXPECT_EQ(kStringIntData[i].int_data, |
+ map.at(mojo::String(kStringIntData[i].string_data))); |
+ } |
+} |
+ |
+TEST_F(MapTest, DecomposeMapTo) { |
+ Array<String> keys(kStringIntDataSize); |
+ Array<int> values(kStringIntDataSize); |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) { |
+ keys[i] = kStringIntData[i].string_data; |
+ values[i] = kStringIntData[i].int_data; |
+ } |
+ |
+ Map<String, int> map(keys.Pass(), values.Pass()); |
+ EXPECT_EQ(kStringIntDataSize, map.size()); |
+ |
+ Array<String> keys2; |
+ Array<int> values2; |
+ map.DecomposeMapTo(&keys2, &values2); |
+ EXPECT_EQ(0u, map.size()); |
+ |
+ EXPECT_EQ(kStringIntDataSize, keys2.size()); |
+ EXPECT_EQ(kStringIntDataSize, values2.size()); |
+ |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) { |
+ // We are not guaranteed that the copies have the same sorting as the |
+ // originals. |
+ String key = kStringIntData[i].string_data; |
+ int value = kStringIntData[i].int_data; |
+ |
+ bool found = false; |
+ for (size_t j = 0; j < keys2.size(); ++j) { |
+ if (keys2[j] == key) { |
+ EXPECT_EQ(value, values2[j]); |
+ found = true; |
+ break; |
+ } |
+ } |
+ |
+ EXPECT_TRUE(found); |
+ } |
+} |
+ |
+TEST_F(MapTest, Insert_Copyable) { |
+ ASSERT_EQ(0u, CopyableType::num_instances()); |
+ mojo::Map<mojo::String, CopyableType> map; |
+ std::vector<CopyableType*> value_ptrs; |
+ |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) { |
+ const char* key = kStringIntData[i].string_data; |
+ CopyableType value; |
+ value_ptrs.push_back(value.ptr()); |
+ map.insert(key, value); |
+ ASSERT_EQ(i + 1, map.size()); |
+ ASSERT_EQ(i + 1, value_ptrs.size()); |
+ EXPECT_EQ(map.size() + 1, CopyableType::num_instances()); |
+ EXPECT_TRUE(map.at(key).copied()); |
+ EXPECT_EQ(value_ptrs[i], map.at(key).ptr()); |
+ map.at(key).ResetCopied(); |
+ EXPECT_TRUE(map); |
+ } |
+ |
+ // std::map doesn't have a capacity() method like std::vector so this test is |
+ // a lot more boring. |
+ |
+ map.reset(); |
+ EXPECT_EQ(0u, CopyableType::num_instances()); |
+} |
+ |
+TEST_F(MapTest, Insert_MoveOnly) { |
+ ASSERT_EQ(0u, MoveOnlyType::num_instances()); |
+ mojo::Map<mojo::String, MoveOnlyType> map; |
+ std::vector<MoveOnlyType*> value_ptrs; |
+ |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) { |
+ const char* key = kStringIntData[i].string_data; |
+ MoveOnlyType value; |
+ value_ptrs.push_back(value.ptr()); |
+ map.insert(key, value.Pass()); |
+ ASSERT_EQ(i + 1, map.size()); |
+ ASSERT_EQ(i + 1, value_ptrs.size()); |
+ EXPECT_EQ(map.size() + 1, MoveOnlyType::num_instances()); |
+ EXPECT_TRUE(map.at(key).moved()); |
+ EXPECT_EQ(value_ptrs[i], map.at(key).ptr()); |
+ map.at(key).ResetMoved(); |
+ EXPECT_TRUE(map); |
+ } |
+ |
+ // std::map doesn't have a capacity() method like std::vector so this test is |
+ // a lot more boring. |
+ |
+ map.reset(); |
+ EXPECT_EQ(0u, CopyableType::num_instances()); |
+} |
+ |
+TEST_F(MapTest, STLToMojo) { |
+ std::map<std::string, int> stl_data; |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) |
+ stl_data[kStringIntData[i].string_data] = kStringIntData[i].int_data; |
+ |
+ Map<String, int32_t> mojo_data = Map<String, int32_t>::From(stl_data); |
+ |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) { |
+ EXPECT_EQ(kStringIntData[i].int_data, |
+ mojo_data.at(kStringIntData[i].string_data)); |
+ } |
+} |
+ |
+TEST_F(MapTest, MojoToSTL) { |
+ Map<String, int32_t> mojo_map; |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) |
+ mojo_map.insert(kStringIntData[i].string_data, kStringIntData[i].int_data); |
+ |
+ std::map<std::string, int> stl_map = |
+ mojo_map.To<std::map<std::string, int> >(); |
+ for (size_t i = 0; i < kStringIntDataSize; ++i) { |
+ auto it = stl_map.find(kStringIntData[i].string_data); |
+ ASSERT_TRUE(it != stl_map.end()); |
+ EXPECT_EQ(kStringIntData[i].int_data, it->second); |
+ } |
+} |
+ |
+} // namespace |
+} // namespace test |
+} // namespace mojo |
+ |