This source file includes following definitions.
- InvokePostMessageThreadFunc
- VarsEqual
- VarsEqual
- instance_
- Init
- RunTests
- HandleMessage
- AddEchoingListener
- PostMessageFromJavaScript
- ClearListeners
- WaitForMessages
- CheckMessageProperties
- TestSendInInit
- TestSendingData
- TestSendingString
- TestSendingArrayBuffer
- TestSendingArray
- TestSendingDictionary
- TestSendingResource
- TestSendingComplexVar
- TestMessageEvent
- TestNoHandler
- TestExtraParam
- TestNonMainThread
#include "ppapi/tests/test_post_message.h"
#include <string.h>
#include <algorithm>
#include <map>
#include <sstream>
#include "ppapi/c/pp_var.h"
#include "ppapi/c/ppb_file_io.h"
#include "ppapi/cpp/file_io.h"
#include "ppapi/cpp/file_ref.h"
#include "ppapi/cpp/file_system.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/var_array.h"
#include "ppapi/cpp/var_array_buffer.h"
#include "ppapi/cpp/var_dictionary.h"
#include "ppapi/tests/pp_thread.h"
#include "ppapi/tests/test_utils.h"
#include "ppapi/tests/testing_instance.h"
#ifdef PostMessage
#undef PostMessage
#endif
REGISTER_TEST_CASE(PostMessage);
namespace {
const char kTestFilename[] = "testfile.txt";
const char kTestString[] = "Hello world!";
const bool kTestBool = true;
const int32_t kTestInt = 42;
const double kTestDouble = 42.0;
#ifdef PPAPI_OS_WIN
const int32_t kThreadsToRun = 2;
const int32_t kMessagesToSendPerThread = 5;
#else
const int32_t kThreadsToRun = 4;
const int32_t kMessagesToSendPerThread = 10;
#endif
struct InvokePostMessageThreadArg {
InvokePostMessageThreadArg(pp::Instance* i, const pp::Var& v)
: instance(i), value_to_send(v) {}
pp::Instance* instance;
pp::Var value_to_send;
};
void InvokePostMessageThreadFunc(void* user_data) {
InvokePostMessageThreadArg* arg =
static_cast<InvokePostMessageThreadArg*>(user_data);
for (int32_t i = 0; i < kMessagesToSendPerThread; ++i)
arg->instance->PostMessage(arg->value_to_send);
delete arg;
}
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;
}
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;
}
if (!expected.is_string()) {
(*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 expected_array(expected);
pp::VarArray 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 expected_dict(expected);
pp::VarDictionary 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))
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_Private* interface,
PP_Instance instance,
uint32_t threshold)
: interface_(interface),
instance_(instance) {
interface_->SetMinimumArrayBufferSizeForShmem(instance_, threshold);
}
~ScopedArrayBufferSizeSetter() {
interface_->SetMinimumArrayBufferSizeForShmem(instance_, 0);
}
private:
const PPB_Testing_Private* interface_;
PP_Instance instance_;
};
#define FINISHED_WAITING_MESSAGE "TEST_POST_MESSAGE_FINISHED_WAITING"
}
TestPostMessage::TestPostMessage(TestingInstance* instance)
: TestCase(instance) {
}
TestPostMessage::~TestPostMessage() {
instance_->PostMessage(pp::Var("This isn't guaranteed to be received, but "
"shouldn't cause a crash."));
std::string js_code;
js_code += "var plugin = document.getElementById('plugin');"
"plugin.removeEventListener('message',"
" plugin.wait_for_messages_handler);"
"delete plugin.wait_for_messages_handler;";
instance_->EvalScript(js_code);
}
bool TestPostMessage::Init() {
bool success = CheckTestingInterface();
std::string js_code;
js_code += "var plugin = document.getElementById('plugin');"
"var wait_for_messages_handler = function(message_event) {"
" if (!IsTestingMessage(message_event.data) &&"
" message_event.data === '" FINISHED_WAITING_MESSAGE "') {"
" plugin.postMessage('" FINISHED_WAITING_MESSAGE "');"
" }"
"};"
"plugin.addEventListener('message', wait_for_messages_handler);"
"plugin.wait_for_messages_handler = wait_for_messages_handler;";
instance_->EvalScript(js_code);
success = success && AddEchoingListener("message_event.data");
message_data_.clear();
instance_->PostMessage(pp::Var(kTestString));
return success;
}
void TestPostMessage::RunTests(const std::string& filter) {
RUN_TEST(SendInInit, filter);
RUN_TEST(SendingData, filter);
RUN_TEST(SendingString, filter);
RUN_TEST(SendingArrayBuffer, filter);
RUN_TEST(SendingArray, filter);
RUN_TEST(SendingDictionary, filter);
RUN_TEST(SendingResource, filter);
RUN_TEST(SendingComplexVar, filter);
RUN_TEST(MessageEvent, filter);
RUN_TEST(NoHandler, filter);
RUN_TEST(ExtraParam, filter);
if (testing_interface_->IsOutOfProcess())
RUN_TEST(NonMainThread, filter);
}
void TestPostMessage::HandleMessage(const pp::Var& message_data) {
if (message_data.is_string() &&
(message_data.AsString() == FINISHED_WAITING_MESSAGE))
testing_interface_->QuitMessageLoop(instance_->pp_instance());
else
message_data_.push_back(message_data);
}
bool TestPostMessage::AddEchoingListener(const std::string& expression) {
std::string js_code;
js_code += "var plugin = document.getElementById('plugin');"
"var message_handler = function(message_event) {"
" if (!IsTestingMessage(message_event.data) &&"
" !(message_event.data === '" FINISHED_WAITING_MESSAGE "')) {"
" plugin.postMessage(";
js_code += expression;
js_code += " );"
" }"
"};"
"plugin.addEventListener('message', message_handler);"
"if (!plugin.eventListeners) plugin.eventListeners = [];"
"plugin.eventListeners.push(message_handler);";
instance_->EvalScript(js_code);
return true;
}
bool TestPostMessage::PostMessageFromJavaScript(const std::string& func) {
std::string js_code;
js_code += "var plugin = document.getElementById('plugin');"
"plugin.postMessage(";
js_code += func + "()";
js_code += " );";
instance_->EvalScript(js_code);
return true;
}
bool TestPostMessage::ClearListeners() {
std::string js_code;
js_code += "var plugin = document.getElementById('plugin');"
"while (plugin.eventListeners.length) {"
" plugin.removeEventListener('message',"
" plugin.eventListeners.pop());"
"}";
instance_->EvalScript(js_code);
return true;
}
int TestPostMessage::WaitForMessages() {
size_t message_size_before = message_data_.size();
instance_->PostMessage(pp::Var(FINISHED_WAITING_MESSAGE));
testing_interface_->RunMessageLoop(instance_->pp_instance());
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(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
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(1, WaitForMessages());
ASSERT_EQ(1, message_data_.size());
ASSERT_TRUE(message_data_.back().is_string());
ASSERT_EQ(kTestString, message_data_.back().AsString());
message_data_.clear();
PASS();
}
std::string TestPostMessage::TestSendingData() {
WaitForMessages();
ASSERT_TRUE(ClearListeners());
ASSERT_TRUE(AddEchoingListener("message_event.data"));
message_data_.clear();
instance_->PostMessage(pp::Var(kTestBool));
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
ASSERT_TRUE(message_data_.back().is_bool());
ASSERT_EQ(message_data_.back().AsBool(), kTestBool);
message_data_.clear();
instance_->PostMessage(pp::Var(kTestInt));
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
ASSERT_TRUE(message_data_.back().is_number());
ASSERT_DOUBLE_EQ(static_cast<double>(kTestInt),
message_data_.back().AsDouble());
message_data_.clear();
instance_->PostMessage(pp::Var(kTestDouble));
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
ASSERT_TRUE(message_data_.back().is_number());
ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(), kTestDouble);
message_data_.clear();
instance_->PostMessage(pp::Var());
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
ASSERT_TRUE(message_data_.back().is_undefined());
message_data_.clear();
instance_->PostMessage(pp::Var(pp::Var::Null()));
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
ASSERT_TRUE(message_data_.back().is_null());
message_data_.clear();
ASSERT_TRUE(ClearListeners());
PASS();
}
std::string TestPostMessage::TestSendingString() {
WaitForMessages();
ASSERT_TRUE(ClearListeners());
message_data_.clear();
std::vector<std::string> properties_to_check;
properties_to_check.push_back(
"typeof message_event.data === 'string'");
ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(kTestString,
properties_to_check));
ASSERT_TRUE(AddEchoingListener("message_event.data"));
message_data_.clear();
instance_->PostMessage(pp::Var(kTestString));
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
ASSERT_TRUE(message_data_.back().is_string());
ASSERT_EQ(message_data_.back().AsString(), kTestString);
message_data_.clear();
ASSERT_TRUE(ClearListeners());
PASS();
}
std::string TestPostMessage::TestSendingArrayBuffer() {
WaitForMessages();
ASSERT_TRUE(ClearListeners());
ScopedArrayBufferSizeSetter setter(testing_interface_,
instance_->pp_instance(),
200);
uint32_t sizes[] = { 0, 100, 1000, 10000 };
for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[i]); ++i) {
std::ostringstream size_stream;
size_stream << sizes[i];
const std::string kSizeAsString(size_stream.str());
pp::VarArrayBuffer test_data(sizes[i]);
if (sizes[i] > 0)
ASSERT_NE(NULL, test_data.Map());
test_data.Unmap();
test_data.Map();
ASSERT_EQ(sizes[i], test_data.ByteLength());
unsigned char* buff = static_cast<unsigned char*>(test_data.Map());
const uint32_t kByteLength = test_data.ByteLength();
for (size_t j = 0; j < kByteLength; ++j)
buff[j] = static_cast<uint8_t>(j % 256u);
std::vector<std::string> properties_to_check;
properties_to_check.push_back(
"message_event.data.constructor.name === 'ArrayBuffer'");
properties_to_check.push_back(
std::string("message_event.data.byteLength === ") + kSizeAsString);
if (sizes[i] > 0) {
properties_to_check.push_back(
"(new DataView(message_event.data)).getUint8(0) == 0");
std::string received_byte("(new DataView(message_event.data)).getUint8("
" message_event.data.byteLength-1)");
std::string expected_byte("(message_event.data.byteLength-1)%256");
properties_to_check.push_back(received_byte + " == " + expected_byte);
}
ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(test_data,
properties_to_check));
ASSERT_TRUE(AddEchoingListener("message_event.data"));
message_data_.clear();
instance_->PostMessage(test_data);
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
ASSERT_TRUE(message_data_.back().is_array_buffer());
pp::VarArrayBuffer received(message_data_.back());
message_data_.clear();
ASSERT_EQ(test_data.ByteLength(), received.ByteLength());
unsigned char* received_buff = static_cast<unsigned char*>(received.Map());
if (sizes[i] > 0)
ASSERT_NE(buff, received_buff);
for (size_t i = 0; i < test_data.ByteLength(); ++i)
ASSERT_EQ(buff[i], received_buff[i]);
message_data_.clear();
ASSERT_TRUE(ClearListeners());
}
PASS();
}
std::string TestPostMessage::TestSendingArray() {
WaitForMessages();
ASSERT_TRUE(ClearListeners());
pp::VarArray array;
array.Set(0, pp::Var(kTestBool));
array.Set(1, pp::Var(kTestString));
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());
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);
properties_to_check.push_back(
std::string("typeof message_event.data[1] === 'string'"));
ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(array, properties_to_check));
ASSERT_TRUE(AddEchoingListener("message_event.data"));
message_data_.clear();
instance_->PostMessage(array);
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
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() {
WaitForMessages();
ASSERT_TRUE(ClearListeners());
pp::VarDictionary 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());
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);
properties_to_check.push_back(
std::string("typeof message_event.data['bar'] === 'string'"));
ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(dictionary,
properties_to_check));
ASSERT_TRUE(AddEchoingListener("message_event.data"));
message_data_.clear();
instance_->PostMessage(dictionary);
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
ASSERT_TRUE(message_data_.back().is_dictionary());
ASSERT_TRUE(VarsEqual(dictionary, message_data_.back()));
message_data_.clear();
ASSERT_TRUE(ClearListeners());
PASS();
}
std::string TestPostMessage::TestSendingResource() {
WaitForMessages();
message_data_.clear();
ASSERT_TRUE(ClearListeners());
std::string file_path("/");
file_path += kTestFilename;
int content_length = strlen(kTestString);
TestCompletionCallback callback(instance_->pp_instance(), callback_type());
pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(callback);
ASSERT_EQ(PP_OK, callback.result());
pp::FileRef write_file_ref(file_system, file_path.c_str());
pp::FileIO write_file_io(instance_);
ASSERT_NE(0, write_file_io.pp_resource());
callback.WaitForResult(
write_file_io.Open(write_file_ref,
PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE,
callback.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(callback);
ASSERT_EQ(PP_OK, callback.result());
callback.WaitForResult(write_file_io.Write(
0, kTestString, content_length, callback.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(callback);
ASSERT_EQ(callback.result(), content_length);
write_file_io.Close();
pp::Var file_system_var(file_system);
std::vector<std::string> properties_to_check;
properties_to_check.push_back(
"message_event.data.constructor.name === 'DOMFileSystem'");
properties_to_check.push_back(
"message_event.data.root.constructor.name === 'DirectoryEntry'");
properties_to_check.push_back(
"message_event.data.name.indexOf("
" ':Temporary',"
" message_event.data.name.length - ':Temporary'.length) !== -1");
ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(file_system_var,
properties_to_check));
ASSERT_TRUE(AddEchoingListener("message_event.data"));
message_data_.clear();
instance_->PostMessage(file_system_var);
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
pp::Var var = message_data_.back();
ASSERT_TRUE(var.is_resource());
pp::Resource result = var.AsResource();
ASSERT_TRUE(pp::FileSystem::IsFileSystem(result));
{
pp::FileSystem received_file_system(result);
pp::FileRef file_ref(received_file_system, file_path.c_str());
ASSERT_NE(0, file_ref.pp_resource());
TestCompletionCallbackWithOutput<PP_FileInfo> cc(instance_->pp_instance(),
callback_type());
cc.WaitForResult(file_ref.Query(cc.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(cc);
ASSERT_EQ(PP_OK, cc.result());
ASSERT_EQ(cc.output().size, content_length);
pp::FileIO file_io(instance_);
ASSERT_NE(0, file_io.pp_resource());
callback.WaitForResult(
file_io.Open(file_ref, PP_FILEOPENFLAG_READ, callback.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(callback);
ASSERT_EQ(PP_OK, callback.result());
std::vector<char> buffer_vector(content_length);
char* buffer = &buffer_vector[0];
callback.WaitForResult(
file_io.Read(0, buffer, content_length, callback.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(callback);
ASSERT_EQ(callback.result(), content_length);
ASSERT_EQ(0, memcmp(buffer, kTestString, content_length));
}
WaitForMessages();
message_data_.clear();
ASSERT_TRUE(ClearListeners());
PASS();
}
std::string TestPostMessage::TestSendingComplexVar() {
WaitForMessages();
message_data_.clear();
ASSERT_TRUE(ClearListeners());
pp::Var string(kTestString);
pp::VarDictionary 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());
pp::VarArray array;
array.Set(0, pp::Var(kTestBool));
array.Set(1, string);
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);
ASSERT_TRUE(AddEchoingListener("message_event.data"));
instance_->PostMessage(dictionary);
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
ASSERT_TRUE(message_data_.back().is_dictionary());
pp::VarDictionary result(message_data_.back());
ASSERT_TRUE(VarsEqual(dictionary, message_data_.back()));
WaitForMessages();
message_data_.clear();
ASSERT_TRUE(ClearListeners());
pp::VarArray array2;
array2.Set(0, dictionary);
dictionary.Set(pp::Var("array2"), array2);
ASSERT_TRUE(AddEchoingListener("message_event.data"));
instance_->PostMessage(dictionary);
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(WaitForMessages(), 0);
dictionary.Delete(pp::Var("array2"));
WaitForMessages();
message_data_.clear();
ASSERT_TRUE(ClearListeners());
ASSERT_TRUE(AddEchoingListener("message_event.data"));
PostMessageFromJavaScript("function() { var x = []; x[0] = x; return x; }");
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(WaitForMessages(), 0);
WaitForMessages();
message_data_.clear();
ASSERT_TRUE(ClearListeners());
PASS();
}
std::string TestPostMessage::TestMessageEvent() {
WaitForMessages();
ASSERT_TRUE(ClearListeners());
ASSERT_TRUE(AddEchoingListener("message_event.constructor.name"));
message_data_.clear();
instance_->PostMessage(pp::Var(kTestInt));
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
ASSERT_TRUE(message_data_.back().is_string());
ASSERT_EQ(message_data_.back().AsString(), "MessageEvent");
ASSERT_TRUE(ClearListeners());
bool success = AddEchoingListener("((message_event.origin === '')"
" && (message_event.lastEventId === '')"
" && (message_event.source === null)"
" && (message_event.ports.length === 0)"
" && (message_event.bubbles === false)"
" && (message_event.cancelable === false)"
")");
ASSERT_TRUE(success);
message_data_.clear();
instance_->PostMessage(pp::Var(kTestInt));
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(1, WaitForMessages());
ASSERT_TRUE(message_data_.back().is_bool());
ASSERT_TRUE(message_data_.back().AsBool());
ASSERT_TRUE(ClearListeners());
ASSERT_TRUE(AddEchoingListener("1"));
ASSERT_TRUE(AddEchoingListener("2"));
ASSERT_TRUE(AddEchoingListener("3"));
message_data_.clear();
instance_->PostMessage(pp::Var(kTestInt));
ASSERT_EQ(0, message_data_.size());
ASSERT_EQ(WaitForMessages(), 3);
VarVector::iterator iter(message_data_.begin()), the_end(message_data_.end());
std::vector<double> double_vec;
for (; iter != the_end; ++iter) {
ASSERT_TRUE(iter->is_number());
double_vec.push_back(iter->AsDouble());
}
std::sort(double_vec.begin(), double_vec.end());
ASSERT_DOUBLE_EQ(double_vec[0], 1.0);
ASSERT_DOUBLE_EQ(double_vec[1], 2.0);
ASSERT_DOUBLE_EQ(double_vec[2], 3.0);
message_data_.clear();
ASSERT_TRUE(ClearListeners());
PASS();
}
std::string TestPostMessage::TestNoHandler() {
WaitForMessages();
ASSERT_TRUE(ClearListeners());
message_data_.clear();
instance_->PostMessage(pp::Var());
ASSERT_EQ(WaitForMessages(), 0);
ASSERT_TRUE(message_data_.empty());
PASS();
}
std::string TestPostMessage::TestExtraParam() {
WaitForMessages();
ASSERT_TRUE(ClearListeners());
ASSERT_TRUE(AddEchoingListener("1, []"));
message_data_.clear();
instance_->PostMessage(pp::Var());
ASSERT_EQ(WaitForMessages(), 0);
ASSERT_TRUE(message_data_.empty());
ASSERT_TRUE(ClearListeners());
PASS();
}
std::string TestPostMessage::TestNonMainThread() {
WaitForMessages();
ASSERT_TRUE(ClearListeners());
ASSERT_TRUE(AddEchoingListener("message_event.data"));
message_data_.clear();
PP_ThreadType threads[kThreadsToRun];
for (int32_t i = 0; i < kThreadsToRun; ++i) {
void* arg = new InvokePostMessageThreadArg(instance_, pp::Var(i));
PP_CreateThread(&threads[i], &InvokePostMessageThreadFunc, arg);
}
for (int32_t i = 0; i < kMessagesToSendPerThread; ++i)
instance_->PostMessage(pp::Var(kThreadsToRun));
for (int32_t i = 0; i < kThreadsToRun; ++i)
PP_JoinThread(threads[i]);
ASSERT_EQ(0, message_data_.size());
int32_t expected_num = (kThreadsToRun + 1) * kMessagesToSendPerThread;
std::vector<int32_t> expected_counts(kThreadsToRun + 1,
kMessagesToSendPerThread);
std::vector<int32_t> received_counts(kThreadsToRun + 1, 0);
ASSERT_EQ(expected_num, WaitForMessages());
for (int32_t i = 0; i < expected_num; ++i) {
const pp::Var& latest_var(message_data_[i]);
ASSERT_TRUE(latest_var.is_int() || latest_var.is_double());
int32_t received_value = -1;
if (latest_var.is_int()) {
received_value = latest_var.AsInt();
} else if (latest_var.is_double()) {
received_value = static_cast<int32_t>(latest_var.AsDouble() + 0.5);
}
ASSERT_TRUE(received_value >= 0);
ASSERT_TRUE(received_value <= kThreadsToRun);
++received_counts[received_value];
}
ASSERT_EQ(expected_counts, received_counts);
message_data_.clear();
ASSERT_TRUE(ClearListeners());
PASS();
}