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 "chrome/browser/extensions/api/content_settings/content_settings_store.h"
6
7#include "base/memory/scoped_ptr.h"
8#include "chrome/browser/content_settings/content_settings_utils.h"
9#include "components/content_settings/core/browser/content_settings_rule.h"
10#include "testing/gmock/include/gmock/gmock.h"
11#include "testing/gtest/include/gtest/gtest.h"
12#include "url/gurl.h"
13
14using ::testing::Mock;
15
16namespace extensions {
17
18namespace {
19
20void CheckRule(const content_settings::Rule& rule,
21               const ContentSettingsPattern& primary_pattern,
22               const ContentSettingsPattern& secondary_pattern,
23               ContentSetting setting) {
24  EXPECT_EQ(primary_pattern.ToString(), rule.primary_pattern.ToString());
25  EXPECT_EQ(secondary_pattern.ToString(), rule.secondary_pattern.ToString());
26  EXPECT_EQ(setting, content_settings::ValueToContentSetting(rule.value.get()));
27}
28
29// Helper class which returns monotonically-increasing base::Time objects.
30class FakeTimer {
31 public:
32  FakeTimer() : internal_(0) {}
33
34  base::Time GetNext() {
35    return base::Time::FromInternalValue(++internal_);
36  }
37
38 private:
39  int64 internal_;
40};
41
42class MockContentSettingsStoreObserver
43    : public ContentSettingsStore::Observer {
44 public:
45  MOCK_METHOD2(OnContentSettingChanged,
46               void(const std::string& extension_id, bool incognito));
47};
48
49ContentSetting GetContentSettingFromStore(
50    const ContentSettingsStore* store,
51    const GURL& primary_url, const GURL& secondary_url,
52    ContentSettingsType content_type,
53    const std::string& resource_identifier,
54    bool incognito) {
55  scoped_ptr<content_settings::RuleIterator> rule_iterator(
56      store->GetRuleIterator(content_type, resource_identifier, incognito));
57  scoped_ptr<base::Value> setting(
58      content_settings::GetContentSettingValueAndPatterns(
59          rule_iterator.get(), primary_url, secondary_url, NULL, NULL));
60  return content_settings::ValueToContentSetting(setting.get());
61}
62
63void GetSettingsForOneTypeFromStore(
64    const ContentSettingsStore* store,
65    ContentSettingsType content_type,
66    const std::string& resource_identifier,
67    bool incognito,
68    std::vector<content_settings::Rule>* rules) {
69  rules->clear();
70  scoped_ptr<content_settings::RuleIterator> rule_iterator(
71      store->GetRuleIterator(content_type, resource_identifier, incognito));
72  while (rule_iterator->HasNext())
73    rules->push_back(rule_iterator->Next());
74}
75
76}  // namespace
77
78class ContentSettingsStoreTest : public ::testing::Test {
79 public:
80  ContentSettingsStoreTest() :
81      store_(new ContentSettingsStore()) {
82  }
83
84 protected:
85  void RegisterExtension(const std::string& ext_id) {
86    store_->RegisterExtension(ext_id, timer_.GetNext(), true);
87  }
88
89  ContentSettingsStore* store() {
90    return store_.get();
91  }
92
93 private:
94  FakeTimer timer_;
95  scoped_refptr<ContentSettingsStore> store_;
96};
97
98TEST_F(ContentSettingsStoreTest, RegisterUnregister) {
99  ::testing::StrictMock<MockContentSettingsStoreObserver> observer;
100  store()->AddObserver(&observer);
101
102  GURL url("http://www.youtube.com");
103
104  EXPECT_EQ(CONTENT_SETTING_DEFAULT,
105            GetContentSettingFromStore(store(),
106                                       url,
107                                       url,
108                                       CONTENT_SETTINGS_TYPE_COOKIES,
109                                       std::string(),
110                                       false));
111
112  // Register first extension
113  std::string ext_id("my_extension");
114  RegisterExtension(ext_id);
115
116  EXPECT_EQ(CONTENT_SETTING_DEFAULT,
117            GetContentSettingFromStore(store(),
118                                       url,
119                                       url,
120                                       CONTENT_SETTINGS_TYPE_COOKIES,
121                                       std::string(),
122                                       false));
123
124  // Set setting
125  ContentSettingsPattern pattern =
126      ContentSettingsPattern::FromURL(GURL("http://www.youtube.com"));
127  EXPECT_CALL(observer, OnContentSettingChanged(ext_id, false));
128  store()->SetExtensionContentSetting(ext_id,
129                                      pattern,
130                                      pattern,
131                                      CONTENT_SETTINGS_TYPE_COOKIES,
132                                      std::string(),
133                                      CONTENT_SETTING_ALLOW,
134                                      kExtensionPrefsScopeRegular);
135  Mock::VerifyAndClear(&observer);
136
137  EXPECT_EQ(CONTENT_SETTING_ALLOW,
138            GetContentSettingFromStore(store(),
139                                       url,
140                                       url,
141                                       CONTENT_SETTINGS_TYPE_COOKIES,
142                                       std::string(),
143                                       false));
144
145  // Register second extension.
146  std::string ext_id_2("my_second_extension");
147  RegisterExtension(ext_id_2);
148  EXPECT_CALL(observer, OnContentSettingChanged(ext_id_2, false));
149  store()->SetExtensionContentSetting(ext_id_2,
150                                      pattern,
151                                      pattern,
152                                      CONTENT_SETTINGS_TYPE_COOKIES,
153                                      std::string(),
154                                      CONTENT_SETTING_BLOCK,
155                                      kExtensionPrefsScopeRegular);
156
157  EXPECT_EQ(CONTENT_SETTING_BLOCK,
158            GetContentSettingFromStore(store(),
159                                       url,
160                                       url,
161                                       CONTENT_SETTINGS_TYPE_COOKIES,
162                                       std::string(),
163                                       false));
164
165  // Unregister first extension. This shouldn't change the setting.
166  EXPECT_CALL(observer, OnContentSettingChanged(ext_id, false));
167  store()->UnregisterExtension(ext_id);
168  EXPECT_EQ(CONTENT_SETTING_BLOCK,
169            GetContentSettingFromStore(store(),
170                                       url,
171                                       url,
172                                       CONTENT_SETTINGS_TYPE_COOKIES,
173                                       std::string(),
174                                       false));
175  Mock::VerifyAndClear(&observer);
176
177  // Unregister second extension. This should reset the setting to its default
178  // value.
179  EXPECT_CALL(observer, OnContentSettingChanged(ext_id_2, false));
180  store()->UnregisterExtension(ext_id_2);
181  EXPECT_EQ(CONTENT_SETTING_DEFAULT,
182            GetContentSettingFromStore(store(),
183                                       url,
184                                       url,
185                                       CONTENT_SETTINGS_TYPE_COOKIES,
186                                       std::string(),
187                                       false));
188
189  store()->RemoveObserver(&observer);
190}
191
192TEST_F(ContentSettingsStoreTest, GetAllSettings) {
193  bool incognito = false;
194  std::vector<content_settings::Rule> rules;
195  GetSettingsForOneTypeFromStore(
196      store(), CONTENT_SETTINGS_TYPE_COOKIES, std::string(), incognito, &rules);
197  ASSERT_EQ(0u, rules.size());
198
199  // Register first extension.
200  std::string ext_id("my_extension");
201  RegisterExtension(ext_id);
202  ContentSettingsPattern pattern =
203      ContentSettingsPattern::FromURL(GURL("http://www.youtube.com"));
204  store()->SetExtensionContentSetting(ext_id,
205                                      pattern,
206                                      pattern,
207                                      CONTENT_SETTINGS_TYPE_COOKIES,
208                                      std::string(),
209                                      CONTENT_SETTING_ALLOW,
210                                      kExtensionPrefsScopeRegular);
211
212  GetSettingsForOneTypeFromStore(
213      store(), CONTENT_SETTINGS_TYPE_COOKIES, std::string(), incognito, &rules);
214  ASSERT_EQ(1u, rules.size());
215  CheckRule(rules[0], pattern, pattern, CONTENT_SETTING_ALLOW);
216
217  // Register second extension.
218  std::string ext_id_2("my_second_extension");
219  RegisterExtension(ext_id_2);
220  ContentSettingsPattern pattern_2 =
221      ContentSettingsPattern::FromURL(GURL("http://www.example.com"));
222  store()->SetExtensionContentSetting(ext_id_2,
223                                      pattern_2,
224                                      pattern_2,
225                                      CONTENT_SETTINGS_TYPE_COOKIES,
226                                      std::string(),
227                                      CONTENT_SETTING_BLOCK,
228                                      kExtensionPrefsScopeRegular);
229
230  GetSettingsForOneTypeFromStore(
231      store(), CONTENT_SETTINGS_TYPE_COOKIES, std::string(), incognito, &rules);
232  ASSERT_EQ(2u, rules.size());
233  // Rules appear in the reverse installation order of the extensions.
234  CheckRule(rules[0], pattern_2, pattern_2, CONTENT_SETTING_BLOCK);
235  CheckRule(rules[1], pattern, pattern, CONTENT_SETTING_ALLOW);
236
237  // Disable first extension.
238  store()->SetExtensionState(ext_id, false);
239
240  GetSettingsForOneTypeFromStore(
241      store(), CONTENT_SETTINGS_TYPE_COOKIES, std::string(), incognito, &rules);
242  ASSERT_EQ(1u, rules.size());
243  CheckRule(rules[0], pattern_2, pattern_2, CONTENT_SETTING_BLOCK);
244
245  // Uninstall second extension.
246  store()->UnregisterExtension(ext_id_2);
247
248  GetSettingsForOneTypeFromStore(
249      store(), CONTENT_SETTINGS_TYPE_COOKIES, std::string(), incognito, &rules);
250  ASSERT_EQ(0u, rules.size());
251}
252
253}  // namespace extensions
254