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