1// Copyright 2013 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/browser/event_router.h"
6
7#include <string>
8
9#include "base/bind.h"
10#include "base/compiler_specific.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/values.h"
13#include "content/public/browser/notification_service.h"
14#include "extensions/browser/event_listener_map.h"
15#include "extensions/browser/extensions_test.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace extensions {
19
20namespace {
21
22// A simple mock to keep track of listener additions and removals.
23class MockEventRouterObserver : public EventRouter::Observer {
24 public:
25  MockEventRouterObserver()
26      : listener_added_count_(0),
27        listener_removed_count_(0) {}
28  virtual ~MockEventRouterObserver() {}
29
30  int listener_added_count() const { return listener_added_count_; }
31  int listener_removed_count() const { return listener_removed_count_; }
32  const std::string& last_event_name() const { return last_event_name_; }
33
34  void Reset() {
35    listener_added_count_ = 0;
36    listener_removed_count_ = 0;
37    last_event_name_.clear();
38  }
39
40  // EventRouter::Observer overrides:
41  virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE {
42    listener_added_count_++;
43    last_event_name_ = details.event_name;
44  }
45
46  virtual void OnListenerRemoved(const EventListenerInfo& details) OVERRIDE {
47    listener_removed_count_++;
48    last_event_name_ = details.event_name;
49  }
50
51 private:
52  int listener_added_count_;
53  int listener_removed_count_;
54  std::string last_event_name_;
55
56  DISALLOW_COPY_AND_ASSIGN(MockEventRouterObserver);
57};
58
59typedef base::Callback<scoped_ptr<EventListener>(
60    const std::string&,           // event_name
61    content::RenderProcessHost*,  // process
62    base::DictionaryValue*        // filter (takes ownership)
63    )> EventListenerConstructor;
64
65scoped_ptr<EventListener> CreateEventListenerForExtension(
66    const std::string& extension_id,
67    const std::string& event_name,
68    content::RenderProcessHost* process,
69    base::DictionaryValue* filter) {
70  return EventListener::ForExtension(
71      event_name, extension_id, process, make_scoped_ptr(filter));
72}
73
74scoped_ptr<EventListener> CreateEventListenerForURL(
75    const GURL& listener_url,
76    const std::string& event_name,
77    content::RenderProcessHost* process,
78    base::DictionaryValue* filter) {
79  return EventListener::ForURL(
80      event_name, listener_url, process, make_scoped_ptr(filter));
81}
82
83}  // namespace
84
85class EventRouterTest : public ExtensionsTest {
86 public:
87  EventRouterTest()
88      : notification_service_(content::NotificationService::Create()) {}
89
90 protected:
91  // Tests adding and removing observers from EventRouter.
92  void RunEventRouterObserverTest(const EventListenerConstructor& constructor);
93
94 private:
95  scoped_ptr<content::NotificationService> notification_service_;
96
97  DISALLOW_COPY_AND_ASSIGN(EventRouterTest);
98};
99
100TEST_F(EventRouterTest, GetBaseEventName) {
101  // Normal event names are passed through unchanged.
102  EXPECT_EQ("foo.onBar", EventRouter::GetBaseEventName("foo.onBar"));
103
104  // Sub-events are converted to the part before the slash.
105  EXPECT_EQ("foo.onBar", EventRouter::GetBaseEventName("foo.onBar/123"));
106}
107
108// Tests adding and removing observers from EventRouter.
109void EventRouterTest::RunEventRouterObserverTest(
110    const EventListenerConstructor& constructor) {
111  EventRouter router(NULL, NULL);
112  scoped_ptr<EventListener> listener =
113      constructor.Run("event_name", NULL, new base::DictionaryValue());
114
115  // Add/remove works without any observers.
116  router.OnListenerAdded(listener.get());
117  router.OnListenerRemoved(listener.get());
118
119  // Register observers that both match and don't match the event above.
120  MockEventRouterObserver matching_observer;
121  router.RegisterObserver(&matching_observer, "event_name");
122  MockEventRouterObserver non_matching_observer;
123  router.RegisterObserver(&non_matching_observer, "other");
124
125  // Adding a listener notifies the appropriate observers.
126  router.OnListenerAdded(listener.get());
127  EXPECT_EQ(1, matching_observer.listener_added_count());
128  EXPECT_EQ(0, non_matching_observer.listener_added_count());
129
130  // Removing a listener notifies the appropriate observers.
131  router.OnListenerRemoved(listener.get());
132  EXPECT_EQ(1, matching_observer.listener_removed_count());
133  EXPECT_EQ(0, non_matching_observer.listener_removed_count());
134
135  // Adding the listener again notifies again.
136  router.OnListenerAdded(listener.get());
137  EXPECT_EQ(2, matching_observer.listener_added_count());
138  EXPECT_EQ(0, non_matching_observer.listener_added_count());
139
140  // Removing the listener again notifies again.
141  router.OnListenerRemoved(listener.get());
142  EXPECT_EQ(2, matching_observer.listener_removed_count());
143  EXPECT_EQ(0, non_matching_observer.listener_removed_count());
144
145  // Adding a listener with a sub-event notifies the main observer with
146  // proper details.
147  matching_observer.Reset();
148  scoped_ptr<EventListener> sub_event_listener =
149      constructor.Run("event_name/1", NULL, new base::DictionaryValue());
150  router.OnListenerAdded(sub_event_listener.get());
151  EXPECT_EQ(1, matching_observer.listener_added_count());
152  EXPECT_EQ(0, matching_observer.listener_removed_count());
153  EXPECT_EQ("event_name/1", matching_observer.last_event_name());
154
155  // Ditto for removing the listener.
156  matching_observer.Reset();
157  router.OnListenerRemoved(sub_event_listener.get());
158  EXPECT_EQ(0, matching_observer.listener_added_count());
159  EXPECT_EQ(1, matching_observer.listener_removed_count());
160  EXPECT_EQ("event_name/1", matching_observer.last_event_name());
161}
162
163TEST_F(EventRouterTest, EventRouterObserverForExtensions) {
164  RunEventRouterObserverTest(
165      base::Bind(&CreateEventListenerForExtension, "extension_id"));
166}
167
168TEST_F(EventRouterTest, EventRouterObserverForURLs) {
169  RunEventRouterObserverTest(
170      base::Bind(&CreateEventListenerForURL, GURL("http://google.com/path")));
171}
172
173}  // namespace extensions
174