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