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