| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "extensions/browser/event_router.h" |
| |
| #include <string> |
| |
| #include "base/bind.h" |
| #include "base/compiler_specific.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/values.h" |
| #include "content/public/browser/notification_service.h" |
| #include "extensions/browser/event_listener_map.h" |
| #include "extensions/browser/extensions_test.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace extensions { |
| |
| namespace { |
| |
| // A simple mock to keep track of listener additions and removals. |
| class MockEventRouterObserver : public EventRouter::Observer { |
| public: |
| MockEventRouterObserver() |
| : listener_added_count_(0), |
| listener_removed_count_(0) {} |
| virtual ~MockEventRouterObserver() {} |
| |
| int listener_added_count() const { return listener_added_count_; } |
| int listener_removed_count() const { return listener_removed_count_; } |
| const std::string& last_event_name() const { return last_event_name_; } |
| |
| void Reset() { |
| listener_added_count_ = 0; |
| listener_removed_count_ = 0; |
| last_event_name_.clear(); |
| } |
| |
| // EventRouter::Observer overrides: |
| void OnListenerAdded(const EventListenerInfo& details) override { |
| listener_added_count_++; |
| last_event_name_ = details.event_name; |
| } |
| |
| void OnListenerRemoved(const EventListenerInfo& details) override { |
| listener_removed_count_++; |
| last_event_name_ = details.event_name; |
| } |
| |
| private: |
| int listener_added_count_; |
| int listener_removed_count_; |
| std::string last_event_name_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MockEventRouterObserver); |
| }; |
| |
| typedef base::Callback<scoped_ptr<EventListener>( |
| const std::string&, // event_name |
| content::RenderProcessHost*, // process |
| base::DictionaryValue* // filter (takes ownership) |
| )> EventListenerConstructor; |
| |
| scoped_ptr<EventListener> CreateEventListenerForExtension( |
| const std::string& extension_id, |
| const std::string& event_name, |
| content::RenderProcessHost* process, |
| base::DictionaryValue* filter) { |
| return EventListener::ForExtension( |
| event_name, extension_id, process, make_scoped_ptr(filter)); |
| } |
| |
| scoped_ptr<EventListener> CreateEventListenerForURL( |
| const GURL& listener_url, |
| const std::string& event_name, |
| content::RenderProcessHost* process, |
| base::DictionaryValue* filter) { |
| return EventListener::ForURL( |
| event_name, listener_url, process, make_scoped_ptr(filter)); |
| } |
| |
| } // namespace |
| |
| class EventRouterTest : public ExtensionsTest { |
| public: |
| EventRouterTest() |
| : notification_service_(content::NotificationService::Create()) {} |
| |
| protected: |
| // Tests adding and removing observers from EventRouter. |
| void RunEventRouterObserverTest(const EventListenerConstructor& constructor); |
| |
| private: |
| scoped_ptr<content::NotificationService> notification_service_; |
| |
| DISALLOW_COPY_AND_ASSIGN(EventRouterTest); |
| }; |
| |
| TEST_F(EventRouterTest, GetBaseEventName) { |
| // Normal event names are passed through unchanged. |
| EXPECT_EQ("foo.onBar", EventRouter::GetBaseEventName("foo.onBar")); |
| |
| // Sub-events are converted to the part before the slash. |
| EXPECT_EQ("foo.onBar", EventRouter::GetBaseEventName("foo.onBar/123")); |
| } |
| |
| // Tests adding and removing observers from EventRouter. |
| void EventRouterTest::RunEventRouterObserverTest( |
| const EventListenerConstructor& constructor) { |
| EventRouter router(NULL, NULL); |
| scoped_ptr<EventListener> listener = |
| constructor.Run("event_name", NULL, new base::DictionaryValue()); |
| |
| // Add/remove works without any observers. |
| router.OnListenerAdded(listener.get()); |
| router.OnListenerRemoved(listener.get()); |
| |
| // Register observers that both match and don't match the event above. |
| MockEventRouterObserver matching_observer; |
| router.RegisterObserver(&matching_observer, "event_name"); |
| MockEventRouterObserver non_matching_observer; |
| router.RegisterObserver(&non_matching_observer, "other"); |
| |
| // Adding a listener notifies the appropriate observers. |
| router.OnListenerAdded(listener.get()); |
| EXPECT_EQ(1, matching_observer.listener_added_count()); |
| EXPECT_EQ(0, non_matching_observer.listener_added_count()); |
| |
| // Removing a listener notifies the appropriate observers. |
| router.OnListenerRemoved(listener.get()); |
| EXPECT_EQ(1, matching_observer.listener_removed_count()); |
| EXPECT_EQ(0, non_matching_observer.listener_removed_count()); |
| |
| // Adding the listener again notifies again. |
| router.OnListenerAdded(listener.get()); |
| EXPECT_EQ(2, matching_observer.listener_added_count()); |
| EXPECT_EQ(0, non_matching_observer.listener_added_count()); |
| |
| // Removing the listener again notifies again. |
| router.OnListenerRemoved(listener.get()); |
| EXPECT_EQ(2, matching_observer.listener_removed_count()); |
| EXPECT_EQ(0, non_matching_observer.listener_removed_count()); |
| |
| // Adding a listener with a sub-event notifies the main observer with |
| // proper details. |
| matching_observer.Reset(); |
| scoped_ptr<EventListener> sub_event_listener = |
| constructor.Run("event_name/1", NULL, new base::DictionaryValue()); |
| router.OnListenerAdded(sub_event_listener.get()); |
| EXPECT_EQ(1, matching_observer.listener_added_count()); |
| EXPECT_EQ(0, matching_observer.listener_removed_count()); |
| EXPECT_EQ("event_name/1", matching_observer.last_event_name()); |
| |
| // Ditto for removing the listener. |
| matching_observer.Reset(); |
| router.OnListenerRemoved(sub_event_listener.get()); |
| EXPECT_EQ(0, matching_observer.listener_added_count()); |
| EXPECT_EQ(1, matching_observer.listener_removed_count()); |
| EXPECT_EQ("event_name/1", matching_observer.last_event_name()); |
| } |
| |
| TEST_F(EventRouterTest, EventRouterObserverForExtensions) { |
| RunEventRouterObserverTest( |
| base::Bind(&CreateEventListenerForExtension, "extension_id")); |
| } |
| |
| TEST_F(EventRouterTest, EventRouterObserverForURLs) { |
| RunEventRouterObserverTest( |
| base::Bind(&CreateEventListenerForURL, GURL("http://google.com/path"))); |
| } |
| |
| } // namespace extensions |