OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/renderer/api_event_handler.h" | 5 #include "extensions/renderer/api_event_handler.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
10 #include "base/test/mock_callback.h" | 10 #include "base/test/mock_callback.h" |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 | 121 |
122 { | 122 { |
123 v8::Local<v8::Value> argv[] = {event}; | 123 v8::Local<v8::Value> argv[] = {event}; |
124 v8::Local<v8::Value> result = | 124 v8::Local<v8::Value> result = |
125 RunFunction(has_listeners_function, context, arraysize(argv), argv); | 125 RunFunction(has_listeners_function, context, arraysize(argv), argv); |
126 bool has_listeners = false; | 126 bool has_listeners = false; |
127 EXPECT_TRUE( | 127 EXPECT_TRUE( |
128 gin::Converter<bool>::FromV8(isolate(), result, &has_listeners)); | 128 gin::Converter<bool>::FromV8(isolate(), result, &has_listeners)); |
129 EXPECT_FALSE(has_listeners); | 129 EXPECT_FALSE(has_listeners); |
130 } | 130 } |
| 131 |
| 132 handler.InvalidateContext(context); |
131 } | 133 } |
132 | 134 |
133 // Tests listening for and firing different events. | 135 // Tests listening for and firing different events. |
134 TEST_F(APIEventHandlerTest, FiringEvents) { | 136 TEST_F(APIEventHandlerTest, FiringEvents) { |
135 const char kAlphaName[] = "alpha"; | 137 const char kAlphaName[] = "alpha"; |
136 const char kBetaName[] = "beta"; | 138 const char kBetaName[] = "beta"; |
137 v8::HandleScope handle_scope(isolate()); | 139 v8::HandleScope handle_scope(isolate()); |
138 v8::Local<v8::Context> context = ContextLocal(); | 140 v8::Local<v8::Context> context = ContextLocal(); |
139 | 141 |
140 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), | 142 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 | 221 |
220 handler.FireEventInContext(kAlphaName, context, base::ListValue()); | 222 handler.FireEventInContext(kAlphaName, context, base::ListValue()); |
221 EXPECT_EQ(2, get_fired_count("alphaCount1")); | 223 EXPECT_EQ(2, get_fired_count("alphaCount1")); |
222 EXPECT_EQ(2, get_fired_count("alphaCount2")); | 224 EXPECT_EQ(2, get_fired_count("alphaCount2")); |
223 EXPECT_EQ(0, get_fired_count("betaCount")); | 225 EXPECT_EQ(0, get_fired_count("betaCount")); |
224 | 226 |
225 handler.FireEventInContext(kBetaName, context, base::ListValue()); | 227 handler.FireEventInContext(kBetaName, context, base::ListValue()); |
226 EXPECT_EQ(2, get_fired_count("alphaCount1")); | 228 EXPECT_EQ(2, get_fired_count("alphaCount1")); |
227 EXPECT_EQ(2, get_fired_count("alphaCount2")); | 229 EXPECT_EQ(2, get_fired_count("alphaCount2")); |
228 EXPECT_EQ(1, get_fired_count("betaCount")); | 230 EXPECT_EQ(1, get_fired_count("betaCount")); |
| 231 |
| 232 handler.InvalidateContext(context); |
229 } | 233 } |
230 | 234 |
231 // Tests firing events with arguments. | 235 // Tests firing events with arguments. |
232 TEST_F(APIEventHandlerTest, EventArguments) { | 236 TEST_F(APIEventHandlerTest, EventArguments) { |
233 v8::HandleScope handle_scope(isolate()); | 237 v8::HandleScope handle_scope(isolate()); |
234 v8::Local<v8::Context> context = ContextLocal(); | 238 v8::Local<v8::Context> context = ContextLocal(); |
235 | 239 |
236 const char kEventName[] = "alpha"; | 240 const char kEventName[] = "alpha"; |
237 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), | 241 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), |
238 base::Bind(&DoNothingOnEventListenersChanged)); | 242 base::Bind(&DoNothingOnEventListenersChanged)); |
(...skipping 17 matching lines...) Expand all Loading... |
256 } | 260 } |
257 | 261 |
258 const char kArguments[] = "['foo',1,{'prop1':'bar'}]"; | 262 const char kArguments[] = "['foo',1,{'prop1':'bar'}]"; |
259 std::unique_ptr<base::ListValue> event_args = ListValueFromString(kArguments); | 263 std::unique_ptr<base::ListValue> event_args = ListValueFromString(kArguments); |
260 ASSERT_TRUE(event_args); | 264 ASSERT_TRUE(event_args); |
261 handler.FireEventInContext(kEventName, context, *event_args); | 265 handler.FireEventInContext(kEventName, context, *event_args); |
262 | 266 |
263 EXPECT_EQ( | 267 EXPECT_EQ( |
264 ReplaceSingleQuotes(kArguments), | 268 ReplaceSingleQuotes(kArguments), |
265 GetStringPropertyFromObject(context->Global(), context, "eventArgs")); | 269 GetStringPropertyFromObject(context->Global(), context, "eventArgs")); |
| 270 |
| 271 handler.InvalidateContext(context); |
266 } | 272 } |
267 | 273 |
268 // Test dispatching events to multiple contexts. | 274 // Test dispatching events to multiple contexts. |
269 TEST_F(APIEventHandlerTest, MultipleContexts) { | 275 TEST_F(APIEventHandlerTest, MultipleContexts) { |
270 v8::HandleScope handle_scope(isolate()); | 276 v8::HandleScope handle_scope(isolate()); |
271 | 277 |
272 v8::Local<v8::Context> context_a = ContextLocal(); | 278 v8::Local<v8::Context> context_a = ContextLocal(); |
273 v8::Local<v8::Context> context_b = v8::Context::New(isolate()); | 279 v8::Local<v8::Context> context_b = v8::Context::New(isolate()); |
274 gin::ContextHolder holder_b(isolate()); | 280 gin::ContextHolder holder_b(isolate()); |
275 holder_b.SetContext(context_b); | 281 holder_b.SetContext(context_b); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 { | 347 { |
342 EXPECT_EQ("\"result_a:alpha\"", | 348 EXPECT_EQ("\"result_a:alpha\"", |
343 GetStringPropertyFromObject(context_a->Global(), context_a, | 349 GetStringPropertyFromObject(context_a->Global(), context_a, |
344 "eventArgs")); | 350 "eventArgs")); |
345 } | 351 } |
346 { | 352 { |
347 EXPECT_EQ("\"result_b:beta\"", | 353 EXPECT_EQ("\"result_b:beta\"", |
348 GetStringPropertyFromObject(context_b->Global(), context_b, | 354 GetStringPropertyFromObject(context_b->Global(), context_b, |
349 "eventArgs")); | 355 "eventArgs")); |
350 } | 356 } |
| 357 |
| 358 handler.InvalidateContext(context_a); |
| 359 handler.InvalidateContext(context_b); |
351 } | 360 } |
352 | 361 |
353 TEST_F(APIEventHandlerTest, DifferentCallingMethods) { | 362 TEST_F(APIEventHandlerTest, DifferentCallingMethods) { |
354 v8::HandleScope handle_scope(isolate()); | 363 v8::HandleScope handle_scope(isolate()); |
355 v8::Local<v8::Context> context = ContextLocal(); | 364 v8::Local<v8::Context> context = ContextLocal(); |
356 | 365 |
357 const char kEventName[] = "alpha"; | 366 const char kEventName[] = "alpha"; |
358 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), | 367 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), |
359 base::Bind(&DoNothingOnEventListenersChanged)); | 368 base::Bind(&DoNothingOnEventListenersChanged)); |
360 v8::Local<v8::Object> event = | 369 v8::Local<v8::Object> event = |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 " event.addListener(function listener() {\n" | 405 " event.addListener(function listener() {\n" |
397 " event.hasListener(listener);\n" | 406 " event.hasListener(listener);\n" |
398 " });\n" | 407 " });\n" |
399 "})"; | 408 "})"; |
400 { | 409 { |
401 v8::Local<v8::Value> args[] = {event}; | 410 v8::Local<v8::Value> args[] = {event}; |
402 RunFunction(FunctionFromString(context, kAddListenerOnEventWithCapture), | 411 RunFunction(FunctionFromString(context, kAddListenerOnEventWithCapture), |
403 context, 1, args); | 412 context, 1, args); |
404 } | 413 } |
405 EXPECT_EQ(2u, handler.GetNumEventListenersForTesting(kEventName, context)); | 414 EXPECT_EQ(2u, handler.GetNumEventListenersForTesting(kEventName, context)); |
| 415 |
| 416 handler.InvalidateContext(context); |
406 } | 417 } |
407 | 418 |
408 TEST_F(APIEventHandlerTest, TestDispatchFromJs) { | 419 TEST_F(APIEventHandlerTest, TestDispatchFromJs) { |
409 v8::HandleScope handle_scope(isolate()); | 420 v8::HandleScope handle_scope(isolate()); |
410 v8::Local<v8::Context> context = ContextLocal(); | 421 v8::Local<v8::Context> context = ContextLocal(); |
411 | 422 |
412 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), | 423 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), |
413 base::Bind(&DoNothingOnEventListenersChanged)); | 424 base::Bind(&DoNothingOnEventListenersChanged)); |
414 v8::Local<v8::Object> event = handler.CreateEventInstance("alpha", context); | 425 v8::Local<v8::Object> event = handler.CreateEventInstance("alpha", context); |
415 ASSERT_FALSE(event.IsEmpty()); | 426 ASSERT_FALSE(event.IsEmpty()); |
(...skipping 20 matching lines...) Expand all Loading... |
436 context, | 447 context, |
437 "(function(event) { event.dispatch(42, 'foo', {bar: 'baz'}); })"); | 448 "(function(event) { event.dispatch(42, 'foo', {bar: 'baz'}); })"); |
438 { | 449 { |
439 v8::Local<v8::Value> argv[] = {event}; | 450 v8::Local<v8::Value> argv[] = {event}; |
440 RunFunctionOnGlobal(fire_event_function, context, arraysize(argv), argv); | 451 RunFunctionOnGlobal(fire_event_function, context, arraysize(argv), argv); |
441 } | 452 } |
442 | 453 |
443 EXPECT_EQ("[42,\"foo\",{\"bar\":\"baz\"}]", | 454 EXPECT_EQ("[42,\"foo\",{\"bar\":\"baz\"}]", |
444 GetStringPropertyFromObject( | 455 GetStringPropertyFromObject( |
445 context->Global(), context, "eventArgs")); | 456 context->Global(), context, "eventArgs")); |
| 457 |
| 458 handler.InvalidateContext(context); |
446 } | 459 } |
447 | 460 |
448 // Test listeners that remove themselves in their handling of the event. | 461 // Test listeners that remove themselves in their handling of the event. |
449 TEST_F(APIEventHandlerTest, RemovingListenersWhileHandlingEvent) { | 462 TEST_F(APIEventHandlerTest, RemovingListenersWhileHandlingEvent) { |
450 v8::HandleScope handle_scope(isolate()); | 463 v8::HandleScope handle_scope(isolate()); |
451 v8::Local<v8::Context> context = ContextLocal(); | 464 v8::Local<v8::Context> context = ContextLocal(); |
452 | 465 |
453 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), | 466 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), |
454 base::Bind(&DoNothingOnEventListenersChanged)); | 467 base::Bind(&DoNothingOnEventListenersChanged)); |
455 const char kEventName[] = "alpha"; | 468 const char kEventName[] = "alpha"; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
492 v8::Local<v8::Value> argv[] = {event, listener}; | 505 v8::Local<v8::Value> argv[] = {event, listener}; |
493 RunFunctionOnGlobal(add_listener_function, context, arraysize(argv), argv); | 506 RunFunctionOnGlobal(add_listener_function, context, arraysize(argv), argv); |
494 } | 507 } |
495 | 508 |
496 // Fire the event. All listeners should be removed (and we shouldn't crash). | 509 // Fire the event. All listeners should be removed (and we shouldn't crash). |
497 EXPECT_EQ(kNumListeners, | 510 EXPECT_EQ(kNumListeners, |
498 handler.GetNumEventListenersForTesting(kEventName, context)); | 511 handler.GetNumEventListenersForTesting(kEventName, context)); |
499 handler.FireEventInContext(kEventName, context, base::ListValue()); | 512 handler.FireEventInContext(kEventName, context, base::ListValue()); |
500 EXPECT_EQ(0u, handler.GetNumEventListenersForTesting(kEventName, context)); | 513 EXPECT_EQ(0u, handler.GetNumEventListenersForTesting(kEventName, context)); |
501 | 514 |
| 515 handler.InvalidateContext(context); |
502 // TODO(devlin): Another possible test: register listener a and listener b, | 516 // TODO(devlin): Another possible test: register listener a and listener b, |
503 // where a removes b and b removes a. Theoretically, only one should be | 517 // where a removes b and b removes a. Theoretically, only one should be |
504 // notified. Investigate what we currently do in JS-style bindings. | 518 // notified. Investigate what we currently do in JS-style bindings. |
505 } | 519 } |
506 | 520 |
507 // Test an event listener throwing an exception. | 521 // Test an event listener throwing an exception. |
508 TEST_F(APIEventHandlerTest, TestEventListenersThrowingExceptions) { | 522 TEST_F(APIEventHandlerTest, TestEventListenersThrowingExceptions) { |
509 // The default test util methods (RunFunction*) assume no errors will ever | 523 // The default test util methods (RunFunction*) assume no errors will ever |
510 // be encountered. Instead, use an implementation that allows errors. | 524 // be encountered. Instead, use an implementation that allows errors. |
511 auto run_js_and_expect_error = [](v8::Local<v8::Function> function, | 525 auto run_js_and_expect_error = [](v8::Local<v8::Function> function, |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
576 ASSERT_TRUE(event_args); | 590 ASSERT_TRUE(event_args); |
577 handler.FireEventInContext(kEventName, context, *event_args); | 591 handler.FireEventInContext(kEventName, context, *event_args); |
578 | 592 |
579 // An exception should have been thrown by the first listener and the second | 593 // An exception should have been thrown by the first listener and the second |
580 // listener should have recorded the event arguments. | 594 // listener should have recorded the event arguments. |
581 EXPECT_EQ("true", GetStringPropertyFromObject(context->Global(), context, | 595 EXPECT_EQ("true", GetStringPropertyFromObject(context->Global(), context, |
582 "didThrow")); | 596 "didThrow")); |
583 EXPECT_EQ("[42]", GetStringPropertyFromObject(context->Global(), context, | 597 EXPECT_EQ("[42]", GetStringPropertyFromObject(context->Global(), context, |
584 "eventArgs")); | 598 "eventArgs")); |
585 EXPECT_TRUE(did_throw); | 599 EXPECT_TRUE(did_throw); |
| 600 |
| 601 handler.InvalidateContext(context); |
586 } | 602 } |
587 | 603 |
588 // Tests being notified as listeners are added or removed from events. | 604 // Tests being notified as listeners are added or removed from events. |
589 TEST_F(APIEventHandlerTest, CallbackNotifications) { | 605 TEST_F(APIEventHandlerTest, CallbackNotifications) { |
590 v8::HandleScope handle_scope(isolate()); | 606 v8::HandleScope handle_scope(isolate()); |
591 | 607 |
592 v8::Local<v8::Context> context_a = ContextLocal(); | 608 v8::Local<v8::Context> context_a = ContextLocal(); |
593 v8::Local<v8::Context> context_b = v8::Context::New(isolate()); | 609 v8::Local<v8::Context> context_b = v8::Context::New(isolate()); |
594 gin::ContextHolder holder_b(isolate()); | 610 gin::ContextHolder holder_b(isolate()); |
595 holder_b.SetContext(context_b); | 611 holder_b.SetContext(context_b); |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
698 v8::Local<v8::Function> add_listener = | 714 v8::Local<v8::Function> add_listener = |
699 FunctionFromString(context_b, kAddListenerFunction); | 715 FunctionFromString(context_b, kAddListenerFunction); |
700 v8::Local<v8::Function> listener = | 716 v8::Local<v8::Function> listener = |
701 FunctionFromString(context_b, "(function() {})"); | 717 FunctionFromString(context_b, "(function() {})"); |
702 v8::Local<v8::Value> argv[] = {event1_b, listener}; | 718 v8::Local<v8::Value> argv[] = {event1_b, listener}; |
703 RunFunction(add_listener, context_b, arraysize(argv), argv); | 719 RunFunction(add_listener, context_b, arraysize(argv), argv); |
704 ::testing::Mock::VerifyAndClearExpectations(&change_handler); | 720 ::testing::Mock::VerifyAndClearExpectations(&change_handler); |
705 } | 721 } |
706 EXPECT_EQ(1u, | 722 EXPECT_EQ(1u, |
707 handler.GetNumEventListenersForTesting(kEventName1, context_b)); | 723 handler.GetNumEventListenersForTesting(kEventName1, context_b)); |
| 724 |
| 725 // When the contexts are invalidated, we should receive listener removed |
| 726 // notifications. |
| 727 EXPECT_CALL( |
| 728 change_handler, |
| 729 Run(kEventName1, binding::EventListenersChanged::NO_LISTENERS, context_a)) |
| 730 .Times(1); |
| 731 EXPECT_CALL( |
| 732 change_handler, |
| 733 Run(kEventName2, binding::EventListenersChanged::NO_LISTENERS, context_a)) |
| 734 .Times(1); |
| 735 handler.InvalidateContext(context_a); |
| 736 ::testing::Mock::VerifyAndClearExpectations(&change_handler); |
| 737 |
| 738 EXPECT_CALL( |
| 739 change_handler, |
| 740 Run(kEventName1, binding::EventListenersChanged::NO_LISTENERS, context_b)) |
| 741 .Times(1); |
| 742 handler.InvalidateContext(context_b); |
| 743 ::testing::Mock::VerifyAndClearExpectations(&change_handler); |
708 } | 744 } |
709 | 745 |
710 } // namespace extensions | 746 } // namespace extensions |
OLD | NEW |