1 // Copyright 2016 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 "base/bind.h" 6 #include "base/macros.h" 7 #include "base/message_loop/message_loop.h" 8 #include "base/run_loop.h" 9 #include "mojo/public/cpp/bindings/binding.h" 10 #include "mojo/public/cpp/bindings/lib/fixed_buffer.h" 11 #include "mojo/public/cpp/bindings/lib/serialization.h" 12 #include "mojo/public/cpp/bindings/lib/wtf_serialization.h" 13 #include "mojo/public/cpp/bindings/tests/variant_test_util.h" 14 #include "mojo/public/interfaces/bindings/tests/test_wtf_types.mojom-blink.h" 15 #include "mojo/public/interfaces/bindings/tests/test_wtf_types.mojom.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 namespace mojo { 19 namespace test { 20 namespace { 21 22 const char kHelloWorld[] = "hello world"; 23 24 // Replace the "o"s in "hello world" with "o"s with acute. 25 const char kUTF8HelloWorld[] = "hell\xC3\xB3 w\xC3\xB3rld"; 26 27 class TestWTFImpl : public TestWTF { 28 public: 29 explicit TestWTFImpl(TestWTFRequest request) 30 : binding_(this, std::move(request)) {} 31 32 // mojo::test::TestWTF implementation: 33 void EchoString(const base::Optional<std::string>& str, 34 const EchoStringCallback& callback) override { 35 callback.Run(str); 36 } 37 38 void EchoStringArray( 39 const base::Optional<std::vector<base::Optional<std::string>>>& arr, 40 const EchoStringArrayCallback& callback) override { 41 callback.Run(std::move(arr)); 42 } 43 44 void EchoStringMap( 45 const base::Optional< 46 std::unordered_map<std::string, base::Optional<std::string>>>& 47 str_map, 48 const EchoStringMapCallback& callback) override { 49 callback.Run(std::move(str_map)); 50 } 51 52 private: 53 Binding<TestWTF> binding_; 54 }; 55 56 class WTFTypesTest : public testing::Test { 57 public: 58 WTFTypesTest() {} 59 60 private: 61 base::MessageLoop loop_; 62 }; 63 64 WTF::Vector<WTF::String> ConstructStringArray() { 65 WTF::Vector<WTF::String> strs(4); 66 // strs[0] is null. 67 // strs[1] is empty. 68 strs[1] = ""; 69 strs[2] = kHelloWorld; 70 strs[3] = WTF::String::fromUTF8(kUTF8HelloWorld); 71 72 return strs; 73 } 74 75 WTF::HashMap<WTF::String, WTF::String> ConstructStringMap() { 76 WTF::HashMap<WTF::String, WTF::String> str_map; 77 // A null string as value. 78 str_map.add("0", WTF::String()); 79 str_map.add("1", kHelloWorld); 80 str_map.add("2", WTF::String::fromUTF8(kUTF8HelloWorld)); 81 82 return str_map; 83 } 84 85 void ExpectString(const WTF::String& expected_string, 86 const base::Closure& closure, 87 const WTF::String& string) { 88 EXPECT_EQ(expected_string, string); 89 closure.Run(); 90 } 91 92 void ExpectStringArray(WTF::Optional<WTF::Vector<WTF::String>>* expected_arr, 93 const base::Closure& closure, 94 const WTF::Optional<WTF::Vector<WTF::String>>& arr) { 95 EXPECT_EQ(*expected_arr, arr); 96 closure.Run(); 97 } 98 99 void ExpectStringMap( 100 WTF::Optional<WTF::HashMap<WTF::String, WTF::String>>* expected_map, 101 const base::Closure& closure, 102 const WTF::Optional<WTF::HashMap<WTF::String, WTF::String>>& map) { 103 EXPECT_EQ(*expected_map, map); 104 closure.Run(); 105 } 106 107 } // namespace 108 109 TEST_F(WTFTypesTest, Serialization_WTFArrayToWTFArray) { 110 WTFArray<WTF::String> strs = ConstructStringArray(); 111 auto cloned_strs = strs.Clone(); 112 113 mojo::internal::SerializationContext context; 114 size_t size = mojo::internal::PrepareToSerialize<Array<mojo::String>>( 115 cloned_strs, &context); 116 117 mojo::internal::FixedBufferForTesting buf(size); 118 typename mojo::internal::MojomTypeTraits<Array<mojo::String>>::Data* data; 119 mojo::internal::ContainerValidateParams validate_params( 120 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr)); 121 mojo::internal::Serialize<Array<mojo::String>>(cloned_strs, &buf, &data, 122 &validate_params, &context); 123 124 WTFArray<WTF::String> strs2; 125 mojo::internal::Deserialize<Array<mojo::String>>(data, &strs2, &context); 126 127 EXPECT_TRUE(strs.Equals(strs2)); 128 } 129 130 TEST_F(WTFTypesTest, Serialization_WTFVectorToWTFVector) { 131 WTF::Vector<WTF::String> strs = ConstructStringArray(); 132 auto cloned_strs = strs; 133 134 mojo::internal::SerializationContext context; 135 size_t size = mojo::internal::PrepareToSerialize<Array<mojo::String>>( 136 cloned_strs, &context); 137 138 mojo::internal::FixedBufferForTesting buf(size); 139 typename mojo::internal::MojomTypeTraits<Array<mojo::String>>::Data* data; 140 mojo::internal::ContainerValidateParams validate_params( 141 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr)); 142 mojo::internal::Serialize<Array<mojo::String>>(cloned_strs, &buf, &data, 143 &validate_params, &context); 144 145 WTF::Vector<WTF::String> strs2; 146 mojo::internal::Deserialize<Array<mojo::String>>(data, &strs2, &context); 147 148 EXPECT_EQ(strs, strs2); 149 } 150 151 TEST_F(WTFTypesTest, Serialization_WTFArrayToMojoArray) { 152 WTFArray<WTF::String> strs = ConstructStringArray(); 153 154 mojo::internal::SerializationContext context; 155 size_t size = 156 mojo::internal::PrepareToSerialize<Array<mojo::String>>(strs, &context); 157 158 mojo::internal::FixedBufferForTesting buf(size); 159 typename mojo::internal::MojomTypeTraits<Array<mojo::String>>::Data* data; 160 mojo::internal::ContainerValidateParams validate_params( 161 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr)); 162 mojo::internal::Serialize<Array<mojo::String>>(strs, &buf, &data, 163 &validate_params, &context); 164 165 Array<mojo::String> strs2; 166 mojo::internal::Deserialize<Array<mojo::String>>(data, &strs2, &context); 167 168 ASSERT_EQ(4u, strs2.size()); 169 EXPECT_TRUE(strs2[0].is_null()); 170 EXPECT_TRUE("" == strs2[1]); 171 EXPECT_TRUE(kHelloWorld == strs2[2]); 172 EXPECT_TRUE(kUTF8HelloWorld == strs2[3]); 173 } 174 175 TEST_F(WTFTypesTest, Serialization_WTFMapToWTFMap) { 176 using WTFType = WTFMap<WTF::String, WTF::String>; 177 using MojomType = Map<mojo::String, mojo::String>; 178 179 WTFType str_map = ConstructStringMap(); 180 WTFType cloned_str_map = str_map.Clone(); 181 182 mojo::internal::SerializationContext context; 183 size_t size = 184 mojo::internal::PrepareToSerialize<MojomType>(cloned_str_map, &context); 185 186 mojo::internal::FixedBufferForTesting buf(size); 187 typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; 188 mojo::internal::ContainerValidateParams validate_params( 189 new mojo::internal::ContainerValidateParams( 190 0, false, 191 new mojo::internal::ContainerValidateParams(0, false, nullptr)), 192 new mojo::internal::ContainerValidateParams( 193 0, true, 194 new mojo::internal::ContainerValidateParams(0, false, nullptr))); 195 mojo::internal::Serialize<MojomType>(cloned_str_map, &buf, &data, 196 &validate_params, &context); 197 198 WTFType str_map2; 199 mojo::internal::Deserialize<MojomType>(data, &str_map2, &context); 200 201 EXPECT_TRUE(str_map.Equals(str_map2)); 202 } 203 204 TEST_F(WTFTypesTest, Serialization_WTFMapToMojoMap) { 205 using WTFType = WTFMap<WTF::String, WTF::String>; 206 using MojomType = Map<mojo::String, mojo::String>; 207 208 WTFType str_map = ConstructStringMap(); 209 210 mojo::internal::SerializationContext context; 211 size_t size = 212 mojo::internal::PrepareToSerialize<MojomType>(str_map, &context); 213 214 mojo::internal::FixedBufferForTesting buf(size); 215 typename mojo::internal::MojomTypeTraits<MojomType>::Data* data; 216 mojo::internal::ContainerValidateParams validate_params( 217 new mojo::internal::ContainerValidateParams( 218 0, false, 219 new mojo::internal::ContainerValidateParams(0, false, nullptr)), 220 new mojo::internal::ContainerValidateParams( 221 0, true, 222 new mojo::internal::ContainerValidateParams(0, false, nullptr))); 223 mojo::internal::Serialize<MojomType>(str_map, &buf, &data, &validate_params, 224 &context); 225 226 MojomType str_map2; 227 mojo::internal::Deserialize<MojomType>(data, &str_map2, &context); 228 229 ASSERT_EQ(3u, str_map2.size()); 230 EXPECT_TRUE(str_map2["0"].is_null()); 231 EXPECT_TRUE(kHelloWorld == str_map2["1"]); 232 EXPECT_TRUE(kUTF8HelloWorld == str_map2["2"]); 233 } 234 235 TEST_F(WTFTypesTest, Serialization_PublicAPI) { 236 blink::TestWTFStructPtr input(blink::TestWTFStruct::New()); 237 input->str = kHelloWorld; 238 input->integer = 42; 239 240 blink::TestWTFStructPtr cloned_input = input.Clone(); 241 242 WTFArray<uint8_t> data = blink::TestWTFStruct::Serialize(&input); 243 244 blink::TestWTFStructPtr output; 245 ASSERT_TRUE(blink::TestWTFStruct::Deserialize(std::move(data), &output)); 246 EXPECT_TRUE(cloned_input.Equals(output)); 247 } 248 249 TEST_F(WTFTypesTest, SendString) { 250 blink::TestWTFPtr ptr; 251 TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr))); 252 253 WTF::Vector<WTF::String> strs = ConstructStringArray(); 254 255 for (size_t i = 0; i < strs.size(); ++i) { 256 base::RunLoop loop; 257 // Test that a WTF::String is unchanged after the following conversion: 258 // - serialized; 259 // - deserialized as base::Optional<std::string>; 260 // - serialized; 261 // - deserialized as WTF::String. 262 ptr->EchoString(strs[i], 263 base::Bind(&ExpectString, strs[i], loop.QuitClosure())); 264 loop.Run(); 265 } 266 } 267 268 TEST_F(WTFTypesTest, SendStringArray) { 269 blink::TestWTFPtr ptr; 270 TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr))); 271 272 WTF::Optional<WTF::Vector<WTF::String>> arrs[3]; 273 // arrs[0] is empty. 274 arrs[0].emplace(); 275 // arrs[1] is null. 276 arrs[2] = ConstructStringArray(); 277 278 for (size_t i = 0; i < arraysize(arrs); ++i) { 279 base::RunLoop loop; 280 // Test that a WTF::Optional<WTF::Vector<WTF::String>> is unchanged after 281 // the following conversion: 282 // - serialized; 283 // - deserialized as 284 // base::Optional<std::vector<base::Optional<std::string>>>; 285 // - serialized; 286 // - deserialized as WTF::Optional<WTF::Vector<WTF::String>>. 287 ptr->EchoStringArray( 288 arrs[i], base::Bind(&ExpectStringArray, base::Unretained(&arrs[i]), 289 loop.QuitClosure())); 290 loop.Run(); 291 } 292 } 293 294 TEST_F(WTFTypesTest, SendStringMap) { 295 blink::TestWTFPtr ptr; 296 TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr))); 297 298 WTF::Optional<WTF::HashMap<WTF::String, WTF::String>> maps[3]; 299 // maps[0] is empty. 300 maps[0].emplace(); 301 // maps[1] is null. 302 maps[2] = ConstructStringMap(); 303 304 for (size_t i = 0; i < arraysize(maps); ++i) { 305 base::RunLoop loop; 306 // Test that a WTF::Optional<WTF::HashMap<WTF::String, WTF::String>> is 307 // unchanged after the following conversion: 308 // - serialized; 309 // - deserialized as base::Optional< 310 // std::unordered_map<std::string, base::Optional<std::string>>>; 311 // - serialized; 312 // - deserialized as WTF::Optional<WTF::HashMap<WTF::String, 313 // WTF::String>>. 314 ptr->EchoStringMap(maps[i], 315 base::Bind(&ExpectStringMap, base::Unretained(&maps[i]), 316 loop.QuitClosure())); 317 loop.Run(); 318 } 319 } 320 321 } // namespace test 322 } // namespace mojo 323