• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
MathCalculatorImpl(InterfaceRequest<math::Calculator> request)28   explicit MathCalculatorImpl(InterfaceRequest<math::Calculator> request)
29       : total_(0.0), binding_(this, std::move(request)) {}
~MathCalculatorImpl()30   ~MathCalculatorImpl() override {}
31 
CloseMessagePipe()32   void CloseMessagePipe() { binding_.Close(); }
33 
WaitForIncomingMethodCall()34   void WaitForIncomingMethodCall() { binding_.WaitForIncomingMethodCall(); }
35 
Clear(const CalcCallback & callback)36   void Clear(const CalcCallback& callback) override {
37     total_ = 0.0;
38     callback.Run(total_);
39   }
40 
Add(double value,const CalcCallback & callback)41   void Add(double value, const CalcCallback& callback) override {
42     total_ += value;
43     callback.Run(total_);
44   }
45 
Multiply(double value,const CalcCallback & callback)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:
MathCalculatorUI(math::CalculatorPtr calculator)58   explicit MathCalculatorUI(math::CalculatorPtr calculator)
59       : calculator_(std::move(calculator)),
60         output_(0.0) {}
61 
encountered_error() const62   bool encountered_error() const { return calculator_.encountered_error(); }
set_connection_error_handler(const base::Closure & closure)63   void set_connection_error_handler(const base::Closure& closure) {
64     calculator_.set_connection_error_handler(closure);
65   }
66 
Add(double value,const base::Closure & closure)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 
Multiply(double value,const base::Closure & closure)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 
GetOutput() const79   double GetOutput() const { return output_; }
80 
81  private:
Output(const base::Closure & closure,double output)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:
SelfDestructingMathCalculatorUI(math::CalculatorPtr calculator)95   explicit SelfDestructingMathCalculatorUI(math::CalculatorPtr calculator)
96       : calculator_(std::move(calculator)), nesting_level_(0) {
97     ++num_instances_;
98   }
99 
BeginTest(bool nested,const base::Closure & closure)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 
num_instances()108   static int num_instances() { return num_instances_; }
109 
Output(const base::Closure & closure,double value)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:
~SelfDestructingMathCalculatorUI()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:
~ReentrantServiceImpl()136   ~ReentrantServiceImpl() override {}
137 
ReentrantServiceImpl(InterfaceRequest<sample::Service> request)138   explicit ReentrantServiceImpl(InterfaceRequest<sample::Service> request)
139       : call_depth_(0),
140         max_call_depth_(0),
141         binding_(this, std::move(request)) {}
142 
max_call_depth()143   int max_call_depth() { return max_call_depth_; }
144 
Frobinate(sample::FooPtr foo,sample::Service::BazOptions baz,sample::PortPtr port,const sample::Service::FrobinateCallback & callback)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 
GetPort(mojo::InterfaceRequest<sample::Port> port)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:
IntegerAccessorImpl()167   IntegerAccessorImpl() : integer_(0) {}
~IntegerAccessorImpl()168   ~IntegerAccessorImpl() override {}
169 
integer() const170   int64_t integer() const { return integer_; }
171 
set_closure(const base::Closure & closure)172   void set_closure(const base::Closure& closure) { closure_ = closure; }
173 
174  private:
175   // sample::IntegerAccessor implementation.
GetInteger(const GetIntegerCallback & callback)176   void GetInteger(const GetIntegerCallback& callback) override {
177     callback.Run(integer_, sample::Enum::VALUE);
178   }
SetInteger(int64_t data,sample::Enum type)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:
InterfacePtrTest()193   InterfacePtrTest() {}
~InterfacePtrTest()194   ~InterfacePtrTest() override { base::RunLoop().RunUntilIdle(); }
195 
PumpMessages()196   void PumpMessages() { base::RunLoop().RunUntilIdle(); }
197 
198  private:
199   base::MessageLoop loop_;
200 };
201 
SetFlagAndRunClosure(bool * flag,const base::Closure & closure)202 void SetFlagAndRunClosure(bool* flag, const base::Closure& closure) {
203   *flag = true;
204   closure.Run();
205 }
206 
IgnoreValueAndRunClosure(const base::Closure & closure,int32_t value)207 void IgnoreValueAndRunClosure(const base::Closure& closure, int32_t value) {
208   closure.Run();
209 }
210 
ExpectValueAndRunClosure(uint32_t expected_value,const base::Closure & closure,uint32_t value)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 
TEST_F(InterfacePtrTest,IsBound)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 
TEST_F(InterfacePtrTest,EndToEnd)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 
TEST_F(InterfacePtrTest,EndToEnd_Synchronous)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 
TEST_F(InterfacePtrTest,Movable)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 
TEST_F(InterfacePtrTest,Resettable)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 
TEST_F(InterfacePtrTest,BindInvalidHandle)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 
TEST_F(InterfacePtrTest,EncounteredError)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 
TEST_F(InterfacePtrTest,EncounteredErrorCallback)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 
TEST_F(InterfacePtrTest,DestroyInterfacePtrOnMethodResponse)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 
TEST_F(InterfacePtrTest,NestedDestroyInterfacePtrOnMethodResponse)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 
TEST_F(InterfacePtrTest,ReentrantWaitForIncomingMethodCall)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 
TEST_F(InterfacePtrTest,QueryVersion)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 
TEST_F(InterfacePtrTest,RequireVersion)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:
StrongMathCalculatorImpl(ScopedMessagePipeHandle handle,bool * error_received,bool * destroyed,const base::Closure & closure)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   }
~StrongMathCalculatorImpl()493   ~StrongMathCalculatorImpl() override { *destroyed_ = true; }
494 
495   // math::Calculator implementation.
Clear(const CalcCallback & callback)496   void Clear(const CalcCallback& callback) override { callback.Run(total_); }
497 
Add(double value,const CalcCallback & callback)498   void Add(double value, const CalcCallback& callback) override {
499     total_ += value;
500     callback.Run(total_);
501   }
502 
Multiply(double value,const CalcCallback & callback)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 
TEST(StrongConnectorTest,Math)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:
WeakMathCalculatorImpl(ScopedMessagePipeHandle handle,bool * error_received,bool * destroyed,const base::Closure & closure)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   }
~WeakMathCalculatorImpl()567   ~WeakMathCalculatorImpl() override { *destroyed_ = true; }
568 
Clear(const CalcCallback & callback)569   void Clear(const CalcCallback& callback) override { callback.Run(total_); }
570 
Add(double value,const CalcCallback & callback)571   void Add(double value, const CalcCallback& callback) override {
572     total_ += value;
573     callback.Run(total_);
574   }
575 
Multiply(double value,const CalcCallback & callback)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 
TEST(WeakConnectorTest,Math)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:
CImpl(bool * d_called,InterfaceRequest<C> request,const base::Closure & closure)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) {}
~CImpl()633   ~CImpl() override {}
634 
635  private:
D()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:
BImpl(bool * d_called,InterfaceRequest<B> request,const base::Closure & closure)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) {}
~BImpl()652   ~BImpl() override {}
653 
654  private:
GetC(InterfaceRequest<C> c)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:
AImpl(InterfaceRequest<A> request,const base::Closure & closure)666   AImpl(InterfaceRequest<A> request, const base::Closure& closure)
667       : d_called_(false), binding_(this, std::move(request)),
668         closure_(closure) {}
~AImpl()669   ~AImpl() override {}
670 
d_called() const671   bool d_called() const { return d_called_; }
672 
673  private:
GetB(InterfaceRequest<B> b)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 
TEST_F(InterfacePtrTest,Scoping)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:
PingTestImpl(InterfaceRequest<sample::PingTest> request)707   explicit PingTestImpl(InterfaceRequest<sample::PingTest> request)
708       : binding_(this, std::move(request)) {}
~PingTestImpl()709   ~PingTestImpl() override {}
710 
711  private:
712   // sample::PingTest:
Ping(const PingCallback & callback)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.
TEST_F(InterfacePtrTest,Fusion)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