OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 | |
9 #include "mojo/public/environment/environment.h" | |
10 #include "mojom/sample_service.h" | |
11 #include "testing/gtest/include/gtest/gtest.h" | |
12 | |
13 namespace mojo { | |
14 | |
15 template <> | |
16 class TypeConverter<sample::Bar, int32_t> { | |
17 public: | |
18 static int32_t ConvertTo(const sample::Bar& 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 Foo MakeFoo() { | |
38 mojo::String name("foopy"); | |
39 | |
40 Bar::Builder bar; | |
41 bar.set_alpha(20); | |
42 bar.set_beta(40); | |
43 bar.set_gamma(60); | |
44 bar.set_type(BAR_VERTICAL); | |
45 | |
46 mojo::Array<Bar>::Builder extra_bars(3); | |
47 for (size_t i = 0; i < extra_bars.size(); ++i) { | |
48 BarType type = i % 2 == 0 ? BAR_VERTICAL : BAR_HORIZONTAL; | |
49 Bar::Builder bar; | |
50 uint8_t base = static_cast<uint8_t>(i * 100); | |
51 bar.set_alpha(base); | |
52 bar.set_beta(base + 20); | |
53 bar.set_gamma(base + 40); | |
54 bar.set_type(type); | |
55 extra_bars[i] = bar.Finish(); | |
56 } | |
57 | |
58 mojo::Array<uint8_t>::Builder data(10); | |
59 for (size_t i = 0; i < data.size(); ++i) | |
60 data[i] = static_cast<uint8_t>(data.size() - i); | |
61 | |
62 mojo::Array<mojo::DataPipeConsumerHandle>::Builder input_streams(2); | |
63 mojo::Array<mojo::DataPipeProducerHandle>::Builder output_streams(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 mojo::ScopedMessagePipeHandle pipe0, pipe1; | |
78 mojo::CreateMessagePipe(&pipe0, &pipe1); | |
79 | |
80 Foo::Builder foo; | |
81 foo.set_name(name); | |
82 foo.set_x(1); | |
83 foo.set_y(2); | |
84 foo.set_a(false); | |
85 foo.set_b(true); | |
86 foo.set_c(false); | |
87 foo.set_bar(bar.Finish()); | |
88 foo.set_extra_bars(extra_bars.Finish()); | |
89 foo.set_data(data.Finish()); | |
90 foo.set_source(pipe1.Pass()); | |
91 foo.set_input_streams(input_streams.Finish()); | |
92 foo.set_output_streams(output_streams.Finish()); | |
93 | |
94 return foo.Finish(); | |
95 } | |
96 | |
97 // Check that the given |Foo| is identical to the one made by |MakeFoo()|. | |
98 void CheckFoo(const Foo& foo) { | |
99 const std::string kName("foopy"); | |
100 ASSERT_FALSE(foo.name().is_null()); | |
101 EXPECT_EQ(kName.size(), foo.name().size()); | |
102 for (size_t i = 0; i < std::min(kName.size(), foo.name().size()); i++) { | |
103 // Test both |operator[]| and |at|. | |
104 EXPECT_EQ(kName[i], foo.name().at(i)) << i; | |
105 EXPECT_EQ(kName[i], foo.name()[i]) << i; | |
106 } | |
107 EXPECT_EQ(kName, foo.name().To<std::string>()); | |
108 | |
109 EXPECT_EQ(1, foo.x()); | |
110 EXPECT_EQ(2, foo.y()); | |
111 EXPECT_FALSE(foo.a()); | |
112 EXPECT_TRUE(foo.b()); | |
113 EXPECT_FALSE(foo.c()); | |
114 | |
115 EXPECT_EQ(20, foo.bar().alpha()); | |
116 EXPECT_EQ(40, foo.bar().beta()); | |
117 EXPECT_EQ(60, foo.bar().gamma()); | |
118 EXPECT_EQ(BAR_VERTICAL, foo.bar().type()); | |
119 | |
120 EXPECT_EQ(3u, foo.extra_bars().size()); | |
121 for (size_t i = 0; i < foo.extra_bars().size(); i++) { | |
122 uint8_t base = static_cast<uint8_t>(i * 100); | |
123 BarType type = i % 2 == 0 ? BAR_VERTICAL : BAR_HORIZONTAL; | |
124 EXPECT_EQ(base, foo.extra_bars()[i].alpha()) << i; | |
125 EXPECT_EQ(base + 20, foo.extra_bars()[i].beta()) << i; | |
126 EXPECT_EQ(base + 40, foo.extra_bars()[i].gamma()) << i; | |
127 EXPECT_EQ(type, foo.extra_bars()[i].type()) << i; | |
128 } | |
129 | |
130 EXPECT_EQ(10u, foo.data().size()); | |
131 for (size_t i = 0; i < foo.data().size(); ++i) { | |
132 EXPECT_EQ(static_cast<uint8_t>(foo.data().size() - i), foo.data()[i]) << i; | |
133 } | |
134 | |
135 EXPECT_FALSE(foo.input_streams().is_null()); | |
136 EXPECT_EQ(2u, foo.input_streams().size()); | |
137 | |
138 EXPECT_FALSE(foo.output_streams().is_null()); | |
139 EXPECT_EQ(2u, foo.output_streams().size()); | |
140 } | |
141 | |
142 void PrintSpacer(int depth) { | |
143 for (int i = 0; i < depth; ++i) | |
144 std::cout << " "; | |
145 } | |
146 | |
147 void Print(int depth, const char* name, bool value) { | |
148 PrintSpacer(depth); | |
149 std::cout << name << ": " << (value ? "true" : "false") << std::endl; | |
150 } | |
151 | |
152 void Print(int depth, const char* name, int32_t value) { | |
153 PrintSpacer(depth); | |
154 std::cout << name << ": " << value << std::endl; | |
155 } | |
156 | |
157 void Print(int depth, const char* name, uint8_t value) { | |
158 PrintSpacer(depth); | |
159 std::cout << name << ": " << uint32_t(value) << std::endl; | |
160 } | |
161 | |
162 void Print(int depth, const char* name, mojo::Handle value) { | |
163 PrintSpacer(depth); | |
164 std::cout << name << ": 0x" << std::hex << value.value() << std::endl; | |
165 } | |
166 | |
167 void Print(int depth, const char* name, const mojo::String& str) { | |
168 std::string s = str.To<std::string>(); | |
169 PrintSpacer(depth); | |
170 std::cout << name << ": \"" << str.To<std::string>() << "\"" << std::endl; | |
171 } | |
172 | |
173 void Print(int depth, const char* name, const Bar& bar) { | |
174 PrintSpacer(depth); | |
175 std::cout << name << ":" << std::endl; | |
176 if (!bar.is_null()) { | |
177 ++depth; | |
178 Print(depth, "alpha", bar.alpha()); | |
179 Print(depth, "beta", bar.beta()); | |
180 Print(depth, "gamma", bar.gamma()); | |
181 Print(depth, "packed", bar.To<int32_t>()); | |
182 --depth; | |
183 } | |
184 } | |
185 | |
186 template <typename T> | |
187 void Print(int depth, const char* name, | |
188 const mojo::Passable<T>& passable) { | |
189 Print(depth, name, passable.get()); | |
190 } | |
191 | |
192 template <typename T> | |
193 void Print(int depth, const char* name, const mojo::Array<T>& array) { | |
194 PrintSpacer(depth); | |
195 std::cout << name << ":" << std::endl; | |
196 if (!array.is_null()) { | |
197 ++depth; | |
198 for (size_t i = 0; i < array.size(); ++i) { | |
199 std::stringstream buf; | |
200 buf << i; | |
201 Print(depth, buf.str().data(), array.at(i)); | |
202 } | |
203 --depth; | |
204 } | |
205 } | |
206 | |
207 void Print(int depth, const char* name, const Foo& 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().get()); | |
222 Print(depth, "input_streams", foo.input_streams()); | |
223 Print(depth, "output_streams", foo.output_streams()); | |
224 --depth; | |
225 } | |
226 } | |
227 | |
228 void DumpHex(const uint8_t* bytes, uint32_t num_bytes) { | |
229 for (uint32_t i = 0; i < num_bytes; ++i) { | |
230 std::cout << std::setw(2) << std::setfill('0') << std::hex << | |
231 uint32_t(bytes[i]); | |
232 | |
233 if (i % 16 == 15) { | |
234 std::cout << std::endl; | |
235 continue; | |
236 } | |
237 | |
238 if (i % 2 == 1) | |
239 std::cout << " "; | |
240 if (i % 8 == 7) | |
241 std::cout << " "; | |
242 } | |
243 } | |
244 | |
245 class ServiceImpl : public Service { | |
246 public: | |
247 virtual void Frobinate(const Foo& foo, int32_t baz, | |
248 mojo::ScopedMessagePipeHandle port) | |
249 MOJO_OVERRIDE { | |
250 // Users code goes here to handle the incoming Frobinate message. | |
251 | |
252 // We mainly check that we're given the expected arguments. | |
253 CheckFoo(foo); | |
254 EXPECT_EQ(BAZ_EXTRA, baz); | |
255 | |
256 if (g_dump_message_as_text) { | |
257 // Also dump the Foo structure and all of its members. | |
258 std::cout << "Frobinate:" << std::endl; | |
259 int depth = 1; | |
260 Print(depth, "foo", foo); | |
261 Print(depth, "baz", baz); | |
262 Print(depth, "port", port.get()); | |
263 } | |
264 } | |
265 }; | |
266 | |
267 class SimpleMessageReceiver : public mojo::MessageReceiver { | |
268 public: | |
269 virtual bool Accept(mojo::Message* message) MOJO_OVERRIDE { | |
270 // Imagine some IPC happened here. | |
271 | |
272 if (g_dump_message_as_hex) { | |
273 DumpHex(reinterpret_cast<const uint8_t*>(message->data), | |
274 message->data->header.num_bytes); | |
275 } | |
276 | |
277 // In the receiving process, an implementation of ServiceStub is known to | |
278 // the system. It receives the incoming message. | |
279 ServiceImpl impl; | |
280 | |
281 ServiceStub stub(&impl); | |
282 return stub.Accept(message); | |
283 } | |
284 }; | |
285 | |
286 } // namespace | |
287 | |
288 TEST(BindingsSampleTest, Basic) { | |
289 mojo::Environment env; | |
290 SimpleMessageReceiver receiver; | |
291 | |
292 // User has a proxy to a Service somehow. | |
293 Service* service = new ServiceProxy(&receiver); | |
294 | |
295 // User constructs a message to send. | |
296 | |
297 // Notice that it doesn't matter in what order the structs / arrays are | |
298 // allocated. Here, the various members of Foo are allocated before Foo is | |
299 // allocated. | |
300 | |
301 mojo::AllocationScope scope; | |
302 | |
303 Foo foo = MakeFoo(); | |
304 CheckFoo(foo); | |
305 | |
306 mojo::ScopedMessagePipeHandle port0, port1; | |
307 mojo::CreateMessagePipe(&port0, &port1); | |
308 | |
309 service->Frobinate(foo, Service::BAZ_EXTRA, port0.Pass()); | |
310 } | |
311 | |
312 } // namespace sample | |
OLD | NEW |