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