1 // Copyright 2013 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 <stdint.h> 6 #include <utility> 7 8 #include "base/bind.h" 9 #include "base/callback.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/run_loop.h" 12 #include "mojo/public/cpp/bindings/binding.h" 13 #include "mojo/public/cpp/bindings/strong_binding.h" 14 #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h" 15 #include "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.h" 16 #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h" 17 #include "mojo/public/interfaces/bindings/tests/scoping.mojom.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 namespace mojo { 21 namespace test { 22 namespace { 23 24 typedef base::Callback<void(double)> CalcCallback; 25 26 class MathCalculatorImpl : public math::Calculator { 27 public: 28 explicit MathCalculatorImpl(InterfaceRequest<math::Calculator> request) 29 : total_(0.0), binding_(this, std::move(request)) {} 30 ~MathCalculatorImpl() override {} 31 32 void CloseMessagePipe() { binding_.Close(); } 33 34 void WaitForIncomingMethodCall() { binding_.WaitForIncomingMethodCall(); } 35 36 void Clear(const CalcCallback& callback) override { 37 total_ = 0.0; 38 callback.Run(total_); 39 } 40 41 void Add(double value, const CalcCallback& callback) override { 42 total_ += value; 43 callback.Run(total_); 44 } 45 46 void Multiply(double value, const CalcCallback& callback) override { 47 total_ *= value; 48 callback.Run(total_); 49 } 50 51 private: 52 double total_; 53 Binding<math::Calculator> binding_; 54 }; 55 56 class MathCalculatorUI { 57 public: 58 explicit MathCalculatorUI(math::CalculatorPtr calculator) 59 : calculator_(std::move(calculator)), 60 output_(0.0) {} 61 62 bool encountered_error() const { return calculator_.encountered_error(); } 63 void set_connection_error_handler(const base::Closure& closure) { 64 calculator_.set_connection_error_handler(closure); 65 } 66 67 void Add(double value, const base::Closure& closure) { 68 calculator_->Add( 69 value, 70 base::Bind(&MathCalculatorUI::Output, base::Unretained(this), closure)); 71 } 72 73 void Multiply(double value, const base::Closure& closure) { 74 calculator_->Multiply( 75 value, 76 base::Bind(&MathCalculatorUI::Output, base::Unretained(this), closure)); 77 } 78 79 double GetOutput() const { return output_; } 80 81 private: 82 void Output(const base::Closure& closure, double output) { 83 output_ = output; 84 if (!closure.is_null()) 85 closure.Run(); 86 } 87 88 math::CalculatorPtr calculator_; 89 double output_; 90 base::Closure closure_; 91 }; 92 93 class SelfDestructingMathCalculatorUI { 94 public: 95 explicit SelfDestructingMathCalculatorUI(math::CalculatorPtr calculator) 96 : calculator_(std::move(calculator)), nesting_level_(0) { 97 ++num_instances_; 98 } 99 100 void BeginTest(bool nested, const base::Closure& closure) { 101 nesting_level_ = nested ? 2 : 1; 102 calculator_->Add( 103 1.0, 104 base::Bind(&SelfDestructingMathCalculatorUI::Output, 105 base::Unretained(this), closure)); 106 } 107 108 static int num_instances() { return num_instances_; } 109 110 void Output(const base::Closure& closure, double value) { 111 if (--nesting_level_ > 0) { 112 // Add some more and wait for re-entrant call to Output! 113 calculator_->Add( 114 1.0, 115 base::Bind(&SelfDestructingMathCalculatorUI::Output, 116 base::Unretained(this), closure)); 117 } else { 118 closure.Run(); 119 delete this; 120 } 121 } 122 123 private: 124 ~SelfDestructingMathCalculatorUI() { --num_instances_; } 125 126 math::CalculatorPtr calculator_; 127 int nesting_level_; 128 static int num_instances_; 129 }; 130 131 // static 132 int SelfDestructingMathCalculatorUI::num_instances_ = 0; 133 134 class ReentrantServiceImpl : public sample::Service { 135 public: 136 ~ReentrantServiceImpl() override {} 137 138 explicit ReentrantServiceImpl(InterfaceRequest<sample::Service> request) 139 : call_depth_(0), 140 max_call_depth_(0), 141 binding_(this, std::move(request)) {} 142 143 int max_call_depth() { return max_call_depth_; } 144 145 void Frobinate(sample::FooPtr foo, 146 sample::Service::BazOptions baz, 147 sample::PortPtr port, 148 const sample::Service::FrobinateCallback& callback) override { 149 max_call_depth_ = std::max(++call_depth_, max_call_depth_); 150 if (call_depth_ == 1) { 151 EXPECT_TRUE(binding_.WaitForIncomingMethodCall()); 152 } 153 call_depth_--; 154 callback.Run(5); 155 } 156 157 void GetPort(mojo::InterfaceRequest<sample::Port> port) override {} 158 159 private: 160 int call_depth_; 161 int max_call_depth_; 162 Binding<sample::Service> binding_; 163 }; 164 165 class IntegerAccessorImpl : public sample::IntegerAccessor { 166 public: 167 IntegerAccessorImpl() : integer_(0) {} 168 ~IntegerAccessorImpl() override {} 169 170 int64_t integer() const { return integer_; } 171 172 void set_closure(const base::Closure& closure) { closure_ = closure; } 173 174 private: 175 // sample::IntegerAccessor implementation. 176 void GetInteger(const GetIntegerCallback& callback) override { 177 callback.Run(integer_, sample::Enum::VALUE); 178 } 179 void SetInteger(int64_t data, sample::Enum type) override { 180 integer_ = data; 181 if (!closure_.is_null()) { 182 closure_.Run(); 183 closure_.Reset(); 184 } 185 } 186 187 int64_t integer_; 188 base::Closure closure_; 189 }; 190 191 class InterfacePtrTest : public testing::Test { 192 public: 193 InterfacePtrTest() {} 194 ~InterfacePtrTest() override { base::RunLoop().RunUntilIdle(); } 195 196 void PumpMessages() { base::RunLoop().RunUntilIdle(); } 197 198 private: 199 base::MessageLoop loop_; 200 }; 201 202 void SetFlagAndRunClosure(bool* flag, const base::Closure& closure) { 203 *flag = true; 204 closure.Run(); 205 } 206 207 void IgnoreValueAndRunClosure(const base::Closure& closure, int32_t value) { 208 closure.Run(); 209 } 210 211 void ExpectValueAndRunClosure(uint32_t expected_value, 212 const base::Closure& closure, 213 uint32_t value) { 214 EXPECT_EQ(expected_value, value); 215 closure.Run(); 216 } 217 218 TEST_F(InterfacePtrTest, IsBound) { 219 math::CalculatorPtr calc; 220 EXPECT_FALSE(calc.is_bound()); 221 MathCalculatorImpl calc_impl(GetProxy(&calc)); 222 EXPECT_TRUE(calc.is_bound()); 223 } 224 225 TEST_F(InterfacePtrTest, EndToEnd) { 226 math::CalculatorPtr calc; 227 MathCalculatorImpl calc_impl(GetProxy(&calc)); 228 229 // Suppose this is instantiated in a process that has pipe1_. 230 MathCalculatorUI calculator_ui(std::move(calc)); 231 232 base::RunLoop run_loop, run_loop2; 233 calculator_ui.Add(2.0, run_loop.QuitClosure()); 234 calculator_ui.Multiply(5.0, run_loop2.QuitClosure()); 235 run_loop.Run(); 236 run_loop2.Run(); 237 238 EXPECT_EQ(10.0, calculator_ui.GetOutput()); 239 } 240 241 TEST_F(InterfacePtrTest, EndToEnd_Synchronous) { 242 math::CalculatorPtr calc; 243 MathCalculatorImpl calc_impl(GetProxy(&calc)); 244 245 // Suppose this is instantiated in a process that has pipe1_. 246 MathCalculatorUI calculator_ui(std::move(calc)); 247 248 EXPECT_EQ(0.0, calculator_ui.GetOutput()); 249 250 base::RunLoop run_loop; 251 calculator_ui.Add(2.0, run_loop.QuitClosure()); 252 EXPECT_EQ(0.0, calculator_ui.GetOutput()); 253 calc_impl.WaitForIncomingMethodCall(); 254 run_loop.Run(); 255 EXPECT_EQ(2.0, calculator_ui.GetOutput()); 256 257 base::RunLoop run_loop2; 258 calculator_ui.Multiply(5.0, run_loop2.QuitClosure()); 259 EXPECT_EQ(2.0, calculator_ui.GetOutput()); 260 calc_impl.WaitForIncomingMethodCall(); 261 run_loop2.Run(); 262 EXPECT_EQ(10.0, calculator_ui.GetOutput()); 263 } 264 265 TEST_F(InterfacePtrTest, Movable) { 266 math::CalculatorPtr a; 267 math::CalculatorPtr b; 268 MathCalculatorImpl calc_impl(GetProxy(&b)); 269 270 EXPECT_TRUE(!a); 271 EXPECT_FALSE(!b); 272 273 a = std::move(b); 274 275 EXPECT_FALSE(!a); 276 EXPECT_TRUE(!b); 277 } 278 279 TEST_F(InterfacePtrTest, Resettable) { 280 math::CalculatorPtr a; 281 282 EXPECT_TRUE(!a); 283 284 MessagePipe pipe; 285 286 // Save this so we can test it later. 287 Handle handle = pipe.handle0.get(); 288 289 a = MakeProxy( 290 InterfacePtrInfo<math::Calculator>(std::move(pipe.handle0), 0u)); 291 292 EXPECT_FALSE(!a); 293 294 a.reset(); 295 296 EXPECT_TRUE(!a); 297 EXPECT_FALSE(a.internal_state()->is_bound()); 298 299 // Test that handle was closed. 300 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, CloseRaw(handle)); 301 } 302 303 TEST_F(InterfacePtrTest, BindInvalidHandle) { 304 math::CalculatorPtr ptr; 305 EXPECT_FALSE(ptr.get()); 306 EXPECT_FALSE(ptr); 307 308 ptr.Bind(InterfacePtrInfo<math::Calculator>()); 309 EXPECT_FALSE(ptr.get()); 310 EXPECT_FALSE(ptr); 311 } 312 313 TEST_F(InterfacePtrTest, EncounteredError) { 314 math::CalculatorPtr proxy; 315 MathCalculatorImpl calc_impl(GetProxy(&proxy)); 316 317 MathCalculatorUI calculator_ui(std::move(proxy)); 318 319 base::RunLoop run_loop; 320 calculator_ui.Add(2.0, run_loop.QuitClosure()); 321 run_loop.Run(); 322 EXPECT_EQ(2.0, calculator_ui.GetOutput()); 323 EXPECT_FALSE(calculator_ui.encountered_error()); 324 325 calculator_ui.Multiply(5.0, base::Closure()); 326 EXPECT_FALSE(calculator_ui.encountered_error()); 327 328 // Close the server. 329 calc_impl.CloseMessagePipe(); 330 331 // The state change isn't picked up locally yet. 332 base::RunLoop run_loop2; 333 calculator_ui.set_connection_error_handler(run_loop2.QuitClosure()); 334 EXPECT_FALSE(calculator_ui.encountered_error()); 335 336 run_loop2.Run(); 337 338 // OK, now we see the error. 339 EXPECT_TRUE(calculator_ui.encountered_error()); 340 } 341 342 TEST_F(InterfacePtrTest, EncounteredErrorCallback) { 343 math::CalculatorPtr proxy; 344 MathCalculatorImpl calc_impl(GetProxy(&proxy)); 345 346 bool encountered_error = false; 347 base::RunLoop run_loop; 348 proxy.set_connection_error_handler( 349 base::Bind(&SetFlagAndRunClosure, &encountered_error, 350 run_loop.QuitClosure())); 351 352 MathCalculatorUI calculator_ui(std::move(proxy)); 353 354 base::RunLoop run_loop2; 355 calculator_ui.Add(2.0, run_loop2.QuitClosure()); 356 run_loop2.Run(); 357 EXPECT_EQ(2.0, calculator_ui.GetOutput()); 358 EXPECT_FALSE(calculator_ui.encountered_error()); 359 360 calculator_ui.Multiply(5.0, base::Closure()); 361 EXPECT_FALSE(calculator_ui.encountered_error()); 362 363 // Close the server. 364 calc_impl.CloseMessagePipe(); 365 366 // The state change isn't picked up locally yet. 367 EXPECT_FALSE(calculator_ui.encountered_error()); 368 369 run_loop.Run(); 370 371 // OK, now we see the error. 372 EXPECT_TRUE(calculator_ui.encountered_error()); 373 374 // We should have also been able to observe the error through the error 375 // handler. 376 EXPECT_TRUE(encountered_error); 377 } 378 379 TEST_F(InterfacePtrTest, DestroyInterfacePtrOnMethodResponse) { 380 math::CalculatorPtr proxy; 381 MathCalculatorImpl calc_impl(GetProxy(&proxy)); 382 383 EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances()); 384 385 SelfDestructingMathCalculatorUI* impl = 386 new SelfDestructingMathCalculatorUI(std::move(proxy)); 387 base::RunLoop run_loop; 388 impl->BeginTest(false, run_loop.QuitClosure()); 389 run_loop.Run(); 390 391 EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances()); 392 } 393 394 TEST_F(InterfacePtrTest, NestedDestroyInterfacePtrOnMethodResponse) { 395 math::CalculatorPtr proxy; 396 MathCalculatorImpl calc_impl(GetProxy(&proxy)); 397 398 EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances()); 399 400 SelfDestructingMathCalculatorUI* impl = 401 new SelfDestructingMathCalculatorUI(std::move(proxy)); 402 base::RunLoop run_loop; 403 impl->BeginTest(true, run_loop.QuitClosure()); 404 run_loop.Run(); 405 406 EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances()); 407 } 408 409 TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) { 410 sample::ServicePtr proxy; 411 ReentrantServiceImpl impl(GetProxy(&proxy)); 412 413 base::RunLoop run_loop, run_loop2; 414 proxy->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, 415 base::Bind(&IgnoreValueAndRunClosure, 416 run_loop.QuitClosure())); 417 proxy->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr, 418 base::Bind(&IgnoreValueAndRunClosure, 419 run_loop2.QuitClosure())); 420 421 run_loop.Run(); 422 run_loop2.Run(); 423 424 EXPECT_EQ(2, impl.max_call_depth()); 425 } 426 427 TEST_F(InterfacePtrTest, QueryVersion) { 428 IntegerAccessorImpl impl; 429 sample::IntegerAccessorPtr ptr; 430 Binding<sample::IntegerAccessor> binding(&impl, GetProxy(&ptr)); 431 432 EXPECT_EQ(0u, ptr.version()); 433 434 base::RunLoop run_loop; 435 ptr.QueryVersion(base::Bind(&ExpectValueAndRunClosure, 3u, 436 run_loop.QuitClosure())); 437 run_loop.Run(); 438 439 EXPECT_EQ(3u, ptr.version()); 440 } 441 442 TEST_F(InterfacePtrTest, RequireVersion) { 443 IntegerAccessorImpl impl; 444 sample::IntegerAccessorPtr ptr; 445 Binding<sample::IntegerAccessor> binding(&impl, GetProxy(&ptr)); 446 447 EXPECT_EQ(0u, ptr.version()); 448 449 ptr.RequireVersion(1u); 450 EXPECT_EQ(1u, ptr.version()); 451 base::RunLoop run_loop; 452 impl.set_closure(run_loop.QuitClosure()); 453 ptr->SetInteger(123, sample::Enum::VALUE); 454 run_loop.Run(); 455 EXPECT_FALSE(ptr.encountered_error()); 456 EXPECT_EQ(123, impl.integer()); 457 458 ptr.RequireVersion(3u); 459 EXPECT_EQ(3u, ptr.version()); 460 base::RunLoop run_loop2; 461 impl.set_closure(run_loop2.QuitClosure()); 462 ptr->SetInteger(456, sample::Enum::VALUE); 463 run_loop2.Run(); 464 EXPECT_FALSE(ptr.encountered_error()); 465 EXPECT_EQ(456, impl.integer()); 466 467 // Require a version that is not supported by the impl side. 468 ptr.RequireVersion(4u); 469 // This value is set to the input of RequireVersion() synchronously. 470 EXPECT_EQ(4u, ptr.version()); 471 base::RunLoop run_loop3; 472 ptr.set_connection_error_handler(run_loop3.QuitClosure()); 473 ptr->SetInteger(789, sample::Enum::VALUE); 474 run_loop3.Run(); 475 EXPECT_TRUE(ptr.encountered_error()); 476 // The call to SetInteger() after RequireVersion(4u) is ignored. 477 EXPECT_EQ(456, impl.integer()); 478 } 479 480 class StrongMathCalculatorImpl : public math::Calculator { 481 public: 482 StrongMathCalculatorImpl(ScopedMessagePipeHandle handle, 483 bool* error_received, 484 bool* destroyed, 485 const base::Closure& closure) 486 : error_received_(error_received), 487 destroyed_(destroyed), 488 closure_(closure), 489 binding_(this, std::move(handle)) { 490 binding_.set_connection_error_handler( 491 base::Bind(&SetFlagAndRunClosure, error_received_, closure_)); 492 } 493 ~StrongMathCalculatorImpl() override { *destroyed_ = true; } 494 495 // math::Calculator implementation. 496 void Clear(const CalcCallback& callback) override { callback.Run(total_); } 497 498 void Add(double value, const CalcCallback& callback) override { 499 total_ += value; 500 callback.Run(total_); 501 } 502 503 void Multiply(double value, const CalcCallback& callback) override { 504 total_ *= value; 505 callback.Run(total_); 506 } 507 508 private: 509 double total_ = 0.0; 510 bool* error_received_; 511 bool* destroyed_; 512 base::Closure closure_; 513 514 StrongBinding<math::Calculator> binding_; 515 }; 516 517 TEST(StrongConnectorTest, Math) { 518 base::MessageLoop loop; 519 520 bool error_received = false; 521 bool destroyed = false; 522 MessagePipe pipe; 523 base::RunLoop run_loop; 524 new StrongMathCalculatorImpl(std::move(pipe.handle0), &error_received, 525 &destroyed, run_loop.QuitClosure()); 526 527 math::CalculatorPtr calc; 528 calc.Bind(InterfacePtrInfo<math::Calculator>(std::move(pipe.handle1), 0u)); 529 530 { 531 // Suppose this is instantiated in a process that has the other end of the 532 // message pipe. 533 MathCalculatorUI calculator_ui(std::move(calc)); 534 535 base::RunLoop run_loop, run_loop2; 536 calculator_ui.Add(2.0, run_loop.QuitClosure()); 537 calculator_ui.Multiply(5.0, run_loop2.QuitClosure()); 538 run_loop.Run(); 539 run_loop2.Run(); 540 541 EXPECT_EQ(10.0, calculator_ui.GetOutput()); 542 EXPECT_FALSE(error_received); 543 EXPECT_FALSE(destroyed); 544 } 545 // Destroying calculator_ui should close the pipe and generate an error on the 546 // other 547 // end which will destroy the instance since it is strongly bound. 548 549 run_loop.Run(); 550 EXPECT_TRUE(error_received); 551 EXPECT_TRUE(destroyed); 552 } 553 554 class WeakMathCalculatorImpl : public math::Calculator { 555 public: 556 WeakMathCalculatorImpl(ScopedMessagePipeHandle handle, 557 bool* error_received, 558 bool* destroyed, 559 const base::Closure& closure) 560 : error_received_(error_received), 561 destroyed_(destroyed), 562 closure_(closure), 563 binding_(this, std::move(handle)) { 564 binding_.set_connection_error_handler( 565 base::Bind(&SetFlagAndRunClosure, error_received_, closure_)); 566 } 567 ~WeakMathCalculatorImpl() override { *destroyed_ = true; } 568 569 void Clear(const CalcCallback& callback) override { callback.Run(total_); } 570 571 void Add(double value, const CalcCallback& callback) override { 572 total_ += value; 573 callback.Run(total_); 574 } 575 576 void Multiply(double value, const CalcCallback& callback) override { 577 total_ *= value; 578 callback.Run(total_); 579 } 580 581 private: 582 double total_ = 0.0; 583 bool* error_received_; 584 bool* destroyed_; 585 base::Closure closure_; 586 587 Binding<math::Calculator> binding_; 588 }; 589 590 TEST(WeakConnectorTest, Math) { 591 base::MessageLoop loop; 592 593 bool error_received = false; 594 bool destroyed = false; 595 MessagePipe pipe; 596 base::RunLoop run_loop; 597 WeakMathCalculatorImpl impl(std::move(pipe.handle0), &error_received, 598 &destroyed, run_loop.QuitClosure()); 599 600 math::CalculatorPtr calc; 601 calc.Bind(InterfacePtrInfo<math::Calculator>(std::move(pipe.handle1), 0u)); 602 603 { 604 // Suppose this is instantiated in a process that has the other end of the 605 // message pipe. 606 MathCalculatorUI calculator_ui(std::move(calc)); 607 608 base::RunLoop run_loop, run_loop2; 609 calculator_ui.Add(2.0, run_loop.QuitClosure()); 610 calculator_ui.Multiply(5.0, run_loop2.QuitClosure()); 611 run_loop.Run(); 612 run_loop2.Run(); 613 614 EXPECT_EQ(10.0, calculator_ui.GetOutput()); 615 EXPECT_FALSE(error_received); 616 EXPECT_FALSE(destroyed); 617 // Destroying calculator_ui should close the pipe and generate an error on 618 // the other 619 // end which will destroy the instance since it is strongly bound. 620 } 621 622 run_loop.Run(); 623 EXPECT_TRUE(error_received); 624 EXPECT_FALSE(destroyed); 625 } 626 627 class CImpl : public C { 628 public: 629 CImpl(bool* d_called, InterfaceRequest<C> request, 630 const base::Closure& closure) 631 : d_called_(d_called), binding_(this, std::move(request)), 632 closure_(closure) {} 633 ~CImpl() override {} 634 635 private: 636 void D() override { 637 *d_called_ = true; 638 closure_.Run(); 639 } 640 641 bool* d_called_; 642 StrongBinding<C> binding_; 643 base::Closure closure_; 644 }; 645 646 class BImpl : public B { 647 public: 648 BImpl(bool* d_called, InterfaceRequest<B> request, 649 const base::Closure& closure) 650 : d_called_(d_called), binding_(this, std::move(request)), 651 closure_(closure) {} 652 ~BImpl() override {} 653 654 private: 655 void GetC(InterfaceRequest<C> c) override { 656 new CImpl(d_called_, std::move(c), closure_); 657 } 658 659 bool* d_called_; 660 StrongBinding<B> binding_; 661 base::Closure closure_; 662 }; 663 664 class AImpl : public A { 665 public: 666 AImpl(InterfaceRequest<A> request, const base::Closure& closure) 667 : d_called_(false), binding_(this, std::move(request)), 668 closure_(closure) {} 669 ~AImpl() override {} 670 671 bool d_called() const { return d_called_; } 672 673 private: 674 void GetB(InterfaceRequest<B> b) override { 675 new BImpl(&d_called_, std::move(b), closure_); 676 } 677 678 bool d_called_; 679 Binding<A> binding_; 680 base::Closure closure_; 681 }; 682 683 TEST_F(InterfacePtrTest, Scoping) { 684 APtr a; 685 base::RunLoop run_loop; 686 AImpl a_impl(GetProxy(&a), run_loop.QuitClosure()); 687 688 EXPECT_FALSE(a_impl.d_called()); 689 690 { 691 BPtr b; 692 a->GetB(GetProxy(&b)); 693 CPtr c; 694 b->GetC(GetProxy(&c)); 695 c->D(); 696 } 697 698 // While B & C have fallen out of scope, the pipes will remain until they are 699 // flushed. 700 EXPECT_FALSE(a_impl.d_called()); 701 run_loop.Run(); 702 EXPECT_TRUE(a_impl.d_called()); 703 } 704 705 class PingTestImpl : public sample::PingTest { 706 public: 707 explicit PingTestImpl(InterfaceRequest<sample::PingTest> request) 708 : binding_(this, std::move(request)) {} 709 ~PingTestImpl() override {} 710 711 private: 712 // sample::PingTest: 713 void Ping(const PingCallback& callback) override { callback.Run(); } 714 715 Binding<sample::PingTest> binding_; 716 }; 717 718 // Tests that FuseProxy does what it's supposed to do. 719 TEST_F(InterfacePtrTest, Fusion) { 720 sample::PingTestPtr proxy; 721 PingTestImpl impl(GetProxy(&proxy)); 722 723 // Create another PingTest pipe. 724 sample::PingTestPtr ptr; 725 sample::PingTestRequest request = GetProxy(&ptr); 726 727 // Fuse the new pipe to the one hanging off |impl|. 728 EXPECT_TRUE(FuseInterface(std::move(request), proxy.PassInterface())); 729 730 // Ping! 731 bool called = false; 732 base::RunLoop loop; 733 ptr->Ping(base::Bind(&SetFlagAndRunClosure, &called, loop.QuitClosure())); 734 loop.Run(); 735 EXPECT_TRUE(called); 736 } 737 738 } // namespace 739 } // namespace test 740 } // namespace mojo 741