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/string16.h" 6 #include "base/utf_string_conversions.h" 7 #include "chrome/browser/profiles/profile.h" 8 #include "chrome/browser/search_engines/template_url.h" 9 #include "chrome/browser/search_engines/template_url_model.h" 10 #include "chrome/browser/ui/search_engines/keyword_editor_controller.h" 11 #include "chrome/browser/ui/search_engines/template_url_table_model.h" 12 #include "chrome/common/pref_names.h" 13 #include "chrome/test/testing_pref_service.h" 14 #include "chrome/test/testing_profile.h" 15 #include "content/common/notification_details.h" 16 #include "content/common/notification_source.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 #include "ui/base/models/table_model_observer.h" 19 20 static const string16 kA(ASCIIToUTF16("a")); 21 static const string16 kA1(ASCIIToUTF16("a1")); 22 static const string16 kB(ASCIIToUTF16("b")); 23 static const string16 kB1(ASCIIToUTF16("b1")); 24 25 // Base class for keyword editor tests. Creates a profile containing an 26 // empty TemplateURLModel. 27 class KeywordEditorControllerTest : public testing::Test, 28 public ui::TableModelObserver { 29 public: 30 // Initializes all of the state. 31 void Init(bool simulate_load_failure); 32 33 virtual void SetUp() { 34 Init(false); 35 } 36 37 virtual void OnModelChanged() { 38 model_changed_count_++; 39 } 40 41 virtual void OnItemsChanged(int start, int length) { 42 items_changed_count_++; 43 } 44 45 virtual void OnItemsAdded(int start, int length) { 46 added_count_++; 47 } 48 49 virtual void OnItemsRemoved(int start, int length) { 50 removed_count_++; 51 } 52 53 void VerifyChangeCount(int model_changed_count, int item_changed_count, 54 int added_count, int removed_count) { 55 ASSERT_EQ(model_changed_count, model_changed_count_); 56 ASSERT_EQ(item_changed_count, items_changed_count_); 57 ASSERT_EQ(added_count, added_count_); 58 ASSERT_EQ(removed_count, removed_count_); 59 ClearChangeCount(); 60 } 61 62 void ClearChangeCount() { 63 model_changed_count_ = items_changed_count_ = added_count_ = 64 removed_count_ = 0; 65 } 66 67 void SimulateDefaultSearchIsManaged(const std::string& url) { 68 ASSERT_FALSE(url.empty()); 69 TestingPrefService* service = profile_->GetTestingPrefService(); 70 service->SetManagedPref( 71 prefs::kDefaultSearchProviderEnabled, 72 Value::CreateBooleanValue(true)); 73 service->SetManagedPref( 74 prefs::kDefaultSearchProviderSearchURL, 75 Value::CreateStringValue(url)); 76 service->SetManagedPref( 77 prefs::kDefaultSearchProviderName, 78 Value::CreateStringValue("managed")); 79 // Clear the IDs that are not specified via policy. 80 service->SetManagedPref( 81 prefs::kDefaultSearchProviderID, new StringValue("")); 82 service->SetManagedPref( 83 prefs::kDefaultSearchProviderPrepopulateID, new StringValue("")); 84 model_->Observe( 85 NotificationType::PREF_CHANGED, 86 Source<PrefService>(profile_->GetTestingPrefService()), 87 Details<std::string>(NULL)); 88 } 89 90 TemplateURLTableModel* table_model() const { 91 return controller_->table_model(); 92 } 93 94 protected: 95 MessageLoopForUI message_loop_; 96 scoped_ptr<TestingProfile> profile_; 97 scoped_ptr<KeywordEditorController> controller_; 98 TemplateURLModel* model_; 99 100 int model_changed_count_; 101 int items_changed_count_; 102 int added_count_; 103 int removed_count_; 104 }; 105 106 void KeywordEditorControllerTest::Init(bool simulate_load_failure) { 107 ClearChangeCount(); 108 109 // If init is called twice, make sure that the controller is destroyed before 110 // the profile is. 111 controller_.reset(); 112 profile_.reset(new TestingProfile()); 113 profile_->CreateTemplateURLModel(); 114 115 model_ = profile_->GetTemplateURLModel(); 116 if (simulate_load_failure) 117 model_->OnWebDataServiceRequestDone(0, NULL); 118 119 controller_.reset(new KeywordEditorController(profile_.get())); 120 controller_->table_model()->SetObserver(this); 121 } 122 123 // Tests adding a TemplateURL. 124 TEST_F(KeywordEditorControllerTest, Add) { 125 controller_->AddTemplateURL(kA, kB, "http://c"); 126 127 // Verify the observer was notified. 128 VerifyChangeCount(0, 0, 1, 0); 129 if (HasFatalFailure()) 130 return; 131 132 // Verify the TableModel has the new data. 133 ASSERT_EQ(1, table_model()->RowCount()); 134 135 // Verify the TemplateURLModel has the new entry. 136 ASSERT_EQ(1U, model_->GetTemplateURLs().size()); 137 138 // Verify the entry is what we added. 139 const TemplateURL* turl = model_->GetTemplateURLs()[0]; 140 EXPECT_EQ(ASCIIToUTF16("a"), turl->short_name()); 141 EXPECT_EQ(ASCIIToUTF16("b"), turl->keyword()); 142 ASSERT_TRUE(turl->url() != NULL); 143 EXPECT_EQ("http://c", turl->url()->url()); 144 } 145 146 // Tests modifying a TemplateURL. 147 TEST_F(KeywordEditorControllerTest, Modify) { 148 controller_->AddTemplateURL(kA, kB, "http://c"); 149 ClearChangeCount(); 150 151 // Modify the entry. 152 const TemplateURL* turl = model_->GetTemplateURLs()[0]; 153 controller_->ModifyTemplateURL(turl, kA1, kB1, "http://c1"); 154 155 // Make sure it was updated appropriately. 156 VerifyChangeCount(0, 1, 0, 0); 157 EXPECT_EQ(ASCIIToUTF16("a1"), turl->short_name()); 158 EXPECT_EQ(ASCIIToUTF16("b1"), turl->keyword()); 159 ASSERT_TRUE(turl->url() != NULL); 160 EXPECT_EQ("http://c1", turl->url()->url()); 161 } 162 163 // Tests making a TemplateURL the default search provider. 164 TEST_F(KeywordEditorControllerTest, MakeDefault) { 165 controller_->AddTemplateURL(kA, kB, "http://c{searchTerms}"); 166 ClearChangeCount(); 167 168 const TemplateURL* turl = model_->GetTemplateURLs()[0]; 169 int new_default = controller_->MakeDefaultTemplateURL(0); 170 EXPECT_EQ(0, new_default); 171 // Making an item the default sends a handful of changes. Which are sent isn't 172 // important, what is important is 'something' is sent. 173 ASSERT_TRUE(items_changed_count_ > 0 || added_count_ > 0 || 174 removed_count_ > 0); 175 ASSERT_TRUE(model_->GetDefaultSearchProvider() == turl); 176 177 // Making it default a second time should fail. 178 new_default = controller_->MakeDefaultTemplateURL(0); 179 EXPECT_EQ(-1, new_default); 180 } 181 182 // Tests that a TemplateURL can't be made the default if the default search 183 // provider is managed via policy. 184 TEST_F(KeywordEditorControllerTest, CannotSetDefaultWhileManaged) { 185 controller_->AddTemplateURL(kA, kB, "http://c{searchTerms}"); 186 controller_->AddTemplateURL(kA1, kB1, "http://d{searchTerms}"); 187 ClearChangeCount(); 188 189 const TemplateURL* turl1 = 190 model_->GetTemplateURLForKeyword(ASCIIToUTF16("b")); 191 ASSERT_TRUE(turl1 != NULL); 192 const TemplateURL* turl2 = 193 model_->GetTemplateURLForKeyword(ASCIIToUTF16("b1")); 194 ASSERT_TRUE(turl2 != NULL); 195 196 EXPECT_TRUE(controller_->CanMakeDefault(turl1)); 197 EXPECT_TRUE(controller_->CanMakeDefault(turl2)); 198 199 SimulateDefaultSearchIsManaged(turl2->url()->url()); 200 EXPECT_TRUE(model_->is_default_search_managed()); 201 202 EXPECT_FALSE(controller_->CanMakeDefault(turl1)); 203 EXPECT_FALSE(controller_->CanMakeDefault(turl2)); 204 } 205 206 // Tests that a TemplateURL can't be edited if it is the managed default search 207 // provider. 208 TEST_F(KeywordEditorControllerTest, EditManagedDefault) { 209 controller_->AddTemplateURL(kA, kB, "http://c{searchTerms}"); 210 controller_->AddTemplateURL(kA1, kB1, "http://d{searchTerms}"); 211 ClearChangeCount(); 212 213 const TemplateURL* turl1 = 214 model_->GetTemplateURLForKeyword(ASCIIToUTF16("b")); 215 ASSERT_TRUE(turl1 != NULL); 216 const TemplateURL* turl2 = 217 model_->GetTemplateURLForKeyword(ASCIIToUTF16("b1")); 218 ASSERT_TRUE(turl2 != NULL); 219 220 EXPECT_TRUE(controller_->CanEdit(turl1)); 221 EXPECT_TRUE(controller_->CanEdit(turl2)); 222 223 // Simulate setting a managed default. This will add another template URL to 224 // the model. 225 SimulateDefaultSearchIsManaged(turl2->url()->url()); 226 EXPECT_TRUE(model_->is_default_search_managed()); 227 EXPECT_TRUE(controller_->CanEdit(turl1)); 228 EXPECT_TRUE(controller_->CanEdit(turl2)); 229 EXPECT_FALSE(controller_->CanEdit(model_->GetDefaultSearchProvider())); 230 } 231 232 TEST_F(KeywordEditorControllerTest, MakeDefaultNoWebData) { 233 // Simulate a failure to load Web Data. 234 Init(true); 235 236 controller_->AddTemplateURL(kA, kB, "http://c{searchTerms}"); 237 ClearChangeCount(); 238 239 // This should not result in a crash. 240 int new_default = controller_->MakeDefaultTemplateURL(0); 241 EXPECT_EQ(0, new_default); 242 } 243 244 // Mutates the TemplateURLModel and make sure table model is updating 245 // appropriately. 246 TEST_F(KeywordEditorControllerTest, MutateTemplateURLModel) { 247 TemplateURL* turl = new TemplateURL(); 248 turl->set_keyword(ASCIIToUTF16("a")); 249 turl->set_short_name(ASCIIToUTF16("b")); 250 model_->Add(turl); 251 252 // Table model should have updated. 253 VerifyChangeCount(1, 0, 0, 0); 254 255 // And should contain the newly added TemplateURL. 256 ASSERT_EQ(1, table_model()->RowCount()); 257 ASSERT_EQ(0, table_model()->IndexOfTemplateURL(turl)); 258 } 259