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