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. 4 5 #include "ppapi/tests/test_post_message.h" 6 7 #include <algorithm> 8 #include <map> 9 #include <sstream> 10 11 #include "ppapi/c/dev/ppb_testing_dev.h" 12 #include "ppapi/c/pp_var.h" 13 #include "ppapi/cpp/instance.h" 14 #include "ppapi/cpp/var.h" 15 #include "ppapi/cpp/var_array.h" 16 #include "ppapi/cpp/var_array_buffer.h" 17 #include "ppapi/cpp/var_dictionary.h" 18 #include "ppapi/tests/pp_thread.h" 19 #include "ppapi/tests/test_utils.h" 20 #include "ppapi/tests/testing_instance.h" 21 22 // Windows defines 'PostMessage', so we have to undef it. 23 #ifdef PostMessage 24 #undef PostMessage 25 #endif 26 27 REGISTER_TEST_CASE(PostMessage); 28 29 namespace { 30 31 const char kTestString[] = "Hello world!"; 32 const bool kTestBool = true; 33 const int32_t kTestInt = 42; 34 const double kTestDouble = 42.0; 35 36 // On Windows XP bots, the NonMainThread test can run very slowly. So we dial 37 // back the number of threads & messages when running on Windows. 38 #ifdef PPAPI_OS_WIN 39 const int32_t kThreadsToRun = 2; 40 const int32_t kMessagesToSendPerThread = 5; 41 #else 42 const int32_t kThreadsToRun = 4; 43 const int32_t kMessagesToSendPerThread = 10; 44 #endif 45 46 // The struct that invoke_post_message_thread_func expects for its argument. 47 // It includes the instance on which to invoke PostMessage, and the value to 48 // pass to PostMessage. 49 struct InvokePostMessageThreadArg { 50 InvokePostMessageThreadArg(pp::Instance* i, const pp::Var& v) 51 : instance(i), value_to_send(v) {} 52 pp::Instance* instance; 53 pp::Var value_to_send; 54 }; 55 56 void InvokePostMessageThreadFunc(void* user_data) { 57 InvokePostMessageThreadArg* arg = 58 static_cast<InvokePostMessageThreadArg*>(user_data); 59 for (int32_t i = 0; i < kMessagesToSendPerThread; ++i) 60 arg->instance->PostMessage(arg->value_to_send); 61 delete arg; 62 } 63 64 // TODO(raymes): Consider putting something like this into pp::Var. 65 bool VarsEqual(const pp::Var& expected, 66 const pp::Var& actual, 67 std::map<int64_t, int64_t>* visited_ids) { 68 if (expected.pp_var().type != actual.pp_var().type) { 69 if (!expected.is_number() && !actual.is_number()) 70 return false; 71 } 72 // TODO(raymes): Implement a pp::Var::IsRefCounted() function. 73 if (expected.pp_var().type > PP_VARTYPE_DOUBLE) { 74 std::map<int64_t, int64_t>::const_iterator it = 75 visited_ids->find(expected.pp_var().value.as_id); 76 if (it != visited_ids->end()) { 77 if (it->second == actual.pp_var().value.as_id) 78 return true; 79 return false; 80 } 81 (*visited_ids)[expected.pp_var().value.as_id] = actual.pp_var().value.as_id; 82 } 83 84 if (expected.is_number()) { 85 return fabs(expected.AsDouble() - actual.AsDouble()) < 1.0e-4; 86 } else if (expected.is_array()) { 87 pp::VarArray expected_array(expected); 88 pp::VarArray actual_array(actual); 89 if (expected_array.GetLength() != actual_array.GetLength()) 90 return false; 91 for (uint32_t i = 0; i < expected_array.GetLength(); ++i) { 92 if (!VarsEqual(expected_array.Get(i), actual_array.Get(i), visited_ids)) 93 return false; 94 } 95 return true; 96 } else if (expected.is_dictionary()) { 97 pp::VarDictionary expected_dict(expected); 98 pp::VarDictionary actual_dict(actual); 99 if (expected_dict.GetKeys().GetLength() != 100 actual_dict.GetKeys().GetLength()) { 101 return false; 102 } 103 for (uint32_t i = 0; i < expected_dict.GetKeys().GetLength(); ++i) { 104 pp::Var key = expected_dict.GetKeys().Get(i); 105 if (!actual_dict.HasKey(key)) 106 return false; 107 if (!VarsEqual(expected_dict.Get(key), actual_dict.Get(key), visited_ids)) 108 return false; 109 } 110 return true; 111 } else { 112 return expected == actual; 113 } 114 } 115 116 bool VarsEqual(const pp::Var& expected, 117 const pp::Var& actual) { 118 std::map<int64_t, int64_t> visited_ids; 119 return VarsEqual(expected, actual, &visited_ids); 120 } 121 122 class ScopedArrayBufferSizeSetter { 123 public: 124 ScopedArrayBufferSizeSetter(const PPB_Testing_Dev* interface, 125 PP_Instance instance, 126 uint32_t threshold) 127 : interface_(interface), 128 instance_(instance) { 129 interface_->SetMinimumArrayBufferSizeForShmem(instance_, threshold); 130 } 131 ~ScopedArrayBufferSizeSetter() { 132 interface_->SetMinimumArrayBufferSizeForShmem(instance_, 0); 133 } 134 private: 135 const PPB_Testing_Dev* interface_; 136 PP_Instance instance_; 137 }; 138 139 #define FINISHED_WAITING_MESSAGE "TEST_POST_MESSAGE_FINISHED_WAITING" 140 141 } // namespace 142 143 TestPostMessage::TestPostMessage(TestingInstance* instance) 144 : TestCase(instance) { 145 } 146 147 TestPostMessage::~TestPostMessage() { 148 instance_->PostMessage(pp::Var("This isn't guaranteed to be received, but " 149 "shouldn't cause a crash.")); 150 151 // Remove the special listener that only responds to a FINISHED_WAITING 152 // string. See Init for where it gets added. 153 std::string js_code; 154 js_code += "var plugin = document.getElementById('plugin');" 155 "plugin.removeEventListener('message'," 156 " plugin.wait_for_messages_handler);" 157 "delete plugin.wait_for_messages_handler;"; 158 instance_->EvalScript(js_code); 159 } 160 161 bool TestPostMessage::Init() { 162 bool success = CheckTestingInterface(); 163 164 // Set up a special listener that only responds to a FINISHED_WAITING string. 165 // This is for use by WaitForMessages. 166 std::string js_code; 167 // Note the following code is dependent on some features of test_case.html. 168 // E.g., it is assumed that the DOM element where the plugin is embedded has 169 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows 170 // us to ignore the messages that are intended for use by the testing 171 // framework itself. 172 js_code += "var plugin = document.getElementById('plugin');" 173 "var wait_for_messages_handler = function(message_event) {" 174 " if (!IsTestingMessage(message_event.data) &&" 175 " message_event.data === '" FINISHED_WAITING_MESSAGE "') {" 176 " plugin.postMessage('" FINISHED_WAITING_MESSAGE "');" 177 " }" 178 "};" 179 "plugin.addEventListener('message', wait_for_messages_handler);" 180 // Stash it on the plugin so we can remove it in the destructor. 181 "plugin.wait_for_messages_handler = wait_for_messages_handler;"; 182 instance_->EvalScript(js_code); 183 184 // Set up the JavaScript message event listener to echo the data part of the 185 // message event back to us. 186 success = success && AddEchoingListener("message_event.data"); 187 message_data_.clear(); 188 // Send a message that the first test will expect to receive. This is to 189 // verify that we can send messages when the 'Instance::Init' function is on 190 // the stack. 191 instance_->PostMessage(pp::Var(kTestString)); 192 193 return success; 194 } 195 196 void TestPostMessage::RunTests(const std::string& filter) { 197 // Note: SendInInit must be first, because it expects to receive a message 198 // that was sent in Init above. 199 RUN_TEST(SendInInit, filter); 200 RUN_TEST(SendingData, filter); 201 RUN_TEST(SendingArrayBuffer, filter); 202 RUN_TEST(SendingArray, filter); 203 RUN_TEST(SendingDictionary, filter); 204 RUN_TEST(SendingComplexVar, filter); 205 RUN_TEST(MessageEvent, filter); 206 RUN_TEST(NoHandler, filter); 207 RUN_TEST(ExtraParam, filter); 208 if (testing_interface_->IsOutOfProcess()) 209 RUN_TEST(NonMainThread, filter); 210 } 211 212 void TestPostMessage::HandleMessage(const pp::Var& message_data) { 213 if (message_data.is_string() && 214 (message_data.AsString() == FINISHED_WAITING_MESSAGE)) 215 testing_interface_->QuitMessageLoop(instance_->pp_instance()); 216 else 217 message_data_.push_back(message_data); 218 } 219 220 bool TestPostMessage::AddEchoingListener(const std::string& expression) { 221 std::string js_code; 222 // Note the following code is dependent on some features of test_case.html. 223 // E.g., it is assumed that the DOM element where the plugin is embedded has 224 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows 225 // us to ignore the messages that are intended for use by the testing 226 // framework itself. 227 js_code += "var plugin = document.getElementById('plugin');" 228 "var message_handler = function(message_event) {" 229 " if (!IsTestingMessage(message_event.data) &&" 230 " !(message_event.data === '" FINISHED_WAITING_MESSAGE "')) {" 231 " plugin.postMessage("; 232 js_code += expression; 233 js_code += " );" 234 " }" 235 "};" 236 "plugin.addEventListener('message', message_handler);" 237 // Maintain an array of all event listeners, attached to the 238 // plugin. This is so that we can easily remove them later (see 239 // ClearListeners()). 240 "if (!plugin.eventListeners) plugin.eventListeners = [];" 241 "plugin.eventListeners.push(message_handler);"; 242 instance_->EvalScript(js_code); 243 return true; 244 } 245 246 bool TestPostMessage::PostMessageFromJavaScript(const std::string& func) { 247 std::string js_code; 248 js_code += "var plugin = document.getElementById('plugin');" 249 "plugin.postMessage("; 250 js_code += func + "()"; 251 js_code += " );"; 252 instance_->EvalScript(js_code); 253 return true; 254 } 255 256 bool TestPostMessage::ClearListeners() { 257 std::string js_code; 258 js_code += "var plugin = document.getElementById('plugin');" 259 "while (plugin.eventListeners.length) {" 260 " plugin.removeEventListener('message'," 261 " plugin.eventListeners.pop());" 262 "}"; 263 instance_->EvalScript(js_code); 264 return true; 265 } 266 267 int TestPostMessage::WaitForMessages() { 268 size_t message_size_before = message_data_.size(); 269 // We first post a FINISHED_WAITING_MESSAGE. This should be guaranteed to 270 // come back _after_ any other incoming messages that were already pending. 271 instance_->PostMessage(pp::Var(FINISHED_WAITING_MESSAGE)); 272 testing_interface_->RunMessageLoop(instance_->pp_instance()); 273 // Now that the FINISHED_WAITING_MESSAGE has been echoed back to us, we know 274 // that all pending messages have been slurped up. Return the number we 275 // received (which may be zero). 276 return message_data_.size() - message_size_before; 277 } 278 279 std::string TestPostMessage::CheckMessageProperties( 280 const pp::Var& test_data, 281 const std::vector<std::string>& properties_to_check) { 282 typedef std::vector<std::string>::const_iterator Iterator; 283 for (Iterator iter = properties_to_check.begin(); 284 iter != properties_to_check.end(); 285 ++iter) { 286 ASSERT_TRUE(AddEchoingListener(*iter)); 287 message_data_.clear(); 288 instance_->PostMessage(test_data); 289 ASSERT_EQ(message_data_.size(), 0); 290 ASSERT_EQ(WaitForMessages(), 1); 291 ASSERT_TRUE(message_data_.back().is_bool()); 292 if (!message_data_.back().AsBool()) 293 return std::string("Failed: ") + *iter; 294 ASSERT_TRUE(message_data_.back().AsBool()); 295 ASSERT_TRUE(ClearListeners()); 296 } 297 PASS(); 298 } 299 300 std::string TestPostMessage::TestSendInInit() { 301 ASSERT_EQ(WaitForMessages(), 1); 302 // This test assumes Init already sent a message. 303 ASSERT_EQ(message_data_.size(), 1); 304 ASSERT_TRUE(message_data_.back().is_string()); 305 ASSERT_EQ(message_data_.back().AsString(), kTestString); 306 message_data_.clear(); 307 PASS(); 308 } 309 310 std::string TestPostMessage::TestSendingData() { 311 // Clean up after previous tests. This also swallows the message sent by Init 312 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 313 // should start with these. 314 WaitForMessages(); 315 ASSERT_TRUE(ClearListeners()); 316 // Set up the JavaScript message event listener to echo the data part of the 317 // message event back to us. 318 ASSERT_TRUE(AddEchoingListener("message_event.data")); 319 320 // Test sending a message to JavaScript for each supported type. The JS sends 321 // the data back to us, and we check that they match. 322 message_data_.clear(); 323 instance_->PostMessage(pp::Var(kTestString)); 324 // PostMessage is asynchronous, so we should not receive a response yet. 325 ASSERT_EQ(message_data_.size(), 0); 326 ASSERT_EQ(WaitForMessages(), 1); 327 ASSERT_TRUE(message_data_.back().is_string()); 328 ASSERT_EQ(message_data_.back().AsString(), kTestString); 329 330 message_data_.clear(); 331 instance_->PostMessage(pp::Var(kTestBool)); 332 ASSERT_EQ(message_data_.size(), 0); 333 ASSERT_EQ(WaitForMessages(), 1); 334 ASSERT_TRUE(message_data_.back().is_bool()); 335 ASSERT_EQ(message_data_.back().AsBool(), kTestBool); 336 337 message_data_.clear(); 338 instance_->PostMessage(pp::Var(kTestInt)); 339 ASSERT_EQ(message_data_.size(), 0); 340 ASSERT_EQ(WaitForMessages(), 1); 341 ASSERT_TRUE(message_data_.back().is_number()); 342 ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(), 343 static_cast<double>(kTestInt)); 344 345 message_data_.clear(); 346 instance_->PostMessage(pp::Var(kTestDouble)); 347 ASSERT_EQ(message_data_.size(), 0); 348 ASSERT_EQ(WaitForMessages(), 1); 349 ASSERT_TRUE(message_data_.back().is_number()); 350 ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(), kTestDouble); 351 352 message_data_.clear(); 353 instance_->PostMessage(pp::Var()); 354 ASSERT_EQ(message_data_.size(), 0); 355 ASSERT_EQ(WaitForMessages(), 1); 356 ASSERT_TRUE(message_data_.back().is_undefined()); 357 358 message_data_.clear(); 359 instance_->PostMessage(pp::Var(pp::Var::Null())); 360 ASSERT_EQ(message_data_.size(), 0); 361 ASSERT_EQ(WaitForMessages(), 1); 362 ASSERT_TRUE(message_data_.back().is_null()); 363 364 message_data_.clear(); 365 ASSERT_TRUE(ClearListeners()); 366 367 PASS(); 368 } 369 370 std::string TestPostMessage::TestSendingArrayBuffer() { 371 // Clean up after previous tests. This also swallows the message sent by Init 372 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 373 // should start with these. 374 WaitForMessages(); 375 ASSERT_TRUE(ClearListeners()); 376 377 // TODO(sehr,dmichael): Add testing of longer array buffers when 378 // crbug.com/110086 is fixed. 379 ScopedArrayBufferSizeSetter setter(testing_interface_, 380 instance_->pp_instance(), 381 200); 382 uint32_t sizes[] = { 0, 100, 1000, 10000 }; 383 for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[i]); ++i) { 384 std::ostringstream size_stream; 385 size_stream << sizes[i]; 386 const std::string kSizeAsString(size_stream.str()); 387 388 // Create an appropriately sized array buffer with test_data[i] == i. 389 pp::VarArrayBuffer test_data(sizes[i]); 390 if (sizes[i] > 0) 391 ASSERT_NE(NULL, test_data.Map()); 392 // Make sure we can Unmap/Map successfully (there's not really any way to 393 // detect if it's unmapped, so we just re-map before getting the pointer to 394 // the buffer). 395 test_data.Unmap(); 396 test_data.Map(); 397 ASSERT_EQ(sizes[i], test_data.ByteLength()); 398 unsigned char* buff = static_cast<unsigned char*>(test_data.Map()); 399 const uint32_t kByteLength = test_data.ByteLength(); 400 for (size_t j = 0; j < kByteLength; ++j) 401 buff[j] = static_cast<uint8_t>(j % 256u); 402 403 // Have the listener test some properties of the ArrayBuffer. 404 std::vector<std::string> properties_to_check; 405 properties_to_check.push_back( 406 "message_event.data.constructor.name === 'ArrayBuffer'"); 407 properties_to_check.push_back( 408 std::string("message_event.data.byteLength === ") + kSizeAsString); 409 if (sizes[i] > 0) { 410 properties_to_check.push_back( 411 "(new DataView(message_event.data)).getUint8(0) == 0"); 412 // Checks that the last element has the right value: (byteLength-1)%256. 413 std::string received_byte("(new DataView(message_event.data)).getUint8(" 414 " message_event.data.byteLength-1)"); 415 std::string expected_byte("(message_event.data.byteLength-1)%256"); 416 properties_to_check.push_back(received_byte + " == " + expected_byte); 417 } 418 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(test_data, 419 properties_to_check)); 420 421 // Set up the JavaScript message event listener to echo the data part of the 422 // message event back to us. 423 ASSERT_TRUE(AddEchoingListener("message_event.data")); 424 message_data_.clear(); 425 instance_->PostMessage(test_data); 426 // PostMessage is asynchronous, so we should not receive a response yet. 427 ASSERT_EQ(message_data_.size(), 0); 428 ASSERT_EQ(WaitForMessages(), 1); 429 ASSERT_TRUE(message_data_.back().is_array_buffer()); 430 pp::VarArrayBuffer received(message_data_.back()); 431 message_data_.clear(); 432 ASSERT_EQ(test_data.ByteLength(), received.ByteLength()); 433 unsigned char* received_buff = static_cast<unsigned char*>(received.Map()); 434 // The buffer should be copied, so this should be a distinct buffer. When 435 // 'transferrables' are implemented for PPAPI, we'll also want to test that 436 // we get the _same_ buffer back when it's transferred. 437 if (sizes[i] > 0) 438 ASSERT_NE(buff, received_buff); 439 for (size_t i = 0; i < test_data.ByteLength(); ++i) 440 ASSERT_EQ(buff[i], received_buff[i]); 441 442 message_data_.clear(); 443 ASSERT_TRUE(ClearListeners()); 444 } 445 446 PASS(); 447 } 448 449 std::string TestPostMessage::TestSendingArray() { 450 // Clean up after previous tests. This also swallows the message sent by Init 451 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 452 // should start with these. 453 WaitForMessages(); 454 ASSERT_TRUE(ClearListeners()); 455 456 pp::VarArray array; 457 array.Set(0, pp::Var(kTestBool)); 458 array.Set(1, pp::Var(kTestString)); 459 // Purposely leave index 2 empty. 460 array.Set(3, pp::Var(kTestInt)); 461 array.Set(4, pp::Var(kTestDouble)); 462 463 std::stringstream ss; 464 ss << array.GetLength(); 465 std::string length_as_string(ss.str()); 466 467 // Have the listener test some properties of the Array. 468 std::vector<std::string> properties_to_check; 469 properties_to_check.push_back( 470 "message_event.data.constructor.name === 'Array'"); 471 properties_to_check.push_back( 472 std::string("message_event.data.length === ") + length_as_string); 473 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(array, properties_to_check)); 474 475 // Set up the JavaScript message event listener to echo the data part of the 476 // message event back to us. 477 ASSERT_TRUE(AddEchoingListener("message_event.data")); 478 message_data_.clear(); 479 instance_->PostMessage(array); 480 // PostMessage is asynchronous, so we should not receive a response yet. 481 ASSERT_EQ(message_data_.size(), 0); 482 ASSERT_EQ(WaitForMessages(), 1); 483 ASSERT_TRUE(message_data_.back().is_array()); 484 ASSERT_TRUE(VarsEqual(array, message_data_.back())); 485 486 message_data_.clear(); 487 ASSERT_TRUE(ClearListeners()); 488 489 PASS(); 490 } 491 492 std::string TestPostMessage::TestSendingDictionary() { 493 // Clean up after previous tests. This also swallows the message sent by Init 494 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 495 // should start with these. 496 WaitForMessages(); 497 ASSERT_TRUE(ClearListeners()); 498 499 pp::VarDictionary dictionary; 500 dictionary.Set(pp::Var("foo"), pp::Var(kTestBool)); 501 dictionary.Set(pp::Var("bar"), pp::Var(kTestString)); 502 dictionary.Set(pp::Var("abc"), pp::Var(kTestInt)); 503 dictionary.Set(pp::Var("def"), pp::Var()); 504 505 std::stringstream ss; 506 ss << dictionary.GetKeys().GetLength(); 507 std::string length_as_string(ss.str()); 508 509 // Have the listener test some properties of the Dictionary. 510 std::vector<std::string> properties_to_check; 511 properties_to_check.push_back( 512 "message_event.data.constructor.name === 'Object'"); 513 properties_to_check.push_back( 514 std::string("Object.keys(message_event.data).length === ") + 515 length_as_string); 516 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(dictionary, 517 properties_to_check)); 518 519 // Set up the JavaScript message event listener to echo the data part of the 520 // message event back to us. 521 ASSERT_TRUE(AddEchoingListener("message_event.data")); 522 message_data_.clear(); 523 instance_->PostMessage(dictionary); 524 // PostMessage is asynchronous, so we should not receive a response yet. 525 ASSERT_EQ(message_data_.size(), 0); 526 ASSERT_EQ(WaitForMessages(), 1); 527 ASSERT_TRUE(message_data_.back().is_dictionary()); 528 ASSERT_TRUE(VarsEqual(dictionary, message_data_.back())); 529 530 message_data_.clear(); 531 ASSERT_TRUE(ClearListeners()); 532 533 PASS(); 534 } 535 536 std::string TestPostMessage::TestSendingComplexVar() { 537 // Clean up after previous tests. This also swallows the message sent by Init 538 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 539 // should start with these. 540 WaitForMessages(); 541 message_data_.clear(); 542 ASSERT_TRUE(ClearListeners()); 543 544 pp::Var string(kTestString); 545 pp::VarDictionary dictionary; 546 dictionary.Set(pp::Var("foo"), pp::Var(kTestBool)); 547 dictionary.Set(pp::Var("bar"), string); 548 dictionary.Set(pp::Var("abc"), pp::Var(kTestInt)); 549 dictionary.Set(pp::Var("def"), pp::Var()); 550 551 // Reference to array. 552 pp::VarArray array; 553 array.Set(0, pp::Var(kTestBool)); 554 array.Set(1, string); 555 // Purposely leave index 2 empty (which will place an undefined var there). 556 array.Set(3, pp::Var(kTestInt)); 557 array.Set(4, pp::Var(kTestDouble)); 558 559 dictionary.Set(pp::Var("array-ref1"), array); 560 dictionary.Set(pp::Var("array-ref2"), array); 561 562 // Set up the JavaScript message event listener to echo the data part of the 563 // message event back to us. 564 ASSERT_TRUE(AddEchoingListener("message_event.data")); 565 instance_->PostMessage(dictionary); 566 // PostMessage is asynchronous, so we should not receive a response yet. 567 ASSERT_EQ(message_data_.size(), 0); 568 ASSERT_EQ(WaitForMessages(), 1); 569 ASSERT_TRUE(message_data_.back().is_dictionary()); 570 pp::VarDictionary result(message_data_.back()); 571 ASSERT_TRUE(VarsEqual(dictionary, message_data_.back())); 572 573 WaitForMessages(); 574 message_data_.clear(); 575 ASSERT_TRUE(ClearListeners()); 576 577 // Set up a (dictionary -> array -> dictionary) cycle. Cycles shouldn't be 578 // transmitted. 579 pp::VarArray array2; 580 array2.Set(0, dictionary); 581 dictionary.Set(pp::Var("array2"), array2); 582 583 ASSERT_TRUE(AddEchoingListener("message_event.data")); 584 instance_->PostMessage(dictionary); 585 // PostMessage is asynchronous, so we should not receive a response yet. 586 ASSERT_EQ(message_data_.size(), 0); 587 ASSERT_EQ(WaitForMessages(), 0); 588 589 // Break the cycles. 590 dictionary.Delete(pp::Var("array2")); 591 592 WaitForMessages(); 593 message_data_.clear(); 594 ASSERT_TRUE(ClearListeners()); 595 596 // Test sending a cycle from JavaScript to the plugin. 597 ASSERT_TRUE(AddEchoingListener("message_event.data")); 598 PostMessageFromJavaScript("function() { var x = []; x[0] = x; return x; }"); 599 ASSERT_EQ(message_data_.size(), 0); 600 ASSERT_EQ(WaitForMessages(), 0); 601 602 WaitForMessages(); 603 message_data_.clear(); 604 ASSERT_TRUE(ClearListeners()); 605 606 PASS(); 607 } 608 609 std::string TestPostMessage::TestMessageEvent() { 610 // Set up the JavaScript message event listener to pass us some values from 611 // the MessageEvent and make sure they match our expectations. 612 613 WaitForMessages(); 614 ASSERT_TRUE(ClearListeners()); 615 // Have the listener pass back the class name of message_event and make sure 616 // it's "MessageEvent". 617 ASSERT_TRUE(AddEchoingListener("message_event.constructor.name")); 618 message_data_.clear(); 619 instance_->PostMessage(pp::Var(kTestInt)); 620 ASSERT_EQ(message_data_.size(), 0); 621 ASSERT_EQ(WaitForMessages(), 1); 622 ASSERT_TRUE(message_data_.back().is_string()); 623 ASSERT_EQ(message_data_.back().AsString(), "MessageEvent"); 624 ASSERT_TRUE(ClearListeners()); 625 626 // Make sure all the non-data properties have the expected values. 627 bool success = AddEchoingListener("((message_event.origin === '')" 628 " && (message_event.lastEventId === '')" 629 " && (message_event.source === null)" 630 " && (message_event.ports.length === 0)" 631 " && (message_event.bubbles === false)" 632 " && (message_event.cancelable === false)" 633 ")"); 634 ASSERT_TRUE(success); 635 message_data_.clear(); 636 instance_->PostMessage(pp::Var(kTestInt)); 637 ASSERT_EQ(message_data_.size(), 0); 638 ASSERT_EQ(WaitForMessages(), 1); 639 ASSERT_TRUE(message_data_.back().is_bool()); 640 ASSERT_TRUE(message_data_.back().AsBool()); 641 ASSERT_TRUE(ClearListeners()); 642 643 // Add some event handlers to make sure they receive messages. 644 ASSERT_TRUE(AddEchoingListener("1")); 645 ASSERT_TRUE(AddEchoingListener("2")); 646 ASSERT_TRUE(AddEchoingListener("3")); 647 648 message_data_.clear(); 649 instance_->PostMessage(pp::Var(kTestInt)); 650 // Make sure we don't get a response in a re-entrant fashion. 651 ASSERT_EQ(message_data_.size(), 0); 652 // We should get 3 messages. 653 ASSERT_EQ(WaitForMessages(), 3); 654 // Copy to a vector of doubles and sort; w3c does not specify the order for 655 // event listeners. (Copying is easier than writing an operator< for pp::Var.) 656 // 657 // See http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html. 658 VarVector::iterator iter(message_data_.begin()), the_end(message_data_.end()); 659 std::vector<double> double_vec; 660 for (; iter != the_end; ++iter) { 661 ASSERT_TRUE(iter->is_number()); 662 double_vec.push_back(iter->AsDouble()); 663 } 664 std::sort(double_vec.begin(), double_vec.end()); 665 ASSERT_DOUBLE_EQ(double_vec[0], 1.0); 666 ASSERT_DOUBLE_EQ(double_vec[1], 2.0); 667 ASSERT_DOUBLE_EQ(double_vec[2], 3.0); 668 669 message_data_.clear(); 670 ASSERT_TRUE(ClearListeners()); 671 672 PASS(); 673 } 674 675 std::string TestPostMessage::TestNoHandler() { 676 // Delete any lingering messages and event listeners. 677 WaitForMessages(); 678 ASSERT_TRUE(ClearListeners()); 679 680 // Now send a message. We shouldn't get a response. 681 message_data_.clear(); 682 instance_->PostMessage(pp::Var()); 683 ASSERT_EQ(WaitForMessages(), 0); 684 ASSERT_TRUE(message_data_.empty()); 685 686 PASS(); 687 } 688 689 std::string TestPostMessage::TestExtraParam() { 690 // Delete any lingering messages and event listeners. 691 WaitForMessages(); 692 ASSERT_TRUE(ClearListeners()); 693 // Add a listener that will respond with 1 and an empty array (where the 694 // message port array would appear if it was Worker postMessage). 695 ASSERT_TRUE(AddEchoingListener("1, []")); 696 697 // Now send a message. We shouldn't get a response. 698 message_data_.clear(); 699 instance_->PostMessage(pp::Var()); 700 ASSERT_EQ(WaitForMessages(), 0); 701 ASSERT_TRUE(message_data_.empty()); 702 703 ASSERT_TRUE(ClearListeners()); 704 705 PASS(); 706 } 707 708 std::string TestPostMessage::TestNonMainThread() { 709 WaitForMessages(); 710 ASSERT_TRUE(ClearListeners()); 711 ASSERT_TRUE(AddEchoingListener("message_event.data")); 712 message_data_.clear(); 713 714 // Set up a thread for each integer from 0 to (kThreadsToRun - 1). Make each 715 // thread send the number that matches its index kMessagesToSendPerThread 716 // times. For good measure, call postMessage from the main thread 717 // kMessagesToSendPerThread times. At the end, we make sure we got all the 718 // values we expected. 719 PP_ThreadType threads[kThreadsToRun]; 720 for (int32_t i = 0; i < kThreadsToRun; ++i) { 721 // Set up a thread to send a value of i. 722 void* arg = new InvokePostMessageThreadArg(instance_, pp::Var(i)); 723 PP_CreateThread(&threads[i], &InvokePostMessageThreadFunc, arg); 724 } 725 // Invoke PostMessage right now to send a value of (kThreadsToRun). 726 for (int32_t i = 0; i < kMessagesToSendPerThread; ++i) 727 instance_->PostMessage(pp::Var(kThreadsToRun)); 728 729 // Now join all threads. 730 for (int32_t i = 0; i < kThreadsToRun; ++i) 731 PP_JoinThread(threads[i]); 732 733 // PostMessage is asynchronous, so we should not receive a response yet. 734 ASSERT_EQ(message_data_.size(), 0); 735 736 // Make sure we got all values that we expected. Note that because it's legal 737 // for the JavaScript engine to treat our integers as floating points, we 738 // can't just use std::find or equality comparison. So we instead, we convert 739 // each incoming value to an integer, and count them in received_counts. 740 int32_t expected_num = (kThreadsToRun + 1) * kMessagesToSendPerThread; 741 // Count how many we receive per-index. 742 std::vector<int32_t> expected_counts(kThreadsToRun + 1, 743 kMessagesToSendPerThread); 744 std::vector<int32_t> received_counts(kThreadsToRun + 1, 0); 745 ASSERT_EQ(WaitForMessages(), expected_num); 746 for (int32_t i = 0; i < expected_num; ++i) { 747 const pp::Var& latest_var(message_data_[i]); 748 ASSERT_TRUE(latest_var.is_int() || latest_var.is_double()); 749 int32_t received_value = -1; 750 if (latest_var.is_int()) { 751 received_value = latest_var.AsInt(); 752 } else if (latest_var.is_double()) { 753 received_value = static_cast<int32_t>(latest_var.AsDouble() + 0.5); 754 } 755 ASSERT_TRUE(received_value >= 0); 756 ASSERT_TRUE(received_value <= kThreadsToRun); 757 ++received_counts[received_value]; 758 } 759 ASSERT_EQ(received_counts, expected_counts); 760 761 message_data_.clear(); 762 ASSERT_TRUE(ClearListeners()); 763 764 PASS(); 765 } 766