1 // Copyright 2015 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/callback.h" 7 #include "base/logging.h" 8 #include "base/message_loop/message_loop.h" 9 #include "base/run_loop.h" 10 #include "mojo/public/cpp/bindings/binding_set.h" 11 #include "mojo/public/cpp/bindings/interface_request.h" 12 #include "mojo/public/cpp/bindings/tests/rect_blink.h" 13 #include "mojo/public/cpp/bindings/tests/rect_chromium.h" 14 #include "mojo/public/cpp/bindings/tests/struct_with_traits_impl.h" 15 #include "mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h" 16 #include "mojo/public/cpp/bindings/tests/variant_test_util.h" 17 #include "mojo/public/interfaces/bindings/tests/struct_with_traits.mojom.h" 18 #include "mojo/public/interfaces/bindings/tests/test_native_types.mojom-blink.h" 19 #include "mojo/public/interfaces/bindings/tests/test_native_types.mojom.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 22 namespace mojo { 23 namespace test { 24 namespace { 25 26 template <typename T> 27 void DoExpectResult(const T& expected, 28 const base::Closure& callback, 29 const T& actual) { 30 EXPECT_EQ(expected.x(), actual.x()); 31 EXPECT_EQ(expected.y(), actual.y()); 32 EXPECT_EQ(expected.width(), actual.width()); 33 EXPECT_EQ(expected.height(), actual.height()); 34 callback.Run(); 35 } 36 37 template <typename T> 38 base::Callback<void(const T&)> ExpectResult(const T& r, 39 const base::Closure& callback) { 40 return base::Bind(&DoExpectResult<T>, r, callback); 41 } 42 43 template <typename T> 44 void DoFail(const std::string& reason, const T&) { 45 EXPECT_TRUE(false) << reason; 46 } 47 48 template <typename T> 49 base::Callback<void(const T&)> Fail(const std::string& reason) { 50 return base::Bind(&DoFail<T>, reason); 51 } 52 53 template <typename T> 54 void ExpectError(InterfacePtr<T> *proxy, const base::Closure& callback) { 55 proxy->set_connection_error_handler(callback); 56 } 57 58 // This implements the generated Chromium variant of RectService. 59 class ChromiumRectServiceImpl : public RectService { 60 public: 61 ChromiumRectServiceImpl() {} 62 63 // mojo::test::RectService: 64 void AddRect(const RectChromium& r) override { 65 if (r.GetArea() > largest_rect_.GetArea()) 66 largest_rect_ = r; 67 } 68 69 void GetLargestRect(const GetLargestRectCallback& callback) override { 70 callback.Run(largest_rect_); 71 } 72 73 private: 74 RectChromium largest_rect_; 75 }; 76 77 // This implements the generated Blink variant of RectService. 78 class BlinkRectServiceImpl : public blink::RectService { 79 public: 80 BlinkRectServiceImpl() {} 81 82 // mojo::test::blink::RectService: 83 void AddRect(const RectBlink& r) override { 84 if (r.computeArea() > largest_rect_.computeArea()) { 85 largest_rect_.setX(r.x()); 86 largest_rect_.setY(r.y()); 87 largest_rect_.setWidth(r.width()); 88 largest_rect_.setHeight(r.height()); 89 } 90 } 91 92 void GetLargestRect(const GetLargestRectCallback& callback) override { 93 callback.Run(largest_rect_); 94 } 95 96 private: 97 RectBlink largest_rect_; 98 }; 99 100 // A test which runs both Chromium and Blink implementations of a RectService. 101 class StructTraitsTest : public testing::Test, 102 public TraitsTestService { 103 public: 104 StructTraitsTest() {} 105 106 protected: 107 void BindToChromiumService(RectServiceRequest request) { 108 chromium_bindings_.AddBinding(&chromium_service_, std::move(request)); 109 } 110 void BindToChromiumService(blink::RectServiceRequest request) { 111 chromium_bindings_.AddBinding( 112 &chromium_service_, 113 ConvertInterfaceRequest<RectService>(std::move(request))); 114 } 115 116 void BindToBlinkService(blink::RectServiceRequest request) { 117 blink_bindings_.AddBinding(&blink_service_, std::move(request)); 118 } 119 void BindToBlinkService(RectServiceRequest request) { 120 blink_bindings_.AddBinding( 121 &blink_service_, 122 ConvertInterfaceRequest<blink::RectService>(std::move(request))); 123 } 124 125 TraitsTestServicePtr GetTraitsTestProxy() { 126 return traits_test_bindings_.CreateInterfacePtrAndBind(this); 127 } 128 129 private: 130 // TraitsTestService: 131 void EchoStructWithTraits( 132 const StructWithTraitsImpl& s, 133 const EchoStructWithTraitsCallback& callback) override { 134 callback.Run(s); 135 } 136 137 void EchoPassByValueStructWithTraits( 138 PassByValueStructWithTraitsImpl s, 139 const EchoPassByValueStructWithTraitsCallback& callback) override { 140 callback.Run(std::move(s)); 141 } 142 143 void EchoEnumWithTraits(EnumWithTraitsImpl e, 144 const EchoEnumWithTraitsCallback& callback) override { 145 callback.Run(e); 146 } 147 148 void EchoStructWithTraitsForUniquePtrTest( 149 std::unique_ptr<int> e, 150 const EchoStructWithTraitsForUniquePtrTestCallback& callback) override { 151 callback.Run(std::move(e)); 152 } 153 154 base::MessageLoop loop_; 155 156 ChromiumRectServiceImpl chromium_service_; 157 BindingSet<RectService> chromium_bindings_; 158 159 BlinkRectServiceImpl blink_service_; 160 BindingSet<blink::RectService> blink_bindings_; 161 162 BindingSet<TraitsTestService> traits_test_bindings_; 163 }; 164 165 } // namespace 166 167 TEST_F(StructTraitsTest, ChromiumProxyToChromiumService) { 168 RectServicePtr chromium_proxy; 169 BindToChromiumService(GetProxy(&chromium_proxy)); 170 { 171 base::RunLoop loop; 172 chromium_proxy->AddRect(RectChromium(1, 1, 4, 5)); 173 chromium_proxy->AddRect(RectChromium(-1, -1, 2, 2)); 174 chromium_proxy->GetLargestRect( 175 ExpectResult(RectChromium(1, 1, 4, 5), loop.QuitClosure())); 176 loop.Run(); 177 } 178 } 179 180 TEST_F(StructTraitsTest, ChromiumToBlinkService) { 181 RectServicePtr chromium_proxy; 182 BindToBlinkService(GetProxy(&chromium_proxy)); 183 { 184 base::RunLoop loop; 185 chromium_proxy->AddRect(RectChromium(1, 1, 4, 5)); 186 chromium_proxy->AddRect(RectChromium(2, 2, 5, 5)); 187 chromium_proxy->GetLargestRect( 188 ExpectResult(RectChromium(2, 2, 5, 5), loop.QuitClosure())); 189 loop.Run(); 190 } 191 // The Blink service should drop our connection because RectBlink's 192 // deserializer rejects negative origins. 193 { 194 base::RunLoop loop; 195 ExpectError(&chromium_proxy, loop.QuitClosure()); 196 chromium_proxy->AddRect(RectChromium(-1, -1, 2, 2)); 197 chromium_proxy->GetLargestRect( 198 Fail<RectChromium>("The pipe should have been closed.")); 199 loop.Run(); 200 } 201 } 202 203 TEST_F(StructTraitsTest, BlinkProxyToBlinkService) { 204 blink::RectServicePtr blink_proxy; 205 BindToBlinkService(GetProxy(&blink_proxy)); 206 { 207 base::RunLoop loop; 208 blink_proxy->AddRect(RectBlink(1, 1, 4, 5)); 209 blink_proxy->AddRect(RectBlink(10, 10, 20, 20)); 210 blink_proxy->GetLargestRect( 211 ExpectResult(RectBlink(10, 10, 20, 20), loop.QuitClosure())); 212 loop.Run(); 213 } 214 } 215 216 TEST_F(StructTraitsTest, BlinkProxyToChromiumService) { 217 blink::RectServicePtr blink_proxy; 218 BindToChromiumService(GetProxy(&blink_proxy)); 219 { 220 base::RunLoop loop; 221 blink_proxy->AddRect(RectBlink(1, 1, 4, 5)); 222 blink_proxy->AddRect(RectBlink(10, 10, 2, 2)); 223 blink_proxy->GetLargestRect( 224 ExpectResult(RectBlink(1, 1, 4, 5), loop.QuitClosure())); 225 loop.Run(); 226 } 227 } 228 229 void ExpectStructWithTraits(const StructWithTraitsImpl& expected, 230 const base::Closure& closure, 231 const StructWithTraitsImpl& passed) { 232 EXPECT_EQ(expected.get_enum(), passed.get_enum()); 233 EXPECT_EQ(expected.get_bool(), passed.get_bool()); 234 EXPECT_EQ(expected.get_uint32(), passed.get_uint32()); 235 EXPECT_EQ(expected.get_uint64(), passed.get_uint64()); 236 EXPECT_EQ(expected.get_string(), passed.get_string()); 237 EXPECT_EQ(expected.get_string_array(), passed.get_string_array()); 238 EXPECT_EQ(expected.get_struct(), passed.get_struct()); 239 EXPECT_EQ(expected.get_struct_array(), passed.get_struct_array()); 240 EXPECT_EQ(expected.get_struct_map(), passed.get_struct_map()); 241 closure.Run(); 242 } 243 244 TEST_F(StructTraitsTest, EchoStructWithTraits) { 245 StructWithTraitsImpl input; 246 input.set_enum(EnumWithTraitsImpl::CUSTOM_VALUE_1); 247 input.set_bool(true); 248 input.set_uint32(7); 249 input.set_uint64(42); 250 input.set_string("hello world!"); 251 input.get_mutable_string_array().assign({"hello", "world!"}); 252 input.get_mutable_struct().value = 42; 253 input.get_mutable_struct_array().resize(2); 254 input.get_mutable_struct_array()[0].value = 1; 255 input.get_mutable_struct_array()[1].value = 2; 256 input.get_mutable_struct_map()["hello"] = NestedStructWithTraitsImpl(1024); 257 input.get_mutable_struct_map()["world"] = NestedStructWithTraitsImpl(2048); 258 259 base::RunLoop loop; 260 TraitsTestServicePtr proxy = GetTraitsTestProxy(); 261 262 proxy->EchoStructWithTraits( 263 input, 264 base::Bind(&ExpectStructWithTraits, input, loop.QuitClosure())); 265 loop.Run(); 266 } 267 268 TEST_F(StructTraitsTest, CloneStructWithTraitsContainer) { 269 StructWithTraitsContainerPtr container = StructWithTraitsContainer::New(); 270 container->f_struct.set_uint32(7); 271 container->f_struct.set_uint64(42); 272 StructWithTraitsContainerPtr cloned_container = container.Clone(); 273 EXPECT_EQ(7u, cloned_container->f_struct.get_uint32()); 274 EXPECT_EQ(42u, cloned_container->f_struct.get_uint64()); 275 } 276 277 void CaptureMessagePipe(ScopedMessagePipeHandle* storage, 278 const base::Closure& closure, 279 PassByValueStructWithTraitsImpl passed) { 280 storage->reset(MessagePipeHandle( 281 passed.get_mutable_handle().release().value())); 282 closure.Run(); 283 } 284 285 TEST_F(StructTraitsTest, EchoPassByValueStructWithTraits) { 286 MessagePipe mp; 287 PassByValueStructWithTraitsImpl input; 288 input.get_mutable_handle().reset(mp.handle0.release()); 289 290 base::RunLoop loop; 291 TraitsTestServicePtr proxy = GetTraitsTestProxy(); 292 293 ScopedMessagePipeHandle received; 294 proxy->EchoPassByValueStructWithTraits( 295 std::move(input), 296 base::Bind(&CaptureMessagePipe, &received, loop.QuitClosure())); 297 loop.Run(); 298 299 ASSERT_TRUE(received.is_valid()); 300 301 // Verify that the message pipe handle is correctly passed. 302 const char kHello[] = "hello"; 303 const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello)); 304 EXPECT_EQ(MOJO_RESULT_OK, 305 WriteMessageRaw(mp.handle1.get(), kHello, kHelloSize, nullptr, 0, 306 MOJO_WRITE_MESSAGE_FLAG_NONE)); 307 308 EXPECT_EQ(MOJO_RESULT_OK, Wait(received.get(), MOJO_HANDLE_SIGNAL_READABLE, 309 MOJO_DEADLINE_INDEFINITE, nullptr)); 310 311 char buffer[10] = {0}; 312 uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer)); 313 EXPECT_EQ(MOJO_RESULT_OK, 314 ReadMessageRaw(received.get(), buffer, &buffer_size, nullptr, 315 nullptr, MOJO_READ_MESSAGE_FLAG_NONE)); 316 EXPECT_EQ(kHelloSize, buffer_size); 317 EXPECT_STREQ(kHello, buffer); 318 } 319 320 void ExpectEnumWithTraits(EnumWithTraitsImpl expected_value, 321 const base::Closure& closure, 322 EnumWithTraitsImpl value) { 323 EXPECT_EQ(expected_value, value); 324 closure.Run(); 325 } 326 327 TEST_F(StructTraitsTest, EchoEnumWithTraits) { 328 base::RunLoop loop; 329 TraitsTestServicePtr proxy = GetTraitsTestProxy(); 330 331 proxy->EchoEnumWithTraits( 332 EnumWithTraitsImpl::CUSTOM_VALUE_1, 333 base::Bind(&ExpectEnumWithTraits, EnumWithTraitsImpl::CUSTOM_VALUE_1, 334 loop.QuitClosure())); 335 loop.Run(); 336 } 337 338 TEST_F(StructTraitsTest, SerializeStructWithTraits) { 339 StructWithTraitsImpl input; 340 input.set_enum(EnumWithTraitsImpl::CUSTOM_VALUE_1); 341 input.set_bool(true); 342 input.set_uint32(7); 343 input.set_uint64(42); 344 input.set_string("hello world!"); 345 input.get_mutable_string_array().assign({"hello", "world!"}); 346 input.get_mutable_struct().value = 42; 347 input.get_mutable_struct_array().resize(2); 348 input.get_mutable_struct_array()[0].value = 1; 349 input.get_mutable_struct_array()[1].value = 2; 350 input.get_mutable_struct_map()["hello"] = NestedStructWithTraitsImpl(1024); 351 input.get_mutable_struct_map()["world"] = NestedStructWithTraitsImpl(2048); 352 353 mojo::Array<uint8_t> data = StructWithTraits::Serialize(&input); 354 StructWithTraitsImpl output; 355 ASSERT_TRUE(StructWithTraits::Deserialize(std::move(data), &output)); 356 357 EXPECT_EQ(input.get_enum(), output.get_enum()); 358 EXPECT_EQ(input.get_bool(), output.get_bool()); 359 EXPECT_EQ(input.get_uint32(), output.get_uint32()); 360 EXPECT_EQ(input.get_uint64(), output.get_uint64()); 361 EXPECT_EQ(input.get_string(), output.get_string()); 362 EXPECT_EQ(input.get_string_array(), output.get_string_array()); 363 EXPECT_EQ(input.get_struct(), output.get_struct()); 364 EXPECT_EQ(input.get_struct_array(), output.get_struct_array()); 365 EXPECT_EQ(input.get_struct_map(), output.get_struct_map()); 366 } 367 368 void ExpectUniquePtr(int expected, 369 const base::Closure& closure, 370 std::unique_ptr<int> value) { 371 EXPECT_EQ(expected, *value); 372 closure.Run(); 373 } 374 375 TEST_F(StructTraitsTest, TypemapUniquePtr) { 376 base::RunLoop loop; 377 TraitsTestServicePtr proxy = GetTraitsTestProxy(); 378 379 proxy->EchoStructWithTraitsForUniquePtrTest( 380 base::MakeUnique<int>(12345), 381 base::Bind(&ExpectUniquePtr, 12345, loop.QuitClosure())); 382 loop.Run(); 383 } 384 385 } // namespace test 386 } // namespace mojo 387