1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "mojo/public/cpp/bindings/map.h"
6
7#include <stddef.h>
8#include <stdint.h>
9#include <utility>
10
11#include "mojo/public/cpp/bindings/array.h"
12#include "mojo/public/cpp/bindings/string.h"
13#include "mojo/public/cpp/bindings/tests/container_test_util.h"
14#include "mojo/public/cpp/bindings/tests/map_common_test.h"
15#include "testing/gtest/include/gtest/gtest.h"
16
17namespace mojo {
18namespace test {
19
20namespace {
21
22using MapTest = testing::Test;
23
24MAP_COMMON_TEST(Map, NullAndEmpty)
25MAP_COMMON_TEST(Map, InsertWorks)
26MAP_COMMON_TEST(Map, TestIndexOperator)
27MAP_COMMON_TEST(Map, TestIndexOperatorAsRValue)
28MAP_COMMON_TEST(Map, TestIndexOperatorMoveOnly)
29MAP_COMMON_TEST(Map, MapArrayClone)
30MAP_COMMON_TEST(Map, ArrayOfMap)
31
32TEST_F(MapTest, ConstructedFromArray) {
33  Array<String> keys(kStringIntDataSize);
34  Array<int> values(kStringIntDataSize);
35  for (size_t i = 0; i < kStringIntDataSize; ++i) {
36    keys[i] = kStringIntData[i].string_data;
37    values[i] = kStringIntData[i].int_data;
38  }
39
40  Map<String, int> map(std::move(keys), std::move(values));
41
42  for (size_t i = 0; i < kStringIntDataSize; ++i) {
43    EXPECT_EQ(kStringIntData[i].int_data,
44              map.at(mojo::String(kStringIntData[i].string_data)));
45  }
46}
47
48TEST_F(MapTest, DecomposeMapTo) {
49  Array<String> keys(kStringIntDataSize);
50  Array<int> values(kStringIntDataSize);
51  for (size_t i = 0; i < kStringIntDataSize; ++i) {
52    keys[i] = kStringIntData[i].string_data;
53    values[i] = kStringIntData[i].int_data;
54  }
55
56  Map<String, int> map(std::move(keys), std::move(values));
57  EXPECT_EQ(kStringIntDataSize, map.size());
58
59  Array<String> keys2;
60  Array<int> values2;
61  map.DecomposeMapTo(&keys2, &values2);
62  EXPECT_EQ(0u, map.size());
63
64  EXPECT_EQ(kStringIntDataSize, keys2.size());
65  EXPECT_EQ(kStringIntDataSize, values2.size());
66
67  for (size_t i = 0; i < kStringIntDataSize; ++i) {
68    // We are not guaranteed that the copies have the same sorting as the
69    // originals.
70    String key = kStringIntData[i].string_data;
71    int value = kStringIntData[i].int_data;
72
73    bool found = false;
74    for (size_t j = 0; j < keys2.size(); ++j) {
75      if (keys2[j] == key) {
76        EXPECT_EQ(value, values2[j]);
77        found = true;
78        break;
79      }
80    }
81
82    EXPECT_TRUE(found);
83  }
84}
85
86TEST_F(MapTest, Insert_Copyable) {
87  ASSERT_EQ(0u, CopyableType::num_instances());
88  mojo::Map<mojo::String, CopyableType> map;
89  std::vector<CopyableType*> value_ptrs;
90
91  for (size_t i = 0; i < kStringIntDataSize; ++i) {
92    const char* key = kStringIntData[i].string_data;
93    CopyableType value;
94    value_ptrs.push_back(value.ptr());
95    map.insert(key, value);
96    ASSERT_EQ(i + 1, map.size());
97    ASSERT_EQ(i + 1, value_ptrs.size());
98    EXPECT_EQ(map.size() + 1, CopyableType::num_instances());
99    EXPECT_TRUE(map.at(key).copied());
100    EXPECT_EQ(value_ptrs[i], map.at(key).ptr());
101    map.at(key).ResetCopied();
102    EXPECT_TRUE(map);
103  }
104
105  // std::map doesn't have a capacity() method like std::vector so this test is
106  // a lot more boring.
107
108  map = nullptr;
109  EXPECT_EQ(0u, CopyableType::num_instances());
110}
111
112TEST_F(MapTest, Insert_MoveOnly) {
113  ASSERT_EQ(0u, MoveOnlyType::num_instances());
114  mojo::Map<mojo::String, MoveOnlyType> map;
115  std::vector<MoveOnlyType*> value_ptrs;
116
117  for (size_t i = 0; i < kStringIntDataSize; ++i) {
118    const char* key = kStringIntData[i].string_data;
119    MoveOnlyType value;
120    value_ptrs.push_back(value.ptr());
121    map.insert(key, std::move(value));
122    ASSERT_EQ(i + 1, map.size());
123    ASSERT_EQ(i + 1, value_ptrs.size());
124    EXPECT_EQ(map.size() + 1, MoveOnlyType::num_instances());
125    EXPECT_TRUE(map.at(key).moved());
126    EXPECT_EQ(value_ptrs[i], map.at(key).ptr());
127    map.at(key).ResetMoved();
128    EXPECT_TRUE(map);
129  }
130
131  // std::map doesn't have a capacity() method like std::vector so this test is
132  // a lot more boring.
133
134  map = nullptr;
135  EXPECT_EQ(0u, MoveOnlyType::num_instances());
136}
137
138TEST_F(MapTest, IndexOperator_MoveOnly) {
139  ASSERT_EQ(0u, MoveOnlyType::num_instances());
140  mojo::Map<mojo::String, MoveOnlyType> map;
141  std::vector<MoveOnlyType*> value_ptrs;
142
143  for (size_t i = 0; i < kStringIntDataSize; ++i) {
144    const char* key = kStringIntData[i].string_data;
145    MoveOnlyType value;
146    value_ptrs.push_back(value.ptr());
147    map[key] = std::move(value);
148    ASSERT_EQ(i + 1, map.size());
149    ASSERT_EQ(i + 1, value_ptrs.size());
150    EXPECT_EQ(map.size() + 1, MoveOnlyType::num_instances());
151    EXPECT_TRUE(map.at(key).moved());
152    EXPECT_EQ(value_ptrs[i], map.at(key).ptr());
153    map.at(key).ResetMoved();
154    EXPECT_TRUE(map);
155  }
156
157  // std::map doesn't have a capacity() method like std::vector so this test is
158  // a lot more boring.
159
160  map = nullptr;
161  EXPECT_EQ(0u, MoveOnlyType::num_instances());
162}
163
164TEST_F(MapTest, STLToMojo) {
165  std::map<std::string, int> stl_data;
166  for (size_t i = 0; i < kStringIntDataSize; ++i)
167    stl_data[kStringIntData[i].string_data] = kStringIntData[i].int_data;
168
169  Map<String, int32_t> mojo_data = Map<String, int32_t>::From(stl_data);
170  for (size_t i = 0; i < kStringIntDataSize; ++i) {
171    EXPECT_EQ(kStringIntData[i].int_data,
172              mojo_data.at(kStringIntData[i].string_data));
173  }
174}
175
176TEST_F(MapTest, MojoToSTL) {
177  Map<String, int32_t> mojo_map;
178  for (size_t i = 0; i < kStringIntDataSize; ++i)
179    mojo_map.insert(kStringIntData[i].string_data, kStringIntData[i].int_data);
180
181  std::map<std::string, int> stl_map =
182      mojo_map.To<std::map<std::string, int>>();
183  for (size_t i = 0; i < kStringIntDataSize; ++i) {
184    auto it = stl_map.find(kStringIntData[i].string_data);
185    ASSERT_TRUE(it != stl_map.end());
186    EXPECT_EQ(kStringIntData[i].int_data, it->second);
187  }
188}
189
190TEST_F(MapTest, MoveFromAndToSTLMap_Copyable) {
191  std::map<int32_t, CopyableType> map1;
192  map1.insert(std::make_pair(123, CopyableType()));
193  map1[123].ResetCopied();
194
195  Map<int32_t, CopyableType> mojo_map(std::move(map1));
196  ASSERT_EQ(1u, mojo_map.size());
197  ASSERT_NE(mojo_map.end(), mojo_map.find(123));
198  ASSERT_FALSE(mojo_map[123].copied());
199
200  std::map<int32_t, CopyableType> map2(mojo_map.PassStorage());
201  ASSERT_EQ(1u, map2.size());
202  ASSERT_NE(map2.end(), map2.find(123));
203  ASSERT_FALSE(map2[123].copied());
204
205  ASSERT_EQ(0u, mojo_map.size());
206  ASSERT_TRUE(mojo_map.is_null());
207}
208
209TEST_F(MapTest, MoveFromAndToSTLMap_MoveOnly) {
210  std::map<int32_t, MoveOnlyType> map1;
211  map1.insert(std::make_pair(123, MoveOnlyType()));
212
213  Map<int32_t, MoveOnlyType> mojo_map(std::move(map1));
214  ASSERT_EQ(1u, mojo_map.size());
215  ASSERT_NE(mojo_map.end(), mojo_map.find(123));
216
217  std::map<int32_t, MoveOnlyType> map2(mojo_map.PassStorage());
218  ASSERT_EQ(1u, map2.size());
219  ASSERT_NE(map2.end(), map2.find(123));
220
221  ASSERT_EQ(0u, mojo_map.size());
222  ASSERT_TRUE(mojo_map.is_null());
223}
224
225}  // namespace
226}  // namespace test
227}  // namespace mojo
228