Home | History | Annotate | Download | only in tests
      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