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