• 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__anon17c715570111::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   // Set up a special listener that only responds to a FINISHED_WAITING string.
176   // This is for use by WaitForMessages.
177   std::string js_code;
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
182   // framework itself.
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 "');"
188              "  }"
189              "};"
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);
194 
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
201   // the stack.
202   instance_->PostMessage(pp::Var(kTestString));
203 
204   return success;
205 }
206 
RunTests(const std::string & filter)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);
223 }
224 
HandleMessage(const pp::Var & message_data)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());
229   else
230     message_data_.push_back(message_data);
231 }
232 
AddEchoingListener(const std::string & expression)233 bool TestPostMessage::AddEchoingListener(const std::string& expression) {
234   std::string js_code;
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
239   // framework itself.
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;
246   js_code += "                      );"
247              "  }"
248              "};"
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);
256   return true;
257 }
258 
PostMessageFromJavaScript(const std::string & func)259 bool TestPostMessage::PostMessageFromJavaScript(const std::string& func) {
260   std::string js_code;
261   js_code += "var plugin = document.getElementById('plugin');"
262              "plugin.postMessage(";
263   js_code += func + "()";
264   js_code += "                      );";
265   instance_->EvalScript(js_code);
266   return true;
267 }
268 
ClearListeners()269 bool TestPostMessage::ClearListeners() {
270   std::string js_code;
271   js_code += "var plugin = document.getElementById('plugin');"
272              "while (plugin.eventListeners.length) {"
273              "  plugin.removeEventListener('message',"
274              "                             plugin.eventListeners.pop());"
275              "}";
276   instance_->EvalScript(js_code);
277   return true;
278 }
279 
WaitForMessages()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;
290 }
291 
CheckMessageProperties(const pp::Var & test_data,const std::vector<std::string> & properties_to_check)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();
298        ++iter) {
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());
309   }
310   PASS();
311 }
312 
TestSendInInit()313 std::string TestPostMessage::TestSendInInit() {
314   // Wait for the messages from Init() to be guaranteed to be sent.
315   WaitForMessages();
316   // This test assumes Init already sent a message.
317   ASSERT_EQ(1, message_data_.size());
318   ASSERT_TRUE(message_data_.back().is_string());
319   ASSERT_EQ(kTestString, message_data_.back().AsString());
320   message_data_.clear();
321   PASS();
322 }
323 
TestSendingData()324 std::string TestPostMessage::TestSendingData() {
325   // Clean up after previous tests. This also swallows the message sent by Init
326   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
327   // should start with these.
328   WaitForMessages();
329   ASSERT_TRUE(ClearListeners());
330 
331   // Set up the JavaScript message event listener to echo the data part of the
332   // message event back to us.
333   ASSERT_TRUE(AddEchoingListener("message_event.data"));
334 
335   // Test sending a message to JavaScript for each supported type. The JS sends
336   // the data back to us, and we check that they match.
337   message_data_.clear();
338   instance_->PostMessage(pp::Var(kTestBool));
339   ASSERT_EQ(0, message_data_.size());
340   ASSERT_EQ(1, WaitForMessages());
341   ASSERT_TRUE(message_data_.back().is_bool());
342   ASSERT_EQ(message_data_.back().AsBool(), kTestBool);
343 
344   message_data_.clear();
345   instance_->PostMessage(pp::Var(kTestInt));
346   ASSERT_EQ(0, message_data_.size());
347   ASSERT_EQ(1, WaitForMessages());
348   ASSERT_TRUE(message_data_.back().is_number());
349   ASSERT_DOUBLE_EQ(static_cast<double>(kTestInt),
350                    message_data_.back().AsDouble());
351 
352   message_data_.clear();
353   instance_->PostMessage(pp::Var(kTestDouble));
354   ASSERT_EQ(0, message_data_.size());
355   ASSERT_EQ(1, WaitForMessages());
356   ASSERT_TRUE(message_data_.back().is_number());
357   ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(), kTestDouble);
358 
359   message_data_.clear();
360   instance_->PostMessage(pp::Var());
361   ASSERT_EQ(0, message_data_.size());
362   ASSERT_EQ(1, WaitForMessages());
363   ASSERT_TRUE(message_data_.back().is_undefined());
364 
365   message_data_.clear();
366   instance_->PostMessage(pp::Var(pp::Var::Null()));
367   ASSERT_EQ(0, message_data_.size());
368   ASSERT_EQ(1, WaitForMessages());
369   ASSERT_TRUE(message_data_.back().is_null());
370 
371   message_data_.clear();
372   ASSERT_TRUE(ClearListeners());
373 
374   PASS();
375 }
376 
TestSendingString()377 std::string TestPostMessage::TestSendingString() {
378   // Clean up after previous tests. This also swallows the message sent by Init
379   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
380   // should start with these.
381   WaitForMessages();
382   ASSERT_TRUE(ClearListeners());
383 
384   // Test that a string var is converted to a primitive JS string.
385   message_data_.clear();
386   std::vector<std::string> properties_to_check;
387   properties_to_check.push_back(
388       "typeof message_event.data === 'string'");
389   ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(kTestString,
390                                                 properties_to_check));
391 
392   ASSERT_TRUE(AddEchoingListener("message_event.data"));
393   message_data_.clear();
394   instance_->PostMessage(pp::Var(kTestString));
395   // PostMessage is asynchronous, so we should not receive a response yet.
396   ASSERT_EQ(0, message_data_.size());
397   ASSERT_EQ(1, WaitForMessages());
398   ASSERT_TRUE(message_data_.back().is_string());
399   ASSERT_EQ(message_data_.back().AsString(), kTestString);
400 
401   message_data_.clear();
402   ASSERT_TRUE(ClearListeners());
403 
404   PASS();
405 }
406 
TestSendingArrayBuffer()407 std::string TestPostMessage::TestSendingArrayBuffer() {
408   // Clean up after previous tests. This also swallows the message sent by Init
409   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
410   // should start with these.
411   WaitForMessages();
412   ASSERT_TRUE(ClearListeners());
413 
414   // TODO(sehr,dmichael): Add testing of longer array buffers when
415   // crbug.com/110086 is fixed.
416   ScopedArrayBufferSizeSetter setter(testing_interface_,
417                                      instance_->pp_instance(),
418                                      200);
419   uint32_t sizes[] = { 0, 100, 1000, 10000 };
420   for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[i]); ++i) {
421     std::ostringstream size_stream;
422     size_stream << sizes[i];
423     const std::string kSizeAsString(size_stream.str());
424 
425     // Create an appropriately sized array buffer with test_data[i] == i.
426     pp::VarArrayBuffer test_data(sizes[i]);
427     if (sizes[i] > 0)
428       ASSERT_NE(NULL, test_data.Map());
429     // Make sure we can Unmap/Map successfully (there's not really any way to
430     // detect if it's unmapped, so we just re-map before getting the pointer to
431     // the buffer).
432     test_data.Unmap();
433     test_data.Map();
434     ASSERT_EQ(sizes[i], test_data.ByteLength());
435     unsigned char* buff = static_cast<unsigned char*>(test_data.Map());
436     const uint32_t kByteLength = test_data.ByteLength();
437     for (size_t j = 0; j < kByteLength; ++j)
438       buff[j] = static_cast<uint8_t>(j % 256u);
439 
440     // Have the listener test some properties of the ArrayBuffer.
441     std::vector<std::string> properties_to_check;
442     properties_to_check.push_back(
443         "message_event.data.constructor.name === 'ArrayBuffer'");
444     properties_to_check.push_back(
445         std::string("message_event.data.byteLength === ") + kSizeAsString);
446     if (sizes[i] > 0) {
447       properties_to_check.push_back(
448           "(new DataView(message_event.data)).getUint8(0) == 0");
449       // Checks that the last element has the right value: (byteLength-1)%256.
450       std::string received_byte("(new DataView(message_event.data)).getUint8("
451                                 "    message_event.data.byteLength-1)");
452       std::string expected_byte("(message_event.data.byteLength-1)%256");
453       properties_to_check.push_back(received_byte + " == " + expected_byte);
454     }
455     ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(test_data,
456                                                   properties_to_check));
457 
458     // Set up the JavaScript message event listener to echo the data part of the
459     // message event back to us.
460     ASSERT_TRUE(AddEchoingListener("message_event.data"));
461     message_data_.clear();
462     instance_->PostMessage(test_data);
463     // PostMessage is asynchronous, so we should not receive a response yet.
464     ASSERT_EQ(0, message_data_.size());
465     ASSERT_EQ(1, WaitForMessages());
466     ASSERT_TRUE(message_data_.back().is_array_buffer());
467     pp::VarArrayBuffer received(message_data_.back());
468     message_data_.clear();
469     ASSERT_EQ(test_data.ByteLength(), received.ByteLength());
470     unsigned char* received_buff = static_cast<unsigned char*>(received.Map());
471     // The buffer should be copied, so this should be a distinct buffer. When
472     // 'transferrables' are implemented for PPAPI, we'll also want to test that
473     // we get the _same_ buffer back when it's transferred.
474     if (sizes[i] > 0)
475       ASSERT_NE(buff, received_buff);
476     for (size_t i = 0; i < test_data.ByteLength(); ++i)
477       ASSERT_EQ(buff[i], received_buff[i]);
478 
479     message_data_.clear();
480     ASSERT_TRUE(ClearListeners());
481   }
482 
483   PASS();
484 }
485 
TestSendingArray()486 std::string TestPostMessage::TestSendingArray() {
487   // Clean up after previous tests. This also swallows the message sent by Init
488   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
489   // should start with these.
490   WaitForMessages();
491   ASSERT_TRUE(ClearListeners());
492 
493   pp::VarArray array;
494   array.Set(0, pp::Var(kTestBool));
495   array.Set(1, pp::Var(kTestString));
496   // Purposely leave index 2 empty.
497   array.Set(3, pp::Var(kTestInt));
498   array.Set(4, pp::Var(kTestDouble));
499 
500   std::stringstream ss;
501   ss << array.GetLength();
502   std::string length_as_string(ss.str());
503 
504   // Have the listener test some properties of the Array.
505   std::vector<std::string> properties_to_check;
506   properties_to_check.push_back(
507       "message_event.data.constructor.name === 'Array'");
508   properties_to_check.push_back(
509       std::string("message_event.data.length === ") + length_as_string);
510   // Check that the string is converted to a primitive JS string.
511   properties_to_check.push_back(
512       std::string("typeof message_event.data[1] === 'string'"));
513   ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(array, properties_to_check));
514 
515   // Set up the JavaScript message event listener to echo the data part of the
516   // message event back to us.
517   ASSERT_TRUE(AddEchoingListener("message_event.data"));
518   message_data_.clear();
519   instance_->PostMessage(array);
520   // PostMessage is asynchronous, so we should not receive a response yet.
521   ASSERT_EQ(0, message_data_.size());
522   ASSERT_EQ(1, WaitForMessages());
523   ASSERT_TRUE(message_data_.back().is_array());
524   ASSERT_TRUE(VarsEqual(array, message_data_.back()));
525 
526   message_data_.clear();
527   ASSERT_TRUE(ClearListeners());
528 
529   PASS();
530 }
531 
TestSendingDictionary()532 std::string TestPostMessage::TestSendingDictionary() {
533   // Clean up after previous tests. This also swallows the message sent by Init
534   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
535   // should start with these.
536   WaitForMessages();
537   ASSERT_TRUE(ClearListeners());
538 
539   pp::VarDictionary dictionary;
540   dictionary.Set(pp::Var("foo"), pp::Var(kTestBool));
541   dictionary.Set(pp::Var("bar"), pp::Var(kTestString));
542   dictionary.Set(pp::Var("abc"), pp::Var(kTestInt));
543   dictionary.Set(pp::Var("def"), pp::Var());
544 
545   std::stringstream ss;
546   ss << dictionary.GetKeys().GetLength();
547   std::string length_as_string(ss.str());
548 
549   // Have the listener test some properties of the Dictionary.
550   std::vector<std::string> properties_to_check;
551   properties_to_check.push_back(
552       "message_event.data.constructor.name === 'Object'");
553   properties_to_check.push_back(
554       std::string("Object.keys(message_event.data).length === ") +
555       length_as_string);
556   // Check that the string is converted to a primitive JS string.
557   properties_to_check.push_back(
558       std::string("typeof message_event.data['bar'] === 'string'"));
559   ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(dictionary,
560                                                 properties_to_check));
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   message_data_.clear();
566   instance_->PostMessage(dictionary);
567   // PostMessage is asynchronous, so we should not receive a response yet.
568   ASSERT_EQ(0, message_data_.size());
569   ASSERT_EQ(1, WaitForMessages());
570   ASSERT_TRUE(message_data_.back().is_dictionary());
571   ASSERT_TRUE(VarsEqual(dictionary, message_data_.back()));
572 
573   message_data_.clear();
574   ASSERT_TRUE(ClearListeners());
575 
576   PASS();
577 }
578 
TestSendingResource()579 std::string TestPostMessage::TestSendingResource() {
580   // Clean up after previous tests. This also swallows the message sent by Init
581   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
582   // should start with these.
583   WaitForMessages();
584   message_data_.clear();
585   ASSERT_TRUE(ClearListeners());
586 
587   std::string file_path("/");
588   file_path += kTestFilename;
589   int content_length = strlen(kTestString);
590 
591   // Create a file in the HTML5 temporary file system, in the Pepper plugin.
592   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
593   pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
594   callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
595   CHECK_CALLBACK_BEHAVIOR(callback);
596   ASSERT_EQ(PP_OK, callback.result());
597   pp::FileRef write_file_ref(file_system, file_path.c_str());
598   // Write to the file.
599   pp::FileIO write_file_io(instance_);
600   ASSERT_NE(0, write_file_io.pp_resource());
601   callback.WaitForResult(
602       write_file_io.Open(write_file_ref,
603                          PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE,
604                          callback.GetCallback()));
605   CHECK_CALLBACK_BEHAVIOR(callback);
606   ASSERT_EQ(PP_OK, callback.result());
607   callback.WaitForResult(write_file_io.Write(
608       0, kTestString, content_length, callback.GetCallback()));
609   CHECK_CALLBACK_BEHAVIOR(callback);
610   ASSERT_EQ(callback.result(), content_length);
611   write_file_io.Close();
612 
613   // Pass the file system to JavaScript and have the listener test some
614   // properties of the file system.
615   pp::Var file_system_var(file_system);
616   std::vector<std::string> properties_to_check;
617   properties_to_check.push_back(
618       "message_event.data.constructor.name === 'DOMFileSystem'");
619   properties_to_check.push_back(
620       "message_event.data.root.constructor.name === 'DirectoryEntry'");
621   properties_to_check.push_back(
622       "message_event.data.name.indexOf("
623       "    ':Temporary',"
624       "    message_event.data.name.length - ':Temporary'.length) !== -1");
625   ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(file_system_var,
626                                                 properties_to_check));
627 
628   // Set up the JavaScript message event listener to echo the data part of the
629   // message event back to us.
630   ASSERT_TRUE(AddEchoingListener("message_event.data"));
631   // Send the file system in a message from the Pepper plugin to JavaScript.
632   message_data_.clear();
633   instance_->PostMessage(file_system_var);
634   // PostMessage is asynchronous, so we should not receive a response yet.
635   ASSERT_EQ(0, message_data_.size());
636   ASSERT_EQ(1, WaitForMessages());
637 
638   // The JavaScript should have posted the file system back to us. Verify that
639   // it is a file system and read the file contents that we wrote earlier.
640   pp::Var var = message_data_.back();
641   ASSERT_TRUE(var.is_resource());
642   pp::Resource result = var.AsResource();
643   ASSERT_TRUE(pp::FileSystem::IsFileSystem(result));
644   {
645     pp::FileSystem received_file_system(result);
646     pp::FileRef file_ref(received_file_system, file_path.c_str());
647     ASSERT_NE(0, file_ref.pp_resource());
648 
649     // Ensure that the file can be queried.
650     TestCompletionCallbackWithOutput<PP_FileInfo> cc(instance_->pp_instance(),
651                                                      callback_type());
652     cc.WaitForResult(file_ref.Query(cc.GetCallback()));
653     CHECK_CALLBACK_BEHAVIOR(cc);
654     ASSERT_EQ(PP_OK, cc.result());
655     ASSERT_EQ(cc.output().size, content_length);
656 
657     // Read the file and test that its contents match.
658     pp::FileIO file_io(instance_);
659     ASSERT_NE(0, file_io.pp_resource());
660     callback.WaitForResult(
661         file_io.Open(file_ref, PP_FILEOPENFLAG_READ, callback.GetCallback()));
662     CHECK_CALLBACK_BEHAVIOR(callback);
663     ASSERT_EQ(PP_OK, callback.result());
664 
665     std::vector<char> buffer_vector(content_length);
666     char* buffer = &buffer_vector[0];  // Note: Not null-terminated!
667     callback.WaitForResult(
668         file_io.Read(0, buffer, content_length, callback.GetCallback()));
669     CHECK_CALLBACK_BEHAVIOR(callback);
670     ASSERT_EQ(callback.result(), content_length);
671     ASSERT_EQ(0, memcmp(buffer, kTestString, content_length));
672   }
673 
674   WaitForMessages();
675   message_data_.clear();
676   ASSERT_TRUE(ClearListeners());
677 
678   PASS();
679 }
680 
TestSendingComplexVar()681 std::string TestPostMessage::TestSendingComplexVar() {
682   // Clean up after previous tests. This also swallows the message sent by Init
683   // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
684   // should start with these.
685   WaitForMessages();
686   message_data_.clear();
687   ASSERT_TRUE(ClearListeners());
688 
689   pp::Var string(kTestString);
690   pp::VarDictionary dictionary;
691   dictionary.Set(pp::Var("foo"), pp::Var(kTestBool));
692   dictionary.Set(pp::Var("bar"), string);
693   dictionary.Set(pp::Var("abc"), pp::Var(kTestInt));
694   dictionary.Set(pp::Var("def"), pp::Var());
695 
696   // Reference to array.
697   pp::VarArray array;
698   array.Set(0, pp::Var(kTestBool));
699   array.Set(1, string);
700   // Purposely leave index 2 empty (which will place an undefined var there).
701   array.Set(3, pp::Var(kTestInt));
702   array.Set(4, pp::Var(kTestDouble));
703 
704   dictionary.Set(pp::Var("array-ref1"), array);
705   dictionary.Set(pp::Var("array-ref2"), array);
706 
707   // Set up the JavaScript message event listener to echo the data part of the
708   // message event back to us.
709   ASSERT_TRUE(AddEchoingListener("message_event.data"));
710   instance_->PostMessage(dictionary);
711   // PostMessage is asynchronous, so we should not receive a response yet.
712   ASSERT_EQ(0, message_data_.size());
713   ASSERT_EQ(1, WaitForMessages());
714   ASSERT_TRUE(message_data_.back().is_dictionary());
715   pp::VarDictionary result(message_data_.back());
716   ASSERT_TRUE(VarsEqual(dictionary, message_data_.back()));
717 
718   WaitForMessages();
719   message_data_.clear();
720   ASSERT_TRUE(ClearListeners());
721 
722   // Set up a (dictionary -> array -> dictionary) cycle. Cycles shouldn't be
723   // transmitted.
724   pp::VarArray array2;
725   array2.Set(0, dictionary);
726   dictionary.Set(pp::Var("array2"), array2);
727 
728   ASSERT_TRUE(AddEchoingListener("message_event.data"));
729   instance_->PostMessage(dictionary);
730   // PostMessage is asynchronous, so we should not receive a response yet.
731   ASSERT_EQ(0, message_data_.size());
732   ASSERT_EQ(WaitForMessages(), 0);
733 
734   // Break the cycles.
735   dictionary.Delete(pp::Var("array2"));
736 
737   WaitForMessages();
738   message_data_.clear();
739   ASSERT_TRUE(ClearListeners());
740 
741   // Test sending a cycle from JavaScript to the plugin.
742   ASSERT_TRUE(AddEchoingListener("message_event.data"));
743   PostMessageFromJavaScript("function() { var x = []; x[0] = x; return x; }");
744   ASSERT_EQ(0, message_data_.size());
745   ASSERT_EQ(WaitForMessages(), 0);
746 
747   WaitForMessages();
748   message_data_.clear();
749   ASSERT_TRUE(ClearListeners());
750 
751   PASS();
752 }
753 
TestMessageEvent()754 std::string TestPostMessage::TestMessageEvent() {
755   // Set up the JavaScript message event listener to pass us some values from
756   // the MessageEvent and make sure they match our expectations.
757 
758   WaitForMessages();
759   ASSERT_TRUE(ClearListeners());
760   // Have the listener pass back the class name of message_event and make sure
761   // it's "MessageEvent".
762   ASSERT_TRUE(AddEchoingListener("message_event.constructor.name"));
763   message_data_.clear();
764   instance_->PostMessage(pp::Var(kTestInt));
765   ASSERT_EQ(0, message_data_.size());
766   ASSERT_EQ(1, WaitForMessages());
767   ASSERT_TRUE(message_data_.back().is_string());
768   ASSERT_EQ(message_data_.back().AsString(), "MessageEvent");
769   ASSERT_TRUE(ClearListeners());
770 
771   // Make sure all the non-data properties have the expected values.
772   bool success = AddEchoingListener("((message_event.origin === '')"
773                                    " && (message_event.lastEventId === '')"
774                                    " && (message_event.source === null)"
775                                    " && (message_event.ports.length === 0)"
776                                    " && (message_event.bubbles === false)"
777                                    " && (message_event.cancelable === false)"
778                                    ")");
779   ASSERT_TRUE(success);
780   message_data_.clear();
781   instance_->PostMessage(pp::Var(kTestInt));
782   ASSERT_EQ(0, message_data_.size());
783   ASSERT_EQ(1, WaitForMessages());
784   ASSERT_TRUE(message_data_.back().is_bool());
785   ASSERT_TRUE(message_data_.back().AsBool());
786   ASSERT_TRUE(ClearListeners());
787 
788   // Add some event handlers to make sure they receive messages.
789   ASSERT_TRUE(AddEchoingListener("1"));
790   ASSERT_TRUE(AddEchoingListener("2"));
791   ASSERT_TRUE(AddEchoingListener("3"));
792 
793   message_data_.clear();
794   instance_->PostMessage(pp::Var(kTestInt));
795   // Make sure we don't get a response in a re-entrant fashion.
796   ASSERT_EQ(0, message_data_.size());
797   // We should get 3 messages.
798   ASSERT_EQ(WaitForMessages(), 3);
799   // Copy to a vector of doubles and sort; w3c does not specify the order for
800   // event listeners. (Copying is easier than writing an operator< for pp::Var.)
801   //
802   // See http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html.
803   VarVector::iterator iter(message_data_.begin()), the_end(message_data_.end());
804   std::vector<double> double_vec;
805   for (; iter != the_end; ++iter) {
806     ASSERT_TRUE(iter->is_number());
807     double_vec.push_back(iter->AsDouble());
808   }
809   std::sort(double_vec.begin(), double_vec.end());
810   ASSERT_DOUBLE_EQ(double_vec[0], 1.0);
811   ASSERT_DOUBLE_EQ(double_vec[1], 2.0);
812   ASSERT_DOUBLE_EQ(double_vec[2], 3.0);
813 
814   message_data_.clear();
815   ASSERT_TRUE(ClearListeners());
816 
817   PASS();
818 }
819 
TestNoHandler()820 std::string TestPostMessage::TestNoHandler() {
821   // Delete any lingering messages and event listeners.
822   WaitForMessages();
823   ASSERT_TRUE(ClearListeners());
824 
825   // Now send a message.  We shouldn't get a response.
826   message_data_.clear();
827   instance_->PostMessage(pp::Var());
828   ASSERT_EQ(WaitForMessages(), 0);
829   ASSERT_TRUE(message_data_.empty());
830 
831   PASS();
832 }
833 
TestExtraParam()834 std::string TestPostMessage::TestExtraParam() {
835   // Delete any lingering messages and event listeners.
836   WaitForMessages();
837   ASSERT_TRUE(ClearListeners());
838   // Add a listener that will respond with 1 and an empty array (where the
839   // message port array would appear if it was Worker postMessage).
840   ASSERT_TRUE(AddEchoingListener("1, []"));
841 
842   // Now send a message.  We shouldn't get a response.
843   message_data_.clear();
844   instance_->PostMessage(pp::Var());
845   ASSERT_EQ(WaitForMessages(), 0);
846   ASSERT_TRUE(message_data_.empty());
847 
848   ASSERT_TRUE(ClearListeners());
849 
850   PASS();
851 }
852 
TestNonMainThread()853 std::string TestPostMessage::TestNonMainThread() {
854   WaitForMessages();
855   ASSERT_TRUE(ClearListeners());
856   ASSERT_TRUE(AddEchoingListener("message_event.data"));
857   message_data_.clear();
858 
859   // Set up a thread for each integer from 0 to (kThreadsToRun - 1).  Make each
860   // thread send the number that matches its index kMessagesToSendPerThread
861   // times.  For good measure, call postMessage from the main thread
862   // kMessagesToSendPerThread times. At the end, we make sure we got all the
863   // values we expected.
864   PP_ThreadType threads[kThreadsToRun];
865   for (int32_t i = 0; i < kThreadsToRun; ++i) {
866     // Set up a thread to send a value of i.
867     void* arg = new InvokePostMessageThreadArg(instance_, pp::Var(i));
868     PP_CreateThread(&threads[i], &InvokePostMessageThreadFunc, arg);
869   }
870   // Invoke PostMessage right now to send a value of (kThreadsToRun).
871   for (int32_t i = 0; i < kMessagesToSendPerThread; ++i)
872     instance_->PostMessage(pp::Var(kThreadsToRun));
873 
874   // Now join all threads.
875   for (int32_t i = 0; i < kThreadsToRun; ++i)
876     PP_JoinThread(threads[i]);
877 
878   // PostMessage is asynchronous, so we should not receive a response yet.
879   ASSERT_EQ(0, message_data_.size());
880 
881   // Make sure we got all values that we expected.  Note that because it's legal
882   // for the JavaScript engine to treat our integers as floating points, we
883   // can't just use std::find or equality comparison. So we instead, we convert
884   // each incoming value to an integer, and count them in received_counts.
885   int32_t expected_num = (kThreadsToRun + 1) * kMessagesToSendPerThread;
886   // Count how many we receive per-index.
887   std::vector<int32_t> expected_counts(kThreadsToRun + 1,
888                                        kMessagesToSendPerThread);
889   std::vector<int32_t> received_counts(kThreadsToRun + 1, 0);
890   ASSERT_EQ(expected_num, WaitForMessages());
891   for (int32_t i = 0; i < expected_num; ++i) {
892     const pp::Var& latest_var(message_data_[i]);
893     ASSERT_TRUE(latest_var.is_int() || latest_var.is_double());
894     int32_t received_value = -1;
895     if (latest_var.is_int()) {
896       received_value = latest_var.AsInt();
897     } else if (latest_var.is_double()) {
898       received_value = static_cast<int32_t>(latest_var.AsDouble() + 0.5);
899     }
900     ASSERT_TRUE(received_value >= 0);
901     ASSERT_TRUE(received_value <= kThreadsToRun);
902     ++received_counts[received_value];
903   }
904   ASSERT_EQ(expected_counts, received_counts);
905 
906   message_data_.clear();
907   ASSERT_TRUE(ClearListeners());
908 
909   PASS();
910 }
911