• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 <algorithm>
6 #include <ostream>
7 #include <string>
8 
9 #include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 
12 namespace mojo {
13 
14 template <>
15 class TypeConverter<sample::BarPtr, int32_t> {
16  public:
ConvertTo(const sample::BarPtr & bar)17   static int32_t ConvertTo(const sample::BarPtr& bar) {
18     return static_cast<int32_t>(bar->alpha) << 16 |
19            static_cast<int32_t>(bar->beta) << 8 |
20            static_cast<int32_t>(bar->gamma);
21   }
22 };
23 
24 }  // namespace mojo
25 
26 namespace sample {
27 namespace {
28 
29 // Set this variable to true to print the message in hex.
30 bool g_dump_message_as_hex = false;
31 
32 // Set this variable to true to print the message in human readable form.
33 bool g_dump_message_as_text = false;
34 
35 // Make a sample |Foo|.
MakeFoo()36 FooPtr MakeFoo() {
37   mojo::String name("foopy");
38 
39   BarPtr bar(Bar::New());
40   bar->alpha = 20;
41   bar->beta = 40;
42   bar->gamma = 60;
43   bar->type = Bar::TYPE_VERTICAL;
44 
45   mojo::Array<BarPtr> extra_bars(3);
46   for (size_t i = 0; i < extra_bars.size(); ++i) {
47     Bar::Type type = i % 2 == 0 ? Bar::TYPE_VERTICAL : Bar::TYPE_HORIZONTAL;
48     BarPtr bar(Bar::New());
49     uint8_t base = static_cast<uint8_t>(i * 100);
50     bar->alpha = base;
51     bar->beta = base + 20;
52     bar->gamma = base + 40;
53     bar->type = type;
54     extra_bars[i] = bar.Pass();
55   }
56 
57   mojo::Array<uint8_t> data(10);
58   for (size_t i = 0; i < data.size(); ++i)
59     data[i] = static_cast<uint8_t>(data.size() - i);
60 
61   mojo::Array<mojo::ScopedDataPipeConsumerHandle> input_streams(2);
62   mojo::Array<mojo::ScopedDataPipeProducerHandle> output_streams(2);
63   for (size_t i = 0; i < input_streams.size(); ++i) {
64     MojoCreateDataPipeOptions options;
65     options.struct_size = sizeof(MojoCreateDataPipeOptions);
66     options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
67     options.element_num_bytes = 1;
68     options.capacity_num_bytes = 1024;
69     mojo::ScopedDataPipeProducerHandle producer;
70     mojo::ScopedDataPipeConsumerHandle consumer;
71     mojo::CreateDataPipe(&options, &producer, &consumer);
72     input_streams[i] = consumer.Pass();
73     output_streams[i] = producer.Pass();
74   }
75 
76   mojo::Array<mojo::Array<bool> > array_of_array_of_bools(2);
77   for (size_t i = 0; i < 2; ++i) {
78     mojo::Array<bool> array_of_bools(2);
79     for (size_t j = 0; j < 2; ++j)
80       array_of_bools[j] = j;
81     array_of_array_of_bools[i] = array_of_bools.Pass();
82   }
83 
84   mojo::MessagePipe pipe;
85   FooPtr foo(Foo::New());
86   foo->name = name;
87   foo->x = 1;
88   foo->y = 2;
89   foo->a = false;
90   foo->b = true;
91   foo->c = false;
92   foo->bar = bar.Pass();
93   foo->extra_bars = extra_bars.Pass();
94   foo->data = data.Pass();
95   foo->source = pipe.handle1.Pass();
96   foo->input_streams = input_streams.Pass();
97   foo->output_streams = output_streams.Pass();
98   foo->array_of_array_of_bools = array_of_array_of_bools.Pass();
99 
100   return foo.Pass();
101 }
102 
103 // Check that the given |Foo| is identical to the one made by |MakeFoo()|.
CheckFoo(const Foo & foo)104 void CheckFoo(const Foo& foo) {
105   const std::string kName("foopy");
106   ASSERT_FALSE(foo.name.is_null());
107   EXPECT_EQ(kName.size(), foo.name.size());
108   for (size_t i = 0; i < std::min(kName.size(), foo.name.size()); i++) {
109     // Test both |operator[]| and |at|.
110     EXPECT_EQ(kName[i], foo.name.at(i)) << i;
111     EXPECT_EQ(kName[i], foo.name[i]) << i;
112   }
113   EXPECT_EQ(kName, foo.name.get());
114 
115   EXPECT_EQ(1, foo.x);
116   EXPECT_EQ(2, foo.y);
117   EXPECT_FALSE(foo.a);
118   EXPECT_TRUE(foo.b);
119   EXPECT_FALSE(foo.c);
120 
121   EXPECT_EQ(20, foo.bar->alpha);
122   EXPECT_EQ(40, foo.bar->beta);
123   EXPECT_EQ(60, foo.bar->gamma);
124   EXPECT_EQ(Bar::TYPE_VERTICAL, foo.bar->type);
125 
126   EXPECT_EQ(3u, foo.extra_bars.size());
127   for (size_t i = 0; i < foo.extra_bars.size(); i++) {
128     uint8_t base = static_cast<uint8_t>(i * 100);
129     Bar::Type type = i % 2 == 0 ? Bar::TYPE_VERTICAL : Bar::TYPE_HORIZONTAL;
130     EXPECT_EQ(base, foo.extra_bars[i]->alpha) << i;
131     EXPECT_EQ(base + 20, foo.extra_bars[i]->beta) << i;
132     EXPECT_EQ(base + 40, foo.extra_bars[i]->gamma) << i;
133     EXPECT_EQ(type, foo.extra_bars[i]->type) << i;
134   }
135 
136   EXPECT_EQ(10u, foo.data.size());
137   for (size_t i = 0; i < foo.data.size(); ++i) {
138     EXPECT_EQ(static_cast<uint8_t>(foo.data.size() - i), foo.data[i]) << i;
139   }
140 
141   EXPECT_FALSE(foo.input_streams.is_null());
142   EXPECT_EQ(2u, foo.input_streams.size());
143 
144   EXPECT_FALSE(foo.output_streams.is_null());
145   EXPECT_EQ(2u, foo.output_streams.size());
146 
147   EXPECT_EQ(2u, foo.array_of_array_of_bools.size());
148   for (size_t i = 0; i < foo.array_of_array_of_bools.size(); ++i) {
149     EXPECT_EQ(2u, foo.array_of_array_of_bools[i].size());
150     for (size_t j = 0; j < foo.array_of_array_of_bools[i].size(); ++j) {
151       EXPECT_EQ(bool(j), foo.array_of_array_of_bools[i][j]);
152     }
153   }
154 }
155 
PrintSpacer(int depth)156 void PrintSpacer(int depth) {
157   for (int i = 0; i < depth; ++i)
158     std::cout << "   ";
159 }
160 
Print(int depth,const char * name,bool value)161 void Print(int depth, const char* name, bool value) {
162   PrintSpacer(depth);
163   std::cout << name << ": " << (value ? "true" : "false") << std::endl;
164 }
165 
Print(int depth,const char * name,int32_t value)166 void Print(int depth, const char* name, int32_t value) {
167   PrintSpacer(depth);
168   std::cout << name << ": " << value << std::endl;
169 }
170 
Print(int depth,const char * name,uint8_t value)171 void Print(int depth, const char* name, uint8_t value) {
172   PrintSpacer(depth);
173   std::cout << name << ": " << uint32_t(value) << std::endl;
174 }
175 
176 template <typename H>
Print(int depth,const char * name,const mojo::ScopedHandleBase<H> & value)177 void Print(int depth, const char* name,
178            const mojo::ScopedHandleBase<H>& value) {
179   PrintSpacer(depth);
180   std::cout << name << ": 0x" << std::hex << value.get().value() << std::endl;
181 }
182 
Print(int depth,const char * name,const mojo::String & str)183 void Print(int depth, const char* name, const mojo::String& str) {
184   PrintSpacer(depth);
185   std::cout << name << ": \"" << str.get() << "\"" << std::endl;
186 }
187 
Print(int depth,const char * name,const BarPtr & bar)188 void Print(int depth, const char* name, const BarPtr& bar) {
189   PrintSpacer(depth);
190   std::cout << name << ":" << std::endl;
191   if (!bar.is_null()) {
192     ++depth;
193     Print(depth, "alpha", bar->alpha);
194     Print(depth, "beta", bar->beta);
195     Print(depth, "gamma", bar->gamma);
196     Print(depth, "packed", bar.To<int32_t>());
197     --depth;
198   }
199 }
200 
201 template <typename T>
Print(int depth,const char * name,const mojo::Array<T> & array)202 void Print(int depth, const char* name, const mojo::Array<T>& array) {
203   PrintSpacer(depth);
204   std::cout << name << ":" << std::endl;
205   if (!array.is_null()) {
206     ++depth;
207     for (size_t i = 0; i < array.size(); ++i) {
208       std::stringstream buf;
209       buf << i;
210       Print(depth, buf.str().data(), array.at(i));
211     }
212     --depth;
213   }
214 }
215 
Print(int depth,const char * name,const FooPtr & foo)216 void Print(int depth, const char* name, const FooPtr& foo) {
217   PrintSpacer(depth);
218   std::cout << name << ":" << std::endl;
219   if (!foo.is_null()) {
220     ++depth;
221     Print(depth, "name", foo->name);
222     Print(depth, "x", foo->x);
223     Print(depth, "y", foo->y);
224     Print(depth, "a", foo->a);
225     Print(depth, "b", foo->b);
226     Print(depth, "c", foo->c);
227     Print(depth, "bar", foo->bar);
228     Print(depth, "extra_bars", foo->extra_bars);
229     Print(depth, "data", foo->data);
230     Print(depth, "source", foo->source);
231     Print(depth, "input_streams", foo->input_streams);
232     Print(depth, "output_streams", foo->output_streams);
233     Print(depth, "array_of_array_of_bools", foo->array_of_array_of_bools);
234     --depth;
235   }
236 }
237 
DumpHex(const uint8_t * bytes,uint32_t num_bytes)238 void DumpHex(const uint8_t* bytes, uint32_t num_bytes) {
239   for (uint32_t i = 0; i < num_bytes; ++i) {
240     std::cout << std::setw(2) << std::setfill('0') << std::hex <<
241         uint32_t(bytes[i]);
242 
243     if (i % 16 == 15) {
244       std::cout << std::endl;
245       continue;
246     }
247 
248     if (i % 2 == 1)
249       std::cout << " ";
250     if (i % 8 == 7)
251       std::cout << " ";
252   }
253 }
254 
255 class ServiceImpl : public Service {
256  public:
Frobinate(FooPtr foo,BazOptions baz,PortPtr port)257   virtual void Frobinate(FooPtr foo, BazOptions baz, PortPtr port)
258       MOJO_OVERRIDE {
259     // Users code goes here to handle the incoming Frobinate message.
260 
261     // We mainly check that we're given the expected arguments.
262     EXPECT_FALSE(foo.is_null());
263     if (!foo.is_null())
264       CheckFoo(*foo);
265     EXPECT_EQ(BAZ_EXTRA, baz);
266 
267     if (g_dump_message_as_text) {
268       // Also dump the Foo structure and all of its members.
269       std::cout << "Frobinate:" << std::endl;
270       int depth = 1;
271       Print(depth, "foo", foo);
272       Print(depth, "baz", baz);
273       Print(depth, "port", port.get());
274     }
275   }
276 
GetPort(mojo::InterfaceRequest<Port> port_request)277   virtual void GetPort(mojo::InterfaceRequest<Port> port_request)
278       MOJO_OVERRIDE {
279   }
280 };
281 
282 class ServiceProxyImpl : public ServiceProxy {
283  public:
ServiceProxyImpl(mojo::MessageReceiverWithResponder * receiver)284   explicit ServiceProxyImpl(mojo::MessageReceiverWithResponder* receiver)
285       : ServiceProxy(receiver) {
286   }
287 };
288 
289 class SimpleMessageReceiver : public mojo::MessageReceiverWithResponder {
290  public:
Accept(mojo::Message * message)291   virtual bool Accept(mojo::Message* message) MOJO_OVERRIDE {
292     // Imagine some IPC happened here.
293 
294     if (g_dump_message_as_hex) {
295       DumpHex(reinterpret_cast<const uint8_t*>(message->data()),
296               message->data_num_bytes());
297     }
298 
299     // In the receiving process, an implementation of ServiceStub is known to
300     // the system. It receives the incoming message.
301     ServiceImpl impl;
302 
303     ServiceStub stub;
304     stub.set_sink(&impl);
305     return stub.Accept(message);
306   }
307 
AcceptWithResponder(mojo::Message * message,mojo::MessageReceiver * responder)308   virtual bool AcceptWithResponder(mojo::Message* message,
309                                    mojo::MessageReceiver* responder)
310                                        MOJO_OVERRIDE {
311     return false;
312   }
313 };
314 
TEST(BindingsSampleTest,Basic)315 TEST(BindingsSampleTest, Basic) {
316   SimpleMessageReceiver receiver;
317 
318   // User has a proxy to a Service somehow.
319   Service* service = new ServiceProxyImpl(&receiver);
320 
321   // User constructs a message to send.
322 
323   // Notice that it doesn't matter in what order the structs / arrays are
324   // allocated. Here, the various members of Foo are allocated before Foo is
325   // allocated.
326 
327   FooPtr foo = MakeFoo();
328   CheckFoo(*foo);
329 
330   PortPtr port;
331   service->Frobinate(foo.Pass(), Service::BAZ_EXTRA, port.Pass());
332 
333   delete service;
334 }
335 
TEST(BindingsSampleTest,DefaultValues)336 TEST(BindingsSampleTest, DefaultValues) {
337   DefaultsTestPtr defaults(DefaultsTest::New());
338   EXPECT_EQ(-12, defaults->a0);
339   EXPECT_EQ(kTwelve, defaults->a1);
340   EXPECT_EQ(1234, defaults->a2);
341   EXPECT_EQ(34567U, defaults->a3);
342   EXPECT_EQ(123456, defaults->a4);
343   // TODO(vtl): crbug.com/375522
344   // EXPECT_EQ(3456789012U, defaults->a5);
345   EXPECT_EQ(111111111111LL, defaults->a6);
346   // TODO(vtl): crbug.com/375522
347   // EXPECT_EQ(9999999999999999999ULL, defaults->a7);
348   EXPECT_EQ(0x12345, defaults->a8);
349   EXPECT_EQ(-0x12345, defaults->a9);
350   EXPECT_EQ(1234, defaults->a10);
351   EXPECT_TRUE(defaults->a11);
352   EXPECT_FALSE(defaults->a12);
353   EXPECT_FLOAT_EQ(123.25f, defaults->a13);
354   EXPECT_DOUBLE_EQ(1234567890.123, defaults->a14);
355   EXPECT_DOUBLE_EQ(1E10, defaults->a15);
356   EXPECT_DOUBLE_EQ(-1.2E+20, defaults->a16);
357   EXPECT_DOUBLE_EQ(1.23E-20, defaults->a17);
358   EXPECT_TRUE(defaults->a18.is_null());
359   EXPECT_TRUE(defaults->a19.is_null());
360   EXPECT_EQ(Bar::TYPE_BOTH, defaults->a20);
361   EXPECT_TRUE(defaults->a21.is_null());
362   ASSERT_FALSE(defaults->a22.is_null());
363   EXPECT_EQ(imported::SHAPE_RECTANGLE, defaults->a22->shape);
364   EXPECT_EQ(imported::COLOR_BLACK, defaults->a22->color);
365 }
366 
367 }  // namespace
368 }  // namespace sample
369