OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 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_listeners.h" |
| 6 |
| 7 #include "base/test/mock_callback.h" |
| 8 #include "base/values.h" |
| 9 #include "extensions/common/event_filter.h" |
| 10 #include "extensions/renderer/api_binding_test.h" |
| 11 #include "extensions/renderer/api_binding_test_util.h" |
| 12 #include "testing/gmock/include/gmock/gmock.h" |
| 13 |
| 14 namespace extensions { |
| 15 |
| 16 namespace { |
| 17 |
| 18 using APIEventListenersTest = APIBindingTest; |
| 19 using MockEventChangeHandler = ::testing::StrictMock< |
| 20 base::MockCallback<APIEventListeners::ListenersUpdated>>; |
| 21 |
| 22 void DoNothingOnUpdate(binding::EventListenersChanged changed, |
| 23 const base::DictionaryValue* filter, |
| 24 v8::Local<v8::Context> context) {} |
| 25 |
| 26 const char kFunction[] = "(function() {})"; |
| 27 const char kEvent[] = "event"; |
| 28 |
| 29 } // namespace |
| 30 |
| 31 // Test unfiltered listeners. |
| 32 TEST_F(APIEventListenersTest, UnfilteredListeners) { |
| 33 v8::HandleScope handle_scope(isolate()); |
| 34 v8::Local<v8::Context> context = MainContext(); |
| 35 |
| 36 MockEventChangeHandler handler; |
| 37 UnfilteredEventListeners listeners(handler.Get()); |
| 38 |
| 39 // Starting out, there should be no listeners. |
| 40 v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction); |
| 41 EXPECT_EQ(0u, listeners.GetNumListeners()); |
| 42 EXPECT_FALSE(listeners.HasListener(function_a)); |
| 43 |
| 44 std::string error; |
| 45 v8::Local<v8::Object> filter; |
| 46 |
| 47 // Adding a new listener should trigger the callback (0 -> 1). |
| 48 EXPECT_CALL(handler, Run(binding::EventListenersChanged::HAS_LISTENERS, |
| 49 nullptr, context)); |
| 50 EXPECT_TRUE(listeners.AddListener(function_a, filter, context, &error)); |
| 51 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 52 |
| 53 // function_a should be registered as a listener, and should be returned when |
| 54 // we get the listeners. |
| 55 EXPECT_TRUE(listeners.HasListener(function_a)); |
| 56 EXPECT_EQ(1u, listeners.GetNumListeners()); |
| 57 EXPECT_THAT(listeners.GetListeners(nullptr, context), |
| 58 testing::UnorderedElementsAre(function_a)); |
| 59 |
| 60 // Trying to add function_a again should have no effect. |
| 61 EXPECT_FALSE(listeners.AddListener(function_a, filter, context, &error)); |
| 62 EXPECT_TRUE(listeners.HasListener(function_a)); |
| 63 EXPECT_EQ(1u, listeners.GetNumListeners()); |
| 64 |
| 65 v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction); |
| 66 |
| 67 // We should not yet have function_b registered, and trying to remove it |
| 68 // should have no effect. |
| 69 EXPECT_FALSE(listeners.HasListener(function_b)); |
| 70 listeners.RemoveListener(function_b, context); |
| 71 EXPECT_EQ(1u, listeners.GetNumListeners()); |
| 72 EXPECT_THAT(listeners.GetListeners(nullptr, context), |
| 73 testing::UnorderedElementsAre(function_a)); |
| 74 |
| 75 // Add function_b; there should now be two listeners, and both should be |
| 76 // returned when we get the listeners. However, the callback shouldn't be |
| 77 // triggered, since this isn't a 0 -> 1 or 1 -> 0 transition. |
| 78 EXPECT_TRUE(listeners.AddListener(function_b, filter, context, &error)); |
| 79 EXPECT_TRUE(listeners.HasListener(function_b)); |
| 80 EXPECT_EQ(2u, listeners.GetNumListeners()); |
| 81 EXPECT_THAT(listeners.GetListeners(nullptr, context), |
| 82 testing::UnorderedElementsAre(function_a, function_b)); |
| 83 |
| 84 // Remove function_a; there should now be only one listener. The callback |
| 85 // shouldn't be triggered. |
| 86 listeners.RemoveListener(function_a, context); |
| 87 EXPECT_FALSE(listeners.HasListener(function_a)); |
| 88 EXPECT_EQ(1u, listeners.GetNumListeners()); |
| 89 EXPECT_THAT(listeners.GetListeners(nullptr, context), |
| 90 testing::UnorderedElementsAre(function_b)); |
| 91 |
| 92 // Remove function_b (the final listener). No more listeners should remain. |
| 93 EXPECT_CALL(handler, Run(binding::EventListenersChanged::NO_LISTENERS, |
| 94 nullptr, context)); |
| 95 listeners.RemoveListener(function_b, context); |
| 96 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 97 EXPECT_FALSE(listeners.HasListener(function_b)); |
| 98 EXPECT_EQ(0u, listeners.GetNumListeners()); |
| 99 EXPECT_TRUE(listeners.GetListeners(nullptr, context).empty()); |
| 100 } |
| 101 |
| 102 // Tests the invalidation of unfiltered listeners. |
| 103 TEST_F(APIEventListenersTest, UnfilteredListenersInvalidation) { |
| 104 v8::HandleScope handle_scope(isolate()); |
| 105 v8::Local<v8::Context> context = MainContext(); |
| 106 |
| 107 MockEventChangeHandler handler; |
| 108 UnfilteredEventListeners listeners(handler.Get()); |
| 109 |
| 110 listeners.Invalidate(context); |
| 111 |
| 112 v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction); |
| 113 v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction); |
| 114 std::string error; |
| 115 v8::Local<v8::Object> filter; |
| 116 EXPECT_CALL(handler, Run(binding::EventListenersChanged::HAS_LISTENERS, |
| 117 nullptr, context)); |
| 118 EXPECT_TRUE(listeners.AddListener(function_a, filter, context, &error)); |
| 119 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 120 EXPECT_TRUE(listeners.AddListener(function_b, filter, context, &error)); |
| 121 |
| 122 EXPECT_CALL(handler, Run(binding::EventListenersChanged::NO_LISTENERS, |
| 123 nullptr, context)); |
| 124 listeners.Invalidate(context); |
| 125 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 126 |
| 127 EXPECT_EQ(0u, listeners.GetNumListeners()); |
| 128 } |
| 129 |
| 130 // Tests that unfiltered listeners ignore the filtering info. |
| 131 TEST_F(APIEventListenersTest, UnfilteredListenersIgnoreFilteringInfo) { |
| 132 v8::HandleScope handle_scope(isolate()); |
| 133 v8::Local<v8::Context> context = MainContext(); |
| 134 |
| 135 UnfilteredEventListeners listeners(base::Bind(&DoNothingOnUpdate)); |
| 136 v8::Local<v8::Function> function = FunctionFromString(context, kFunction); |
| 137 std::string error; |
| 138 v8::Local<v8::Object> filter; |
| 139 EXPECT_TRUE(listeners.AddListener(function, filter, context, &error)); |
| 140 std::unique_ptr<base::DictionaryValue> filtering_info_dict = |
| 141 DictionaryValueFromString("{'url': 'http://example.com/foo'}"); |
| 142 EventFilteringInfo filtering_info(*filtering_info_dict); |
| 143 EXPECT_THAT(listeners.GetListeners(&filtering_info, context), |
| 144 testing::UnorderedElementsAre(function)); |
| 145 } |
| 146 |
| 147 // Tests filtered listeners. |
| 148 TEST_F(APIEventListenersTest, FilteredListeners) { |
| 149 v8::HandleScope handle_scope(isolate()); |
| 150 v8::Local<v8::Context> context = MainContext(); |
| 151 |
| 152 MockEventChangeHandler handler; |
| 153 EventFilter event_filter; |
| 154 FilteredEventListeners listeners(handler.Get(), kEvent, &event_filter); |
| 155 |
| 156 // Starting out, there should be no listeners registered. |
| 157 v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction); |
| 158 EXPECT_EQ(0u, listeners.GetNumListeners()); |
| 159 EXPECT_EQ(0, event_filter.GetMatcherCountForEventForTesting(kEvent)); |
| 160 EXPECT_FALSE(listeners.HasListener(function_a)); |
| 161 |
| 162 v8::Local<v8::Object> empty_filter; |
| 163 std::string error; |
| 164 |
| 165 // Register function_a with no filter; this is equivalent to registering for |
| 166 // all events. The callback should be triggered since this is a 0 -> 1 |
| 167 // transition. |
| 168 // Note that we don't test the passed filter here. This is mostly because it's |
| 169 // a pain to match against a DictionaryValue (which doesn't have an |
| 170 // operator==). |
| 171 EXPECT_CALL(handler, Run(binding::EventListenersChanged::HAS_LISTENERS, |
| 172 testing::NotNull(), context)); |
| 173 EXPECT_TRUE(listeners.AddListener(function_a, empty_filter, context, &error)); |
| 174 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 175 |
| 176 // function_a should be registered, and should be returned when we get the |
| 177 // listeners. |
| 178 EXPECT_TRUE(listeners.HasListener(function_a)); |
| 179 EXPECT_EQ(1u, listeners.GetNumListeners()); |
| 180 EXPECT_THAT(listeners.GetListeners(nullptr, context), |
| 181 testing::UnorderedElementsAre(function_a)); |
| 182 |
| 183 // It should also be registered in the event filter. |
| 184 EXPECT_EQ(1, event_filter.GetMatcherCountForEventForTesting(kEvent)); |
| 185 |
| 186 // Since function_a has no filter, associating a specific url should still |
| 187 // return function_a. |
| 188 std::unique_ptr<base::DictionaryValue> filtering_info_match_dict = |
| 189 DictionaryValueFromString("{'url': 'http://example.com/foo'}"); |
| 190 ASSERT_TRUE(filtering_info_match_dict); |
| 191 EventFilteringInfo filtering_info_match(*filtering_info_match_dict); |
| 192 EXPECT_THAT(listeners.GetListeners(&filtering_info_match, context), |
| 193 testing::UnorderedElementsAre(function_a)); |
| 194 |
| 195 // Trying to add function_a again should have no effect. |
| 196 EXPECT_FALSE( |
| 197 listeners.AddListener(function_a, empty_filter, context, &error)); |
| 198 EXPECT_TRUE(listeners.HasListener(function_a)); |
| 199 EXPECT_EQ(1u, listeners.GetNumListeners()); |
| 200 |
| 201 v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction); |
| 202 |
| 203 // function_b should not yet be registered, and trying to remove it should |
| 204 // have no effect. |
| 205 EXPECT_FALSE(listeners.HasListener(function_b)); |
| 206 listeners.RemoveListener(function_b, context); |
| 207 EXPECT_EQ(1u, listeners.GetNumListeners()); |
| 208 EXPECT_THAT(listeners.GetListeners(nullptr, context), |
| 209 testing::UnorderedElementsAre(function_a)); |
| 210 |
| 211 // Register function_b with a filter for pathContains: 'foo'. Unlike |
| 212 // unfiltered listeners, this *should* trigger the callback, since there is |
| 213 // no other listener registered with this same filter. |
| 214 v8::Local<v8::Object> path_filter; |
| 215 { |
| 216 v8::Local<v8::Value> val = |
| 217 V8ValueFromScriptSource(context, "({url: [{pathContains: 'foo'}]})"); |
| 218 ASSERT_TRUE(val->IsObject()); |
| 219 path_filter = val.As<v8::Object>(); |
| 220 } |
| 221 EXPECT_CALL(handler, Run(binding::EventListenersChanged::HAS_LISTENERS, |
| 222 testing::NotNull(), context)); |
| 223 EXPECT_TRUE(listeners.AddListener(function_b, path_filter, context, &error)); |
| 224 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 225 |
| 226 // function_b should be present. |
| 227 EXPECT_TRUE(listeners.HasListener(function_b)); |
| 228 EXPECT_EQ(2u, listeners.GetNumListeners()); |
| 229 EXPECT_EQ(2, event_filter.GetMatcherCountForEventForTesting(kEvent)); |
| 230 |
| 231 // function_b should ignore calls that don't specify an url, since they, by |
| 232 // definition, don't match. |
| 233 EXPECT_THAT(listeners.GetListeners(nullptr, context), |
| 234 testing::UnorderedElementsAre(function_a)); |
| 235 // function_b should be included for matching urls... |
| 236 EXPECT_THAT(listeners.GetListeners(&filtering_info_match, context), |
| 237 testing::UnorderedElementsAre(function_a, function_b)); |
| 238 // ... but not urls that don't match. |
| 239 std::unique_ptr<base::DictionaryValue> filtering_info_no_match_dict = |
| 240 DictionaryValueFromString("{'url': 'http://example.com/bar'}"); |
| 241 ASSERT_TRUE(filtering_info_no_match_dict); |
| 242 EventFilteringInfo filtering_info_no_match(*filtering_info_no_match_dict); |
| 243 EXPECT_THAT(listeners.GetListeners(&filtering_info_no_match, context), |
| 244 testing::UnorderedElementsAre(function_a)); |
| 245 |
| 246 // Remove function_a. Since filtered listeners notify whenever there's a |
| 247 // change in listeners registered with a specific filter, this should trigger |
| 248 // the callback. |
| 249 EXPECT_CALL(handler, Run(binding::EventListenersChanged::NO_LISTENERS, |
| 250 testing::NotNull(), context)); |
| 251 listeners.RemoveListener(function_a, context); |
| 252 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 253 EXPECT_FALSE(listeners.HasListener(function_a)); |
| 254 EXPECT_EQ(1u, listeners.GetNumListeners()); |
| 255 EXPECT_EQ(1, event_filter.GetMatcherCountForEventForTesting(kEvent)); |
| 256 // function_b should be the only listener remaining, so we shouldn't find |
| 257 // any listeners for events without matching filters. |
| 258 EXPECT_TRUE(listeners.GetListeners(nullptr, context).empty()); |
| 259 EXPECT_THAT(listeners.GetListeners(&filtering_info_match, context), |
| 260 testing::UnorderedElementsAre(function_b)); |
| 261 EXPECT_TRUE( |
| 262 listeners.GetListeners(&filtering_info_no_match, context).empty()); |
| 263 |
| 264 // Remove function_b. No listeners should remain. |
| 265 EXPECT_CALL(handler, Run(binding::EventListenersChanged::NO_LISTENERS, |
| 266 testing::NotNull(), context)); |
| 267 listeners.RemoveListener(function_b, context); |
| 268 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 269 EXPECT_FALSE(listeners.HasListener(function_b)); |
| 270 EXPECT_EQ(0u, listeners.GetNumListeners()); |
| 271 EXPECT_TRUE(listeners.GetListeners(nullptr, context).empty()); |
| 272 EXPECT_TRUE(listeners.GetListeners(&filtering_info_match, context).empty()); |
| 273 EXPECT_EQ(0, event_filter.GetMatcherCountForEventForTesting(kEvent)); |
| 274 } |
| 275 |
| 276 // Tests that adding multiple listeners with the same filter doesn't trigger |
| 277 // the update callback. |
| 278 TEST_F(APIEventListenersTest, |
| 279 UnfilteredListenersWithSameFilterDontTriggerUpdate) { |
| 280 v8::HandleScope handle_scope(isolate()); |
| 281 v8::Local<v8::Context> context = MainContext(); |
| 282 |
| 283 MockEventChangeHandler handler; |
| 284 EventFilter event_filter; |
| 285 FilteredEventListeners listeners(handler.Get(), kEvent, &event_filter); |
| 286 |
| 287 auto get_filter = [context]() { |
| 288 return V8ValueFromScriptSource(context, "({url: [{pathContains: 'foo'}]})") |
| 289 .As<v8::Object>(); |
| 290 }; |
| 291 |
| 292 v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction); |
| 293 |
| 294 std::string error; |
| 295 EXPECT_CALL(handler, Run(binding::EventListenersChanged::HAS_LISTENERS, |
| 296 testing::NotNull(), context)); |
| 297 EXPECT_TRUE(listeners.AddListener(function_a, get_filter(), context, &error)); |
| 298 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 299 EXPECT_EQ(1, event_filter.GetMatcherCountForEventForTesting(kEvent)); |
| 300 |
| 301 v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction); |
| 302 v8::Local<v8::Function> function_c = FunctionFromString(context, kFunction); |
| 303 EXPECT_TRUE(listeners.AddListener(function_b, get_filter(), context, &error)); |
| 304 EXPECT_TRUE(listeners.AddListener(function_c, get_filter(), context, &error)); |
| 305 EXPECT_EQ(3u, listeners.GetNumListeners()); |
| 306 EXPECT_EQ(3, event_filter.GetMatcherCountForEventForTesting(kEvent)); |
| 307 |
| 308 std::unique_ptr<base::DictionaryValue> filtering_info_match_dict = |
| 309 DictionaryValueFromString("{'url': 'http://example.com/foo'}"); |
| 310 ASSERT_TRUE(filtering_info_match_dict); |
| 311 EventFilteringInfo filtering_info_match(*filtering_info_match_dict); |
| 312 EXPECT_THAT( |
| 313 listeners.GetListeners(&filtering_info_match, context), |
| 314 testing::UnorderedElementsAre(function_a, function_b, function_c)); |
| 315 |
| 316 listeners.RemoveListener(function_c, context); |
| 317 listeners.RemoveListener(function_b, context); |
| 318 |
| 319 EXPECT_CALL(handler, Run(binding::EventListenersChanged::NO_LISTENERS, |
| 320 testing::NotNull(), context)); |
| 321 listeners.RemoveListener(function_a, context); |
| 322 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 323 EXPECT_EQ(0, event_filter.GetMatcherCountForEventForTesting(kEvent)); |
| 324 } |
| 325 |
| 326 // Tests that trying to add a listener with an invalid filter fails. |
| 327 TEST_F(APIEventListenersTest, UnfilteredListenersError) { |
| 328 v8::HandleScope handle_scope(isolate()); |
| 329 v8::Local<v8::Context> context = MainContext(); |
| 330 |
| 331 EventFilter event_filter; |
| 332 FilteredEventListeners listeners(base::Bind(&DoNothingOnUpdate), kEvent, |
| 333 &event_filter); |
| 334 |
| 335 v8::Local<v8::Object> invalid_filter = |
| 336 V8ValueFromScriptSource(context, "({url: 'some string'})") |
| 337 .As<v8::Object>(); |
| 338 v8::Local<v8::Function> function = FunctionFromString(context, kFunction); |
| 339 std::string error; |
| 340 EXPECT_FALSE( |
| 341 listeners.AddListener(function, invalid_filter, context, &error)); |
| 342 EXPECT_FALSE(error.empty()); |
| 343 } |
| 344 |
| 345 // Tests that adding listeners for multiple different events is correctly |
| 346 // recorded in the EventFilter. |
| 347 TEST_F(APIEventListenersTest, MultipleUnfilteredListenerEvents) { |
| 348 v8::HandleScope handle_scope(isolate()); |
| 349 v8::Local<v8::Context> context = MainContext(); |
| 350 |
| 351 const char kAlpha[] = "alpha"; |
| 352 const char kBeta[] = "beta"; |
| 353 |
| 354 EventFilter event_filter; |
| 355 FilteredEventListeners listeners_a(base::Bind(&DoNothingOnUpdate), kAlpha, |
| 356 &event_filter); |
| 357 FilteredEventListeners listeners_b(base::Bind(&DoNothingOnUpdate), kBeta, |
| 358 &event_filter); |
| 359 |
| 360 EXPECT_EQ(0, event_filter.GetMatcherCountForEventForTesting(kAlpha)); |
| 361 EXPECT_EQ(0, event_filter.GetMatcherCountForEventForTesting(kBeta)); |
| 362 |
| 363 std::string error; |
| 364 v8::Local<v8::Object> filter; |
| 365 |
| 366 v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction); |
| 367 EXPECT_TRUE(listeners_a.AddListener(function_a, filter, context, &error)); |
| 368 EXPECT_EQ(1, event_filter.GetMatcherCountForEventForTesting(kAlpha)); |
| 369 EXPECT_EQ(0, event_filter.GetMatcherCountForEventForTesting(kBeta)); |
| 370 |
| 371 v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction); |
| 372 EXPECT_TRUE(listeners_b.AddListener(function_b, filter, context, &error)); |
| 373 EXPECT_EQ(1, event_filter.GetMatcherCountForEventForTesting(kAlpha)); |
| 374 EXPECT_EQ(1, event_filter.GetMatcherCountForEventForTesting(kBeta)); |
| 375 |
| 376 listeners_b.RemoveListener(function_b, context); |
| 377 EXPECT_EQ(1, event_filter.GetMatcherCountForEventForTesting(kAlpha)); |
| 378 EXPECT_EQ(0, event_filter.GetMatcherCountForEventForTesting(kBeta)); |
| 379 |
| 380 listeners_a.RemoveListener(function_a, context); |
| 381 EXPECT_EQ(0, event_filter.GetMatcherCountForEventForTesting(kAlpha)); |
| 382 EXPECT_EQ(0, event_filter.GetMatcherCountForEventForTesting(kBeta)); |
| 383 } |
| 384 |
| 385 // Tests the invalidation of filtered listeners. |
| 386 TEST_F(APIEventListenersTest, FilteredListenersInvalidation) { |
| 387 v8::HandleScope handle_scope(isolate()); |
| 388 v8::Local<v8::Context> context = MainContext(); |
| 389 |
| 390 MockEventChangeHandler handler; |
| 391 EventFilter event_filter; |
| 392 FilteredEventListeners listeners(handler.Get(), kEvent, &event_filter); |
| 393 listeners.Invalidate(context); |
| 394 |
| 395 v8::Local<v8::Object> empty_filter; |
| 396 v8::Local<v8::Object> filter = |
| 397 V8ValueFromScriptSource(context, "({url: [{pathContains: 'foo'}]})") |
| 398 .As<v8::Object>(); |
| 399 std::string error; |
| 400 |
| 401 v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction); |
| 402 v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction); |
| 403 v8::Local<v8::Function> function_c = FunctionFromString(context, kFunction); |
| 404 |
| 405 EXPECT_CALL(handler, Run(binding::EventListenersChanged::HAS_LISTENERS, |
| 406 testing::NotNull(), context)); |
| 407 EXPECT_TRUE(listeners.AddListener(function_a, empty_filter, context, &error)); |
| 408 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 409 EXPECT_CALL(handler, Run(binding::EventListenersChanged::HAS_LISTENERS, |
| 410 testing::NotNull(), context)); |
| 411 EXPECT_TRUE(listeners.AddListener(function_b, filter, context, &error)); |
| 412 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 413 EXPECT_TRUE(listeners.AddListener(function_c, filter, context, &error)); |
| 414 |
| 415 // Since two listener filters are present in the list, we should be notified |
| 416 // of each going away when we invalidate the context. |
| 417 EXPECT_CALL(handler, Run(binding::EventListenersChanged::NO_LISTENERS, |
| 418 testing::NotNull(), context)) |
| 419 .Times(2); |
| 420 listeners.Invalidate(context); |
| 421 ::testing::Mock::VerifyAndClearExpectations(&handler); |
| 422 |
| 423 EXPECT_EQ(0u, listeners.GetNumListeners()); |
| 424 EXPECT_EQ(0, event_filter.GetMatcherCountForEventForTesting(kEvent)); |
| 425 } |
| 426 |
| 427 } // namespace extensions |
OLD | NEW |