diff options
author | raymes@chromium.org <raymes@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-17 20:54:00 +0000 |
---|---|---|
committer | raymes@chromium.org <raymes@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-17 20:54:00 +0000 |
commit | ffd49dfc0729301c77dcf5026d29fa9cbedaecc1 (patch) | |
tree | 24bf475f55603bc61de7a7a9ff8c425cd16b120d /ppapi/tests/test_post_message.cc | |
parent | 30dca89c84bec4276bf9ad89b9fdbd18b8cf56a5 (diff) | |
download | chromium_src-ffd49dfc0729301c77dcf5026d29fa9cbedaecc1.zip chromium_src-ffd49dfc0729301c77dcf5026d29fa9cbedaecc1.tar.gz chromium_src-ffd49dfc0729301c77dcf5026d29fa9cbedaecc1.tar.bz2 |
Hook up V8<->Var conversion in the pepper message channel
This hooks up V8<->Var conversion in the pepper message channel so that Array/Dictionaries can be transmitted to and from the plugin using Post/HandleMessage.
This CL also adds integration tests for transmitting Arrays/Dictionaries.
BUG=236958
Review URL: https://chromiumcodereview.appspot.com/14636009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@200880 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/tests/test_post_message.cc')
-rw-r--r-- | ppapi/tests/test_post_message.cc | 241 |
1 files changed, 227 insertions, 14 deletions
diff --git a/ppapi/tests/test_post_message.cc b/ppapi/tests/test_post_message.cc index 39102e1..8c67ee5 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. |