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
15namespace mojo {
16
17template <>
18struct TypeConverter<int32_t, sample::BarPtr> {
19  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
28namespace sample {
29namespace {
30
31// Set this variable to true to print the message in hex.
32bool g_dump_message_as_hex = false;
33
34// Set this variable to true to print the message in human readable form.
35bool g_dump_message_as_text = false;
36
37// Make a sample |Foo|.
38FooPtr 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()|.
106void 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
157void PrintSpacer(int depth) {
158  for (int i = 0; i < depth; ++i)
159    std::cout << "   ";
160}
161
162void Print(int depth, const char* name, bool value) {
163  PrintSpacer(depth);
164  std::cout << name << ": " << (value ? "true" : "false") << std::endl;
165}
166
167void Print(int depth, const char* name, int32_t value) {
168  PrintSpacer(depth);
169  std::cout << name << ": " << value << std::endl;
170}
171
172void Print(int depth, const char* name, uint8_t value) {
173  PrintSpacer(depth);
174  std::cout << name << ": " << uint32_t(value) << std::endl;
175}
176
177template <typename H>
178void 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
185void Print(int depth, const char* name, const std::string& str) {
186  PrintSpacer(depth);
187  std::cout << name << ": \"" << str << "\"" << std::endl;
188}
189
190void 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
203template <typename T>
204void 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
216template <typename T>
217void 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
226void 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
248void 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
265class ServiceImpl : public Service {
266 public:
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
290  void GetPort(mojo::InterfaceRequest<Port> port_request) override {}
291};
292
293class ServiceProxyImpl : public ServiceProxy {
294 public:
295  explicit ServiceProxyImpl(mojo::MessageReceiverWithResponder* receiver)
296      : ServiceProxy(receiver) {}
297};
298
299class SimpleMessageReceiver : public mojo::MessageReceiverWithResponder {
300 public:
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
318  bool AcceptWithResponder(mojo::Message* message,
319                           mojo::MessageReceiver* responder) override {
320    return false;
321  }
322};
323
324using BindingsSampleTest = testing::Test;
325
326TEST_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
348TEST_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