Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 { | |
|
yzshen1
2014/10/09 22:24:41
Shall we move these classes which are shared with
| |
| 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<mojo::internal::Map_Data<int32_t, int8_t>*> | |
| 269 first; | |
| 270 mojo::internal::ArrayPointer< | |
| 271 mojo::internal::Map_Data<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, | |
| 311 mojo::internal::Buffer* buf, | |
| 312 internal::ArrayOfMap_Data** output) { | |
| 313 if (input) { | |
| 314 internal::ArrayOfMap_Data* result = internal::ArrayOfMap_Data::New(buf); | |
| 315 mojo::SerializeArray_<mojo::internal::ArrayValidateParams< | |
| 316 0, | |
| 317 false, | |
| 318 mojo::internal:: | |
| 319 ArrayValidateParams<0, false, mojo::internal::NoValidateParams>>>( | |
| 320 mojo::internal::Forward(input->first), buf, &result->first.ptr); | |
| 321 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
| 322 !result->first.ptr, | |
| 323 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, | |
| 324 "null first field in ArrayOfMapImpl struct"); | |
| 325 mojo::SerializeArray_<mojo::internal::ArrayValidateParams< | |
| 326 0, | |
| 327 false, | |
| 328 mojo::internal::ArrayValidateParams< | |
| 329 0, | |
| 330 false, | |
| 331 mojo::internal::ArrayValidateParams< | |
| 332 0, | |
| 333 false, | |
| 334 mojo::internal::NoValidateParams>>>>( | |
| 335 mojo::internal::Forward(input->second), buf, &result->second.ptr); | |
| 336 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
| 337 !result->second.ptr, | |
| 338 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, | |
| 339 "null second field in ArrayOfMapImpl struct"); | |
| 340 *output = result; | |
| 341 } else { | |
| 342 *output = nullptr; | |
| 343 } | |
| 344 } | |
| 345 | |
| 346 void Deserialize_(internal::ArrayOfMap_Data* input, ArrayOfMapImplPtr* output) { | |
| 347 if (input) { | |
| 348 ArrayOfMapImplPtr result(ArrayOfMapImpl::New()); | |
| 349 Deserialize_(input->first.ptr, &result->first); | |
| 350 Deserialize_(input->second.ptr, &result->second); | |
| 351 *output = result.Pass(); | |
| 352 } else { | |
| 353 output->reset(); | |
| 354 } | |
| 355 } | |
| 356 | |
| 357 TEST_F(MapTest, ArrayOfMap) { | |
| 358 Array<Map<int32_t, int8_t>> first_array(1); | |
| 359 first_array[0].insert(1, 42); | |
| 360 | |
| 361 Array<Map<String, Array<bool>>> second_array(1); | |
| 362 Array<bool> map_value(2); | |
| 363 map_value[0] = false; | |
| 364 map_value[1] = true; | |
| 365 second_array[0].insert("hello world", map_value.Pass()); | |
| 366 | |
| 367 ArrayOfMapImplPtr to_pass(ArrayOfMapImpl::New()); | |
| 368 to_pass->first = first_array.Pass(); | |
| 369 to_pass->second = second_array.Pass(); | |
| 370 | |
| 371 size_t size = GetSerializedSize_(to_pass); | |
| 372 mojo::internal::FixedBuffer buf(size); | |
| 373 internal::ArrayOfMap_Data* data; | |
| 374 Serialize_(mojo::internal::Forward(to_pass), &buf, &data); | |
| 375 | |
| 376 ArrayOfMapImplPtr to_receive(ArrayOfMapImpl::New()); | |
| 377 Deserialize_(data, &to_receive); | |
| 378 | |
| 379 ASSERT_EQ(1u, to_receive->first.size()); | |
| 380 ASSERT_EQ(1u, to_receive->first[0].size()); | |
| 381 ASSERT_EQ(42, to_receive->first[0].at(1)); | |
| 382 | |
| 383 ASSERT_EQ(1u, to_receive->second.size()); | |
| 384 ASSERT_EQ(1u, to_receive->second[0].size()); | |
| 385 ASSERT_FALSE(to_receive->second[0].at("hello world")[0]); | |
| 386 ASSERT_TRUE(to_receive->second[0].at("hello world")[1]); | |
| 387 } | |
| 388 | |
| 389 } // namespace | |
| 390 } // namespace test | |
| 391 } // namespace mojo | |
| OLD | NEW |