1 // Copyright (c) 2011 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/auto_reset.h"
6 #include "base/command_line.h"
7 #include "base/utf_string_conversions.h"
8 #include "chrome/browser/mock_plugin_exceptions_table_model.h"
9 #include "chrome/common/chrome_switches.h"
10 #include "chrome/test/testing_pref_service.h"
11 #include "chrome/test/testing_profile.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "ui/base/models/table_model_observer.h"
15 #include "webkit/plugins/npapi/plugin_group.h"
16 #include "webkit/plugins/npapi/webplugininfo.h"
17
18 // Can't be an internal namespace because PluginExceptionsTableModel declares
19 // as a friend.
20 namespace plugin_test_internal {
21
22 using ::testing::_;
23 using ::testing::Invoke;
24
25 class MockTableModelObserver : public ui::TableModelObserver {
26 public:
MockTableModelObserver(ui::TableModel * model)27 explicit MockTableModelObserver(ui::TableModel* model)
28 : model_(model) {
29 ON_CALL(*this, OnItemsRemoved(_, _))
30 .WillByDefault(
31 Invoke(this, &MockTableModelObserver::CheckOnItemsRemoved));
32 }
33
34 MOCK_METHOD0(OnModelChanged, void());
35 MOCK_METHOD2(OnItemsChanged, void(int start, int length));
36 MOCK_METHOD2(OnItemsAdded, void(int start, int length));
37 MOCK_METHOD2(OnItemsRemoved, void(int start, int length));
38
39 private:
CheckOnItemsRemoved(int start,int length)40 void CheckOnItemsRemoved(int start, int length) {
41 if (!model_)
42 return;
43 // This method is called *after* the items have been removed, so we check if
44 // the first removed item was still inside the correct range.
45 EXPECT_LT(start, model_->RowCount() + 1);
46 }
47
48 ui::TableModel* model_;
49 };
50
51 } // namespace plugin_test_internal
52
53 using ::testing::InSequence;
54
55 class PluginExceptionsTableModelTest : public testing::Test {
56 public:
PluginExceptionsTableModelTest()57 PluginExceptionsTableModelTest()
58 : ui_thread_(BrowserThread::UI, &message_loop_),
59 command_line_(CommandLine::ForCurrentProcess(),
60 *CommandLine::ForCurrentProcess()) {}
61
SetUp()62 virtual void SetUp() {
63 CommandLine::ForCurrentProcess()->AppendSwitch(
64 switches::kEnableResourceContentSettings);
65
66 profile_.reset(new TestingProfile());
67
68 HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
69
70 ContentSettingsPattern example_com("[*.]example.com");
71 ContentSettingsPattern moose_org("[*.]moose.org");
72 map->SetContentSetting(example_com,
73 CONTENT_SETTINGS_TYPE_PLUGINS,
74 "a-foo",
75 CONTENT_SETTING_ALLOW);
76 map->SetContentSetting(moose_org,
77 CONTENT_SETTINGS_TYPE_PLUGINS,
78 "b-bar",
79 CONTENT_SETTING_BLOCK);
80 map->SetContentSetting(example_com,
81 CONTENT_SETTINGS_TYPE_PLUGINS,
82 "b-bar",
83 CONTENT_SETTING_ALLOW);
84
85 table_model_.reset(new MockPluginExceptionsTableModel(map, NULL));
86
87 std::vector<webkit::npapi::PluginGroup> plugins;
88 webkit::npapi::WebPluginInfo foo_plugin;
89 foo_plugin.path = FilePath(FILE_PATH_LITERAL("a-foo"));
90 foo_plugin.name = ASCIIToUTF16("FooPlugin");
91 foo_plugin.enabled =
92 webkit::npapi::WebPluginInfo::USER_ENABLED_POLICY_UNMANAGED;
93 scoped_ptr<webkit::npapi::PluginGroup> foo_group(
94 webkit::npapi::PluginGroup::FromWebPluginInfo(foo_plugin));
95 plugins.push_back(*foo_group);
96
97 webkit::npapi::WebPluginInfo bar_plugin;
98 bar_plugin.path = FilePath(FILE_PATH_LITERAL("b-bar"));
99 bar_plugin.name = ASCIIToUTF16("BarPlugin");
100 bar_plugin.enabled =
101 webkit::npapi::WebPluginInfo::USER_ENABLED_POLICY_UNMANAGED;
102 scoped_ptr<webkit::npapi::PluginGroup> bar_group(
103 webkit::npapi::PluginGroup::FromWebPluginInfo(bar_plugin));
104 plugins.push_back(*bar_group);
105
106 table_model_->set_plugins(plugins);
107 table_model_->ReloadSettings();
108 }
109
110 protected:
CheckInvariants() const111 void CheckInvariants() const {
112 typedef std::vector<PluginExceptionsTableModel::SettingsEntry> Entries;
113 const Entries& settings = table_model_->settings_;
114 const std::vector<int>& row_counts = table_model_->row_counts_;
115 const std::vector<std::string>& resources = table_model_->resources_;
116 const ui::TableModel::Groups& groups = table_model_->groups_;
117
118 EXPECT_EQ(groups.size(), row_counts.size());
119 EXPECT_EQ(groups.size(), resources.size());
120
121 int last_plugin = 0;
122 int count = 0;
123 for (Entries::const_iterator it = settings.begin();
124 it != settings.end(); ++it) {
125 // Plugin IDs are indices into |groups|.
126 EXPECT_GE(it->plugin_id, 0);
127 EXPECT_LT(it->plugin_id, static_cast<int>(groups.size()));
128 if (it->plugin_id == last_plugin) {
129 count++;
130 } else {
131 // Plugin IDs are ascending one by one.
132 EXPECT_EQ(last_plugin+1, it->plugin_id);
133
134 // Consecutive runs of plugins with id |x| are |row_counts[x]| long.
135 EXPECT_EQ(count, row_counts[last_plugin]);
136 count = 1;
137 last_plugin = it->plugin_id;
138 }
139 }
140 if (!row_counts.empty())
141 EXPECT_EQ(count, row_counts[last_plugin]);
142 }
143
144 protected:
145 MessageLoop message_loop_;
146 BrowserThread ui_thread_;
147
148 scoped_ptr<TestingProfile> profile_;
149 scoped_ptr<MockPluginExceptionsTableModel> table_model_;
150
151 private:
152 AutoReset<CommandLine> command_line_;
153 };
154
TEST_F(PluginExceptionsTableModelTest,Basic)155 TEST_F(PluginExceptionsTableModelTest, Basic) {
156 EXPECT_EQ(3, table_model_->RowCount());
157 CheckInvariants();
158 }
159
TEST_F(PluginExceptionsTableModelTest,RemoveOneRow)160 TEST_F(PluginExceptionsTableModelTest, RemoveOneRow) {
161 plugin_test_internal::MockTableModelObserver observer(table_model_.get());
162 table_model_->SetObserver(&observer);
163
164 EXPECT_CALL(observer, OnItemsRemoved(1, 1));
165 RemoveRowsTableModel::Rows rows;
166 rows.insert(1);
167 table_model_->RemoveRows(rows);
168 EXPECT_EQ(2, table_model_->RowCount());
169 EXPECT_EQ(2, static_cast<int>(table_model_->GetGroups().size()));
170 CheckInvariants();
171 table_model_->SetObserver(NULL);
172 }
173
TEST_F(PluginExceptionsTableModelTest,RemoveLastRowInGroup)174 TEST_F(PluginExceptionsTableModelTest, RemoveLastRowInGroup) {
175 plugin_test_internal::MockTableModelObserver observer(table_model_.get());
176 table_model_->SetObserver(&observer);
177
178 EXPECT_CALL(observer, OnModelChanged());
179 RemoveRowsTableModel::Rows rows;
180 rows.insert(0);
181 table_model_->RemoveRows(rows);
182 EXPECT_EQ(2, table_model_->RowCount());
183 EXPECT_EQ(1, static_cast<int>(table_model_->GetGroups().size()));
184 CheckInvariants();
185
186 HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
187 EXPECT_CALL(observer, OnModelChanged());
188 map->SetContentSetting(ContentSettingsPattern("[*.]blurp.net"),
189 CONTENT_SETTINGS_TYPE_PLUGINS,
190 "b-bar",
191 CONTENT_SETTING_BLOCK);
192 EXPECT_EQ(3, table_model_->RowCount());
193
194 InSequence s;
195 EXPECT_CALL(observer, OnItemsRemoved(2, 1));
196 EXPECT_CALL(observer, OnItemsRemoved(0, 1));
197 rows.clear();
198 rows.insert(0);
199 rows.insert(2);
200 table_model_->RemoveRows(rows);
201 EXPECT_EQ(1, table_model_->RowCount());
202 EXPECT_EQ(1, static_cast<int>(table_model_->GetGroups().size()));
203 CheckInvariants();
204
205 table_model_->SetObserver(NULL);
206 }
207
TEST_F(PluginExceptionsTableModelTest,RemoveAllRows)208 TEST_F(PluginExceptionsTableModelTest, RemoveAllRows) {
209 plugin_test_internal::MockTableModelObserver observer(table_model_.get());
210 table_model_->SetObserver(&observer);
211
212 EXPECT_CALL(observer, OnModelChanged());
213 table_model_->RemoveAll();
214 EXPECT_EQ(0, table_model_->RowCount());
215 EXPECT_EQ(0, static_cast<int>(table_model_->GetGroups().size()));
216 CheckInvariants();
217 table_model_->SetObserver(NULL);
218 }
219