Make certificate viewer a tab-modal dialog.
[chromium-blink-merge.git] / ppapi / tests / test_post_message.cc
blob39102e1f6ebb64cf964c1d490d399158f4c0f2b7
1 // Copyright (c) 2012 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.
5 #include "ppapi/tests/test_post_message.h"
7 #include <algorithm>
8 #include <sstream>
10 #include "ppapi/c/dev/ppb_testing_dev.h"
11 #include "ppapi/c/pp_var.h"
12 #include "ppapi/cpp/instance.h"
13 #include "ppapi/cpp/var.h"
14 #include "ppapi/cpp/var_array_buffer.h"
15 #include "ppapi/tests/pp_thread.h"
16 #include "ppapi/tests/test_utils.h"
17 #include "ppapi/tests/testing_instance.h"
19 // Windows defines 'PostMessage', so we have to undef it.
20 #ifdef PostMessage
21 #undef PostMessage
22 #endif
24 REGISTER_TEST_CASE(PostMessage);
26 namespace {
28 const char kTestString[] = "Hello world!";
29 const bool kTestBool = true;
30 const int32_t kTestInt = 42;
31 const double kTestDouble = 42.0;
33 // On Windows XP bots, the NonMainThread test can run very slowly. So we dial
34 // back the number of threads & messages when running on Windows.
35 #ifdef PPAPI_OS_WIN
36 const int32_t kThreadsToRun = 2;
37 const int32_t kMessagesToSendPerThread = 5;
38 #else
39 const int32_t kThreadsToRun = 4;
40 const int32_t kMessagesToSendPerThread = 10;
41 #endif
43 // The struct that invoke_post_message_thread_func expects for its argument.
44 // It includes the instance on which to invoke PostMessage, and the value to
45 // pass to PostMessage.
46 struct InvokePostMessageThreadArg {
47 InvokePostMessageThreadArg(pp::Instance* i, const pp::Var& v)
48 : instance(i), value_to_send(v) {}
49 pp::Instance* instance;
50 pp::Var value_to_send;
53 void InvokePostMessageThreadFunc(void* user_data) {
54 InvokePostMessageThreadArg* arg =
55 static_cast<InvokePostMessageThreadArg*>(user_data);
56 for (int32_t i = 0; i < kMessagesToSendPerThread; ++i)
57 arg->instance->PostMessage(arg->value_to_send);
58 delete arg;
61 class ScopedArrayBufferSizeSetter {
62 public:
63 ScopedArrayBufferSizeSetter(const PPB_Testing_Dev* interface,
64 PP_Instance instance,
65 uint32_t threshold)
66 : interface_(interface),
67 instance_(instance) {
68 interface_->SetMinimumArrayBufferSizeForShmem(instance_, threshold);
70 ~ScopedArrayBufferSizeSetter() {
71 interface_->SetMinimumArrayBufferSizeForShmem(instance_, 0);
73 private:
74 const PPB_Testing_Dev* interface_;
75 PP_Instance instance_;
78 #define FINISHED_WAITING_MESSAGE "TEST_POST_MESSAGE_FINISHED_WAITING"
80 } // namespace
82 TestPostMessage::TestPostMessage(TestingInstance* instance)
83 : TestCase(instance) {
86 TestPostMessage::~TestPostMessage() {
87 // Remove the special listener that only responds to a FINISHED_WAITING
88 // string. See Init for where it gets added.
89 std::string js_code;
90 js_code += "var plugin = document.getElementById('plugin');"
91 "plugin.removeEventListener('message',"
92 " plugin.wait_for_messages_handler);"
93 "delete plugin.wait_for_messages_handler;";
94 instance_->EvalScript(js_code);
97 bool TestPostMessage::Init() {
98 bool success = CheckTestingInterface();
100 // Set up a special listener that only responds to a FINISHED_WAITING string.
101 // This is for use by WaitForMessages.
102 std::string js_code;
103 // Note the following code is dependent on some features of test_case.html.
104 // E.g., it is assumed that the DOM element where the plugin is embedded has
105 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows
106 // us to ignore the messages that are intended for use by the testing
107 // framework itself.
108 js_code += "var plugin = document.getElementById('plugin');"
109 "var wait_for_messages_handler = function(message_event) {"
110 " if (!IsTestingMessage(message_event.data) &&"
111 " message_event.data === '" FINISHED_WAITING_MESSAGE "') {"
112 " plugin.postMessage('" FINISHED_WAITING_MESSAGE "');"
113 " }"
114 "};"
115 "plugin.addEventListener('message', wait_for_messages_handler);"
116 // Stash it on the plugin so we can remove it in the destructor.
117 "plugin.wait_for_messages_handler = wait_for_messages_handler;";
118 instance_->EvalScript(js_code);
120 // Set up the JavaScript message event listener to echo the data part of the
121 // message event back to us.
122 success = success && AddEchoingListener("message_event.data");
123 message_data_.clear();
124 // Send a message that the first test will expect to receive. This is to
125 // verify that we can send messages when the 'Instance::Init' function is on
126 // the stack.
127 instance_->PostMessage(pp::Var(kTestString));
129 return success;
132 void TestPostMessage::RunTests(const std::string& filter) {
133 // Note: SendInInit must be first, because it expects to receive a message
134 // that was sent in Init above.
135 RUN_TEST(SendInInit, filter);
136 RUN_TEST(SendingData, filter);
137 RUN_TEST(SendingArrayBuffer, filter);
138 RUN_TEST(MessageEvent, filter);
139 RUN_TEST(NoHandler, filter);
140 RUN_TEST(ExtraParam, filter);
141 if (testing_interface_->IsOutOfProcess())
142 RUN_TEST(NonMainThread, filter);
145 void TestPostMessage::HandleMessage(const pp::Var& message_data) {
146 if (message_data.is_string() &&
147 (message_data.AsString() == FINISHED_WAITING_MESSAGE))
148 testing_interface_->QuitMessageLoop(instance_->pp_instance());
149 else
150 message_data_.push_back(message_data);
153 bool TestPostMessage::AddEchoingListener(const std::string& expression) {
154 std::string js_code;
155 // Note the following code is dependent on some features of test_case.html.
156 // E.g., it is assumed that the DOM element where the plugin is embedded has
157 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows
158 // us to ignore the messages that are intended for use by the testing
159 // framework itself.
160 js_code += "var plugin = document.getElementById('plugin');"
161 "var message_handler = function(message_event) {"
162 " if (!IsTestingMessage(message_event.data) &&"
163 " !(message_event.data === '" FINISHED_WAITING_MESSAGE "')) {"
164 " plugin.postMessage(";
165 js_code += expression;
166 js_code += " );"
167 " }"
168 "};"
169 "plugin.addEventListener('message', message_handler);"
170 // Maintain an array of all event listeners, attached to the
171 // plugin. This is so that we can easily remove them later (see
172 // ClearListeners()).
173 "if (!plugin.eventListeners) plugin.eventListeners = [];"
174 "plugin.eventListeners.push(message_handler);";
175 instance_->EvalScript(js_code);
176 return true;
179 bool TestPostMessage::ClearListeners() {
180 std::string js_code;
181 js_code += "var plugin = document.getElementById('plugin');"
182 "while (plugin.eventListeners.length) {"
183 " plugin.removeEventListener('message',"
184 " plugin.eventListeners.pop());"
185 "}";
186 instance_->EvalScript(js_code);
187 return true;
190 int TestPostMessage::WaitForMessages() {
191 size_t message_size_before = message_data_.size();
192 // We first post a FINISHED_WAITING_MESSAGE. This should be guaranteed to
193 // come back _after_ any other incoming messages that were already pending.
194 instance_->PostMessage(pp::Var(FINISHED_WAITING_MESSAGE));
195 testing_interface_->RunMessageLoop(instance_->pp_instance());
196 // Now that the FINISHED_WAITING_MESSAGE has been echoed back to us, we know
197 // that all pending messages have been slurped up. Return the number we
198 // received (which may be zero).
199 return message_data_.size() - message_size_before;
202 std::string TestPostMessage::TestSendInInit() {
203 ASSERT_EQ(WaitForMessages(), 1);
204 // This test assumes Init already sent a message.
205 ASSERT_EQ(message_data_.size(), 1);
206 ASSERT_TRUE(message_data_.back().is_string());
207 ASSERT_EQ(message_data_.back().AsString(), kTestString);
208 message_data_.clear();
209 PASS();
212 std::string TestPostMessage::TestSendingData() {
213 // Clean up after previous tests. This also swallows the message sent by Init
214 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
215 // should start with these.
216 WaitForMessages();
217 ASSERT_TRUE(ClearListeners());
218 // Set up the JavaScript message event listener to echo the data part of the
219 // message event back to us.
220 ASSERT_TRUE(AddEchoingListener("message_event.data"));
222 // Test sending a message to JavaScript for each supported type. The JS sends
223 // the data back to us, and we check that they match.
224 message_data_.clear();
225 instance_->PostMessage(pp::Var(kTestString));
226 // PostMessage is asynchronous, so we should not receive a response yet.
227 ASSERT_EQ(message_data_.size(), 0);
228 ASSERT_EQ(WaitForMessages(), 1);
229 ASSERT_TRUE(message_data_.back().is_string());
230 ASSERT_EQ(message_data_.back().AsString(), kTestString);
232 message_data_.clear();
233 instance_->PostMessage(pp::Var(kTestBool));
234 ASSERT_EQ(message_data_.size(), 0);
235 ASSERT_EQ(WaitForMessages(), 1);
236 ASSERT_TRUE(message_data_.back().is_bool());
237 ASSERT_EQ(message_data_.back().AsBool(), kTestBool);
239 message_data_.clear();
240 instance_->PostMessage(pp::Var(kTestInt));
241 ASSERT_EQ(message_data_.size(), 0);
242 ASSERT_EQ(WaitForMessages(), 1);
243 ASSERT_TRUE(message_data_.back().is_number());
244 ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(),
245 static_cast<double>(kTestInt));
247 message_data_.clear();
248 instance_->PostMessage(pp::Var(kTestDouble));
249 ASSERT_EQ(message_data_.size(), 0);
250 ASSERT_EQ(WaitForMessages(), 1);
251 ASSERT_TRUE(message_data_.back().is_number());
252 ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(), kTestDouble);
254 message_data_.clear();
255 instance_->PostMessage(pp::Var());
256 ASSERT_EQ(message_data_.size(), 0);
257 ASSERT_EQ(WaitForMessages(), 1);
258 ASSERT_TRUE(message_data_.back().is_undefined());
260 message_data_.clear();
261 instance_->PostMessage(pp::Var(pp::Var::Null()));
262 ASSERT_EQ(message_data_.size(), 0);
263 ASSERT_EQ(WaitForMessages(), 1);
264 ASSERT_TRUE(message_data_.back().is_null());
266 message_data_.clear();
267 ASSERT_TRUE(ClearListeners());
269 PASS();
272 std::string TestPostMessage::TestSendingArrayBuffer() {
273 // Clean up after previous tests. This also swallows the message sent by Init
274 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
275 // should start with these.
276 WaitForMessages();
277 ASSERT_TRUE(ClearListeners());
279 // TODO(sehr,dmichael): Add testing of longer array buffers when
280 // crbug.com/110086 is fixed.
281 ScopedArrayBufferSizeSetter setter(testing_interface_,
282 instance_->pp_instance(),
283 200);
284 uint32_t sizes[] = { 0, 100, 1000, 10000 };
285 for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[i]); ++i) {
286 std::ostringstream size_stream;
287 size_stream << sizes[i];
288 const std::string kSizeAsString(size_stream.str());
290 // Create an appropriately sized array buffer with test_data[i] == i.
291 pp::VarArrayBuffer test_data(sizes[i]);
292 if (sizes[i] > 0)
293 ASSERT_NE(NULL, test_data.Map());
294 // Make sure we can Unmap/Map successfully (there's not really any way to
295 // detect if it's unmapped, so we just re-map before getting the pointer to
296 // the buffer).
297 test_data.Unmap();
298 test_data.Map();
299 ASSERT_EQ(sizes[i], test_data.ByteLength());
300 unsigned char* buff = static_cast<unsigned char*>(test_data.Map());
301 const uint32_t kByteLength = test_data.ByteLength();
302 for (size_t j = 0; j < kByteLength; ++j)
303 buff[j] = static_cast<uint8_t>(j % 256u);
305 // Have the listener test some properties of the ArrayBuffer.
306 std::vector<std::string> properties_to_check;
307 properties_to_check.push_back(
308 "message_event.data.constructor.name === 'ArrayBuffer'");
309 properties_to_check.push_back(
310 std::string("message_event.data.byteLength === ") + kSizeAsString);
311 if (sizes[i] > 0) {
312 properties_to_check.push_back(
313 "(new DataView(message_event.data)).getUint8(0) == 0");
314 // Checks that the last element has the right value: (byteLength-1)%256.
315 std::string received_byte("(new DataView(message_event.data)).getUint8("
316 " message_event.data.byteLength-1)");
317 std::string expected_byte("(message_event.data.byteLength-1)%256");
318 properties_to_check.push_back(received_byte + " == " + expected_byte);
320 for (std::vector<std::string>::iterator iter = properties_to_check.begin();
321 iter != properties_to_check.end();
322 ++iter) {
323 ASSERT_TRUE(AddEchoingListener(*iter));
324 message_data_.clear();
325 instance_->PostMessage(test_data);
326 ASSERT_EQ(message_data_.size(), 0);
327 ASSERT_EQ(WaitForMessages(), 1);
328 ASSERT_TRUE(message_data_.back().is_bool());
329 if (!message_data_.back().AsBool())
330 return std::string("Failed: ") + *iter + ", size: " + kSizeAsString;
331 ASSERT_TRUE(message_data_.back().AsBool());
332 ASSERT_TRUE(ClearListeners());
335 // Set up the JavaScript message event listener to echo the data part of the
336 // message event back to us.
337 ASSERT_TRUE(AddEchoingListener("message_event.data"));
338 message_data_.clear();
339 instance_->PostMessage(test_data);
340 // PostMessage is asynchronous, so we should not receive a response yet.
341 ASSERT_EQ(message_data_.size(), 0);
342 ASSERT_EQ(WaitForMessages(), 1);
343 ASSERT_TRUE(message_data_.back().is_array_buffer());
344 pp::VarArrayBuffer received(message_data_.back());
345 message_data_.clear();
346 ASSERT_EQ(test_data.ByteLength(), received.ByteLength());
347 unsigned char* received_buff = static_cast<unsigned char*>(received.Map());
348 // The buffer should be copied, so this should be a distinct buffer. When
349 // 'transferrables' are implemented for PPAPI, we'll also want to test that
350 // we get the _same_ buffer back when it's transferred.
351 if (sizes[i] > 0)
352 ASSERT_NE(buff, received_buff);
353 for (size_t i = 0; i < test_data.ByteLength(); ++i)
354 ASSERT_EQ(buff[i], received_buff[i]);
356 message_data_.clear();
357 ASSERT_TRUE(ClearListeners());
360 PASS();
363 std::string TestPostMessage::TestMessageEvent() {
364 // Set up the JavaScript message event listener to pass us some values from
365 // the MessageEvent and make sure they match our expectations.
367 WaitForMessages();
368 ASSERT_TRUE(ClearListeners());
369 // Have the listener pass back the class name of message_event and make sure
370 // it's "MessageEvent".
371 ASSERT_TRUE(AddEchoingListener("message_event.constructor.name"));
372 message_data_.clear();
373 instance_->PostMessage(pp::Var(kTestInt));
374 ASSERT_EQ(message_data_.size(), 0);
375 ASSERT_EQ(WaitForMessages(), 1);
376 ASSERT_TRUE(message_data_.back().is_string());
377 ASSERT_EQ(message_data_.back().AsString(), "MessageEvent");
378 ASSERT_TRUE(ClearListeners());
380 // Make sure all the non-data properties have the expected values.
381 bool success = AddEchoingListener("((message_event.origin === '')"
382 " && (message_event.lastEventId === '')"
383 " && (message_event.source === null)"
384 " && (message_event.ports.length === 0)"
385 " && (message_event.bubbles === false)"
386 " && (message_event.cancelable === false)"
387 ")");
388 ASSERT_TRUE(success);
389 message_data_.clear();
390 instance_->PostMessage(pp::Var(kTestInt));
391 ASSERT_EQ(message_data_.size(), 0);
392 ASSERT_EQ(WaitForMessages(), 1);
393 ASSERT_TRUE(message_data_.back().is_bool());
394 ASSERT_TRUE(message_data_.back().AsBool());
395 ASSERT_TRUE(ClearListeners());
397 // Add some event handlers to make sure they receive messages.
398 ASSERT_TRUE(AddEchoingListener("1"));
399 ASSERT_TRUE(AddEchoingListener("2"));
400 ASSERT_TRUE(AddEchoingListener("3"));
402 message_data_.clear();
403 instance_->PostMessage(pp::Var(kTestInt));
404 // Make sure we don't get a response in a re-entrant fashion.
405 ASSERT_EQ(message_data_.size(), 0);
406 // We should get 3 messages.
407 ASSERT_EQ(WaitForMessages(), 3);
408 // Copy to a vector of doubles and sort; w3c does not specify the order for
409 // event listeners. (Copying is easier than writing an operator< for pp::Var.)
411 // See http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html.
412 VarVector::iterator iter(message_data_.begin()), the_end(message_data_.end());
413 std::vector<double> double_vec;
414 for (; iter != the_end; ++iter) {
415 ASSERT_TRUE(iter->is_number());
416 double_vec.push_back(iter->AsDouble());
418 std::sort(double_vec.begin(), double_vec.end());
419 ASSERT_DOUBLE_EQ(double_vec[0], 1.0);
420 ASSERT_DOUBLE_EQ(double_vec[1], 2.0);
421 ASSERT_DOUBLE_EQ(double_vec[2], 3.0);
423 message_data_.clear();
424 ASSERT_TRUE(ClearListeners());
426 PASS();
429 std::string TestPostMessage::TestNoHandler() {
430 // Delete any lingering messages and event listeners.
431 WaitForMessages();
432 ASSERT_TRUE(ClearListeners());
434 // Now send a message. We shouldn't get a response.
435 message_data_.clear();
436 instance_->PostMessage(pp::Var());
437 ASSERT_EQ(WaitForMessages(), 0);
438 ASSERT_TRUE(message_data_.empty());
440 PASS();
443 std::string TestPostMessage::TestExtraParam() {
444 // Delete any lingering messages and event listeners.
445 WaitForMessages();
446 ASSERT_TRUE(ClearListeners());
447 // Add a listener that will respond with 1 and an empty array (where the
448 // message port array would appear if it was Worker postMessage).
449 ASSERT_TRUE(AddEchoingListener("1, []"));
451 // Now send a message. We shouldn't get a response.
452 message_data_.clear();
453 instance_->PostMessage(pp::Var());
454 ASSERT_EQ(WaitForMessages(), 0);
455 ASSERT_TRUE(message_data_.empty());
457 ASSERT_TRUE(ClearListeners());
459 PASS();
462 std::string TestPostMessage::TestNonMainThread() {
463 WaitForMessages();
464 ASSERT_TRUE(ClearListeners());
465 ASSERT_TRUE(AddEchoingListener("message_event.data"));
466 message_data_.clear();
468 // Set up a thread for each integer from 0 to (kThreadsToRun - 1). Make each
469 // thread send the number that matches its index kMessagesToSendPerThread
470 // times. For good measure, call postMessage from the main thread
471 // kMessagesToSendPerThread times. At the end, we make sure we got all the
472 // values we expected.
473 PP_ThreadType threads[kThreadsToRun];
474 for (int32_t i = 0; i < kThreadsToRun; ++i) {
475 // Set up a thread to send a value of i.
476 void* arg = new InvokePostMessageThreadArg(instance_, pp::Var(i));
477 PP_CreateThread(&threads[i], &InvokePostMessageThreadFunc, arg);
479 // Invoke PostMessage right now to send a value of (kThreadsToRun).
480 for (int32_t i = 0; i < kMessagesToSendPerThread; ++i)
481 instance_->PostMessage(pp::Var(kThreadsToRun));
483 // Now join all threads.
484 for (int32_t i = 0; i < kThreadsToRun; ++i)
485 PP_JoinThread(threads[i]);
487 // PostMessage is asynchronous, so we should not receive a response yet.
488 ASSERT_EQ(message_data_.size(), 0);
490 // Make sure we got all values that we expected. Note that because it's legal
491 // for the JavaScript engine to treat our integers as floating points, we
492 // can't just use std::find or equality comparison. So we instead, we convert
493 // each incoming value to an integer, and count them in received_counts.
494 int32_t expected_num = (kThreadsToRun + 1) * kMessagesToSendPerThread;
495 // Count how many we receive per-index.
496 std::vector<int32_t> expected_counts(kThreadsToRun + 1,
497 kMessagesToSendPerThread);
498 std::vector<int32_t> received_counts(kThreadsToRun + 1, 0);
499 ASSERT_EQ(WaitForMessages(), expected_num);
500 for (int32_t i = 0; i < expected_num; ++i) {
501 const pp::Var& latest_var(message_data_[i]);
502 ASSERT_TRUE(latest_var.is_int() || latest_var.is_double());
503 int32_t received_value = -1;
504 if (latest_var.is_int()) {
505 received_value = latest_var.AsInt();
506 } else if (latest_var.is_double()) {
507 received_value = static_cast<int32_t>(latest_var.AsDouble() + 0.5);
509 ASSERT_TRUE(received_value >= 0);
510 ASSERT_TRUE(received_value <= kThreadsToRun);
511 ++received_counts[received_value];
513 ASSERT_EQ(received_counts, expected_counts);
515 message_data_.clear();
516 ASSERT_TRUE(ClearListeners());
518 PASS();