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"
12 #include "ppapi/c/pp_var.h"
13 #include "ppapi/c/ppb_file_io.h"
14 #include "ppapi/cpp/file_io.h"
15 #include "ppapi/cpp/file_ref.h"
16 #include "ppapi/cpp/file_system.h"
17 #include "ppapi/cpp/instance.h"
18 #include "ppapi/cpp/var.h"
19 #include "ppapi/cpp/var_array.h"
20 #include "ppapi/cpp/var_array_buffer.h"
21 #include "ppapi/cpp/var_dictionary.h"
22 #include "ppapi/tests/pp_thread.h"
23 #include "ppapi/tests/test_utils.h"
24 #include "ppapi/tests/testing_instance.h"
26 // Windows defines 'PostMessage', so we have to undef it.
31 REGISTER_TEST_CASE(PostMessage);
35 const char kTestFilename[] = "testfile.txt";
36 const char kTestString[] = "Hello world!";
37 const bool kTestBool = true;
38 const int32_t kTestInt = 42;
39 const double kTestDouble = 42.0;
41 // On Windows XP bots, the NonMainThread test can run very slowly. So we dial
42 // back the number of threads & messages when running on Windows.
44 const int32_t kThreadsToRun = 2;
45 const int32_t kMessagesToSendPerThread = 5;
47 const int32_t kThreadsToRun = 4;
48 const int32_t kMessagesToSendPerThread = 10;
51 // The struct that invoke_post_message_thread_func expects for its argument.
52 // It includes the instance on which to invoke PostMessage, and the value to
53 // pass to PostMessage.
54 struct InvokePostMessageThreadArg {
55 InvokePostMessageThreadArg(pp::Instance* i, const pp::Var& v)
56 : instance(i), value_to_send(v) {}
57 pp::Instance* instance;
58 pp::Var value_to_send;
61 void InvokePostMessageThreadFunc(void* user_data) {
62 InvokePostMessageThreadArg* arg =
63 static_cast<InvokePostMessageThreadArg*>(user_data);
64 for (int32_t i = 0; i < kMessagesToSendPerThread; ++i)
65 arg->instance->PostMessage(arg->value_to_send);
69 // TODO(raymes): Consider putting something like this into pp::Var.
70 bool VarsEqual(const pp::Var& expected,
71 const pp::Var& actual,
72 std::map<int64_t, int64_t>* visited_ids) {
73 if (expected.pp_var().type != actual.pp_var().type) {
74 if (!expected.is_number() && !actual.is_number())
77 // TODO(raymes): Implement a pp::Var::IsRefCounted() function.
78 if (expected.pp_var().type > PP_VARTYPE_DOUBLE) {
79 std::map<int64_t, int64_t>::const_iterator it =
80 visited_ids->find(expected.pp_var().value.as_id);
81 if (it != visited_ids->end()) {
82 if (it->second == actual.pp_var().value.as_id)
86 // Round-tripping reference graphs with strings will not necessarily
87 // result in isomorphic graphs. This is because string vars are converted
88 // to string primitives in JS which cannot be referenced.
89 if (!expected.is_string()) {
90 (*visited_ids)[expected.pp_var().value.as_id] =
91 actual.pp_var().value.as_id;
95 if (expected.is_number()) {
96 return fabs(expected.AsDouble() - actual.AsDouble()) < 1.0e-4;
97 } else if (expected.is_array()) {
98 pp::VarArray expected_array(expected);
99 pp::VarArray actual_array(actual);
100 if (expected_array.GetLength() != actual_array.GetLength())
102 for (uint32_t i = 0; i < expected_array.GetLength(); ++i) {
103 if (!VarsEqual(expected_array.Get(i), actual_array.Get(i), visited_ids))
107 } else if (expected.is_dictionary()) {
108 pp::VarDictionary expected_dict(expected);
109 pp::VarDictionary actual_dict(actual);
110 if (expected_dict.GetKeys().GetLength() !=
111 actual_dict.GetKeys().GetLength()) {
114 for (uint32_t i = 0; i < expected_dict.GetKeys().GetLength(); ++i) {
115 pp::Var key = expected_dict.GetKeys().Get(i);
116 if (!actual_dict.HasKey(key))
118 if (!VarsEqual(expected_dict.Get(key), actual_dict.Get(key), visited_ids))
123 return expected == actual;
127 bool VarsEqual(const pp::Var& expected,
128 const pp::Var& actual) {
129 std::map<int64_t, int64_t> visited_ids;
130 return VarsEqual(expected, actual, &visited_ids);
133 class ScopedArrayBufferSizeSetter {
135 ScopedArrayBufferSizeSetter(const PPB_Testing_Private* interface,
136 PP_Instance instance,
138 : interface_(interface),
139 instance_(instance) {
140 interface_->SetMinimumArrayBufferSizeForShmem(instance_, threshold);
142 ~ScopedArrayBufferSizeSetter() {
143 interface_->SetMinimumArrayBufferSizeForShmem(instance_, 0);
146 const PPB_Testing_Private* interface_;
147 PP_Instance instance_;
150 #define FINISHED_WAITING_MESSAGE "TEST_POST_MESSAGE_FINISHED_WAITING"
154 TestPostMessage::TestPostMessage(TestingInstance* instance)
155 : TestCase(instance) {
158 TestPostMessage::~TestPostMessage() {
159 instance_->PostMessage(pp::Var("This isn't guaranteed to be received, but "
160 "shouldn't cause a crash."));
162 // Remove the special listener that only responds to a FINISHED_WAITING
163 // string. See Init for where it gets added.
165 js_code += "var plugin = document.getElementById('plugin');"
166 "plugin.removeEventListener('message',"
167 " plugin.wait_for_messages_handler);"
168 "delete plugin.wait_for_messages_handler;";
169 instance_->EvalScript(js_code);
172 bool TestPostMessage::Init() {
173 bool success = CheckTestingInterface();
175 // Set up a special listener that only responds to a FINISHED_WAITING string.
176 // This is for use by WaitForMessages.
178 // Note the following code is dependent on some features of test_case.html.
179 // E.g., it is assumed that the DOM element where the plugin is embedded has
180 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows
181 // us to ignore the messages that are intended for use by the testing
183 js_code += "var plugin = document.getElementById('plugin');"
184 "var wait_for_messages_handler = function(message_event) {"
185 " if (!IsTestingMessage(message_event.data) &&"
186 " message_event.data === '" FINISHED_WAITING_MESSAGE "') {"
187 " plugin.postMessage('" FINISHED_WAITING_MESSAGE "');"
190 "plugin.addEventListener('message', wait_for_messages_handler);"
191 // Stash it on the plugin so we can remove it in the destructor.
192 "plugin.wait_for_messages_handler = wait_for_messages_handler;";
193 instance_->EvalScript(js_code);
195 // Set up the JavaScript message event listener to echo the data part of the
196 // message event back to us.
197 success = success && AddEchoingListener("message_event.data");
198 message_data_.clear();
199 // Send a message that the first test will expect to receive. This is to
200 // verify that we can send messages when the 'Instance::Init' function is on
202 instance_->PostMessage(pp::Var(kTestString));
207 void TestPostMessage::RunTests(const std::string& filter) {
208 // Note: SendInInit must be first, because it expects to receive a message
209 // that was sent in Init above.
210 RUN_TEST(SendInInit, filter);
211 RUN_TEST(SendingData, filter);
212 RUN_TEST(SendingString, filter);
213 RUN_TEST(SendingArrayBuffer, filter);
214 RUN_TEST(SendingArray, filter);
215 RUN_TEST(SendingDictionary, filter);
216 RUN_TEST(SendingResource, filter);
217 RUN_TEST(SendingComplexVar, filter);
218 RUN_TEST(MessageEvent, filter);
219 RUN_TEST(NoHandler, filter);
220 RUN_TEST(ExtraParam, filter);
221 if (testing_interface_->IsOutOfProcess())
222 RUN_TEST(NonMainThread, filter);
225 void TestPostMessage::HandleMessage(const pp::Var& message_data) {
226 if (message_data.is_string() &&
227 (message_data.AsString() == FINISHED_WAITING_MESSAGE))
228 testing_interface_->QuitMessageLoop(instance_->pp_instance());
230 message_data_.push_back(message_data);
233 bool TestPostMessage::AddEchoingListener(const std::string& expression) {
235 // Note the following code is dependent on some features of test_case.html.
236 // E.g., it is assumed that the DOM element where the plugin is embedded has
237 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows
238 // us to ignore the messages that are intended for use by the testing
240 js_code += "var plugin = document.getElementById('plugin');"
241 "var message_handler = function(message_event) {"
242 " if (!IsTestingMessage(message_event.data) &&"
243 " !(message_event.data === '" FINISHED_WAITING_MESSAGE "')) {"
244 " plugin.postMessage(";
245 js_code += expression;
249 "plugin.addEventListener('message', message_handler);"
250 // Maintain an array of all event listeners, attached to the
251 // plugin. This is so that we can easily remove them later (see
252 // ClearListeners()).
253 "if (!plugin.eventListeners) plugin.eventListeners = [];"
254 "plugin.eventListeners.push(message_handler);";
255 instance_->EvalScript(js_code);
259 bool TestPostMessage::PostMessageFromJavaScript(const std::string& func) {
261 js_code += "var plugin = document.getElementById('plugin');"
262 "plugin.postMessage(";
263 js_code += func + "()";
265 instance_->EvalScript(js_code);
269 bool TestPostMessage::ClearListeners() {
271 js_code += "var plugin = document.getElementById('plugin');"
272 "while (plugin.eventListeners.length) {"
273 " plugin.removeEventListener('message',"
274 " plugin.eventListeners.pop());"
276 instance_->EvalScript(js_code);
280 int TestPostMessage::WaitForMessages() {
281 size_t message_size_before = message_data_.size();
282 // We first post a FINISHED_WAITING_MESSAGE. This should be guaranteed to
283 // come back _after_ any other incoming messages that were already pending.
284 instance_->PostMessage(pp::Var(FINISHED_WAITING_MESSAGE));
285 testing_interface_->RunMessageLoop(instance_->pp_instance());
286 // Now that the FINISHED_WAITING_MESSAGE has been echoed back to us, we know
287 // that all pending messages have been slurped up. Return the number we
288 // received (which may be zero).
289 return message_data_.size() - message_size_before;
292 std::string TestPostMessage::CheckMessageProperties(
293 const pp::Var& test_data,
294 const std::vector<std::string>& properties_to_check) {
295 typedef std::vector<std::string>::const_iterator Iterator;
296 for (Iterator iter = properties_to_check.begin();
297 iter != properties_to_check.end();
299 ASSERT_TRUE(AddEchoingListener(*iter));
300 message_data_.clear();
301 instance_->PostMessage(test_data);
302 ASSERT_EQ(0, message_data_.size());
303 ASSERT_EQ(1, WaitForMessages());
304 ASSERT_TRUE(message_data_.back().is_bool());
305 if (!message_data_.back().AsBool())
306 return std::string("Failed: ") + *iter;
307 ASSERT_TRUE(message_data_.back().AsBool());
308 ASSERT_TRUE(ClearListeners());
313 std::string TestPostMessage::TestSendInInit() {
314 ASSERT_EQ(1, WaitForMessages());
315 // This test assumes Init already sent a message.
316 ASSERT_EQ(1, message_data_.size());
317 ASSERT_TRUE(message_data_.back().is_string());
318 ASSERT_EQ(kTestString, message_data_.back().AsString());
319 message_data_.clear();
323 std::string TestPostMessage::TestSendingData() {
324 // Clean up after previous tests. This also swallows the message sent by Init
325 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
326 // should start with these.
328 ASSERT_TRUE(ClearListeners());
330 // Set up the JavaScript message event listener to echo the data part of the
331 // message event back to us.
332 ASSERT_TRUE(AddEchoingListener("message_event.data"));
334 // Test sending a message to JavaScript for each supported type. The JS sends
335 // the data back to us, and we check that they match.
336 message_data_.clear();
337 instance_->PostMessage(pp::Var(kTestBool));
338 ASSERT_EQ(0, message_data_.size());
339 ASSERT_EQ(1, WaitForMessages());
340 ASSERT_TRUE(message_data_.back().is_bool());
341 ASSERT_EQ(message_data_.back().AsBool(), kTestBool);
343 message_data_.clear();
344 instance_->PostMessage(pp::Var(kTestInt));
345 ASSERT_EQ(0, message_data_.size());
346 ASSERT_EQ(1, WaitForMessages());
347 ASSERT_TRUE(message_data_.back().is_number());
348 ASSERT_DOUBLE_EQ(static_cast<double>(kTestInt),
349 message_data_.back().AsDouble());
351 message_data_.clear();
352 instance_->PostMessage(pp::Var(kTestDouble));
353 ASSERT_EQ(0, message_data_.size());
354 ASSERT_EQ(1, WaitForMessages());
355 ASSERT_TRUE(message_data_.back().is_number());
356 ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(), kTestDouble);
358 message_data_.clear();
359 instance_->PostMessage(pp::Var());
360 ASSERT_EQ(0, message_data_.size());
361 ASSERT_EQ(1, WaitForMessages());
362 ASSERT_TRUE(message_data_.back().is_undefined());
364 message_data_.clear();
365 instance_->PostMessage(pp::Var(pp::Var::Null()));
366 ASSERT_EQ(0, message_data_.size());
367 ASSERT_EQ(1, WaitForMessages());
368 ASSERT_TRUE(message_data_.back().is_null());
370 message_data_.clear();
371 ASSERT_TRUE(ClearListeners());
376 std::string TestPostMessage::TestSendingString() {
377 // Clean up after previous tests. This also swallows the message sent by Init
378 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
379 // should start with these.
381 ASSERT_TRUE(ClearListeners());
383 // Test that a string var is converted to a primitive JS string.
384 message_data_.clear();
385 std::vector<std::string> properties_to_check;
386 properties_to_check.push_back(
387 "typeof message_event.data === 'string'");
388 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(kTestString,
389 properties_to_check));
391 ASSERT_TRUE(AddEchoingListener("message_event.data"));
392 message_data_.clear();
393 instance_->PostMessage(pp::Var(kTestString));
394 // PostMessage is asynchronous, so we should not receive a response yet.
395 ASSERT_EQ(0, message_data_.size());
396 ASSERT_EQ(1, WaitForMessages());
397 ASSERT_TRUE(message_data_.back().is_string());
398 ASSERT_EQ(message_data_.back().AsString(), kTestString);
400 message_data_.clear();
401 ASSERT_TRUE(ClearListeners());
406 std::string TestPostMessage::TestSendingArrayBuffer() {
407 // Clean up after previous tests. This also swallows the message sent by Init
408 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
409 // should start with these.
411 ASSERT_TRUE(ClearListeners());
413 // TODO(sehr,dmichael): Add testing of longer array buffers when
414 // crbug.com/110086 is fixed.
415 ScopedArrayBufferSizeSetter setter(testing_interface_,
416 instance_->pp_instance(),
418 uint32_t sizes[] = { 0, 100, 1000, 10000 };
419 for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[i]); ++i) {
420 std::ostringstream size_stream;
421 size_stream << sizes[i];
422 const std::string kSizeAsString(size_stream.str());
424 // Create an appropriately sized array buffer with test_data[i] == i.
425 pp::VarArrayBuffer test_data(sizes[i]);
427 ASSERT_NE(NULL, test_data.Map());
428 // Make sure we can Unmap/Map successfully (there's not really any way to
429 // detect if it's unmapped, so we just re-map before getting the pointer to
433 ASSERT_EQ(sizes[i], test_data.ByteLength());
434 unsigned char* buff = static_cast<unsigned char*>(test_data.Map());
435 const uint32_t kByteLength = test_data.ByteLength();
436 for (size_t j = 0; j < kByteLength; ++j)
437 buff[j] = static_cast<uint8_t>(j % 256u);
439 // Have the listener test some properties of the ArrayBuffer.
440 std::vector<std::string> properties_to_check;
441 properties_to_check.push_back(
442 "message_event.data.constructor.name === 'ArrayBuffer'");
443 properties_to_check.push_back(
444 std::string("message_event.data.byteLength === ") + kSizeAsString);
446 properties_to_check.push_back(
447 "(new DataView(message_event.data)).getUint8(0) == 0");
448 // Checks that the last element has the right value: (byteLength-1)%256.
449 std::string received_byte("(new DataView(message_event.data)).getUint8("
450 " message_event.data.byteLength-1)");
451 std::string expected_byte("(message_event.data.byteLength-1)%256");
452 properties_to_check.push_back(received_byte + " == " + expected_byte);
454 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(test_data,
455 properties_to_check));
457 // Set up the JavaScript message event listener to echo the data part of the
458 // message event back to us.
459 ASSERT_TRUE(AddEchoingListener("message_event.data"));
460 message_data_.clear();
461 instance_->PostMessage(test_data);
462 // PostMessage is asynchronous, so we should not receive a response yet.
463 ASSERT_EQ(0, message_data_.size());
464 ASSERT_EQ(1, WaitForMessages());
465 ASSERT_TRUE(message_data_.back().is_array_buffer());
466 pp::VarArrayBuffer received(message_data_.back());
467 message_data_.clear();
468 ASSERT_EQ(test_data.ByteLength(), received.ByteLength());
469 unsigned char* received_buff = static_cast<unsigned char*>(received.Map());
470 // The buffer should be copied, so this should be a distinct buffer. When
471 // 'transferrables' are implemented for PPAPI, we'll also want to test that
472 // we get the _same_ buffer back when it's transferred.
474 ASSERT_NE(buff, received_buff);
475 for (size_t i = 0; i < test_data.ByteLength(); ++i)
476 ASSERT_EQ(buff[i], received_buff[i]);
478 message_data_.clear();
479 ASSERT_TRUE(ClearListeners());
485 std::string TestPostMessage::TestSendingArray() {
486 // Clean up after previous tests. This also swallows the message sent by Init
487 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
488 // should start with these.
490 ASSERT_TRUE(ClearListeners());
493 array.Set(0, pp::Var(kTestBool));
494 array.Set(1, pp::Var(kTestString));
495 // Purposely leave index 2 empty.
496 array.Set(3, pp::Var(kTestInt));
497 array.Set(4, pp::Var(kTestDouble));
499 std::stringstream ss;
500 ss << array.GetLength();
501 std::string length_as_string(ss.str());
503 // Have the listener test some properties of the Array.
504 std::vector<std::string> properties_to_check;
505 properties_to_check.push_back(
506 "message_event.data.constructor.name === 'Array'");
507 properties_to_check.push_back(
508 std::string("message_event.data.length === ") + length_as_string);
509 // Check that the string is converted to a primitive JS string.
510 properties_to_check.push_back(
511 std::string("typeof message_event.data[1] === 'string'"));
512 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(array, properties_to_check));
514 // Set up the JavaScript message event listener to echo the data part of the
515 // message event back to us.
516 ASSERT_TRUE(AddEchoingListener("message_event.data"));
517 message_data_.clear();
518 instance_->PostMessage(array);
519 // PostMessage is asynchronous, so we should not receive a response yet.
520 ASSERT_EQ(0, message_data_.size());
521 ASSERT_EQ(1, WaitForMessages());
522 ASSERT_TRUE(message_data_.back().is_array());
523 ASSERT_TRUE(VarsEqual(array, message_data_.back()));
525 message_data_.clear();
526 ASSERT_TRUE(ClearListeners());
531 std::string TestPostMessage::TestSendingDictionary() {
532 // Clean up after previous tests. This also swallows the message sent by Init
533 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
534 // should start with these.
536 ASSERT_TRUE(ClearListeners());
538 pp::VarDictionary dictionary;
539 dictionary.Set(pp::Var("foo"), pp::Var(kTestBool));
540 dictionary.Set(pp::Var("bar"), pp::Var(kTestString));
541 dictionary.Set(pp::Var("abc"), pp::Var(kTestInt));
542 dictionary.Set(pp::Var("def"), pp::Var());
544 std::stringstream ss;
545 ss << dictionary.GetKeys().GetLength();
546 std::string length_as_string(ss.str());
548 // Have the listener test some properties of the Dictionary.
549 std::vector<std::string> properties_to_check;
550 properties_to_check.push_back(
551 "message_event.data.constructor.name === 'Object'");
552 properties_to_check.push_back(
553 std::string("Object.keys(message_event.data).length === ") +
555 // Check that the string is converted to a primitive JS string.
556 properties_to_check.push_back(
557 std::string("typeof message_event.data['bar'] === 'string'"));
558 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(dictionary,
559 properties_to_check));
561 // Set up the JavaScript message event listener to echo the data part of the
562 // message event back to us.
563 ASSERT_TRUE(AddEchoingListener("message_event.data"));
564 message_data_.clear();
565 instance_->PostMessage(dictionary);
566 // PostMessage is asynchronous, so we should not receive a response yet.
567 ASSERT_EQ(0, message_data_.size());
568 ASSERT_EQ(1, WaitForMessages());
569 ASSERT_TRUE(message_data_.back().is_dictionary());
570 ASSERT_TRUE(VarsEqual(dictionary, message_data_.back()));
572 message_data_.clear();
573 ASSERT_TRUE(ClearListeners());
578 std::string TestPostMessage::TestSendingResource() {
579 // Clean up after previous tests. This also swallows the message sent by Init
580 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
581 // should start with these.
583 message_data_.clear();
584 ASSERT_TRUE(ClearListeners());
586 std::string file_path("/");
587 file_path += kTestFilename;
588 int content_length = strlen(kTestString);
590 // Create a file in the HTML5 temporary file system, in the Pepper plugin.
591 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
592 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
593 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
594 CHECK_CALLBACK_BEHAVIOR(callback);
595 ASSERT_EQ(PP_OK, callback.result());
596 pp::FileRef write_file_ref(file_system, file_path.c_str());
597 // Write to the file.
598 pp::FileIO write_file_io(instance_);
599 ASSERT_NE(0, write_file_io.pp_resource());
600 callback.WaitForResult(
601 write_file_io.Open(write_file_ref,
602 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE,
603 callback.GetCallback()));
604 CHECK_CALLBACK_BEHAVIOR(callback);
605 ASSERT_EQ(PP_OK, callback.result());
606 callback.WaitForResult(write_file_io.Write(
607 0, kTestString, content_length, callback.GetCallback()));
608 CHECK_CALLBACK_BEHAVIOR(callback);
609 ASSERT_EQ(callback.result(), content_length);
610 write_file_io.Close();
612 // Pass the file system to JavaScript and have the listener test some
613 // properties of the file system.
614 pp::Var file_system_var(file_system);
615 std::vector<std::string> properties_to_check;
616 properties_to_check.push_back(
617 "message_event.data.constructor.name === 'DOMFileSystem'");
618 properties_to_check.push_back(
619 "message_event.data.root.constructor.name === 'DirectoryEntry'");
620 properties_to_check.push_back(
621 "message_event.data.name.indexOf("
623 " message_event.data.name.length - ':Temporary'.length) !== -1");
624 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(file_system_var,
625 properties_to_check));
627 // Set up the JavaScript message event listener to echo the data part of the
628 // message event back to us.
629 ASSERT_TRUE(AddEchoingListener("message_event.data"));
630 // Send the file system in a message from the Pepper plugin to JavaScript.
631 message_data_.clear();
632 instance_->PostMessage(file_system_var);
633 // PostMessage is asynchronous, so we should not receive a response yet.
634 ASSERT_EQ(0, message_data_.size());
635 ASSERT_EQ(1, WaitForMessages());
637 // The JavaScript should have posted the file system back to us. Verify that
638 // it is a file system and read the file contents that we wrote earlier.
639 pp::Var var = message_data_.back();
640 ASSERT_TRUE(var.is_resource());
641 pp::Resource result = var.AsResource();
642 ASSERT_TRUE(pp::FileSystem::IsFileSystem(result));
644 pp::FileSystem received_file_system(result);
645 pp::FileRef file_ref(received_file_system, file_path.c_str());
646 ASSERT_NE(0, file_ref.pp_resource());
648 // Ensure that the file can be queried.
649 TestCompletionCallbackWithOutput<PP_FileInfo> cc(instance_->pp_instance(),
651 cc.WaitForResult(file_ref.Query(cc.GetCallback()));
652 CHECK_CALLBACK_BEHAVIOR(cc);
653 ASSERT_EQ(PP_OK, cc.result());
654 ASSERT_EQ(cc.output().size, content_length);
656 // Read the file and test that its contents match.
657 pp::FileIO file_io(instance_);
658 ASSERT_NE(0, file_io.pp_resource());
659 callback.WaitForResult(
660 file_io.Open(file_ref, PP_FILEOPENFLAG_READ, callback.GetCallback()));
661 CHECK_CALLBACK_BEHAVIOR(callback);
662 ASSERT_EQ(PP_OK, callback.result());
664 std::vector<char> buffer_vector(content_length);
665 char* buffer = &buffer_vector[0]; // Note: Not null-terminated!
666 callback.WaitForResult(
667 file_io.Read(0, buffer, content_length, callback.GetCallback()));
668 CHECK_CALLBACK_BEHAVIOR(callback);
669 ASSERT_EQ(callback.result(), content_length);
670 ASSERT_EQ(0, memcmp(buffer, kTestString, content_length));
674 message_data_.clear();
675 ASSERT_TRUE(ClearListeners());
680 std::string TestPostMessage::TestSendingComplexVar() {
681 // Clean up after previous tests. This also swallows the message sent by Init
682 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
683 // should start with these.
685 message_data_.clear();
686 ASSERT_TRUE(ClearListeners());
688 pp::Var string(kTestString);
689 pp::VarDictionary dictionary;
690 dictionary.Set(pp::Var("foo"), pp::Var(kTestBool));
691 dictionary.Set(pp::Var("bar"), string);
692 dictionary.Set(pp::Var("abc"), pp::Var(kTestInt));
693 dictionary.Set(pp::Var("def"), pp::Var());
695 // Reference to array.
697 array.Set(0, pp::Var(kTestBool));
698 array.Set(1, string);
699 // Purposely leave index 2 empty (which will place an undefined var there).
700 array.Set(3, pp::Var(kTestInt));
701 array.Set(4, pp::Var(kTestDouble));
703 dictionary.Set(pp::Var("array-ref1"), array);
704 dictionary.Set(pp::Var("array-ref2"), array);
706 // Set up the JavaScript message event listener to echo the data part of the
707 // message event back to us.
708 ASSERT_TRUE(AddEchoingListener("message_event.data"));
709 instance_->PostMessage(dictionary);
710 // PostMessage is asynchronous, so we should not receive a response yet.
711 ASSERT_EQ(0, message_data_.size());
712 ASSERT_EQ(1, WaitForMessages());
713 ASSERT_TRUE(message_data_.back().is_dictionary());
714 pp::VarDictionary result(message_data_.back());
715 ASSERT_TRUE(VarsEqual(dictionary, message_data_.back()));
718 message_data_.clear();
719 ASSERT_TRUE(ClearListeners());
721 // Set up a (dictionary -> array -> dictionary) cycle. Cycles shouldn't be
724 array2.Set(0, dictionary);
725 dictionary.Set(pp::Var("array2"), array2);
727 ASSERT_TRUE(AddEchoingListener("message_event.data"));
728 instance_->PostMessage(dictionary);
729 // PostMessage is asynchronous, so we should not receive a response yet.
730 ASSERT_EQ(0, message_data_.size());
731 ASSERT_EQ(WaitForMessages(), 0);
734 dictionary.Delete(pp::Var("array2"));
737 message_data_.clear();
738 ASSERT_TRUE(ClearListeners());
740 // Test sending a cycle from JavaScript to the plugin.
741 ASSERT_TRUE(AddEchoingListener("message_event.data"));
742 PostMessageFromJavaScript("function() { var x = []; x[0] = x; return x; }");
743 ASSERT_EQ(0, message_data_.size());
744 ASSERT_EQ(WaitForMessages(), 0);
747 message_data_.clear();
748 ASSERT_TRUE(ClearListeners());
753 std::string TestPostMessage::TestMessageEvent() {
754 // Set up the JavaScript message event listener to pass us some values from
755 // the MessageEvent and make sure they match our expectations.
758 ASSERT_TRUE(ClearListeners());
759 // Have the listener pass back the class name of message_event and make sure
760 // it's "MessageEvent".
761 ASSERT_TRUE(AddEchoingListener("message_event.constructor.name"));
762 message_data_.clear();
763 instance_->PostMessage(pp::Var(kTestInt));
764 ASSERT_EQ(0, message_data_.size());
765 ASSERT_EQ(1, WaitForMessages());
766 ASSERT_TRUE(message_data_.back().is_string());
767 ASSERT_EQ(message_data_.back().AsString(), "MessageEvent");
768 ASSERT_TRUE(ClearListeners());
770 // Make sure all the non-data properties have the expected values.
771 bool success = AddEchoingListener("((message_event.origin === '')"
772 " && (message_event.lastEventId === '')"
773 " && (message_event.source === null)"
774 " && (message_event.ports.length === 0)"
775 " && (message_event.bubbles === false)"
776 " && (message_event.cancelable === false)"
778 ASSERT_TRUE(success);
779 message_data_.clear();
780 instance_->PostMessage(pp::Var(kTestInt));
781 ASSERT_EQ(0, message_data_.size());
782 ASSERT_EQ(1, WaitForMessages());
783 ASSERT_TRUE(message_data_.back().is_bool());
784 ASSERT_TRUE(message_data_.back().AsBool());
785 ASSERT_TRUE(ClearListeners());
787 // Add some event handlers to make sure they receive messages.
788 ASSERT_TRUE(AddEchoingListener("1"));
789 ASSERT_TRUE(AddEchoingListener("2"));
790 ASSERT_TRUE(AddEchoingListener("3"));
792 message_data_.clear();
793 instance_->PostMessage(pp::Var(kTestInt));
794 // Make sure we don't get a response in a re-entrant fashion.
795 ASSERT_EQ(0, message_data_.size());
796 // We should get 3 messages.
797 ASSERT_EQ(WaitForMessages(), 3);
798 // Copy to a vector of doubles and sort; w3c does not specify the order for
799 // event listeners. (Copying is easier than writing an operator< for pp::Var.)
801 // See http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html.
802 VarVector::iterator iter(message_data_.begin()), the_end(message_data_.end());
803 std::vector<double> double_vec;
804 for (; iter != the_end; ++iter) {
805 ASSERT_TRUE(iter->is_number());
806 double_vec.push_back(iter->AsDouble());
808 std::sort(double_vec.begin(), double_vec.end());
809 ASSERT_DOUBLE_EQ(double_vec[0], 1.0);
810 ASSERT_DOUBLE_EQ(double_vec[1], 2.0);
811 ASSERT_DOUBLE_EQ(double_vec[2], 3.0);
813 message_data_.clear();
814 ASSERT_TRUE(ClearListeners());
819 std::string TestPostMessage::TestNoHandler() {
820 // Delete any lingering messages and event listeners.
822 ASSERT_TRUE(ClearListeners());
824 // Now send a message. We shouldn't get a response.
825 message_data_.clear();
826 instance_->PostMessage(pp::Var());
827 ASSERT_EQ(WaitForMessages(), 0);
828 ASSERT_TRUE(message_data_.empty());
833 std::string TestPostMessage::TestExtraParam() {
834 // Delete any lingering messages and event listeners.
836 ASSERT_TRUE(ClearListeners());
837 // Add a listener that will respond with 1 and an empty array (where the
838 // message port array would appear if it was Worker postMessage).
839 ASSERT_TRUE(AddEchoingListener("1, []"));
841 // Now send a message. We shouldn't get a response.
842 message_data_.clear();
843 instance_->PostMessage(pp::Var());
844 ASSERT_EQ(WaitForMessages(), 0);
845 ASSERT_TRUE(message_data_.empty());
847 ASSERT_TRUE(ClearListeners());
852 std::string TestPostMessage::TestNonMainThread() {
854 ASSERT_TRUE(ClearListeners());
855 ASSERT_TRUE(AddEchoingListener("message_event.data"));
856 message_data_.clear();
858 // Set up a thread for each integer from 0 to (kThreadsToRun - 1). Make each
859 // thread send the number that matches its index kMessagesToSendPerThread
860 // times. For good measure, call postMessage from the main thread
861 // kMessagesToSendPerThread times. At the end, we make sure we got all the
862 // values we expected.
863 PP_ThreadType threads[kThreadsToRun];
864 for (int32_t i = 0; i < kThreadsToRun; ++i) {
865 // Set up a thread to send a value of i.
866 void* arg = new InvokePostMessageThreadArg(instance_, pp::Var(i));
867 PP_CreateThread(&threads[i], &InvokePostMessageThreadFunc, arg);
869 // Invoke PostMessage right now to send a value of (kThreadsToRun).
870 for (int32_t i = 0; i < kMessagesToSendPerThread; ++i)
871 instance_->PostMessage(pp::Var(kThreadsToRun));
873 // Now join all threads.
874 for (int32_t i = 0; i < kThreadsToRun; ++i)
875 PP_JoinThread(threads[i]);
877 // PostMessage is asynchronous, so we should not receive a response yet.
878 ASSERT_EQ(0, message_data_.size());
880 // Make sure we got all values that we expected. Note that because it's legal
881 // for the JavaScript engine to treat our integers as floating points, we
882 // can't just use std::find or equality comparison. So we instead, we convert
883 // each incoming value to an integer, and count them in received_counts.
884 int32_t expected_num = (kThreadsToRun + 1) * kMessagesToSendPerThread;
885 // Count how many we receive per-index.
886 std::vector<int32_t> expected_counts(kThreadsToRun + 1,
887 kMessagesToSendPerThread);
888 std::vector<int32_t> received_counts(kThreadsToRun + 1, 0);
889 ASSERT_EQ(expected_num, WaitForMessages());
890 for (int32_t i = 0; i < expected_num; ++i) {
891 const pp::Var& latest_var(message_data_[i]);
892 ASSERT_TRUE(latest_var.is_int() || latest_var.is_double());
893 int32_t received_value = -1;
894 if (latest_var.is_int()) {
895 received_value = latest_var.AsInt();
896 } else if (latest_var.is_double()) {
897 received_value = static_cast<int32_t>(latest_var.AsDouble() + 0.5);
899 ASSERT_TRUE(received_value >= 0);
900 ASSERT_TRUE(received_value <= kThreadsToRun);
901 ++received_counts[received_value];
903 ASSERT_EQ(expected_counts, received_counts);
905 message_data_.clear();
906 ASSERT_TRUE(ClearListeners());