• 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 "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:
ErrorObserver()18   ErrorObserver() : encountered_error_(false) {
19   }
20 
encountered_error() const21   bool encountered_error() const { return encountered_error_; }
22 
OnConnectionError()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:
~MathCalculatorImpl()33   virtual ~MathCalculatorImpl() {}
34 
MathCalculatorImpl()35   MathCalculatorImpl()
36       : total_(0.0),
37         got_connection_(false) {
38   }
39 
OnConnectionEstablished()40   virtual void OnConnectionEstablished() MOJO_OVERRIDE {
41     got_connection_ = true;
42   }
43 
OnConnectionError()44   virtual void OnConnectionError() MOJO_OVERRIDE {
45     delete this;
46   }
47 
Clear()48   virtual void Clear() MOJO_OVERRIDE {
49     client()->Output(total_);
50   }
51 
Add(double value)52   virtual void Add(double value) MOJO_OVERRIDE {
53     total_ += value;
54     client()->Output(total_);
55   }
56 
Multiply(double value)57   virtual void Multiply(double value) MOJO_OVERRIDE {
58     total_ *= value;
59     client()->Output(total_);
60   }
61 
got_connection() const62   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:
MathCalculatorUIImpl(math::CalculatorPtr calculator)73   explicit MathCalculatorUIImpl(math::CalculatorPtr calculator)
74       : calculator_(calculator.Pass()),
75         output_(0.0) {
76     calculator_.set_client(this);
77   }
78 
encountered_error() const79   bool encountered_error() const {
80     return calculator_.encountered_error();
81   }
82 
Add(double value)83   void Add(double value) {
84     calculator_->Add(value);
85   }
86 
Subtract(double value)87   void Subtract(double value) {
88     calculator_->Add(-value);
89   }
90 
Multiply(double value)91   void Multiply(double value) {
92     calculator_->Multiply(value);
93   }
94 
Divide(double value)95   void Divide(double value) {
96     calculator_->Multiply(1.0 / value);
97   }
98 
GetOutput() const99   double GetOutput() const {
100     return output_;
101   }
102 
103  private:
104   // math::CalculatorUI implementation:
Output(double value)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:
SelfDestructingMathCalculatorUIImpl(math::CalculatorPtr calculator)115   explicit SelfDestructingMathCalculatorUIImpl(math::CalculatorPtr calculator)
116       : calculator_(calculator.Pass()),
117         nesting_level_(0) {
118     ++num_instances_;
119     calculator_.set_client(this);
120   }
121 
BeginTest(bool nested)122   void BeginTest(bool nested) {
123     nesting_level_ = nested ? 2 : 1;
124     calculator_->Add(1.0);
125   }
126 
num_instances()127   static int num_instances() { return num_instances_; }
128 
129  private:
~SelfDestructingMathCalculatorUIImpl()130   virtual ~SelfDestructingMathCalculatorUIImpl() {
131     --num_instances_;
132   }
133 
Output(double value)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:
~InterfacePtrTest()154   virtual ~InterfacePtrTest() {
155     loop_.RunUntilIdle();
156   }
157 
PumpMessages()158   void PumpMessages() {
159     loop_.RunUntilIdle();
160   }
161 
162  private:
163   Environment env_;
164   RunLoop loop_;
165 };
166 
TEST_F(InterfacePtrTest,EndToEnd)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 
TEST_F(InterfacePtrTest,Movable)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 
TEST_F(InterfacePtrTest,Resettable)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 
TEST_F(InterfacePtrTest,EncounteredError)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 
TEST_F(InterfacePtrTest,EncounteredErrorCallback)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 
TEST_F(InterfacePtrTest,NoClientAttribute)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 
TEST_F(InterfacePtrTest,DestroyInterfacePtrOnClientMethod)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 
TEST_F(InterfacePtrTest,NestedDestroyInterfacePtrOnClientMethod)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
320