c4f7c5171b20876eb23298341eced67f10bc931a
[platform/framework/web/crosswalk.git] / src / mojo / public / cpp / bindings / tests / interface_ptr_unittest.cc
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 "mojo/public/cpp/bindings/error_handler.h"
6 #include "mojo/public/cpp/environment/environment.h"
7 #include "mojo/public/cpp/utility/run_loop.h"
8 #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h"
9 #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11
12 namespace mojo {
13 namespace test {
14 namespace {
15
16 class ErrorObserver : public ErrorHandler {
17  public:
18   ErrorObserver() : encountered_error_(false) {
19   }
20
21   bool encountered_error() const { return encountered_error_; }
22
23   virtual void OnConnectionError() MOJO_OVERRIDE {
24     encountered_error_ = true;
25   }
26
27  private:
28   bool encountered_error_;
29 };
30
31 class MathCalculatorImpl : public InterfaceImpl<math::Calculator> {
32  public:
33   virtual ~MathCalculatorImpl() {}
34
35   MathCalculatorImpl()
36       : total_(0.0),
37         got_connection_(false) {
38   }
39
40   virtual void OnConnectionEstablished() MOJO_OVERRIDE {
41     got_connection_ = true;
42   }
43
44   virtual void OnConnectionError() MOJO_OVERRIDE {
45     delete this;
46   }
47
48   virtual void Clear() MOJO_OVERRIDE {
49     client()->Output(total_);
50   }
51
52   virtual void Add(double value) MOJO_OVERRIDE {
53     total_ += value;
54     client()->Output(total_);
55   }
56
57   virtual void Multiply(double value) MOJO_OVERRIDE {
58     total_ *= value;
59     client()->Output(total_);
60   }
61
62   bool got_connection() const {
63     return got_connection_;
64   }
65
66 private:
67   double total_;
68   bool got_connection_;
69 };
70
71 class MathCalculatorUIImpl : public math::CalculatorUI {
72  public:
73   explicit MathCalculatorUIImpl(math::CalculatorPtr calculator)
74       : calculator_(calculator.Pass()),
75         output_(0.0) {
76     calculator_.set_client(this);
77   }
78
79   bool encountered_error() const {
80     return calculator_.encountered_error();
81   }
82
83   void Add(double value) {
84     calculator_->Add(value);
85   }
86
87   void Subtract(double value) {
88     calculator_->Add(-value);
89   }
90
91   void Multiply(double value) {
92     calculator_->Multiply(value);
93   }
94
95   void Divide(double value) {
96     calculator_->Multiply(1.0 / value);
97   }
98
99   double GetOutput() const {
100     return output_;
101   }
102
103  private:
104   // math::CalculatorUI implementation:
105   virtual void Output(double value) MOJO_OVERRIDE {
106     output_ = value;
107   }
108
109   math::CalculatorPtr calculator_;
110   double output_;
111 };
112
113 class SelfDestructingMathCalculatorUIImpl : public math::CalculatorUI {
114  public:
115   explicit SelfDestructingMathCalculatorUIImpl(math::CalculatorPtr calculator)
116       : calculator_(calculator.Pass()),
117         nesting_level_(0) {
118     ++num_instances_;
119     calculator_.set_client(this);
120   }
121
122   void BeginTest(bool nested) {
123     nesting_level_ = nested ? 2 : 1;
124     calculator_->Add(1.0);
125   }
126
127   static int num_instances() { return num_instances_; }
128
129  private:
130   virtual ~SelfDestructingMathCalculatorUIImpl() {
131     --num_instances_;
132   }
133
134   virtual void Output(double value) MOJO_OVERRIDE {
135     if (--nesting_level_ > 0) {
136       // Add some more and wait for re-entrant call to Output!
137       calculator_->Add(1.0);
138       RunLoop::current()->RunUntilIdle();
139     } else {
140       delete this;
141     }
142   }
143
144   math::CalculatorPtr calculator_;
145   int nesting_level_;
146   static int num_instances_;
147 };
148
149 // static
150 int SelfDestructingMathCalculatorUIImpl::num_instances_ = 0;
151
152 class InterfacePtrTest : public testing::Test {
153  public:
154   virtual ~InterfacePtrTest() {
155     loop_.RunUntilIdle();
156   }
157
158   void PumpMessages() {
159     loop_.RunUntilIdle();
160   }
161
162  private:
163   Environment env_;
164   RunLoop loop_;
165 };
166
167 TEST_F(InterfacePtrTest, EndToEnd) {
168   math::CalculatorPtr calc;
169   MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc);
170   EXPECT_TRUE(impl->got_connection());
171
172   // Suppose this is instantiated in a process that has pipe1_.
173   MathCalculatorUIImpl calculator_ui(calc.Pass());
174
175   calculator_ui.Add(2.0);
176   calculator_ui.Multiply(5.0);
177
178   PumpMessages();
179
180   EXPECT_EQ(10.0, calculator_ui.GetOutput());
181 }
182
183 TEST_F(InterfacePtrTest, Movable) {
184   math::CalculatorPtr a;
185   math::CalculatorPtr b;
186   BindToProxy(new MathCalculatorImpl(), &b);
187
188   EXPECT_TRUE(!a.get());
189   EXPECT_FALSE(!b.get());
190
191   a = b.Pass();
192
193   EXPECT_FALSE(!a.get());
194   EXPECT_TRUE(!b.get());
195 }
196
197 TEST_F(InterfacePtrTest, Resettable) {
198   math::CalculatorPtr a;
199
200   EXPECT_TRUE(!a.get());
201
202   MessagePipe pipe;
203
204   // Save this so we can test it later.
205   Handle handle = pipe.handle0.get();
206
207   a = MakeProxy<math::Calculator>(pipe.handle0.Pass());
208
209   EXPECT_FALSE(!a.get());
210
211   a.reset();
212
213   EXPECT_TRUE(!a.get());
214   EXPECT_FALSE(a.internal_state()->router());
215
216   // Test that handle was closed.
217   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, CloseRaw(handle));
218 }
219
220 TEST_F(InterfacePtrTest, EncounteredError) {
221   math::CalculatorPtr proxy;
222   MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy);
223
224   MathCalculatorUIImpl calculator_ui(proxy.Pass());
225
226   calculator_ui.Add(2.0);
227   PumpMessages();
228   EXPECT_EQ(2.0, calculator_ui.GetOutput());
229   EXPECT_FALSE(calculator_ui.encountered_error());
230
231   calculator_ui.Multiply(5.0);
232   EXPECT_FALSE(calculator_ui.encountered_error());
233
234   // Close the server.
235   server->internal_state()->router()->CloseMessagePipe();
236
237   // The state change isn't picked up locally yet.
238   EXPECT_FALSE(calculator_ui.encountered_error());
239
240   PumpMessages();
241
242   // OK, now we see the error.
243   EXPECT_TRUE(calculator_ui.encountered_error());
244 }
245
246 TEST_F(InterfacePtrTest, EncounteredErrorCallback) {
247   math::CalculatorPtr proxy;
248   MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy);
249
250   ErrorObserver error_observer;
251   proxy.set_error_handler(&error_observer);
252
253   MathCalculatorUIImpl calculator_ui(proxy.Pass());
254
255   calculator_ui.Add(2.0);
256   PumpMessages();
257   EXPECT_EQ(2.0, calculator_ui.GetOutput());
258   EXPECT_FALSE(calculator_ui.encountered_error());
259
260   calculator_ui.Multiply(5.0);
261   EXPECT_FALSE(calculator_ui.encountered_error());
262
263   // Close the server.
264   server->internal_state()->router()->CloseMessagePipe();
265
266   // The state change isn't picked up locally yet.
267   EXPECT_FALSE(calculator_ui.encountered_error());
268
269   PumpMessages();
270
271   // OK, now we see the error.
272   EXPECT_TRUE(calculator_ui.encountered_error());
273
274   // We should have also been able to observe the error through the
275   // ErrorHandler interface.
276   EXPECT_TRUE(error_observer.encountered_error());
277 }
278
279 TEST_F(InterfacePtrTest, NoClientAttribute) {
280   // This is a test to ensure the following compiles. The sample::Port interface
281   // does not have an explicit Client attribute.
282   sample::PortPtr port;
283   MessagePipe pipe;
284   port.Bind(pipe.handle0.Pass());
285 }
286
287 TEST_F(InterfacePtrTest, DestroyInterfacePtrOnClientMethod) {
288   math::CalculatorPtr proxy;
289   BindToProxy(new MathCalculatorImpl(), &proxy);
290
291   EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
292
293   SelfDestructingMathCalculatorUIImpl* impl =
294       new SelfDestructingMathCalculatorUIImpl(proxy.Pass());
295   impl->BeginTest(false);
296
297   PumpMessages();
298
299   EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
300 }
301
302 TEST_F(InterfacePtrTest, NestedDestroyInterfacePtrOnClientMethod) {
303   math::CalculatorPtr proxy;
304   BindToProxy(new MathCalculatorImpl(), &proxy);
305
306   EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
307
308   SelfDestructingMathCalculatorUIImpl* impl =
309       new SelfDestructingMathCalculatorUIImpl(proxy.Pass());
310   impl->BeginTest(true);
311
312   PumpMessages();
313
314   EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
315 }
316
317 }  // namespace
318 }  // namespace test
319 }  // namespace mojo