Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc

Issue 2250183003: Make the fuchsia mojo/public repo the source of truth. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW
« no previous file with comments | « mojo/public/cpp/bindings/tests/interface_ptr_set_unittest.cc ('k') | mojo/public/cpp/bindings/tests/interface_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698