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.
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"
16 class ErrorObserver : public ErrorHandler {
18 ErrorObserver() : encountered_error_(false) {
21 bool encountered_error() const { return encountered_error_; }
23 virtual void OnConnectionError() MOJO_OVERRIDE {
24 encountered_error_ = true;
28 bool encountered_error_;
31 class MathCalculatorImpl : public InterfaceImpl<math::Calculator> {
33 virtual ~MathCalculatorImpl() {}
37 got_connection_(false) {
40 virtual void OnConnectionEstablished() MOJO_OVERRIDE {
41 got_connection_ = true;
44 virtual void OnConnectionError() MOJO_OVERRIDE {
48 virtual void Clear() MOJO_OVERRIDE {
49 client()->Output(total_);
52 virtual void Add(double value) MOJO_OVERRIDE {
54 client()->Output(total_);
57 virtual void Multiply(double value) MOJO_OVERRIDE {
59 client()->Output(total_);
62 bool got_connection() const {
63 return got_connection_;
71 class MathCalculatorUIImpl : public math::CalculatorUI {
73 explicit MathCalculatorUIImpl(math::CalculatorPtr calculator)
74 : calculator_(calculator.Pass()),
76 calculator_.set_client(this);
79 bool encountered_error() const {
80 return calculator_.encountered_error();
83 void Add(double value) {
84 calculator_->Add(value);
87 void Subtract(double value) {
88 calculator_->Add(-value);
91 void Multiply(double value) {
92 calculator_->Multiply(value);
95 void Divide(double value) {
96 calculator_->Multiply(1.0 / value);
99 double GetOutput() const {
104 // math::CalculatorUI implementation:
105 virtual void Output(double value) MOJO_OVERRIDE {
109 math::CalculatorPtr calculator_;
113 class SelfDestructingMathCalculatorUIImpl : public math::CalculatorUI {
115 explicit SelfDestructingMathCalculatorUIImpl(math::CalculatorPtr calculator)
116 : calculator_(calculator.Pass()),
119 calculator_.set_client(this);
122 void BeginTest(bool nested) {
123 nesting_level_ = nested ? 2 : 1;
124 calculator_->Add(1.0);
127 static int num_instances() { return num_instances_; }
130 virtual ~SelfDestructingMathCalculatorUIImpl() {
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();
144 math::CalculatorPtr calculator_;
146 static int num_instances_;
150 int SelfDestructingMathCalculatorUIImpl::num_instances_ = 0;
152 class InterfacePtrTest : public testing::Test {
154 virtual ~InterfacePtrTest() {
155 loop_.RunUntilIdle();
158 void PumpMessages() {
159 loop_.RunUntilIdle();
167 TEST_F(InterfacePtrTest, EndToEnd) {
168 math::CalculatorPtr calc;
169 MathCalculatorImpl* impl = BindToProxy(new MathCalculatorImpl(), &calc);
170 EXPECT_TRUE(impl->got_connection());
172 // Suppose this is instantiated in a process that has pipe1_.
173 MathCalculatorUIImpl calculator_ui(calc.Pass());
175 calculator_ui.Add(2.0);
176 calculator_ui.Multiply(5.0);
180 EXPECT_EQ(10.0, calculator_ui.GetOutput());
183 TEST_F(InterfacePtrTest, Movable) {
184 math::CalculatorPtr a;
185 math::CalculatorPtr b;
186 BindToProxy(new MathCalculatorImpl(), &b);
188 EXPECT_TRUE(!a.get());
189 EXPECT_FALSE(!b.get());
193 EXPECT_FALSE(!a.get());
194 EXPECT_TRUE(!b.get());
197 TEST_F(InterfacePtrTest, Resettable) {
198 math::CalculatorPtr a;
200 EXPECT_TRUE(!a.get());
204 // Save this so we can test it later.
205 Handle handle = pipe.handle0.get();
207 a = MakeProxy<math::Calculator>(pipe.handle0.Pass());
209 EXPECT_FALSE(!a.get());
213 EXPECT_TRUE(!a.get());
214 EXPECT_FALSE(a.internal_state()->router());
216 // Test that handle was closed.
217 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, CloseRaw(handle));
220 TEST_F(InterfacePtrTest, EncounteredError) {
221 math::CalculatorPtr proxy;
222 MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy);
224 MathCalculatorUIImpl calculator_ui(proxy.Pass());
226 calculator_ui.Add(2.0);
228 EXPECT_EQ(2.0, calculator_ui.GetOutput());
229 EXPECT_FALSE(calculator_ui.encountered_error());
231 calculator_ui.Multiply(5.0);
232 EXPECT_FALSE(calculator_ui.encountered_error());
235 server->internal_state()->router()->CloseMessagePipe();
237 // The state change isn't picked up locally yet.
238 EXPECT_FALSE(calculator_ui.encountered_error());
242 // OK, now we see the error.
243 EXPECT_TRUE(calculator_ui.encountered_error());
246 TEST_F(InterfacePtrTest, EncounteredErrorCallback) {
247 math::CalculatorPtr proxy;
248 MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy);
250 ErrorObserver error_observer;
251 proxy.set_error_handler(&error_observer);
253 MathCalculatorUIImpl calculator_ui(proxy.Pass());
255 calculator_ui.Add(2.0);
257 EXPECT_EQ(2.0, calculator_ui.GetOutput());
258 EXPECT_FALSE(calculator_ui.encountered_error());
260 calculator_ui.Multiply(5.0);
261 EXPECT_FALSE(calculator_ui.encountered_error());
264 server->internal_state()->router()->CloseMessagePipe();
266 // The state change isn't picked up locally yet.
267 EXPECT_FALSE(calculator_ui.encountered_error());
271 // OK, now we see the error.
272 EXPECT_TRUE(calculator_ui.encountered_error());
274 // We should have also been able to observe the error through the
275 // ErrorHandler interface.
276 EXPECT_TRUE(error_observer.encountered_error());
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;
284 port.Bind(pipe.handle0.Pass());
287 TEST_F(InterfacePtrTest, DestroyInterfacePtrOnClientMethod) {
288 math::CalculatorPtr proxy;
289 BindToProxy(new MathCalculatorImpl(), &proxy);
291 EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
293 SelfDestructingMathCalculatorUIImpl* impl =
294 new SelfDestructingMathCalculatorUIImpl(proxy.Pass());
295 impl->BeginTest(false);
299 EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
302 TEST_F(InterfacePtrTest, NestedDestroyInterfacePtrOnClientMethod) {
303 math::CalculatorPtr proxy;
304 BindToProxy(new MathCalculatorImpl(), &proxy);
306 EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());
308 SelfDestructingMathCalculatorUIImpl* impl =
309 new SelfDestructingMathCalculatorUIImpl(proxy.Pass());
310 impl->BeginTest(true);
314 EXPECT_EQ(0, SelfDestructingMathCalculatorUIImpl::num_instances());