Index: ppapi/tests/test_post_message.cc |
diff --git a/ppapi/tests/test_post_message.cc b/ppapi/tests/test_post_message.cc |
index 39102e1f6ebb64cf964c1d490d399158f4c0f2b7..8c67ee5a7c1b8907c89d6d86708ba8145cccba1f 100644 |
--- a/ppapi/tests/test_post_message.cc |
+++ b/ppapi/tests/test_post_message.cc |
@@ -5,6 +5,7 @@ |
#include "ppapi/tests/test_post_message.h" |
#include <algorithm> |
+#include <map> |
#include <sstream> |
#include "ppapi/c/dev/ppb_testing_dev.h" |
@@ -58,6 +59,64 @@ void InvokePostMessageThreadFunc(void* user_data) { |
delete arg; |
} |
+// TODO(raymes): Consider putting something like this into pp::Var. |
+bool VarsEqual(const pp::Var& expected, |
+ const pp::Var& actual, |
+ std::map<int64_t, int64_t>* visited_ids) { |
+ if (expected.pp_var().type != actual.pp_var().type) { |
+ if (!expected.is_number() && !actual.is_number()) |
+ return false; |
+ } |
+ // TODO(raymes): Implement a pp::Var::IsRefCounted() function. |
+ if (expected.pp_var().type > PP_VARTYPE_DOUBLE) { |
+ std::map<int64_t, int64_t>::const_iterator it = |
+ visited_ids->find(expected.pp_var().value.as_id); |
+ if (it != visited_ids->end()) { |
+ if (it->second == actual.pp_var().value.as_id) |
+ return true; |
+ return false; |
+ } |
+ (*visited_ids)[expected.pp_var().value.as_id] = actual.pp_var().value.as_id; |
+ } |
+ |
+ if (expected.is_number()) { |
+ return fabs(expected.AsDouble() - actual.AsDouble()) < 1.0e-4; |
+ } else if (expected.is_array()) { |
+ pp::VarArray_Dev expected_array(expected); |
+ pp::VarArray_Dev actual_array(actual); |
+ if (expected_array.GetLength() != actual_array.GetLength()) |
+ return false; |
+ for (uint32_t i = 0; i < expected_array.GetLength(); ++i) { |
+ if (!VarsEqual(expected_array.Get(i), actual_array.Get(i), visited_ids)) |
+ return false; |
+ } |
+ return true; |
+ } else if (expected.is_dictionary()) { |
+ pp::VarDictionary_Dev expected_dict(expected); |
+ pp::VarDictionary_Dev actual_dict(actual); |
+ if (expected_dict.GetKeys().GetLength() != |
+ actual_dict.GetKeys().GetLength()) { |
+ return false; |
+ } |
+ for (uint32_t i = 0; i < expected_dict.GetKeys().GetLength(); ++i) { |
+ pp::Var key = expected_dict.GetKeys().Get(i); |
+ if (actual_dict.HasKey(key) == PP_FALSE) |
+ return false; |
+ if (!VarsEqual(expected_dict.Get(key), actual_dict.Get(key), visited_ids)) |
+ return false; |
+ } |
+ return true; |
+ } else { |
+ return expected == actual; |
+ } |
+} |
+ |
+bool VarsEqual(const pp::Var& expected, |
+ const pp::Var& actual) { |
+ std::map<int64_t, int64_t> visited_ids; |
+ return VarsEqual(expected, actual, &visited_ids); |
+} |
+ |
class ScopedArrayBufferSizeSetter { |
public: |
ScopedArrayBufferSizeSetter(const PPB_Testing_Dev* interface, |
@@ -135,6 +194,9 @@ void TestPostMessage::RunTests(const std::string& filter) { |
RUN_TEST(SendInInit, filter); |
RUN_TEST(SendingData, filter); |
RUN_TEST(SendingArrayBuffer, filter); |
+ RUN_TEST(SendingArray, filter); |
+ RUN_TEST(SendingDictionary, filter); |
+ RUN_TEST(SendingComplexVar, filter); |
RUN_TEST(MessageEvent, filter); |
RUN_TEST(NoHandler, filter); |
RUN_TEST(ExtraParam, filter); |
@@ -199,6 +261,27 @@ int TestPostMessage::WaitForMessages() { |
return message_data_.size() - message_size_before; |
} |
+std::string TestPostMessage::CheckMessageProperties( |
+ const pp::Var& test_data, |
+ const std::vector<std::string>& properties_to_check) { |
+ typedef std::vector<std::string>::const_iterator Iterator; |
+ for (Iterator iter = properties_to_check.begin(); |
+ iter != properties_to_check.end(); |
+ ++iter) { |
+ ASSERT_TRUE(AddEchoingListener(*iter)); |
+ message_data_.clear(); |
+ instance_->PostMessage(test_data); |
+ ASSERT_EQ(message_data_.size(), 0); |
+ ASSERT_EQ(WaitForMessages(), 1); |
+ ASSERT_TRUE(message_data_.back().is_bool()); |
+ if (!message_data_.back().AsBool()) |
+ return std::string("Failed: ") + *iter; |
+ ASSERT_TRUE(message_data_.back().AsBool()); |
+ ASSERT_TRUE(ClearListeners()); |
+ } |
+ PASS(); |
+} |
+ |
std::string TestPostMessage::TestSendInInit() { |
ASSERT_EQ(WaitForMessages(), 1); |
// This test assumes Init already sent a message. |
@@ -317,20 +400,8 @@ std::string TestPostMessage::TestSendingArrayBuffer() { |
std::string expected_byte("(message_event.data.byteLength-1)%256"); |
properties_to_check.push_back(received_byte + " == " + expected_byte); |
} |
- for (std::vector<std::string>::iterator iter = properties_to_check.begin(); |
- iter != properties_to_check.end(); |
- ++iter) { |
- ASSERT_TRUE(AddEchoingListener(*iter)); |
- message_data_.clear(); |
- instance_->PostMessage(test_data); |
- ASSERT_EQ(message_data_.size(), 0); |
- ASSERT_EQ(WaitForMessages(), 1); |
- ASSERT_TRUE(message_data_.back().is_bool()); |
- if (!message_data_.back().AsBool()) |
- return std::string("Failed: ") + *iter + ", size: " + kSizeAsString; |
- ASSERT_TRUE(message_data_.back().AsBool()); |
- ASSERT_TRUE(ClearListeners()); |
- } |
+ ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(test_data, |
+ properties_to_check)); |
// Set up the JavaScript message event listener to echo the data part of the |
// message event back to us. |
@@ -360,6 +431,148 @@ std::string TestPostMessage::TestSendingArrayBuffer() { |
PASS(); |
} |
+std::string TestPostMessage::TestSendingArray() { |
+ // Clean up after previous tests. This also swallows the message sent by Init |
+ // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' |
+ // should start with these. |
+ WaitForMessages(); |
+ ASSERT_TRUE(ClearListeners()); |
+ |
+ pp::VarArray_Dev array; |
+ array.Set(0, pp::Var(kTestBool)); |
+ array.Set(1, pp::Var(kTestString)); |
+ // Purposely leave index 2 empty. |
+ array.Set(3, pp::Var(kTestInt)); |
+ array.Set(4, pp::Var(kTestDouble)); |
+ |
+ std::stringstream ss; |
+ ss << array.GetLength(); |
+ std::string length_as_string(ss.str()); |
+ |
+ // Have the listener test some properties of the Array. |
+ std::vector<std::string> properties_to_check; |
+ properties_to_check.push_back( |
+ "message_event.data.constructor.name === 'Array'"); |
+ properties_to_check.push_back( |
+ std::string("message_event.data.length === ") + length_as_string); |
+ ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(array, properties_to_check)); |
+ |
+ // Set up the JavaScript message event listener to echo the data part of the |
+ // message event back to us. |
+ ASSERT_TRUE(AddEchoingListener("message_event.data")); |
+ message_data_.clear(); |
+ instance_->PostMessage(array); |
+ // PostMessage is asynchronous, so we should not receive a response yet. |
+ ASSERT_EQ(message_data_.size(), 0); |
+ ASSERT_EQ(WaitForMessages(), 1); |
+ ASSERT_TRUE(message_data_.back().is_array()); |
+ ASSERT_TRUE(VarsEqual(array, message_data_.back())); |
+ |
+ message_data_.clear(); |
+ ASSERT_TRUE(ClearListeners()); |
+ |
+ PASS(); |
+} |
+ |
+std::string TestPostMessage::TestSendingDictionary() { |
+ // Clean up after previous tests. This also swallows the message sent by Init |
+ // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' |
+ // should start with these. |
+ WaitForMessages(); |
+ ASSERT_TRUE(ClearListeners()); |
+ |
+ pp::VarDictionary_Dev dictionary; |
+ dictionary.Set(pp::Var("foo"), pp::Var(kTestBool)); |
+ dictionary.Set(pp::Var("bar"), pp::Var(kTestString)); |
+ dictionary.Set(pp::Var("abc"), pp::Var(kTestInt)); |
+ dictionary.Set(pp::Var("def"), pp::Var()); |
+ |
+ std::stringstream ss; |
+ ss << dictionary.GetKeys().GetLength(); |
+ std::string length_as_string(ss.str()); |
+ |
+ // Have the listener test some properties of the Dictionary. |
+ std::vector<std::string> properties_to_check; |
+ properties_to_check.push_back( |
+ "message_event.data.constructor.name === 'Object'"); |
+ properties_to_check.push_back( |
+ std::string("Object.keys(message_event.data).length === ") + |
+ length_as_string); |
+ ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(dictionary, |
+ properties_to_check)); |
+ |
+ // Set up the JavaScript message event listener to echo the data part of the |
+ // message event back to us. |
+ ASSERT_TRUE(AddEchoingListener("message_event.data")); |
+ message_data_.clear(); |
+ instance_->PostMessage(dictionary); |
+ // PostMessage is asynchronous, so we should not receive a response yet. |
+ ASSERT_EQ(message_data_.size(), 0); |
+ ASSERT_EQ(WaitForMessages(), 1); |
+ ASSERT_TRUE(message_data_.back().is_dictionary()); |
+ ASSERT_TRUE(VarsEqual(dictionary, message_data_.back())); |
+ |
+ message_data_.clear(); |
+ ASSERT_TRUE(ClearListeners()); |
+ |
+ PASS(); |
+} |
+ |
+std::string TestPostMessage::TestSendingComplexVar() { |
+ // Clean up after previous tests. This also swallows the message sent by Init |
+ // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' |
+ // should start with these. |
+ WaitForMessages(); |
+ ASSERT_TRUE(ClearListeners()); |
+ |
+ pp::Var string(kTestString); |
+ pp::VarDictionary_Dev dictionary; |
+ dictionary.Set(pp::Var("foo"), pp::Var(kTestBool)); |
+ dictionary.Set(pp::Var("bar"), string); |
+ dictionary.Set(pp::Var("abc"), pp::Var(kTestInt)); |
+ dictionary.Set(pp::Var("def"), pp::Var()); |
+ dictionary.Set(pp::Var("dictionary"), dictionary); // Self-reference. |
+ |
+ // Reference to array. |
+ pp::VarArray_Dev array; |
+ array.Set(0, pp::Var(kTestBool)); |
+ array.Set(1, string); |
+ // Purposely leave index 2 empty (which will place an undefined var there). |
+ array.Set(3, pp::Var(kTestInt)); |
+ array.Set(4, pp::Var(kTestDouble)); |
+ |
+ dictionary.Set(pp::Var("array-ref1"), array); |
+ dictionary.Set(pp::Var("array-ref2"), array); |
+ |
+ // Set up a (dictionary -> array -> dictionary) cycle. |
+ pp::VarArray_Dev array2; |
+ array2.Set(0, dictionary); |
+ dictionary.Set(pp::Var("array2"), array2); |
+ |
+ // Set up the JavaScript message event listener to echo the data part of the |
+ // message event back to us. |
+ ASSERT_TRUE(AddEchoingListener("message_event.data")); |
+ message_data_.clear(); |
+ instance_->PostMessage(dictionary); |
+ // PostMessage is asynchronous, so we should not receive a response yet. |
+ ASSERT_EQ(message_data_.size(), 0); |
+ ASSERT_EQ(WaitForMessages(), 1); |
+ ASSERT_TRUE(message_data_.back().is_dictionary()); |
+ pp::VarDictionary_Dev result(message_data_.back()); |
+ ASSERT_TRUE(VarsEqual(dictionary, message_data_.back())); |
+ |
+ // Break the cycles. |
+ dictionary.Delete(pp::Var("dictionary")); |
+ dictionary.Delete(pp::Var("array2")); |
+ result.Delete(pp::Var("dictionary")); |
+ result.Delete(pp::Var("array2")); |
+ |
+ message_data_.clear(); |
+ ASSERT_TRUE(ClearListeners()); |
+ |
+ PASS(); |
+} |
+ |
std::string TestPostMessage::TestMessageEvent() { |
// Set up the JavaScript message event listener to pass us some values from |
// the MessageEvent and make sure they match our expectations. |