1// Copyright (c) 2012 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 "base/memory/scoped_ptr.h"
6#include "base/values.h"
7#include "extensions/common/event_filter.h"
8#include "extensions/common/event_filtering_info.h"
9#include "extensions/common/event_matcher.h"
10#include "ipc/ipc_message.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13namespace extensions {
14
15class EventFilterUnittest : public testing::Test {
16 public:
17  EventFilterUnittest() {
18    google_event_.SetURL(GURL("http://google.com"));
19    yahoo_event_.SetURL(GURL("http://yahoo.com"));
20    random_url_event_.SetURL(GURL("http://www.something-else.com"));
21    empty_url_event_.SetURL(GURL());
22  }
23
24 protected:
25  scoped_ptr<base::Value> HostSuffixDict(const std::string& host_suffix) {
26    scoped_ptr<base::DictionaryValue> dict(new DictionaryValue());
27    dict->Set("hostSuffix", base::Value::CreateStringValue(host_suffix));
28    return scoped_ptr<base::Value>(dict.release());
29  }
30
31  scoped_ptr<base::ListValue> ValueAsList(scoped_ptr<base::Value> value) {
32    scoped_ptr<base::ListValue> result(new base::ListValue());
33    result->Append(value.release());
34    return result.Pass();
35  }
36
37  scoped_ptr<EventMatcher> AllURLs() {
38    return scoped_ptr<EventMatcher>(new EventMatcher(
39        scoped_ptr<DictionaryValue>(new DictionaryValue), MSG_ROUTING_NONE));
40  }
41
42  scoped_ptr<EventMatcher> HostSuffixMatcher(const std::string& host_suffix) {
43    return MatcherFromURLFilterList(ValueAsList(HostSuffixDict(host_suffix)));
44  }
45
46  scoped_ptr<EventMatcher> MatcherFromURLFilterList(
47      scoped_ptr<ListValue> url_filter_list) {
48    scoped_ptr<DictionaryValue> filter_dict(new DictionaryValue);
49    filter_dict->Set("url", url_filter_list.release());
50    return scoped_ptr<EventMatcher>(
51        new EventMatcher(filter_dict.Pass(), MSG_ROUTING_NONE));
52  }
53
54  EventFilter event_filter_;
55  EventFilteringInfo empty_event_;
56  EventFilteringInfo google_event_;
57  EventFilteringInfo yahoo_event_;
58  EventFilteringInfo random_url_event_;
59  EventFilteringInfo empty_url_event_;
60};
61
62TEST_F(EventFilterUnittest, NoMatchersMatchIfEmpty) {
63  std::set<int> matches = event_filter_.MatchEvent("some-event",
64                                                   empty_event_,
65                                                   MSG_ROUTING_NONE);
66  ASSERT_EQ(0u, matches.size());
67}
68
69TEST_F(EventFilterUnittest, AddingEventMatcherDoesntCrash) {
70  event_filter_.AddEventMatcher("event1", AllURLs());
71}
72
73TEST_F(EventFilterUnittest,
74    DontMatchAgainstMatchersForDifferentEvents) {
75  event_filter_.AddEventMatcher("event1", AllURLs());
76  std::set<int> matches = event_filter_.MatchEvent("event2",
77                                                   empty_event_,
78                                                   MSG_ROUTING_NONE);
79  ASSERT_EQ(0u, matches.size());
80}
81
82TEST_F(EventFilterUnittest, DoMatchAgainstMatchersForSameEvent) {
83  int id = event_filter_.AddEventMatcher("event1", AllURLs());
84  std::set<int> matches = event_filter_.MatchEvent("event1",
85      google_event_, MSG_ROUTING_NONE);
86  ASSERT_EQ(1u, matches.size());
87  ASSERT_EQ(1u, matches.count(id));
88}
89
90TEST_F(EventFilterUnittest, DontMatchUnlessMatcherMatches) {
91  EventFilteringInfo info;
92  info.SetURL(GURL("http://www.yahoo.com"));
93  event_filter_.AddEventMatcher("event1", HostSuffixMatcher("google.com"));
94  std::set<int> matches = event_filter_.MatchEvent(
95      "event1", info, MSG_ROUTING_NONE);
96  ASSERT_TRUE(matches.empty());
97}
98
99TEST_F(EventFilterUnittest, RemovingAnEventMatcherStopsItMatching) {
100  int id = event_filter_.AddEventMatcher("event1", AllURLs());
101  event_filter_.RemoveEventMatcher(id);
102  std::set<int> matches = event_filter_.MatchEvent("event1",
103                                                   empty_event_,
104                                                   MSG_ROUTING_NONE);
105  ASSERT_TRUE(matches.empty());
106}
107
108TEST_F(EventFilterUnittest, MultipleEventMatches) {
109  int id1 = event_filter_.AddEventMatcher("event1", AllURLs());
110  int id2 = event_filter_.AddEventMatcher("event1", AllURLs());
111  std::set<int> matches = event_filter_.MatchEvent("event1",
112      google_event_, MSG_ROUTING_NONE);
113  ASSERT_EQ(2u, matches.size());
114  ASSERT_EQ(1u, matches.count(id1));
115  ASSERT_EQ(1u, matches.count(id2));
116}
117
118TEST_F(EventFilterUnittest, TestURLMatching) {
119  EventFilteringInfo info;
120  info.SetURL(GURL("http://www.google.com"));
121  int id = event_filter_.AddEventMatcher("event1",
122                                         HostSuffixMatcher("google.com"));
123  std::set<int> matches = event_filter_.MatchEvent(
124      "event1", info, MSG_ROUTING_NONE);
125  ASSERT_EQ(1u, matches.size());
126  ASSERT_EQ(1u, matches.count(id));
127}
128
129TEST_F(EventFilterUnittest, TestMultipleURLFiltersMatchOnAny) {
130  scoped_ptr<base::ListValue> filters(new base::ListValue());
131  filters->Append(HostSuffixDict("google.com").release());
132  filters->Append(HostSuffixDict("yahoo.com").release());
133
134  scoped_ptr<EventMatcher> matcher(MatcherFromURLFilterList(filters.Pass()));
135  int id = event_filter_.AddEventMatcher("event1", matcher.Pass());
136
137  {
138    std::set<int> matches = event_filter_.MatchEvent("event1",
139        google_event_, MSG_ROUTING_NONE);
140    ASSERT_EQ(1u, matches.size());
141    ASSERT_EQ(1u, matches.count(id));
142  }
143  {
144    std::set<int> matches = event_filter_.MatchEvent("event1",
145        yahoo_event_, MSG_ROUTING_NONE);
146    ASSERT_EQ(1u, matches.size());
147    ASSERT_EQ(1u, matches.count(id));
148  }
149  {
150    std::set<int> matches = event_filter_.MatchEvent("event1",
151        random_url_event_, MSG_ROUTING_NONE);
152    ASSERT_EQ(0u, matches.size());
153  }
154}
155
156TEST_F(EventFilterUnittest, TestStillMatchesAfterRemoval) {
157  int id1 = event_filter_.AddEventMatcher("event1", AllURLs());
158  int id2 = event_filter_.AddEventMatcher("event1", AllURLs());
159
160  event_filter_.RemoveEventMatcher(id1);
161  {
162    std::set<int> matches = event_filter_.MatchEvent("event1",
163        google_event_, MSG_ROUTING_NONE);
164    ASSERT_EQ(1u, matches.size());
165    ASSERT_EQ(1u, matches.count(id2));
166  }
167}
168
169TEST_F(EventFilterUnittest, TestMatchesOnlyAgainstPatternsForCorrectEvent) {
170  int id1 = event_filter_.AddEventMatcher("event1", AllURLs());
171  event_filter_.AddEventMatcher("event2", AllURLs());
172
173  {
174    std::set<int> matches = event_filter_.MatchEvent("event1",
175        google_event_, MSG_ROUTING_NONE);
176    ASSERT_EQ(1u, matches.size());
177    ASSERT_EQ(1u, matches.count(id1));
178  }
179}
180
181TEST_F(EventFilterUnittest, TestGetMatcherCountForEvent) {
182  ASSERT_EQ(0, event_filter_.GetMatcherCountForEvent("event1"));
183  int id1 = event_filter_.AddEventMatcher("event1", AllURLs());
184  ASSERT_EQ(1, event_filter_.GetMatcherCountForEvent("event1"));
185  int id2 = event_filter_.AddEventMatcher("event1", AllURLs());
186  ASSERT_EQ(2, event_filter_.GetMatcherCountForEvent("event1"));
187  event_filter_.RemoveEventMatcher(id1);
188  ASSERT_EQ(1, event_filter_.GetMatcherCountForEvent("event1"));
189  event_filter_.RemoveEventMatcher(id2);
190  ASSERT_EQ(0, event_filter_.GetMatcherCountForEvent("event1"));
191}
192
193TEST_F(EventFilterUnittest, RemoveEventMatcherReturnsEventName) {
194  int id1 = event_filter_.AddEventMatcher("event1", AllURLs());
195  int id2 = event_filter_.AddEventMatcher("event1", AllURLs());
196  int id3 = event_filter_.AddEventMatcher("event2", AllURLs());
197
198  ASSERT_EQ("event1", event_filter_.RemoveEventMatcher(id1));
199  ASSERT_EQ("event1", event_filter_.RemoveEventMatcher(id2));
200  ASSERT_EQ("event2", event_filter_.RemoveEventMatcher(id3));
201}
202
203TEST_F(EventFilterUnittest, InvalidURLFilterCantBeAdded) {
204  scoped_ptr<base::ListValue> filter_list(new base::ListValue());
205  filter_list->Append(new base::ListValue());  // Should be a dict.
206  scoped_ptr<EventMatcher> matcher(MatcherFromURLFilterList(
207      filter_list.Pass()));
208  int id1 = event_filter_.AddEventMatcher("event1", matcher.Pass());
209  EXPECT_TRUE(event_filter_.IsURLMatcherEmpty());
210  ASSERT_EQ(-1, id1);
211}
212
213TEST_F(EventFilterUnittest, EmptyListOfURLFiltersMatchesAllURLs) {
214  scoped_ptr<base::ListValue> filter_list(new base::ListValue());
215  scoped_ptr<EventMatcher> matcher(MatcherFromURLFilterList(
216      scoped_ptr<ListValue>(new ListValue)));
217  int id = event_filter_.AddEventMatcher("event1", matcher.Pass());
218  std::set<int> matches = event_filter_.MatchEvent("event1",
219      google_event_, MSG_ROUTING_NONE);
220  ASSERT_EQ(1u, matches.size());
221  ASSERT_EQ(1u, matches.count(id));
222}
223
224TEST_F(EventFilterUnittest,
225    InternalURLMatcherShouldBeEmptyWhenThereAreNoEventMatchers) {
226  ASSERT_TRUE(event_filter_.IsURLMatcherEmpty());
227  int id = event_filter_.AddEventMatcher("event1",
228                                         HostSuffixMatcher("google.com"));
229  ASSERT_FALSE(event_filter_.IsURLMatcherEmpty());
230  event_filter_.RemoveEventMatcher(id);
231  ASSERT_TRUE(event_filter_.IsURLMatcherEmpty());
232}
233
234TEST_F(EventFilterUnittest, EmptyURLsShouldBeMatchedByEmptyURLFilters) {
235  int id = event_filter_.AddEventMatcher("event1", AllURLs());
236  std::set<int> matches = event_filter_.MatchEvent(
237      "event1", empty_url_event_, MSG_ROUTING_NONE);
238  ASSERT_EQ(1u, matches.size());
239  ASSERT_EQ(1u, matches.count(id));
240}
241
242TEST_F(EventFilterUnittest,
243    EmptyURLsShouldBeMatchedByEmptyURLFiltersWithAnEmptyItem) {
244  scoped_ptr<EventMatcher> matcher(MatcherFromURLFilterList(ValueAsList(
245      scoped_ptr<Value>(new DictionaryValue()))));
246  int id = event_filter_.AddEventMatcher("event1", matcher.Pass());
247  std::set<int> matches = event_filter_.MatchEvent(
248      "event1", empty_url_event_, MSG_ROUTING_NONE);
249  ASSERT_EQ(1u, matches.size());
250  ASSERT_EQ(1u, matches.count(id));
251}
252
253}  // namespace extensions
254