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