• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string.h>
8 #include <algorithm>
9 #include <map>
10 #include <sstream>
11 
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"
25 
26 // Windows defines 'PostMessage', so we have to undef it.
27 #ifdef PostMessage
28 #undef PostMessage
29 #endif
30 
31 REGISTER_TEST_CASE(PostMessage);
32 
33 namespace {
34 
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;
40 
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.
43 #ifdef PPAPI_OS_WIN
44 const int32_t kThreadsToRun = 2;
45 const int32_t kMessagesToSendPerThread = 5;
46 #else
47 const int32_t kThreadsToRun = 4;
48 const int32_t kMessagesToSendPerThread = 10;
49 #endif
50 
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 {
InvokePostMessageThreadArg__anonbfd0c7aa0111::InvokePostMessageThreadArg55   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;
59 };
60 
InvokePostMessageThreadFunc(void * user_data)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);
66   delete arg;
67 }
68 
69 // TODO(raymes): Consider putting something like this into pp::Var.
VarsEqual(const pp::Var & expected,const pp::Var & actual,std::map<int64_t,int64_t> * visited_ids)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())
75       return false;
76   }
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)
83         return true;
84       return false;
85     }
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;
92     }
93   }
94 
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())
101       return false;
102     for (uint32_t i = 0; i < expected_array.GetLength(); ++i) {
103       if (!VarsEqual(expected_array.Get(i), actual_array.Get(i), visited_ids))
104         return false;
105     }
106     return true;
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()) {
112       return false;
113     }
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))
117         return false;
118       if (!VarsEqual(expected_dict.Get(key), actual_dict.Get(key), visited_ids))
119         return false;
120     }
121     return true;
122   } else {
123     return expected == actual;
124   }
125 }
126 
VarsEqual(const pp::Var & expected,const pp::Var & 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);
131 }
132 
133 class ScopedArrayBufferSizeSetter {
134  public:
ScopedArrayBufferSizeSetter(const PPB_Testing_Private * interface,PP_Instance instance,uint32_t threshold)135   ScopedArrayBufferSizeSetter(const PPB_Testing_Private* interface,
136                               PP_Instance instance,
137                               uint32_t threshold)
138      : interface_(interface),
139        instance_(instance) {
140     interface_->SetMinimumArrayBufferSizeForShmem(instance_, threshold);
141   }
~ScopedArrayBufferSizeSetter()142   ~ScopedArrayBufferSizeSetter() {
143     interface_->SetMinimumArrayBufferSizeForShmem(instance_, 0);
144   }
145  private:
146   const PPB_Testing_Private* interface_;
147   PP_Instance instance_;
148 };
149 
150 #define FINISHED_WAITING_MESSAGE "TEST_POST_MESSAGE_FINISHED_WAITING"
151 
152 }  // namespace
153 
TestPostMessage(TestingInstance * instance)154 TestPostMessage::TestPostMessage(TestingInstance* instance)
155     : TestCase(instance) {
156 }
157 
~TestPostMessage()158 TestPostMessage::~TestPostMessage() {
159   instance_->PostMessage(pp::Var("This isn't guaranteed to be received, but "
160                                  "shouldn't cause a crash."));
161 
162   // Remove the special listener that only responds to a FINISHED_WAITING
163   // string. See Init for where it gets added.
164   std::string js_code;
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);
170 }
171 
Init()172 bool TestPostMessage::Init() {
173   bool success = CheckTestingInterface();
174 
175   // Add a post condition to tests which caches the postMessage function and
176   // then calls it after the instance is destroyed. The ensures that no UAF
177   // occurs because the MessageChannel may still be alive after the plugin
178   // instance is destroyed (it will get garbage collected eventually).
179   instance_->EvalScript("window.pluginPostMessage = "
180                         "document.getElementById('plugin').postMessage");
181   instance_->AddPostCondition("window.pluginPostMessage('') === undefined");
182 
183   // Set up a special listener that only responds to a FINISHED_WAITING string.
184   // This is for use by WaitForMessages.
185   std::string js_code;
186   // Note the following code is dependent on some features of test_case.html.
187   // E.g., it is assumed that the DOM element where the plugin is embedded has
188   // an id of 'plugin', and there is a function 'IsTestingMessage' that allows
189   // us to ignore the messages that are intended for use by the testing
190   // framework itself.
191   js_code += "var plugin = document.getElementById('plugin');"
192              "var wait_for_messages_handler = function(message_event) {"
193              "  if (!IsTestingMessage(message_event.data) &&"
194              "      message_event.data === '" FINISHED_WAITING_MESSAGE "') {"
195              "    plugin.postMessage('" FINISHED_WAITING_MESSAGE "');"
196              "  }"
197              "};"
198              "plugin.addEventListener('message', wait_for_messages_handler);"
199              // Stash it on the plugin so we can remove it in the destructor.
200              "plugin.wait_for_messages_handler = wait_for_messages_handler;";
201   instance_->EvalScript(js_code);
202 
203   // Set up the JavaScript message event listener to echo the data part of the
204   // message event back to us.
205   success = success && AddEchoingListener("message_event.data");
206   message_data_.clear();
207   // Send a message that the first test will expect to receive. This is to
208   // verify that we can send messages when the 'Instance::Init' function is on
209   // the stack.
210   instance_->PostMessage(pp::Var(kTestString));
211 
212   return success;
213 }
214 
RunTests(const std::string & filter)215 void TestPostMessage::RunTests(const std::string& filter) {
216   // Note: SendInInit must be first, because it expects to receive a message
217   // that was sent in Init above.
218   RUN_TEST(SendInInit, filter);
219   RUN_TEST(SendingData, filter);
220   RUN_TEST(SendingString, filter);
221   RUN_TEST(SendingArrayBuffer, filter);
222   RUN_TEST(SendingArray, filter);
223   RUN_TEST(SendingDictionary, filter);
224   RUN_TEST(SendingResource, filter);
225   RUN_TEST(SendingComplexVar, filter);
226   RUN_TEST(MessageEvent, filter);
227   RUN_TEST(NoHandler, filter);
228   RUN_TEST(ExtraParam, filter);
229   if (testing_interface_->IsOutOfProcess())
230     RUN_TEST(NonMainThread, filter);
231 }
232 
HandleMessage(const pp::Var & message_data)233 void TestPostMessage::HandleMessage(const pp::Var& message_data) {
234   if (message_data.is_string() &&
235       (message_data.AsString() == FINISHED_WAITING_MESSAGE))
236     testing_interface_->QuitMessageLoop(instance_->pp_instance());
237   else
238     message_data_.push_back(message_data);
239 }
240 
AddEchoingListener(const std::string & expression)241 bool TestPostMessage::AddEchoingListener(const std::string& expression) {
242   std::string js_code;
243   // Note the following code is dependent on some features of test_case.html.
244   // E.g., it is assumed that the DOM element where the plugin is embedded has
245   // an id of 'plugin', and there is a function 'IsTestingMessage' that allows
246   // us to ignore the messages that are intended for use by the testing
247   // framework itself.
248   js_code += "var plugin = document.getElementById('plugin');"
249              "var message_handler = function(message_event) {"
250              "  if (!IsTestingMessage(message_event.data) &&"
251              "      !(message_event.data === '" FINISHED_WAITING_MESSAGE "')) {"
252              "    plugin.postMessage(";
253   js_code += expression;
254   js_code += "                      );"
255              "  }"
256              "};"
257              "plugin.addEventListener('message', message_handler);"
258              // Maintain an array of all event listeners, attached to the
259              // plugin. This is so that we can easily remove them later (see
260              // ClearListeners()).
261              "if (!plugin.eventListeners) plugin.eventListeners = [];"
262              "plugin.eventListeners.push(message_handler);";
263   instance_->EvalScript(js_code);
264   return true;
265 }
266 
PostMessageFromJavaScript(const std::string & func)267 bool TestPostMessage::PostMessageFromJavaScript(const std::string& func) {
268   std::string js_code;
269   js_code += "var plugin = document.getElementById('plugin');"
270              "plugin.postMessage(";
271   js_code += func + "()";
272   js_code += "                      );";
273   instance_->EvalScript(js_code);
274   return true;
275 }
276 
ClearListeners()277 bool TestPostMessage::ClearListeners() {
278   std::string js_code;
279   js_code += "var plugin = document.getElementById('plugin');"
280              "while (plugin.eventListeners.length) {"
281              "  plugin.removeEventListener('message',"
282              "                             plugin.eventListeners.pop());"
283              "}";
284   instance_->EvalScript(js_code);
285   return true;
286 }
287 
WaitForMessages()288 int TestPostMessage::WaitForMessages() {
289   size_t message_size_before = message_data_.size();
290   // We first post a FINISHED_WAITING_MESSAGE. This should be guaranteed to
291   // come back _after_ any other incoming messages that were already pending.
292   instance_->PostMessage(pp::Var(FINISHED_WAITING_MESSAGE));
293   testing_interface_->RunMessageLoop(instance_->pp_instance());
294   // Now that the FINISHED_WAITING_MESSAGE has been echoed back to us, we know
295   // that all pending messages have been slurped up. Return the number we
296   // received (which may be zero).
297   return message_data_.size() - message_size_before;
298 }
299 
CheckMessageProperties(const pp::Var & test_data,const std::vector<std::string> & properties_to_check)300 std::string TestPostMessage::CheckMessageProperties(
301     const pp::Var& test_data,
302     const std::vector<std::string>& properties_to_check) {
303   typedef std::vector<std::string>::const_iterator Iterator;
304   for (Iterator iter = properties_to_check.begin();
305        iter != properties_to_check.end();
306        ++iter) {
307     ASSERT_TRUE(AddEchoingListener(*iter));
308     message_data_.clear();
309     instance_->PostMessage(test_data);
310     ASSERT_EQ(0, message_data_.size());
311     ASSERT_EQ(1, WaitForMessages());
312     ASSERT_TRUE(message_data_.back().is_bool());
313     if (!message_data_.back().AsBool())
314       return std::string("Failed: ") + *iter;
315     ASSERT_TRUE(message_data_.back().AsBool());
316     ASSERT_TRUE(ClearListeners());
317   }
318   PASS();
319 }
320 
TestSendInInit()321 std::string TestPostMessage::TestSendInInit() {
322   // Wait for the messages from Init() to be guaranteed to be sent.
323   WaitForMessages();
324   // This test assumes Init already sent a message.
325   ASSERT_EQ(1, message_data_.size());
326   ASSERT_TRUE(message_data_.back().is_string());
327   ASSERT_EQ(kTestString, message_data_.back().AsString());
328   message_data_.clear();
329   PASS();
330 }
331 
TestSendingData()332 std::string TestPostMessage::TestSendingData() {
333   // Clean up after previous tests. This also swallows the message sent by Init
334   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
335   // should start with these.
336   WaitForMessages();
337   ASSERT_TRUE(ClearListeners());
338 
339   // Set up the JavaScript message event listener to echo the data part of the
340   // message event back to us.
341   ASSERT_TRUE(AddEchoingListener("message_event.data"));
342 
343   // Test sending a message to JavaScript for each supported type. The JS sends
344   // the data back to us, and we check that they match.
345   message_data_.clear();
346   instance_->PostMessage(pp::Var(kTestBool));
347   ASSERT_EQ(0, message_data_.size());
348   ASSERT_EQ(1, WaitForMessages());
349   ASSERT_TRUE(message_data_.back().is_bool());
350   ASSERT_EQ(message_data_.back().AsBool(), kTestBool);
351 
352   message_data_.clear();
353   instance_->PostMessage(pp::Var(kTestInt));
354   ASSERT_EQ(0, message_data_.size());
355   ASSERT_EQ(1, WaitForMessages());
356   ASSERT_TRUE(message_data_.back().is_number());
357   ASSERT_DOUBLE_EQ(static_cast<double>(kTestInt),
358                    message_data_.back().AsDouble());
359 
360   message_data_.clear();
361   instance_->PostMessage(pp::Var(kTestDouble));
362   ASSERT_EQ(0, message_data_.size());
363   ASSERT_EQ(1, WaitForMessages());
364   ASSERT_TRUE(message_data_.back().is_number());
365   ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(), kTestDouble);
366 
367   message_data_.clear();
368   instance_->PostMessage(pp::Var());
369   ASSERT_EQ(0, message_data_.size());
370   ASSERT_EQ(1, WaitForMessages());
371   ASSERT_TRUE(message_data_.back().is_undefined());
372 
373   message_data_.clear();
374   instance_->PostMessage(pp::Var(pp::Var::Null()));
375   ASSERT_EQ(0, message_data_.size());
376   ASSERT_EQ(1, WaitForMessages());
377   ASSERT_TRUE(message_data_.back().is_null());
378 
379   message_data_.clear();
380   ASSERT_TRUE(ClearListeners());
381 
382   PASS();
383 }
384 
TestSendingString()385 std::string TestPostMessage::TestSendingString() {
386   // Clean up after previous tests. This also swallows the message sent by Init
387   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
388   // should start with these.
389   WaitForMessages();
390   ASSERT_TRUE(ClearListeners());
391 
392   // Test that a string var is converted to a primitive JS string.
393   message_data_.clear();
394   std::vector<std::string> properties_to_check;
395   properties_to_check.push_back(
396       "typeof message_event.data === 'string'");
397   ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(kTestString,
398                                                 properties_to_check));
399 
400   ASSERT_TRUE(AddEchoingListener("message_event.data"));
401   message_data_.clear();
402   instance_->PostMessage(pp::Var(kTestString));
403   // PostMessage is asynchronous, so we should not receive a response yet.
404   ASSERT_EQ(0, message_data_.size());
405   ASSERT_EQ(1, WaitForMessages());
406   ASSERT_TRUE(message_data_.back().is_string());
407   ASSERT_EQ(message_data_.back().AsString(), kTestString);
408 
409   message_data_.clear();
410   ASSERT_TRUE(ClearListeners());
411 
412   PASS();
413 }
414 
TestSendingArrayBuffer()415 std::string TestPostMessage::TestSendingArrayBuffer() {
416   // Clean up after previous tests. This also swallows the message sent by Init
417   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
418   // should start with these.
419   WaitForMessages();
420   ASSERT_TRUE(ClearListeners());
421 
422   // TODO(sehr,dmichael): Add testing of longer array buffers when
423   // crbug.com/110086 is fixed.
424   ScopedArrayBufferSizeSetter setter(testing_interface_,
425                                      instance_->pp_instance(),
426                                      200);
427   uint32_t sizes[] = { 0, 100, 1000, 10000 };
428   for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[i]); ++i) {
429     std::ostringstream size_stream;
430     size_stream << sizes[i];
431     const std::string kSizeAsString(size_stream.str());
432 
433     // Create an appropriately sized array buffer with test_data[i] == i.
434     pp::VarArrayBuffer test_data(sizes[i]);
435     if (sizes[i] > 0)
436       ASSERT_NE(NULL, test_data.Map());
437     // Make sure we can Unmap/Map successfully (there's not really any way to
438     // detect if it's unmapped, so we just re-map before getting the pointer to
439     // the buffer).
440     test_data.Unmap();
441     test_data.Map();
442     ASSERT_EQ(sizes[i], test_data.ByteLength());
443     unsigned char* buff = static_cast<unsigned char*>(test_data.Map());
444     const uint32_t kByteLength = test_data.ByteLength();
445     for (size_t j = 0; j < kByteLength; ++j)
446       buff[j] = static_cast<uint8_t>(j % 256u);
447 
448     // Have the listener test some properties of the ArrayBuffer.
449     std::vector<std::string> properties_to_check;
450     properties_to_check.push_back(
451         "message_event.data.constructor.name === 'ArrayBuffer'");
452     properties_to_check.push_back(
453         std::string("message_event.data.byteLength === ") + kSizeAsString);
454     if (sizes[i] > 0) {
455       properties_to_check.push_back(
456           "(new DataView(message_event.data)).getUint8(0) == 0");
457       // Checks that the last element has the right value: (byteLength-1)%256.
458       std::string received_byte("(new DataView(message_event.data)).getUint8("
459                                 "    message_event.data.byteLength-1)");
460       std::string expected_byte("(message_event.data.byteLength-1)%256");
461       properties_to_check.push_back(received_byte + " == " + expected_byte);
462     }
463     ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(test_data,
464                                                   properties_to_check));
465 
466     // Set up the JavaScript message event listener to echo the data part of the
467     // message event back to us.
468     ASSERT_TRUE(AddEchoingListener("message_event.data"));
469     message_data_.clear();
470     instance_->PostMessage(test_data);
471     // PostMessage is asynchronous, so we should not receive a response yet.
472     ASSERT_EQ(0, message_data_.size());
473     ASSERT_EQ(1, WaitForMessages());
474     ASSERT_TRUE(message_data_.back().is_array_buffer());
475     pp::VarArrayBuffer received(message_data_.back());
476     message_data_.clear();
477     ASSERT_EQ(test_data.ByteLength(), received.ByteLength());
478     unsigned char* received_buff = static_cast<unsigned char*>(received.Map());
479     // The buffer should be copied, so this should be a distinct buffer. When
480     // 'transferrables' are implemented for PPAPI, we'll also want to test that
481     // we get the _same_ buffer back when it's transferred.
482     if (sizes[i] > 0)
483       ASSERT_NE(buff, received_buff);
484     for (size_t i = 0; i < test_data.ByteLength(); ++i)
485       ASSERT_EQ(buff[i], received_buff[i]);
486 
487     message_data_.clear();
488     ASSERT_TRUE(ClearListeners());
489   }
490 
491   PASS();
492 }
493 
TestSendingArray()494 std::string TestPostMessage::TestSendingArray() {
495   // Clean up after previous tests. This also swallows the message sent by Init
496   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
497   // should start with these.
498   WaitForMessages();
499   ASSERT_TRUE(ClearListeners());
500 
501   pp::VarArray array;
502   array.Set(0, pp::Var(kTestBool));
503   array.Set(1, pp::Var(kTestString));
504   // Purposely leave index 2 empty.
505   array.Set(3, pp::Var(kTestInt));
506   array.Set(4, pp::Var(kTestDouble));
507 
508   std::stringstream ss;
509   ss << array.GetLength();
510   std::string length_as_string(ss.str());
511 
512   // Have the listener test some properties of the Array.
513   std::vector<std::string> properties_to_check;
514   properties_to_check.push_back(
515       "message_event.data.constructor.name === 'Array'");
516   properties_to_check.push_back(
517       std::string("message_event.data.length === ") + length_as_string);
518   // Check that the string is converted to a primitive JS string.
519   properties_to_check.push_back(
520       std::string("typeof message_event.data[1] === 'string'"));
521   ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(array, properties_to_check));
522 
523   // Set up the JavaScript message event listener to echo the data part of the
524   // message event back to us.
525   ASSERT_TRUE(AddEchoingListener("message_event.data"));
526   message_data_.clear();
527   instance_->PostMessage(array);
528   // PostMessage is asynchronous, so we should not receive a response yet.
529   ASSERT_EQ(0, message_data_.size());
530   ASSERT_EQ(1, WaitForMessages());
531   ASSERT_TRUE(message_data_.back().is_array());
532   ASSERT_TRUE(VarsEqual(array, message_data_.back()));
533 
534   message_data_.clear();
535   ASSERT_TRUE(ClearListeners());
536 
537   PASS();
538 }
539 
TestSendingDictionary()540 std::string TestPostMessage::TestSendingDictionary() {
541   // Clean up after previous tests. This also swallows the message sent by Init
542   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
543   // should start with these.
544   WaitForMessages();
545   ASSERT_TRUE(ClearListeners());
546 
547   pp::VarDictionary dictionary;
548   dictionary.Set(pp::Var("foo"), pp::Var(kTestBool));
549   dictionary.Set(pp::Var("bar"), pp::Var(kTestString));
550   dictionary.Set(pp::Var("abc"), pp::Var(kTestInt));
551   dictionary.Set(pp::Var("def"), pp::Var());
552 
553   std::stringstream ss;
554   ss << dictionary.GetKeys().GetLength();
555   std::string length_as_string(ss.str());
556 
557   // Have the listener test some properties of the Dictionary.
558   std::vector<std::string> properties_to_check;
559   properties_to_check.push_back(
560       "message_event.data.constructor.name === 'Object'");
561   properties_to_check.push_back(
562       std::string("Object.keys(message_event.data).length === ") +
563       length_as_string);
564   // Check that the string is converted to a primitive JS string.
565   properties_to_check.push_back(
566       std::string("typeof message_event.data['bar'] === 'string'"));
567   ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(dictionary,
568                                                 properties_to_check));
569 
570   // Set up the JavaScript message event listener to echo the data part of the
571   // message event back to us.
572   ASSERT_TRUE(AddEchoingListener("message_event.data"));
573   message_data_.clear();
574   instance_->PostMessage(dictionary);
575   // PostMessage is asynchronous, so we should not receive a response yet.
576   ASSERT_EQ(0, message_data_.size());
577   ASSERT_EQ(1, WaitForMessages());
578   ASSERT_TRUE(message_data_.back().is_dictionary());
579   ASSERT_TRUE(VarsEqual(dictionary, message_data_.back()));
580 
581   message_data_.clear();
582   ASSERT_TRUE(ClearListeners());
583 
584   PASS();
585 }
586 
TestSendingResource()587 std::string TestPostMessage::TestSendingResource() {
588   // Clean up after previous tests. This also swallows the message sent by Init
589   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
590   // should start with these.
591   WaitForMessages();
592   message_data_.clear();
593   ASSERT_TRUE(ClearListeners());
594 
595   std::string file_path("/");
596   file_path += kTestFilename;
597   int content_length = strlen(kTestString);
598 
599   // Create a file in the HTML5 temporary file system, in the Pepper plugin.
600   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
601   pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
602   callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
603   CHECK_CALLBACK_BEHAVIOR(callback);
604   ASSERT_EQ(PP_OK, callback.result());
605   pp::FileRef write_file_ref(file_system, file_path.c_str());
606   // Write to the file.
607   pp::FileIO write_file_io(instance_);
608   ASSERT_NE(0, write_file_io.pp_resource());
609   callback.WaitForResult(
610       write_file_io.Open(write_file_ref,
611                          PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE,
612                          callback.GetCallback()));
613   CHECK_CALLBACK_BEHAVIOR(callback);
614   ASSERT_EQ(PP_OK, callback.result());
615   callback.WaitForResult(write_file_io.Write(
616       0, kTestString, content_length, callback.GetCallback()));
617   CHECK_CALLBACK_BEHAVIOR(callback);
618   ASSERT_EQ(callback.result(), content_length);
619   write_file_io.Close();
620 
621   // Pass the file system to JavaScript and have the listener test some
622   // properties of the file system.
623   pp::Var file_system_var(file_system);
624   std::vector<std::string> properties_to_check;
625   properties_to_check.push_back(
626       "message_event.data.constructor.name === 'DOMFileSystem'");
627   properties_to_check.push_back(
628       "message_event.data.root.constructor.name === 'DirectoryEntry'");
629   properties_to_check.push_back(
630       "message_event.data.name.indexOf("
631       "    ':Temporary',"
632       "    message_event.data.name.length - ':Temporary'.length) !== -1");
633   ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(file_system_var,
634                                                 properties_to_check));
635 
636   // Set up the JavaScript message event listener to echo the data part of the
637   // message event back to us.
638   ASSERT_TRUE(AddEchoingListener("message_event.data"));
639   // Send the file system in a message from the Pepper plugin to JavaScript.
640   message_data_.clear();
641   instance_->PostMessage(file_system_var);
642   // PostMessage is asynchronous, so we should not receive a response yet.
643   ASSERT_EQ(0, message_data_.size());
644   ASSERT_EQ(1, WaitForMessages());
645 
646   // The JavaScript should have posted the file system back to us. Verify that
647   // it is a file system and read the file contents that we wrote earlier.
648   pp::Var var = message_data_.back();
649   ASSERT_TRUE(var.is_resource());
650   pp::Resource result = var.AsResource();
651   ASSERT_TRUE(pp::FileSystem::IsFileSystem(result));
652   {
653     pp::FileSystem received_file_system(result);
654     pp::FileRef file_ref(received_file_system, file_path.c_str());
655     ASSERT_NE(0, file_ref.pp_resource());
656 
657     // Ensure that the file can be queried.
658     TestCompletionCallbackWithOutput<PP_FileInfo> cc(instance_->pp_instance(),
659                                                      callback_type());
660     cc.WaitForResult(file_ref.Query(cc.GetCallback()));
661     CHECK_CALLBACK_BEHAVIOR(cc);
662     ASSERT_EQ(PP_OK, cc.result());
663     ASSERT_EQ(cc.output().size, content_length);
664 
665     // Read the file and test that its contents match.
666     pp::FileIO file_io(instance_);
667     ASSERT_NE(0, file_io.pp_resource());
668     callback.WaitForResult(
669         file_io.Open(file_ref, PP_FILEOPENFLAG_READ, callback.GetCallback()));
670     CHECK_CALLBACK_BEHAVIOR(callback);
671     ASSERT_EQ(PP_OK, callback.result());
672 
673     std::vector<char> buffer_vector(content_length);
674     char* buffer = &buffer_vector[0];  // Note: Not null-terminated!
675     callback.WaitForResult(
676         file_io.Read(0, buffer, content_length, callback.GetCallback()));
677     CHECK_CALLBACK_BEHAVIOR(callback);
678     ASSERT_EQ(callback.result(), content_length);
679     ASSERT_EQ(0, memcmp(buffer, kTestString, content_length));
680   }
681 
682   WaitForMessages();
683   message_data_.clear();
684   ASSERT_TRUE(ClearListeners());
685 
686   PASS();
687 }
688 
TestSendingComplexVar()689 std::string TestPostMessage::TestSendingComplexVar() {
690   // Clean up after previous tests. This also swallows the message sent by Init
691   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
692   // should start with these.
693   WaitForMessages();
694   message_data_.clear();
695   ASSERT_TRUE(ClearListeners());
696 
697   pp::Var string(kTestString);
698   pp::VarDictionary dictionary;
699   dictionary.Set(pp::Var("foo"), pp::Var(kTestBool));
700   dictionary.Set(pp::Var("bar"), string);
701   dictionary.Set(pp::Var("abc"), pp::Var(kTestInt));
702   dictionary.Set(pp::Var("def"), pp::Var());
703 
704   // Reference to array.
705   pp::VarArray array;
706   array.Set(0, pp::Var(kTestBool));
707   array.Set(1, string);
708   // Purposely leave index 2 empty (which will place an undefined var there).
709   array.Set(3, pp::Var(kTestInt));
710   array.Set(4, pp::Var(kTestDouble));
711 
712   dictionary.Set(pp::Var("array-ref1"), array);
713   dictionary.Set(pp::Var("array-ref2"), array);
714 
715   // Set up the JavaScript message event listener to echo the data part of the
716   // message event back to us.
717   ASSERT_TRUE(AddEchoingListener("message_event.data"));
718   instance_->PostMessage(dictionary);
719   // PostMessage is asynchronous, so we should not receive a response yet.
720   ASSERT_EQ(0, message_data_.size());
721   ASSERT_EQ(1, WaitForMessages());
722   ASSERT_TRUE(message_data_.back().is_dictionary());
723   pp::VarDictionary result(message_data_.back());
724   ASSERT_TRUE(VarsEqual(dictionary, message_data_.back()));
725 
726   WaitForMessages();
727   message_data_.clear();
728   ASSERT_TRUE(ClearListeners());
729 
730   // Set up a (dictionary -> array -> dictionary) cycle. Cycles shouldn't be
731   // transmitted.
732   pp::VarArray array2;
733   array2.Set(0, dictionary);
734   dictionary.Set(pp::Var("array2"), array2);
735 
736   ASSERT_TRUE(AddEchoingListener("message_event.data"));
737   instance_->PostMessage(dictionary);
738   // PostMessage is asynchronous, so we should not receive a response yet.
739   ASSERT_EQ(0, message_data_.size());
740   ASSERT_EQ(WaitForMessages(), 0);
741 
742   // Break the cycles.
743   dictionary.Delete(pp::Var("array2"));
744 
745   WaitForMessages();
746   message_data_.clear();
747   ASSERT_TRUE(ClearListeners());
748 
749   // Test sending a cycle from JavaScript to the plugin.
750   ASSERT_TRUE(AddEchoingListener("message_event.data"));
751   PostMessageFromJavaScript("function() { var x = []; x[0] = x; return x; }");
752   ASSERT_EQ(0, message_data_.size());
753   ASSERT_EQ(WaitForMessages(), 0);
754 
755   WaitForMessages();
756   message_data_.clear();
757   ASSERT_TRUE(ClearListeners());
758 
759   PASS();
760 }
761 
TestMessageEvent()762 std::string TestPostMessage::TestMessageEvent() {
763   // Set up the JavaScript message event listener to pass us some values from
764   // the MessageEvent and make sure they match our expectations.
765 
766   WaitForMessages();
767   ASSERT_TRUE(ClearListeners());
768   // Have the listener pass back the class name of message_event and make sure
769   // it's "MessageEvent".
770   ASSERT_TRUE(AddEchoingListener("message_event.constructor.name"));
771   message_data_.clear();
772   instance_->PostMessage(pp::Var(kTestInt));
773   ASSERT_EQ(0, message_data_.size());
774   ASSERT_EQ(1, WaitForMessages());
775   ASSERT_TRUE(message_data_.back().is_string());
776   ASSERT_EQ(message_data_.back().AsString(), "MessageEvent");
777   ASSERT_TRUE(ClearListeners());
778 
779   // Make sure all the non-data properties have the expected values.
780   bool success = AddEchoingListener("((message_event.origin === '')"
781                                    " && (message_event.lastEventId === '')"
782                                    " && (message_event.source === null)"
783                                    " && (message_event.ports.length === 0)"
784                                    " && (message_event.bubbles === false)"
785                                    " && (message_event.cancelable === false)"
786                                    ")");
787   ASSERT_TRUE(success);
788   message_data_.clear();
789   instance_->PostMessage(pp::Var(kTestInt));
790   ASSERT_EQ(0, message_data_.size());
791   ASSERT_EQ(1, WaitForMessages());
792   ASSERT_TRUE(message_data_.back().is_bool());
793   ASSERT_TRUE(message_data_.back().AsBool());
794   ASSERT_TRUE(ClearListeners());
795 
796   // Add some event handlers to make sure they receive messages.
797   ASSERT_TRUE(AddEchoingListener("1"));
798   ASSERT_TRUE(AddEchoingListener("2"));
799   ASSERT_TRUE(AddEchoingListener("3"));
800 
801   message_data_.clear();
802   instance_->PostMessage(pp::Var(kTestInt));
803   // Make sure we don't get a response in a re-entrant fashion.
804   ASSERT_EQ(0, message_data_.size());
805   // We should get 3 messages.
806   ASSERT_EQ(WaitForMessages(), 3);
807   // Copy to a vector of doubles and sort; w3c does not specify the order for
808   // event listeners. (Copying is easier than writing an operator< for pp::Var.)
809   //
810   // See http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html.
811   VarVector::iterator iter(message_data_.begin()), the_end(message_data_.end());
812   std::vector<double> double_vec;
813   for (; iter != the_end; ++iter) {
814     ASSERT_TRUE(iter->is_number());
815     double_vec.push_back(iter->AsDouble());
816   }
817   std::sort(double_vec.begin(), double_vec.end());
818   ASSERT_DOUBLE_EQ(double_vec[0], 1.0);
819   ASSERT_DOUBLE_EQ(double_vec[1], 2.0);
820   ASSERT_DOUBLE_EQ(double_vec[2], 3.0);
821 
822   message_data_.clear();
823   ASSERT_TRUE(ClearListeners());
824 
825   PASS();
826 }
827 
TestNoHandler()828 std::string TestPostMessage::TestNoHandler() {
829   // Delete any lingering messages and event listeners.
830   WaitForMessages();
831   ASSERT_TRUE(ClearListeners());
832 
833   // Now send a message.  We shouldn't get a response.
834   message_data_.clear();
835   instance_->PostMessage(pp::Var());
836   ASSERT_EQ(WaitForMessages(), 0);
837   ASSERT_TRUE(message_data_.empty());
838 
839   PASS();
840 }
841 
TestExtraParam()842 std::string TestPostMessage::TestExtraParam() {
843   // Delete any lingering messages and event listeners.
844   WaitForMessages();
845   ASSERT_TRUE(ClearListeners());
846   // Add a listener that will respond with 1 and an empty array (where the
847   // message port array would appear if it was Worker postMessage).
848   ASSERT_TRUE(AddEchoingListener("1, []"));
849 
850   // Now send a message.  We shouldn't get a response.
851   message_data_.clear();
852   instance_->PostMessage(pp::Var());
853   ASSERT_EQ(WaitForMessages(), 0);
854   ASSERT_TRUE(message_data_.empty());
855 
856   ASSERT_TRUE(ClearListeners());
857 
858   PASS();
859 }
860 
TestNonMainThread()861 std::string TestPostMessage::TestNonMainThread() {
862   WaitForMessages();
863   ASSERT_TRUE(ClearListeners());
864   ASSERT_TRUE(AddEchoingListener("message_event.data"));
865   message_data_.clear();
866 
867   // Set up a thread for each integer from 0 to (kThreadsToRun - 1).  Make each
868   // thread send the number that matches its index kMessagesToSendPerThread
869   // times.  For good measure, call postMessage from the main thread
870   // kMessagesToSendPerThread times. At the end, we make sure we got all the
871   // values we expected.
872   PP_Thread threads[kThreadsToRun];
873   for (int32_t i = 0; i < kThreadsToRun; ++i) {
874     // Set up a thread to send a value of i.
875     void* arg = new InvokePostMessageThreadArg(instance_, pp::Var(i));
876     PP_CreateThread(&threads[i], &InvokePostMessageThreadFunc, arg);
877   }
878   // Invoke PostMessage right now to send a value of (kThreadsToRun).
879   for (int32_t i = 0; i < kMessagesToSendPerThread; ++i)
880     instance_->PostMessage(pp::Var(kThreadsToRun));
881 
882   // Now join all threads.
883   for (int32_t i = 0; i < kThreadsToRun; ++i)
884     PP_JoinThread(threads[i]);
885 
886   // PostMessage is asynchronous, so we should not receive a response yet.
887   ASSERT_EQ(0, message_data_.size());
888 
889   // Make sure we got all values that we expected.  Note that because it's legal
890   // for the JavaScript engine to treat our integers as floating points, we
891   // can't just use std::find or equality comparison. So we instead, we convert
892   // each incoming value to an integer, and count them in received_counts.
893   int32_t expected_num = (kThreadsToRun + 1) * kMessagesToSendPerThread;
894   // Count how many we receive per-index.
895   std::vector<int32_t> expected_counts(kThreadsToRun + 1,
896                                        kMessagesToSendPerThread);
897   std::vector<int32_t> received_counts(kThreadsToRun + 1, 0);
898   ASSERT_EQ(expected_num, WaitForMessages());
899   for (int32_t i = 0; i < expected_num; ++i) {
900     const pp::Var& latest_var(message_data_[i]);
901     ASSERT_TRUE(latest_var.is_int() || latest_var.is_double());
902     int32_t received_value = -1;
903     if (latest_var.is_int()) {
904       received_value = latest_var.AsInt();
905     } else if (latest_var.is_double()) {
906       received_value = static_cast<int32_t>(latest_var.AsDouble() + 0.5);
907     }
908     ASSERT_TRUE(received_value >= 0);
909     ASSERT_TRUE(received_value <= kThreadsToRun);
910     ++received_counts[received_value];
911   }
912   ASSERT_EQ(expected_counts, received_counts);
913 
914   message_data_.clear();
915   ASSERT_TRUE(ClearListeners());
916 
917   PASS();
918 }
919