Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Side by Side Diff: mojo/public/cpp/bindings/tests/map_unittest.cc

Issue 611633002: mojom: Add associative arrays to the mojom language. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase to ToT; fixes clang-format bustage. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/array.h"
6 #include "mojo/public/cpp/bindings/lib/array_serialization.h"
7 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
8 #include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
9 #include "mojo/public/cpp/bindings/map.h"
10 #include "mojo/public/cpp/bindings/string.h"
11 #include "mojo/public/cpp/bindings/struct_ptr.h"
12 #include "mojo/public/cpp/environment/environment.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace mojo {
16 namespace test {
17
18 namespace {
19
20 struct StringIntData {
21 const char* string_data;
22 int int_data;
23 } kStringIntData[] = {
24 { "one", 1 },
25 { "two", 2 },
26 { "three", 3 },
27 { "four", 4 },
28 };
29
30 const size_t kStringIntDataSize = 4;
31
32 class CopyableType {
33 public:
34 CopyableType() : copied_(false), ptr_(this) { num_instances_++; }
35 CopyableType(const CopyableType& other) : copied_(true), ptr_(other.ptr()) {
36 num_instances_++;
37 }
38 CopyableType& operator=(const CopyableType& other) {
39 copied_ = true;
40 ptr_ = other.ptr();
41 return *this;
42 }
43 ~CopyableType() { num_instances_--; }
44
45 bool copied() const { return copied_; }
46 static size_t num_instances() { return num_instances_; }
47 CopyableType* ptr() const { return ptr_; }
48 void ResetCopied() { copied_ = false; }
49
50 private:
51 bool copied_;
52 static size_t num_instances_;
53 CopyableType* ptr_;
54 };
55
56 size_t CopyableType::num_instances_ = 0;
57
58 class MoveOnlyType {
59 MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(MoveOnlyType, RValue)
60 public:
61 typedef MoveOnlyType Data_;
62 MoveOnlyType() : moved_(false), ptr_(this) { num_instances_++; }
63 MoveOnlyType(RValue other) : moved_(true), ptr_(other.object->ptr()) {
64 num_instances_++;
65 }
66 MoveOnlyType& operator=(RValue other) {
67 moved_ = true;
68 ptr_ = other.object->ptr();
69 return *this;
70 }
71 ~MoveOnlyType() { num_instances_--; }
72
73 bool moved() const { return moved_; }
74 static size_t num_instances() { return num_instances_; }
75 MoveOnlyType* ptr() const { return ptr_; }
76 void ResetMoved() { moved_ = false; }
77
78 private:
79 bool moved_;
80 static size_t num_instances_;
81 MoveOnlyType* ptr_;
82 };
83
84 size_t MoveOnlyType::num_instances_ = 0;
85
86 class MapTest : public testing::Test {
87 public:
88 virtual ~MapTest() {}
89
90 private:
91 Environment env_;
92 };
93
94 // Tests that basic Map operations work.
95 TEST_F(MapTest, InsertWorks) {
96 Map<String, int> map;
97 for (size_t i = 0; i < kStringIntDataSize; ++i)
98 map.insert(kStringIntData[i].string_data, kStringIntData[i].int_data);
99
100 for (size_t i = 0; i < kStringIntDataSize; ++i) {
101 EXPECT_EQ(kStringIntData[i].int_data,
102 map.at(kStringIntData[i].string_data));
103 }
104 }
105
106 TEST_F(MapTest, ConstructedFromArray) {
107 Array<String> keys(kStringIntDataSize);
108 Array<int> values(kStringIntDataSize);
109 for (size_t i = 0; i < kStringIntDataSize; ++i) {
110 keys[i] = kStringIntData[i].string_data;
111 values[i] = kStringIntData[i].int_data;
112 }
113
114 Map<String, int> map(keys.Pass(), values.Pass());
115
116 for (size_t i = 0; i < kStringIntDataSize; ++i) {
117 EXPECT_EQ(kStringIntData[i].int_data,
118 map.at(mojo::String(kStringIntData[i].string_data)));
119 }
120 }
121
122 TEST_F(MapTest, DecomposeMapTo) {
123 Array<String> keys(kStringIntDataSize);
124 Array<int> values(kStringIntDataSize);
125 for (size_t i = 0; i < kStringIntDataSize; ++i) {
126 keys[i] = kStringIntData[i].string_data;
127 values[i] = kStringIntData[i].int_data;
128 }
129
130 Map<String, int> map(keys.Pass(), values.Pass());
131 EXPECT_EQ(kStringIntDataSize, map.size());
132
133 Array<String> keys2;
134 Array<int> values2;
135 map.DecomposeMapTo(&keys2, &values2);
136 EXPECT_EQ(0u, map.size());
137
138 EXPECT_EQ(kStringIntDataSize, keys2.size());
139 EXPECT_EQ(kStringIntDataSize, values2.size());
140
141 for (size_t i = 0; i < kStringIntDataSize; ++i) {
142 // We are not guaranteed that the copies have the same sorting as the
143 // originals.
144 String key = kStringIntData[i].string_data;
145 int value = kStringIntData[i].int_data;
146
147 bool found = false;
148 for (size_t j = 0; j < keys2.size(); ++j) {
149 if (keys2[j] == key) {
150 EXPECT_EQ(value, values2[j]);
151 found = true;
152 break;
153 }
154 }
155
156 EXPECT_TRUE(found);
157 }
158 }
159
160 TEST_F(MapTest, Insert_Copyable) {
161 ASSERT_EQ(0u, CopyableType::num_instances());
162 mojo::Map<mojo::String, CopyableType> map;
163 std::vector<CopyableType*> value_ptrs;
164
165 for (size_t i = 0; i < kStringIntDataSize; ++i) {
166 const char* key = kStringIntData[i].string_data;
167 CopyableType value;
168 value_ptrs.push_back(value.ptr());
169 map.insert(key, value);
170 ASSERT_EQ(i + 1, map.size());
171 ASSERT_EQ(i + 1, value_ptrs.size());
172 EXPECT_EQ(map.size() + 1, CopyableType::num_instances());
173 EXPECT_TRUE(map.at(key).copied());
174 EXPECT_EQ(value_ptrs[i], map.at(key).ptr());
175 map.at(key).ResetCopied();
176 EXPECT_TRUE(map);
177 }
178
179 // std::map doesn't have a capacity() method like std::vector so this test is
180 // a lot more boring.
181
182 map.reset();
183 EXPECT_EQ(0u, CopyableType::num_instances());
184 }
185
186 TEST_F(MapTest, Insert_MoveOnly) {
187 ASSERT_EQ(0u, MoveOnlyType::num_instances());
188 mojo::Map<mojo::String, MoveOnlyType> map;
189 std::vector<MoveOnlyType*> value_ptrs;
190
191 for (size_t i = 0; i < kStringIntDataSize; ++i) {
192 const char* key = kStringIntData[i].string_data;
193 MoveOnlyType value;
194 value_ptrs.push_back(value.ptr());
195 map.insert(key, value.Pass());
196 ASSERT_EQ(i + 1, map.size());
197 ASSERT_EQ(i + 1, value_ptrs.size());
198 EXPECT_EQ(map.size() + 1, MoveOnlyType::num_instances());
199 EXPECT_TRUE(map.at(key).moved());
200 EXPECT_EQ(value_ptrs[i], map.at(key).ptr());
201 map.at(key).ResetMoved();
202 EXPECT_TRUE(map);
203 }
204
205 // std::map doesn't have a capacity() method like std::vector so this test is
206 // a lot more boring.
207
208 map.reset();
209 EXPECT_EQ(0u, CopyableType::num_instances());
210 }
211
212 TEST_F(MapTest, STLToMojo) {
213 std::map<std::string, int> stl_data;
214 for (size_t i = 0; i < kStringIntDataSize; ++i)
215 stl_data[kStringIntData[i].string_data] = kStringIntData[i].int_data;
216
217 Map<String, int32_t> mojo_data = Map<String, int32_t>::From(stl_data);
218
219 for (size_t i = 0; i < kStringIntDataSize; ++i) {
220 EXPECT_EQ(kStringIntData[i].int_data,
221 mojo_data.at(kStringIntData[i].string_data));
222 }
223 }
224
225 TEST_F(MapTest, MojoToSTL) {
226 Map<String, int32_t> mojo_map;
227 for (size_t i = 0; i < kStringIntDataSize; ++i)
228 mojo_map.insert(kStringIntData[i].string_data, kStringIntData[i].int_data);
229
230 std::map<std::string, int> stl_map =
231 mojo_map.To<std::map<std::string, int> >();
232 for (size_t i = 0; i < kStringIntDataSize; ++i) {
233 auto it = stl_map.find(kStringIntData[i].string_data);
234 ASSERT_TRUE(it != stl_map.end());
235 EXPECT_EQ(kStringIntData[i].int_data, it->second);
236 }
237 }
238
239 TEST_F(MapTest, MapArrayClone) {
240 Map<String, Array<String> > m;
241 for (size_t i = 0; i < kStringIntDataSize; ++i) {
242 Array<String> s;
243 s.push_back(kStringIntData[i].string_data);
244 m.insert(kStringIntData[i].string_data, s.Pass());
245 }
246
247 Map<String, Array<String> > m2 = m.Clone();
248
249 for (auto it = m2.begin(); it != m2.end(); ++it) {
250 ASSERT_EQ(1u, it.GetValue().size());
251 EXPECT_EQ(it.GetKey(), it.GetValue().at(0));
252 }
253 }
254
255 // Data class for an end-to-end test of serialization. Because making a more
256 // limited test case tickles a clang compiler bug, we copy a minimal version of
257 // what our current cpp bindings do.
258 namespace internal {
259
260 class ArrayOfMap_Data {
261 public:
262 static ArrayOfMap_Data* New(mojo::internal::Buffer* buf) {
263 return new (buf->Allocate(sizeof(ArrayOfMap_Data))) ArrayOfMap_Data();
264 }
265
266 mojo::internal::StructHeader header_;
267
268 mojo::internal::ArrayPointer<
269 mojo::internal::Map_Data<int32_t, int8_t>*> first;
270 mojo::internal::ArrayPointer<mojo::internal::Map_Data<
271 mojo::internal::String_Data*,
272 mojo::internal::Array_Data<bool>*>*> second;
273
274 private:
275 ArrayOfMap_Data() {
276 header_.num_bytes = sizeof(*this);
277 header_.num_fields = 2;
278 }
279 ~ArrayOfMap_Data(); // NOT IMPLEMENTED
280 };
281 static_assert(sizeof(ArrayOfMap_Data) == 24, "Bad sizeof(ArrayOfMap_Data)");
282
283 } // namespace internal
284
285 class ArrayOfMapImpl;
286 typedef mojo::StructPtr<ArrayOfMapImpl> ArrayOfMapImplPtr;
287
288 class ArrayOfMapImpl {
289 public:
290 typedef internal::ArrayOfMap_Data Data_;
291 static ArrayOfMapImplPtr New() {
292 ArrayOfMapImplPtr rv;
293 mojo::internal::StructHelper<ArrayOfMapImpl>::Initialize(&rv);
294 return rv.Pass();
295 }
296
297 mojo::Array<mojo::Map<int32_t, int8_t> > first;
298 mojo::Array<mojo::Map<mojo::String, mojo::Array<bool> > > second;
299 };
300
301 size_t GetSerializedSize_(const ArrayOfMapImplPtr& input) {
302 if (!input)
303 return 0;
304 size_t size = sizeof(internal::ArrayOfMap_Data);
305 size += GetSerializedSize_(input->first);
306 size += GetSerializedSize_(input->second);
307 return size;
308 }
309
310 void Serialize_(ArrayOfMapImplPtr input, mojo::internal::Buffer* buf,
311 internal::ArrayOfMap_Data** output) {
312 if (input) {
313 internal::ArrayOfMap_Data* result =
314 internal::ArrayOfMap_Data::New(buf);
315 mojo::SerializeArray_<mojo::internal::ArrayValidateParams<0, false,
316 mojo::internal::ArrayValidateParams<0, false,
317 mojo::internal::NoValidateParams> > >(
318 mojo::internal::Forward(input->first), buf, &result->first.ptr);
319 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
320 !result->first.ptr,
321 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
322 "null first field in ArrayOfMapImpl struct");
323 mojo::SerializeArray_<mojo::internal::ArrayValidateParams<0, false,
324 mojo::internal::ArrayValidateParams<0, false,
325 mojo::internal::ArrayValidateParams<0, false,
326 mojo::internal::NoValidateParams> > > >(
327 mojo::internal::Forward(input->second), buf, &result->second.ptr);
328 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
329 !result->second.ptr,
330 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
331 "null second field in ArrayOfMapImpl struct");
332 *output = result;
333 } else {
334 *output = nullptr;
335 }
336 }
337
338 void Deserialize_(internal::ArrayOfMap_Data* input,
339 ArrayOfMapImplPtr* output) {
340 if (input) {
341 ArrayOfMapImplPtr result(ArrayOfMapImpl::New());
342 Deserialize_(input->first.ptr, &result->first);
343 Deserialize_(input->second.ptr, &result->second);
344 *output = result.Pass();
345 } else {
346 output->reset();
347 }
348 }
349
350 TEST_F(MapTest, ArrayOfMap) {
351 Array<Map<int32_t, int8_t>> first_array(1);
352 first_array[0].insert(1, 42);
353
354 Array<Map<String, Array<bool>>> second_array(1);
355 Array<bool> map_value(2);
356 map_value[0] = false;
357 map_value[1] = true;
358 second_array[0].insert("hello world", map_value.Pass());
359
360 ArrayOfMapImplPtr to_pass(ArrayOfMapImpl::New());
361 to_pass->first = first_array.Pass();
362 to_pass->second = second_array.Pass();
363
364 size_t size = GetSerializedSize_(to_pass);
365 mojo::internal::FixedBuffer buf(size);
366 internal::ArrayOfMap_Data* data;
367 Serialize_(mojo::internal::Forward(to_pass), &buf, &data);
368
369 ArrayOfMapImplPtr to_receive(ArrayOfMapImpl::New());
370 Deserialize_(data, &to_receive);
371
372 ASSERT_EQ(1u, to_receive->first.size());
373 ASSERT_EQ(1u, to_receive->first[0].size());
374 ASSERT_EQ(42, to_receive->first[0].at(1));
375
376 ASSERT_EQ(1u, to_receive->second.size());
377 ASSERT_EQ(1u, to_receive->second[0].size());
378 ASSERT_FALSE(to_receive->second[0].at("hello world")[0]);
379 ASSERT_TRUE(to_receive->second[0].at("hello world")[1]);
380 }
381
382 } // namespace
383 } // namespace test
384 } // namespace mojo
385
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698