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

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

Issue 2469593002: [Extensions Bindings] Add Events support (Closed)
Patch Set: . Created 4 years, 1 month 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "extensions/renderer/api_event_handler.h"
6
7 #include "base/bind.h"
8 #include "base/memory/ptr_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/values.h"
11 #include "extensions/renderer/api_binding_test_util.h"
12 #include "gin/converter.h"
13 #include "gin/public/context_holder.h"
14 #include "gin/public/isolate_holder.h"
15 #include "gin/test/v8_test.h"
16 #include "gin/try_catch.h"
17
18 namespace extensions {
19
20 class APIEventHandlerTest : public gin::V8Test {
21 protected:
22 APIEventHandlerTest() {}
23 ~APIEventHandlerTest() override {}
24
25 void SetUp() override {
26 gin::V8Test::SetUp();
27 v8::HandleScope handle_scope(instance_->isolate());
28 holder_ = base::MakeUnique<gin::ContextHolder>(instance_->isolate());
29 holder_->SetContext(
30 v8::Local<v8::Context>::New(instance_->isolate(), context_));
31 }
32
33 void TearDown() override {
34 holder_.reset();
35 gin::V8Test::TearDown();
36 }
37
38 void CallFunctionOnObject(v8::Local<v8::Context> context,
39 v8::Local<v8::Object> object,
40 const std::string& script_source) {
41 std::string wrapped_script_source =
42 base::StringPrintf("(function(obj) { %s })", script_source.c_str());
43 v8::Local<v8::Function> func =
44 FunctionFromString(context, wrapped_script_source);
45 ASSERT_FALSE(func.IsEmpty());
46
47 v8::Local<v8::Value> argv[] = {object};
48 RunFunction(func, context, object, 1, argv);
49 }
50
51 private:
52 std::unique_ptr<gin::ContextHolder> holder_;
53
54 DISALLOW_COPY_AND_ASSIGN(APIEventHandlerTest);
55 };
56
57 // Tests adding, removing, and querying event listeners by calling the
58 // associated methods on the JS object.
59 TEST_F(APIEventHandlerTest, AddingRemovingAndQueryingEventListeners) {
60 const char kEventName[] = "alpha";
61 v8::Isolate* isolate = instance_->isolate();
62 v8::HandleScope handle_scope(instance_->isolate());
63 v8::Local<v8::Context> context =
64 v8::Local<v8::Context>::New(instance_->isolate(), context_);
65
66 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
67 v8::Local<v8::Object> event =
68 handler.CreateEventInstance(kEventName, context);
69 ASSERT_FALSE(event.IsEmpty());
70
71 EXPECT_TRUE(handler.GetEventListenersForTesting(kEventName, context).empty());
72
73 const char kListenerFunction[] = "(function() {})";
74 v8::Local<v8::Function> listener_function =
75 FunctionFromString(context, kListenerFunction);
76 ASSERT_FALSE(listener_function.IsEmpty());
77
78 const char kAddListenerFunction[] =
79 "(function(event, listener) { event.addListener(listener); })";
80 v8::Local<v8::Function> add_listener_function =
81 FunctionFromString(context, kAddListenerFunction);
82
83 {
84 v8::Local<v8::Value> argv[] = {event, listener_function};
85 RunFunction(add_listener_function, context, arraysize(argv), argv);
86 }
87 // There should only be one listener on the event.
88 EXPECT_EQ(1u,
89 handler.GetEventListenersForTesting(kEventName, context).size());
90
91 {
92 v8::Local<v8::Value> argv[] = {event, listener_function};
93 RunFunction(add_listener_function, context, arraysize(argv), argv);
94 }
95 // Trying to add the same listener again should be a no-op.
96 EXPECT_EQ(1u,
97 handler.GetEventListenersForTesting(kEventName, context).size());
98
99 // Test hasListener returns true for a listener that is present.
100 const char kHasListenerFunction[] =
101 "(function(event, listener) { return event.hasListener(listener); })";
102 v8::Local<v8::Function> has_listener_function =
103 FunctionFromString(context, kHasListenerFunction);
104 {
105 v8::Local<v8::Value> argv[] = {event, listener_function};
106 v8::Local<v8::Value> result =
107 RunFunction(has_listener_function, context, arraysize(argv), argv);
108 bool has_listener = false;
109 EXPECT_TRUE(gin::Converter<bool>::FromV8(isolate, result, &has_listener));
110 EXPECT_TRUE(has_listener);
111 }
112
113 // Test that hasListener returns false for a listener that isn't present.
114 {
115 v8::Local<v8::Function> not_a_listener =
116 FunctionFromString(context, "(function() {})");
117 v8::Local<v8::Value> argv[] = {event, not_a_listener};
118 v8::Local<v8::Value> result =
119 RunFunction(has_listener_function, context, arraysize(argv), argv);
120 bool has_listener = false;
121 EXPECT_TRUE(gin::Converter<bool>::FromV8(isolate, result, &has_listener));
122 EXPECT_FALSE(has_listener);
123 }
124
125 // Test hasListeners returns true
126 const char kHasListenersFunction[] =
127 "(function(event) { return event.hasListeners(); })";
128 v8::Local<v8::Function> has_listeners_function =
129 FunctionFromString(context, kHasListenersFunction);
130 {
131 v8::Local<v8::Value> argv[] = {event};
132 v8::Local<v8::Value> result =
133 RunFunction(has_listeners_function, context, arraysize(argv), argv);
134 bool has_listeners = false;
135 EXPECT_TRUE(gin::Converter<bool>::FromV8(isolate, result, &has_listeners));
136 EXPECT_TRUE(has_listeners);
137 }
138
139 const char kRemoveListenerFunction[] =
140 "(function(event, listener) { event.removeListener(listener); })";
141 v8::Local<v8::Function> remove_listener_function =
142 FunctionFromString(context, kRemoveListenerFunction);
143 {
144 v8::Local<v8::Value> argv[] = {event, listener_function};
145 RunFunction(remove_listener_function, context, arraysize(argv), argv);
146 }
147 EXPECT_TRUE(handler.GetEventListenersForTesting(kEventName, context).empty());
148
149 {
150 v8::Local<v8::Value> argv[] = {event};
151 v8::Local<v8::Value> result =
152 RunFunction(has_listener_function, context, arraysize(argv), argv);
153 bool has_listeners = false;
154 EXPECT_TRUE(gin::Converter<bool>::FromV8(isolate, result, &has_listeners));
155 EXPECT_FALSE(has_listeners);
156 }
157 }
158
159 // Tests listening for and firing different events.
160 TEST_F(APIEventHandlerTest, FiringEvents) {
161 const char kAlphaName[] = "alpha";
162 const char kBetaName[] = "beta";
163 v8::HandleScope handle_scope(instance_->isolate());
164 v8::Local<v8::Context> context =
165 v8::Local<v8::Context>::New(instance_->isolate(), context_);
166
167 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
168 v8::Local<v8::Object> alpha_event =
169 handler.CreateEventInstance(kAlphaName, context);
170 v8::Local<v8::Object> beta_event =
171 handler.CreateEventInstance(kBetaName, context);
172 ASSERT_FALSE(alpha_event.IsEmpty());
173 ASSERT_FALSE(beta_event.IsEmpty());
174
175 const char kAlphaListenerFunction1[] =
176 "(function() {\n"
177 " if (!this.alphaCount1) this.alphaCount1 = 0;\n"
178 " ++this.alphaCount1;\n"
179 "});\n";
180 v8::Local<v8::Function> alpha_listener1 =
181 FunctionFromString(context, kAlphaListenerFunction1);
182 const char kAlphaListenerFunction2[] =
183 "(function() {\n"
184 " if (!this.alphaCount2) this.alphaCount2 = 0;\n"
185 " ++this.alphaCount2;\n"
186 "});\n";
187 v8::Local<v8::Function> alpha_listener2 =
188 FunctionFromString(context, kAlphaListenerFunction2);
189 const char kBetaListenerFunction[] =
190 "(function() {\n"
191 " if (!this.betaCount) this.betaCount = 0;\n"
192 " ++this.betaCount;\n"
193 "});\n";
194 v8::Local<v8::Function> beta_listener =
195 FunctionFromString(context, kBetaListenerFunction);
196 ASSERT_FALSE(alpha_listener1.IsEmpty());
197 ASSERT_FALSE(alpha_listener2.IsEmpty());
198 ASSERT_FALSE(beta_listener.IsEmpty());
199
200 {
201 const char kAddListenerFunction[] =
202 "(function(event, listener) { event.addListener(listener); })";
203 v8::Local<v8::Function> add_listener_function =
204 FunctionFromString(context, kAddListenerFunction);
205 {
206 v8::Local<v8::Value> argv[] = {alpha_event, alpha_listener1};
207 RunFunction(add_listener_function, context, arraysize(argv), argv);
208 }
209 {
210 v8::Local<v8::Value> argv[] = {alpha_event, alpha_listener2};
211 RunFunction(add_listener_function, context, arraysize(argv), argv);
212 }
213 {
214 v8::Local<v8::Value> argv[] = {beta_event, beta_listener};
215 RunFunction(add_listener_function, context, arraysize(argv), argv);
216 }
217 }
218
219 EXPECT_EQ(2u,
220 handler.GetEventListenersForTesting(kAlphaName, context).size());
221 EXPECT_EQ(1u, handler.GetEventListenersForTesting(kBetaName, context).size());
222
223 auto get_fired_count = [&context](const char* name) {
224 v8::Local<v8::Value> res =
225 GetPropertyFromObject(context->Global(), context, name);
226 if (res->IsUndefined())
227 return 0;
228 int32_t count = 0;
229 EXPECT_TRUE(
230 gin::Converter<int32_t>::FromV8(context->GetIsolate(), res, &count))
231 << name;
232 return count;
233 };
234
235 EXPECT_EQ(0, get_fired_count("alphaCount1"));
236 EXPECT_EQ(0, get_fired_count("alphaCount2"));
237 EXPECT_EQ(0, get_fired_count("betaCount"));
238
239 handler.FireEventInContext(kAlphaName, context, base::ListValue());
240 EXPECT_EQ(2u,
241 handler.GetEventListenersForTesting(kAlphaName, context).size());
242 EXPECT_EQ(1u, handler.GetEventListenersForTesting(kBetaName, context).size());
243
244 EXPECT_EQ(1, get_fired_count("alphaCount1"));
245 EXPECT_EQ(1, get_fired_count("alphaCount2"));
246 EXPECT_EQ(0, get_fired_count("betaCount"));
247
248 handler.FireEventInContext(kAlphaName, context, base::ListValue());
249 EXPECT_EQ(2, get_fired_count("alphaCount1"));
250 EXPECT_EQ(2, get_fired_count("alphaCount2"));
251 EXPECT_EQ(0, get_fired_count("betaCount"));
252
253 handler.FireEventInContext(kBetaName, context, base::ListValue());
254 EXPECT_EQ(2, get_fired_count("alphaCount1"));
255 EXPECT_EQ(2, get_fired_count("alphaCount2"));
256 EXPECT_EQ(1, get_fired_count("betaCount"));
257 }
258
259 // Tests firing events with arguments.
260 TEST_F(APIEventHandlerTest, EventArguments) {
261 v8::Isolate* isolate = instance_->isolate();
262 v8::HandleScope handle_scope(isolate);
263 v8::Local<v8::Context> context =
264 v8::Local<v8::Context>::New(isolate, context_);
265
266 const char kEventName[] = "alpha";
267 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
268 v8::Local<v8::Object> event =
269 handler.CreateEventInstance(kEventName, context);
270 ASSERT_FALSE(event.IsEmpty());
271
272 const char kListenerFunction[] =
273 "(function() { this.eventArgs = Array.from(arguments); })";
274 v8::Local<v8::Function> listener_function =
275 FunctionFromString(context, kListenerFunction);
276 ASSERT_FALSE(listener_function.IsEmpty());
277
278 {
279 const char kAddListenerFunction[] =
280 "(function(event, listener) { event.addListener(listener); })";
281 v8::Local<v8::Function> add_listener_function =
282 FunctionFromString(context, kAddListenerFunction);
283 v8::Local<v8::Value> argv[] = {event, listener_function};
284 RunFunction(add_listener_function, context, arraysize(argv), argv);
285 }
286
287 const char kArguments[] = "['foo',1,{'prop1':'bar'}]";
288 std::unique_ptr<base::ListValue> event_args = ListValueFromString(kArguments);
289 ASSERT_TRUE(event_args);
290 handler.FireEventInContext(kEventName, context, *event_args);
291
292 std::unique_ptr<base::Value> result =
293 GetBaseValuePropertyFromObject(context->Global(), context, "eventArgs");
294 ASSERT_TRUE(result);
295 EXPECT_EQ(ReplaceSingleQuotes(kArguments), ValueToString(*result));
296 }
297
298 // Test dispatching events to multiple contexts.
299 TEST_F(APIEventHandlerTest, MultipleContexts) {
300 v8::Isolate* isolate = instance_->isolate();
301 v8::HandleScope handle_scope(instance_->isolate());
302
303 v8::Local<v8::Context> context_a =
304 v8::Local<v8::Context>::New(isolate, context_);
305 v8::Local<v8::Context> context_b = v8::Context::New(isolate);
306 gin::ContextHolder holder_b(isolate);
307 holder_b.SetContext(context_b);
308
309 const char kEventName[] = "onFoo";
310
311 APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
312
313 v8::Local<v8::Function> listener_a = FunctionFromString(
314 context_a, "(function(arg) { this.eventArgs = arg + 'alpha'; })");
315 ASSERT_FALSE(listener_a.IsEmpty());
316 v8::Local<v8::Function> listener_b = FunctionFromString(
317 context_b, "(function(arg) { this.eventArgs = arg + 'beta'; })");
318 ASSERT_FALSE(listener_b.IsEmpty());
319
320 // Create two instances of the same event in different contexts.
321 v8::Local<v8::Object> event_a =
322 handler.CreateEventInstance(kEventName, context_a);
323 ASSERT_FALSE(event_a.IsEmpty());
324 v8::Local<v8::Object> event_b =
325 handler.CreateEventInstance(kEventName, context_b);
326 ASSERT_FALSE(event_b.IsEmpty());
327
328 // Add two separate listeners to the event, one in each context.
329 const char kAddListenerFunction[] =
330 "(function(event, listener) { event.addListener(listener); })";
331 {
332 v8::Local<v8::Function> add_listener_a =
333 FunctionFromString(context_a, kAddListenerFunction);
334 v8::Local<v8::Value> argv[] = {event_a, listener_a};
335 RunFunction(add_listener_a, context_a, arraysize(argv), argv);
336 }
337 EXPECT_EQ(1u,
338 handler.GetEventListenersForTesting(kEventName, context_a).size());
339 EXPECT_EQ(0u,
340 handler.GetEventListenersForTesting(kEventName, context_b).size());
341
342 {
343 v8::Local<v8::Function> add_listener_b =
344 FunctionFromString(context_b, kAddListenerFunction);
345 v8::Local<v8::Value> argv[] = {event_b, listener_b};
346 RunFunction(add_listener_b, context_b, arraysize(argv), argv);
347 }
348 EXPECT_EQ(1u,
349 handler.GetEventListenersForTesting(kEventName, context_a).size());
350 EXPECT_EQ(1u,
351 handler.GetEventListenersForTesting(kEventName, context_b).size());
352
353 // Dispatch the event in context_a - the listener in context_b should not be
354 // notified.
355 std::unique_ptr<base::ListValue> arguments_a =
356 ListValueFromString("['result_a:']");
357 ASSERT_TRUE(arguments_a);
358
359 handler.FireEventInContext(kEventName, context_a, *arguments_a);
360 {
361 std::unique_ptr<base::Value> result_a = GetBaseValuePropertyFromObject(
362 context_a->Global(), context_a, "eventArgs");
363 ASSERT_TRUE(result_a);
364 EXPECT_EQ("\"result_a:alpha\"", ValueToString(*result_a));
365 }
366 {
367 v8::Local<v8::Value> result_b =
368 GetPropertyFromObject(context_b->Global(), context_b, "eventArgs");
369 ASSERT_FALSE(result_b.IsEmpty());
370 EXPECT_TRUE(result_b->IsUndefined());
371 }
372
373 // Dispatch the event in context_b - the listener in context_a should not be
374 // notified.
375 std::unique_ptr<base::ListValue> arguments_b =
376 ListValueFromString("['result_b:']");
377 ASSERT_TRUE(arguments_b);
378 handler.FireEventInContext(kEventName, context_b, *arguments_b);
379 {
380 std::unique_ptr<base::Value> result_a = GetBaseValuePropertyFromObject(
381 context_a->Global(), context_a, "eventArgs");
382 ASSERT_TRUE(result_a);
383 EXPECT_EQ("\"result_a:alpha\"", ValueToString(*result_a));
384 }
385 {
386 std::unique_ptr<base::Value> result_b = GetBaseValuePropertyFromObject(
387 context_b->Global(), context_b, "eventArgs");
388 ASSERT_TRUE(result_b);
389 EXPECT_EQ("\"result_b:beta\"", ValueToString(*result_b));
390 }
391 }
392
393 } // namespace extensions
OLDNEW
« extensions/renderer/api_event_handler.cc ('K') | « extensions/renderer/api_event_handler.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698