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" |
11 #include "base/values.h" | 11 #include "base/values.h" |
12 #include "extensions/renderer/api_binding_test.h" | 12 #include "extensions/renderer/api_binding_test.h" |
13 #include "extensions/renderer/api_binding_test_util.h" | 13 #include "extensions/renderer/api_binding_test_util.h" |
| 14 #include "gin/arguments.h" |
14 #include "gin/converter.h" | 15 #include "gin/converter.h" |
15 #include "gin/public/context_holder.h" | 16 #include "gin/public/context_holder.h" |
16 #include "testing/gmock/include/gmock/gmock.h" | 17 #include "testing/gmock/include/gmock/gmock.h" |
17 | 18 |
18 namespace extensions { | 19 namespace extensions { |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
22 using MockEventChangeHandler = ::testing::StrictMock< | 23 using MockEventChangeHandler = ::testing::StrictMock< |
23 base::MockCallback<APIEventHandler::EventListenersChangedMethod>>; | 24 base::MockCallback<APIEventHandler::EventListenersChangedMethod>>; |
(...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
700 v8::Local<v8::Function> listener = | 701 v8::Local<v8::Function> listener = |
701 FunctionFromString(context_b, "(function() {})"); | 702 FunctionFromString(context_b, "(function() {})"); |
702 v8::Local<v8::Value> argv[] = {event1_b, listener}; | 703 v8::Local<v8::Value> argv[] = {event1_b, listener}; |
703 RunFunction(add_listener, context_b, arraysize(argv), argv); | 704 RunFunction(add_listener, context_b, arraysize(argv), argv); |
704 ::testing::Mock::VerifyAndClearExpectations(&change_handler); | 705 ::testing::Mock::VerifyAndClearExpectations(&change_handler); |
705 } | 706 } |
706 EXPECT_EQ(1u, | 707 EXPECT_EQ(1u, |
707 handler.GetNumEventListenersForTesting(kEventName1, context_b)); | 708 handler.GetNumEventListenersForTesting(kEventName1, context_b)); |
708 } | 709 } |
709 | 710 |
| 711 // Test registering an argument massager for a given event. |
| 712 TEST_F(APIEventHandlerTest, TestArgumentMassagers) { |
| 713 v8::HandleScope handle_scope(isolate()); |
| 714 v8::Local<v8::Context> context = ContextLocal(); |
| 715 |
| 716 const char kEventName[] = "alpha"; |
| 717 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), |
| 718 base::Bind(&DoNothingOnEventListenersChanged)); |
| 719 v8::Local<v8::Object> event = |
| 720 handler.CreateEventInstance(kEventName, context); |
| 721 ASSERT_FALSE(event.IsEmpty()); |
| 722 |
| 723 const char kArgumentMassager[] = |
| 724 "(function(originalArgs, dispatch) {\n" |
| 725 " this.originalArgs = originalArgs;\n" |
| 726 " dispatch(['primary', 'secondary']);\n" |
| 727 "});"; |
| 728 v8::Local<v8::Function> massager = |
| 729 FunctionFromString(context, kArgumentMassager); |
| 730 handler.RegisterArgumentMassager(context, "alpha", massager); |
| 731 |
| 732 const char kListenerFunction[] = |
| 733 "(function() { this.eventArgs = Array.from(arguments); })"; |
| 734 v8::Local<v8::Function> listener_function = |
| 735 FunctionFromString(context, kListenerFunction); |
| 736 ASSERT_FALSE(listener_function.IsEmpty()); |
| 737 |
| 738 { |
| 739 const char kAddListenerFunction[] = |
| 740 "(function(event, listener) { event.addListener(listener); })"; |
| 741 v8::Local<v8::Function> add_listener_function = |
| 742 FunctionFromString(context, kAddListenerFunction); |
| 743 v8::Local<v8::Value> argv[] = {event, listener_function}; |
| 744 RunFunction(add_listener_function, context, arraysize(argv), argv); |
| 745 } |
| 746 |
| 747 const char kArguments[] = "['first','second']"; |
| 748 std::unique_ptr<base::ListValue> event_args = ListValueFromString(kArguments); |
| 749 ASSERT_TRUE(event_args); |
| 750 handler.FireEventInContext(kEventName, context, *event_args); |
| 751 |
| 752 EXPECT_EQ( |
| 753 "[\"first\",\"second\"]", |
| 754 GetStringPropertyFromObject(context->Global(), context, "originalArgs")); |
| 755 EXPECT_EQ( |
| 756 "[\"primary\",\"secondary\"]", |
| 757 GetStringPropertyFromObject(context->Global(), context, "eventArgs")); |
| 758 } |
| 759 |
| 760 // Test registering an argument massager for a given event and dispatching |
| 761 // asynchronously. |
| 762 TEST_F(APIEventHandlerTest, TestArgumentMassagersAsyncDispatch) { |
| 763 v8::HandleScope handle_scope(isolate()); |
| 764 v8::Local<v8::Context> context = ContextLocal(); |
| 765 |
| 766 const char kEventName[] = "alpha"; |
| 767 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), |
| 768 base::Bind(&DoNothingOnEventListenersChanged)); |
| 769 v8::Local<v8::Object> event = |
| 770 handler.CreateEventInstance(kEventName, context); |
| 771 ASSERT_FALSE(event.IsEmpty()); |
| 772 |
| 773 const char kArgumentMassager[] = |
| 774 "(function(originalArgs, dispatch) {\n" |
| 775 " this.originalArgs = originalArgs;\n" |
| 776 " this.dispatch = dispatch;\n" |
| 777 "});"; |
| 778 v8::Local<v8::Function> massager = |
| 779 FunctionFromString(context, kArgumentMassager); |
| 780 handler.RegisterArgumentMassager(context, "alpha", massager); |
| 781 |
| 782 const char kListenerFunction[] = |
| 783 "(function() { this.eventArgs = Array.from(arguments); })"; |
| 784 v8::Local<v8::Function> listener_function = |
| 785 FunctionFromString(context, kListenerFunction); |
| 786 ASSERT_FALSE(listener_function.IsEmpty()); |
| 787 |
| 788 { |
| 789 const char kAddListenerFunction[] = |
| 790 "(function(event, listener) { event.addListener(listener); })"; |
| 791 v8::Local<v8::Function> add_listener_function = |
| 792 FunctionFromString(context, kAddListenerFunction); |
| 793 v8::Local<v8::Value> argv[] = {event, listener_function}; |
| 794 RunFunction(add_listener_function, context, arraysize(argv), argv); |
| 795 } |
| 796 |
| 797 const char kArguments[] = "['first','second']"; |
| 798 std::unique_ptr<base::ListValue> event_args = ListValueFromString(kArguments); |
| 799 ASSERT_TRUE(event_args); |
| 800 handler.FireEventInContext(kEventName, context, *event_args); |
| 801 |
| 802 // The massager should have been triggered, but since it doesn't call |
| 803 // dispatch(), the listener shouldn't have been notified. |
| 804 EXPECT_EQ( |
| 805 "[\"first\",\"second\"]", |
| 806 GetStringPropertyFromObject(context->Global(), context, "originalArgs")); |
| 807 EXPECT_EQ("undefined", GetStringPropertyFromObject(context->Global(), context, |
| 808 "eventArgs")); |
| 809 |
| 810 // Dispatch the event. |
| 811 v8::Local<v8::Value> dispatch_value = |
| 812 GetPropertyFromObject(context->Global(), context, "dispatch"); |
| 813 ASSERT_FALSE(dispatch_value.IsEmpty()); |
| 814 ASSERT_TRUE(dispatch_value->IsFunction()); |
| 815 v8::Local<v8::Value> dispatch_args[] = { |
| 816 V8ValueFromScriptSource(context, "['primary', 'secondary']"), |
| 817 }; |
| 818 RunFunction(dispatch_value.As<v8::Function>(), context, |
| 819 arraysize(dispatch_args), dispatch_args); |
| 820 |
| 821 EXPECT_EQ( |
| 822 "[\"primary\",\"secondary\"]", |
| 823 GetStringPropertyFromObject(context->Global(), context, "eventArgs")); |
| 824 } |
| 825 |
| 826 // Test registering an argument massager and never dispatching. |
| 827 TEST_F(APIEventHandlerTest, TestArgumentMassagersNeverDispatch) { |
| 828 v8::HandleScope handle_scope(isolate()); |
| 829 v8::Local<v8::Context> context = ContextLocal(); |
| 830 |
| 831 const char kEventName[] = "alpha"; |
| 832 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult), |
| 833 base::Bind(&DoNothingOnEventListenersChanged)); |
| 834 v8::Local<v8::Object> event = |
| 835 handler.CreateEventInstance(kEventName, context); |
| 836 ASSERT_FALSE(event.IsEmpty()); |
| 837 |
| 838 // A massager that never dispatches. |
| 839 const char kArgumentMassager[] = "(function(originalArgs, dispatch) {})"; |
| 840 v8::Local<v8::Function> massager = |
| 841 FunctionFromString(context, kArgumentMassager); |
| 842 handler.RegisterArgumentMassager(context, "alpha", massager); |
| 843 |
| 844 const char kListenerFunction[] = "(function() {})"; |
| 845 v8::Local<v8::Function> listener_function = |
| 846 FunctionFromString(context, kListenerFunction); |
| 847 ASSERT_FALSE(listener_function.IsEmpty()); |
| 848 |
| 849 const char kAddListenerFunction[] = |
| 850 "(function(event, listener) { event.addListener(listener); })"; |
| 851 v8::Local<v8::Function> add_listener_function = |
| 852 FunctionFromString(context, kAddListenerFunction); |
| 853 v8::Local<v8::Value> argv[] = {event, listener_function}; |
| 854 RunFunction(add_listener_function, context, arraysize(argv), argv); |
| 855 |
| 856 handler.FireEventInContext(kEventName, context, base::ListValue()); |
| 857 |
| 858 // Nothing should blow up. (We tested in the previous test that the event |
| 859 // isn't notified without calling dispatch, so all there is to test here is |
| 860 // that we don't crash.) |
| 861 } |
| 862 |
710 } // namespace extensions | 863 } // namespace extensions |
OLD | NEW |