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