skia/ext: Early out from analysis when we have more than 1 draw op.
[chromium-blink-merge.git] / ppapi / tests / test_message_handler.cc
blob54474f7033c4b0ef39251da6ba3c84269f3412f7
1 // Copyright 2014 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.
5 #include "ppapi/tests/test_message_handler.h"
7 #include <string.h>
8 #include <algorithm>
9 #include <map>
10 #include <sstream>
12 #include "ppapi/c/pp_var.h"
13 #include "ppapi/c/ppb_file_io.h"
14 #include "ppapi/c/ppp_message_handler.h"
15 #include "ppapi/cpp/file_io.h"
16 #include "ppapi/cpp/file_ref.h"
17 #include "ppapi/cpp/file_system.h"
18 #include "ppapi/cpp/instance.h"
19 #include "ppapi/cpp/module_impl.h"
20 #include "ppapi/cpp/var.h"
21 #include "ppapi/cpp/var_array.h"
22 #include "ppapi/cpp/var_array_buffer.h"
23 #include "ppapi/cpp/var_dictionary.h"
24 #include "ppapi/tests/pp_thread.h"
25 #include "ppapi/tests/test_utils.h"
26 #include "ppapi/tests/testing_instance.h"
28 // Windows defines 'PostMessage', so we have to undef it.
29 #ifdef PostMessage
30 #undef PostMessage
31 #endif
33 REGISTER_TEST_CASE(MessageHandler);
35 namespace {
37 // Created and destroyed on the main thread. All public methods should be called
38 // on the main thread. Most data members are only accessed on the main thread.
39 // (Though it handles messages on the background thread).
40 class EchoingMessageHandler {
41 public:
42 explicit EchoingMessageHandler(PP_Instance instance,
43 const pp::MessageLoop& loop)
44 : pp_instance_(instance),
45 message_handler_loop_(loop),
46 ppb_messaging_if_(static_cast<const PPB_Messaging_1_1*>(
47 pp::Module::Get()->GetBrowserInterface(
48 PPB_MESSAGING_INTERFACE_1_1))),
49 ppp_message_handler_if_(),
50 is_registered_(false),
51 test_finished_event_(instance),
52 destroy_event_(instance) {
53 AssertOnMainThread();
54 ppp_message_handler_if_.HandleMessage = &HandleMessage;
55 ppp_message_handler_if_.HandleBlockingMessage = &HandleBlockingMessage;
56 ppp_message_handler_if_.Destroy = &Destroy;
58 void Register() {
59 AssertOnMainThread();
60 assert(!is_registered_);
61 int32_t result = ppb_messaging_if_->RegisterMessageHandler(
62 pp_instance_,
63 this,
64 &ppp_message_handler_if_,
65 message_handler_loop_.pp_resource());
66 if (result == PP_OK) {
67 is_registered_ = true;
68 } else {
69 std::ostringstream stream;
70 stream << "Failed to register message handler; got error " << result;
71 AddError(stream.str());
72 test_finished_event_.Signal();
74 // Note, at this point, we can't safely read or write errors_ until we wait
75 // on destroy_event_.
77 void Unregister() {
78 AssertOnMainThread();
79 assert(is_registered_);
80 ppb_messaging_if_->UnregisterMessageHandler(pp_instance_);
81 is_registered_ = false;
83 void WaitForTestFinishedMessage() {
84 test_finished_event_.Wait();
85 test_finished_event_.Reset();
87 // Wait for Destroy() to be called on the MessageHandler thread. When it's
88 // done, return any errors that occurred during the time the MessageHandler
89 // was getting messages.
90 std::string WaitForDestroy() {
91 AssertOnMainThread();
92 // If we haven't called Unregister, we'll be waiting forever.
93 assert(!is_registered_);
94 destroy_event_.Wait();
95 destroy_event_.Reset();
96 // Now that we know Destroy() has been called, we know errors_ isn't being
97 // written on the MessageHandler thread anymore. So we can safely read it
98 // here on the main thread (since destroy_event_ gave us a memory barrier).
99 std::string temp_errors;
100 errors_.swap(temp_errors);
101 return temp_errors;
103 private:
104 static void AssertOnMainThread() {
105 assert(pp::MessageLoop::GetForMainThread() ==
106 pp::MessageLoop::GetCurrent());
108 void AddError(const std::string& error) {
109 if (!error.empty()) {
110 if (!errors_.empty())
111 errors_ += "<p>";
112 errors_ += error;
115 static void HandleMessage(PP_Instance instance,
116 void* user_data,
117 struct PP_Var message_data) {
118 EchoingMessageHandler* thiz =
119 static_cast<EchoingMessageHandler*>(user_data);
120 if (pp::MessageLoop::GetCurrent() != thiz->message_handler_loop_)
121 thiz->AddError("HandleMessage was called on the wrong thread!");
122 if (instance != thiz->pp_instance_)
123 thiz->AddError("HandleMessage was passed the wrong instance!");
124 pp::Var var(message_data);
125 if (var.is_string() && var.AsString() == "FINISHED_TEST")
126 thiz->test_finished_event_.Signal();
127 else
128 thiz->ppb_messaging_if_->PostMessage(instance, message_data);
131 static PP_Var HandleBlockingMessage(PP_Instance instance,
132 void* user_data,
133 struct PP_Var message_data) {
134 EchoingMessageHandler* thiz =
135 static_cast<EchoingMessageHandler*>(user_data);
136 if (pp::MessageLoop::GetCurrent() != thiz->message_handler_loop_)
137 thiz->AddError("HandleBlockingMessage was called on the wrong thread!");
138 if (instance != thiz->pp_instance_)
139 thiz->AddError("HandleBlockingMessage was passed the wrong instance!");
141 // The PP_Var we are passed is an in-parameter, so the browser is not
142 // giving us a ref-count. The ref-count it has will be decremented after we
143 // return. But we need to add a ref when returning a PP_Var, to pass to the
144 // caller.
145 pp::Var take_ref(message_data);
146 take_ref.Detach();
147 return message_data;
150 static void Destroy(PP_Instance instance, void* user_data) {
151 EchoingMessageHandler* thiz =
152 static_cast<EchoingMessageHandler*>(user_data);
153 if (pp::MessageLoop::GetCurrent() != thiz->message_handler_loop_)
154 thiz->AddError("Destroy was called on the wrong thread!");
155 if (instance != thiz->pp_instance_)
156 thiz->AddError("Destroy was passed the wrong instance!");
157 thiz->destroy_event_.Signal();
160 // These data members are initialized on the main thread, but don't change for
161 // the life of the object, so are safe to access on the background thread,
162 // because there will be a memory barrier before the the MessageHandler calls
163 // are invoked.
164 const PP_Instance pp_instance_;
165 const pp::MessageLoop message_handler_loop_;
166 const pp::MessageLoop main_loop_;
167 const PPB_Messaging_1_1* const ppb_messaging_if_;
168 // Spiritually, this member is const, but we can't initialize it in C++03,
169 // so it has to be non-const to be set in the constructor body.
170 PPP_MessageHandler_0_1 ppp_message_handler_if_;
172 // is_registered_ is only read/written on the main thread.
173 bool is_registered_;
175 // errors_ is written on the MessageHandler thread. When Destroy() is
176 // called, we stop writing to errors_ and signal destroy_event_. This causes
177 // a memory barrier, so it's safe to read errors_ after that.
178 std::string errors_;
179 NestedEvent test_finished_event_;
180 NestedEvent destroy_event_;
182 // Undefined & private to disallow copy and assign.
183 EchoingMessageHandler(const EchoingMessageHandler&);
184 EchoingMessageHandler& operator=(const EchoingMessageHandler&);
187 void FakeHandleMessage(PP_Instance instance,
188 void* user_data,
189 struct PP_Var message_data) {}
190 PP_Var FakeHandleBlockingMessage(PP_Instance instance,
191 void* user_data,
192 struct PP_Var message_data) {
193 return PP_MakeUndefined();
195 void FakeDestroy(PP_Instance instance, void* user_data) {}
197 } // namespace
199 TestMessageHandler::TestMessageHandler(TestingInstance* instance)
200 : TestCase(instance),
201 ppb_messaging_if_(NULL),
202 handler_thread_(instance) {
205 TestMessageHandler::~TestMessageHandler() {
206 handler_thread_.Join();
209 bool TestMessageHandler::Init() {
210 ppb_messaging_if_ = static_cast<const PPB_Messaging_1_1*>(
211 pp::Module::Get()->GetBrowserInterface(PPB_MESSAGING_INTERFACE_1_1));
212 return ppb_messaging_if_ &&
213 CheckTestingInterface() &&
214 handler_thread_.Start();
217 void TestMessageHandler::RunTests(const std::string& filter) {
218 RUN_TEST(RegisterErrorConditions, filter);
219 RUN_TEST(PostMessageAndAwaitResponse, filter);
222 void TestMessageHandler::HandleMessage(const pp::Var& message_data) {
223 // All messages should go to the background thread message handler.
224 assert(false);
227 std::string TestMessageHandler::TestRegisterErrorConditions() {
229 // Test registering with the main thread as the message loop.
230 PPP_MessageHandler_0_1 fake_ppp_message_handler = {
231 &FakeHandleMessage, &FakeHandleBlockingMessage, &FakeDestroy
233 pp::MessageLoop main_loop = pp::MessageLoop::GetForMainThread();
234 int32_t result = ppb_messaging_if_->RegisterMessageHandler(
235 instance()->pp_instance(),
236 reinterpret_cast<void*>(0xdeadbeef),
237 &fake_ppp_message_handler,
238 main_loop.pp_resource());
239 ASSERT_EQ(PP_ERROR_WRONG_THREAD, result);
242 // Test registering with incomplete PPP_Messaging interface.
243 PPP_MessageHandler_0_1 bad_ppp_ifs[] = {
244 { NULL, &FakeHandleBlockingMessage, &FakeDestroy },
245 { &FakeHandleMessage, NULL, &FakeDestroy },
246 { &FakeHandleMessage, &FakeHandleBlockingMessage, NULL }};
247 for (size_t i = 0; i < sizeof(bad_ppp_ifs)/sizeof(bad_ppp_ifs[0]); ++i) {
248 int32_t result = ppb_messaging_if_->RegisterMessageHandler(
249 instance()->pp_instance(),
250 reinterpret_cast<void*>(0xdeadbeef),
251 &bad_ppp_ifs[i],
252 handler_thread_.message_loop().pp_resource());
253 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
256 PASS();
259 std::string TestMessageHandler::TestPostMessageAndAwaitResponse() {
260 EchoingMessageHandler handler(instance()->pp_instance(),
261 handler_thread_.message_loop());
262 handler.Register();
263 std::string js_code("var plugin = document.getElementById('plugin');\n");
264 js_code += "var result = undefined;\n";
265 const char* const values_to_test[] = {
266 "5",
267 "undefined",
268 "1.5",
269 "'hello'",
270 "{'key': 'value', 'array_key': [1, 2, 3, 4, 5]}",
271 NULL
273 for (size_t i = 0; values_to_test[i]; ++i) {
274 js_code += "result = plugin.postMessageAndAwaitResponse(";
275 js_code += values_to_test[i];
276 js_code += ");\n";
277 js_code += "if (!deepCompare(result, ";
278 js_code += values_to_test[i];
279 js_code += "))\n";
280 js_code += " InternalError(\" Failed postMessageAndAwaitResponse for: ";
281 js_code += values_to_test[i];
282 js_code += " result: \" + result);\n";
284 // TODO(dmichael): Setting a property uses GetInstanceObject, which sends sync
285 // message, which can get interrupted with message to eval script, etc.
286 // FINISHED_WAITING message can therefore jump ahead. This test is
287 // currently carefully crafted to avoid races by doing all the JS in one call.
288 // That should be fixed before this API goes to stable. See crbug.com/384528
289 js_code += "plugin.postMessage('FINISHED_TEST');\n";
290 instance_->EvalScript(js_code);
291 handler.WaitForTestFinishedMessage();
292 handler.Unregister();
293 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy());
295 PASS();