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: 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: 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: 57 PluginExceptionsTableModelTest() 58 : ui_thread_(BrowserThread::UI, &message_loop_), 59 command_line_(CommandLine::ForCurrentProcess(), 60 *CommandLine::ForCurrentProcess()) {} 61 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: 111 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 155 TEST_F(PluginExceptionsTableModelTest, Basic) { 156 EXPECT_EQ(3, table_model_->RowCount()); 157 CheckInvariants(); 158 } 159 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 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 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