Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(524)

Side by Side Diff: extensions/renderer/api_event_handler_unittest.cc

Issue 2613093002: [Extension Bindings] Test event listeners throwing exceptions (Closed)
Patch Set: Remove listener Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | extensions/renderer/event_emitter.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/memory/ptr_util.h" 9 #include "base/memory/ptr_util.h"
9 #include "base/values.h" 10 #include "base/values.h"
10 #include "extensions/renderer/api_binding_test.h" 11 #include "extensions/renderer/api_binding_test.h"
11 #include "extensions/renderer/api_binding_test_util.h" 12 #include "extensions/renderer/api_binding_test_util.h"
12 #include "gin/converter.h" 13 #include "gin/converter.h"
13 #include "gin/public/context_holder.h" 14 #include "gin/public/context_holder.h"
14 15
15 namespace extensions { 16 namespace extensions {
16 17
17 using APIEventHandlerTest = APIBindingTest; 18 using APIEventHandlerTest = APIBindingTest;
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 // Test listeners that remove themselves in their handling of the event. 430 // Test listeners that remove themselves in their handling of the event.
430 TEST_F(APIEventHandlerTest, RemovingListenersWhileHandlingEvent) { 431 TEST_F(APIEventHandlerTest, RemovingListenersWhileHandlingEvent) {
431 v8::HandleScope handle_scope(isolate()); 432 v8::HandleScope handle_scope(isolate());
432 v8::Local<v8::Context> context = ContextLocal(); 433 v8::Local<v8::Context> context = ContextLocal();
433 434
434 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); 435 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
435 const char kEventName[] = "alpha"; 436 const char kEventName[] = "alpha";
436 v8::Local<v8::Object> event = 437 v8::Local<v8::Object> event =
437 handler.CreateEventInstance(kEventName, context); 438 handler.CreateEventInstance(kEventName, context);
438 ASSERT_FALSE(event.IsEmpty()); 439 ASSERT_FALSE(event.IsEmpty());
439
440 { 440 {
441 // Cache the event object on the global in order to allow for easy removal. 441 // Cache the event object on the global in order to allow for easy removal.
442 v8::Local<v8::Function> set_event_on_global = 442 v8::Local<v8::Function> set_event_on_global =
443 FunctionFromString( 443 FunctionFromString(
444 context, 444 context,
445 "(function(event) { this.testEvent = event; })"); 445 "(function(event) { this.testEvent = event; })");
446 v8::Local<v8::Value> args[] = {event}; 446 v8::Local<v8::Value> args[] = {event};
447 RunFunctionOnGlobal(set_event_on_global, context, arraysize(args), args); 447 RunFunctionOnGlobal(set_event_on_global, context, arraysize(args), args);
448 EXPECT_EQ(event, 448 EXPECT_EQ(event,
449 GetPropertyFromObject(context->Global(), context, "testEvent")); 449 GetPropertyFromObject(context->Global(), context, "testEvent"));
(...skipping 28 matching lines...) Expand all
478 EXPECT_EQ(kNumListeners, 478 EXPECT_EQ(kNumListeners,
479 handler.GetNumEventListenersForTesting(kEventName, context)); 479 handler.GetNumEventListenersForTesting(kEventName, context));
480 handler.FireEventInContext(kEventName, context, base::ListValue()); 480 handler.FireEventInContext(kEventName, context, base::ListValue());
481 EXPECT_EQ(0u, handler.GetNumEventListenersForTesting(kEventName, context)); 481 EXPECT_EQ(0u, handler.GetNumEventListenersForTesting(kEventName, context));
482 482
483 // TODO(devlin): Another possible test: register listener a and listener b, 483 // TODO(devlin): Another possible test: register listener a and listener b,
484 // where a removes b and b removes a. Theoretically, only one should be 484 // where a removes b and b removes a. Theoretically, only one should be
485 // notified. Investigate what we currently do in JS-style bindings. 485 // notified. Investigate what we currently do in JS-style bindings.
486 } 486 }
487 487
488 // Test an event listener throwing an exception.
489 TEST_F(APIEventHandlerTest, TestEventListenersThrowingExceptions) {
490 // The default test util methods (RunFunction*) assume no errors will ever
491 // be encountered. Instead, use an implementation that allows errors.
492 auto run_js_and_expect_error = [](v8::Local<v8::Function> function,
493 v8::Local<v8::Context> context, int argc,
494 v8::Local<v8::Value> argv[]) {
495 v8::MaybeLocal<v8::Value> maybe_result =
496 function->Call(context, context->Global(), argc, argv);
497 v8::Global<v8::Value> result;
498 v8::Local<v8::Value> local;
499 if (maybe_result.ToLocal(&local))
500 result.Reset(context->GetIsolate(), local);
501 };
502
503 v8::HandleScope handle_scope(isolate());
504 v8::Local<v8::Context> context = ContextLocal();
505
506 APIEventHandler handler(base::Bind(run_js_and_expect_error));
507 const char kEventName[] = "alpha";
508 v8::Local<v8::Object> event =
509 handler.CreateEventInstance(kEventName, context);
510 ASSERT_FALSE(event.IsEmpty());
511
512 bool did_throw = false;
513 auto message_listener = [](v8::Local<v8::Message> message,
514 v8::Local<v8::Value> data) {
515 ASSERT_FALSE(data.IsEmpty());
516 ASSERT_TRUE(data->IsExternal());
517 bool* did_throw = static_cast<bool*>(data.As<v8::External>()->Value());
518 *did_throw = true;
519 EXPECT_EQ("Uncaught Error: Event handler error",
520 gin::V8ToString(message->Get()));
521 };
522
523 isolate()->AddMessageListener(message_listener,
524 v8::External::New(isolate(), &did_throw));
525 base::ScopedClosureRunner remove_message_listener(base::Bind(
526 [](v8::Isolate* isolate, v8::MessageCallback listener) {
527 isolate->RemoveMessageListeners(listener);
528 },
529 isolate(), message_listener));
530
531 // A listener that will throw an exception. We guarantee that we throw the
532 // exception first so that we don't rely on event listener ordering.
533 const char kListenerFunction[] =
534 "(function() {\n"
535 " if (!this.didThrow) {\n"
536 " this.didThrow = true;\n"
537 " throw new Error('Event handler error');\n"
538 " }\n"
539 " this.eventArgs = Array.from(arguments);\n"
540 "});";
541
542 const char kAddListenerFunction[] =
543 "(function(event, listener) { event.addListener(listener); })";
544 v8::Local<v8::Function> add_listener_function =
545 FunctionFromString(context, kAddListenerFunction);
546
547 for (int i = 0; i < 2; ++i) {
548 v8::Local<v8::Function> listener =
549 FunctionFromString(context, kListenerFunction);
550 v8::Local<v8::Value> argv[] = {event, listener};
551 RunFunctionOnGlobal(add_listener_function, context, arraysize(argv), argv);
552 }
553 EXPECT_EQ(2u, handler.GetNumEventListenersForTesting(kEventName, context));
554
555 std::unique_ptr<base::ListValue> event_args = ListValueFromString("[42]");
556 ASSERT_TRUE(event_args);
557 handler.FireEventInContext(kEventName, context, *event_args);
558
559 // An exception should have been thrown by the first listener and the second
560 // listener should have recorded the event arguments.
561 EXPECT_EQ("true", GetStringPropertyFromObject(context->Global(), context,
562 "didThrow"));
563 EXPECT_EQ("[42]", GetStringPropertyFromObject(context->Global(), context,
564 "eventArgs"));
565 EXPECT_TRUE(did_throw);
566 }
567
488 } // namespace extensions 568 } // namespace extensions
OLDNEW
« no previous file with comments | « no previous file | extensions/renderer/event_emitter.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698