1 // Copyright 2014 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/bind.h" 6 #include "base/command_line.h" 7 #include "base/files/file_path.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/weak_ptr.h" 10 #include "base/run_loop.h" 11 #include "base/strings/string16.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/time/time.h" 14 #include "chrome/browser/extensions/test_extension_system.h" 15 #include "chrome/browser/media_galleries/media_galleries_dialog_controller_test_util.h" 16 #include "chrome/browser/media_galleries/media_galleries_preferences.h" 17 #include "chrome/browser/media_galleries/media_galleries_scan_result_controller.h" 18 #include "chrome/browser/media_galleries/media_galleries_test_util.h" 19 #include "chrome/test/base/testing_profile.h" 20 #include "components/storage_monitor/test_storage_monitor.h" 21 #include "content/public/test/test_browser_thread_bundle.h" 22 #include "extensions/browser/extension_system.h" 23 #include "extensions/common/extension.h" 24 #include "extensions/common/permissions/media_galleries_permission.h" 25 #include "testing/gtest/include/gtest/gtest.h" 26 27 #if defined(OS_CHROMEOS) 28 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" 29 #include "chrome/browser/chromeos/settings/cros_settings.h" 30 #include "chrome/browser/chromeos/settings/device_settings_service.h" 31 #endif 32 33 class MediaGalleriesScanResultControllerTest : public testing::Test { 34 public: 35 MediaGalleriesScanResultControllerTest() 36 : dialog_(NULL), 37 dialog_update_count_at_destruction_(0), 38 controller_(NULL), 39 profile_(new TestingProfile()), 40 weak_factory_(this) { 41 } 42 43 virtual ~MediaGalleriesScanResultControllerTest() { 44 EXPECT_FALSE(controller_); 45 EXPECT_FALSE(dialog_); 46 } 47 48 virtual void SetUp() OVERRIDE { 49 ASSERT_TRUE(storage_monitor::TestStorageMonitor::CreateAndInstall()); 50 51 extensions::TestExtensionSystem* extension_system( 52 static_cast<extensions::TestExtensionSystem*>( 53 extensions::ExtensionSystem::Get(profile_.get()))); 54 extension_system->CreateExtensionService( 55 CommandLine::ForCurrentProcess(), base::FilePath(), false); 56 57 gallery_prefs_.reset(new MediaGalleriesPreferences(profile_.get())); 58 base::RunLoop loop; 59 gallery_prefs_->EnsureInitialized(loop.QuitClosure()); 60 loop.Run(); 61 62 std::vector<std::string> read_permissions; 63 read_permissions.push_back( 64 extensions::MediaGalleriesPermission::kReadPermission); 65 extension_ = AddMediaGalleriesApp("read", read_permissions, profile_.get()); 66 } 67 68 virtual void TearDown() OVERRIDE { 69 storage_monitor::TestStorageMonitor::Destroy(); 70 } 71 72 void StartDialog() { 73 ASSERT_FALSE(controller_); 74 controller_ = new MediaGalleriesScanResultController( 75 *extension_.get(), 76 gallery_prefs_.get(), 77 base::Bind( 78 &MediaGalleriesScanResultControllerTest::CreateMockDialog, 79 base::Unretained(this)), 80 base::Bind( 81 &MediaGalleriesScanResultControllerTest::OnControllerDone, 82 base::Unretained(this))); 83 } 84 85 size_t GetFirstSectionSize() const { 86 return controller()->GetSectionEntries(0).size(); 87 } 88 89 MediaGalleriesScanResultController* controller() const { 90 return controller_; 91 } 92 93 MockMediaGalleriesDialog* dialog() { 94 return dialog_; 95 } 96 97 int dialog_update_count_at_destruction() { 98 EXPECT_FALSE(dialog_); 99 return dialog_update_count_at_destruction_; 100 } 101 102 extensions::Extension* extension() { 103 return extension_.get(); 104 } 105 106 MediaGalleriesPreferences* gallery_prefs() { 107 return gallery_prefs_.get(); 108 } 109 110 MediaGalleryPrefId AddGallery(const std::string& path, 111 MediaGalleryPrefInfo::Type type, 112 int audio_count, int image_count, 113 int video_count) { 114 MediaGalleryPrefInfo gallery_info; 115 gallery_prefs_->LookUpGalleryByPath(MakeMediaGalleriesTestingPath(path), 116 &gallery_info); 117 return gallery_prefs_->AddGallery( 118 gallery_info.device_id, 119 gallery_info.path, 120 type, 121 gallery_info.volume_label, 122 gallery_info.vendor_name, 123 gallery_info.model_name, 124 gallery_info.total_size_in_bytes, 125 gallery_info.last_attach_time, 126 audio_count, image_count, video_count); 127 } 128 129 MediaGalleryPrefId AddScanResult(const std::string& path, int audio_count, 130 int image_count, int video_count) { 131 return AddGallery(path, MediaGalleryPrefInfo::kScanResult, audio_count, 132 image_count, video_count); 133 } 134 135 private: 136 MediaGalleriesDialog* CreateMockDialog( 137 MediaGalleriesDialogController* controller) { 138 EXPECT_FALSE(dialog_); 139 dialog_update_count_at_destruction_ = 0; 140 dialog_ = new MockMediaGalleriesDialog(base::Bind( 141 &MediaGalleriesScanResultControllerTest::OnDialogDestroyed, 142 weak_factory_.GetWeakPtr())); 143 return dialog_; 144 } 145 146 void OnDialogDestroyed(int update_count) { 147 EXPECT_TRUE(dialog_); 148 dialog_update_count_at_destruction_ = update_count; 149 dialog_ = NULL; 150 } 151 152 void OnControllerDone() { 153 controller_ = NULL; 154 } 155 156 // Needed for extension service & friends to work. 157 content::TestBrowserThreadBundle thread_bundle_; 158 159 // The dialog is owned by the controller, but this pointer should only be 160 // valid while the dialog is live within the controller. 161 MockMediaGalleriesDialog* dialog_; 162 int dialog_update_count_at_destruction_; 163 164 // The controller owns itself. 165 MediaGalleriesScanResultController* controller_; 166 167 scoped_refptr<extensions::Extension> extension_; 168 169 EnsureMediaDirectoriesExists mock_gallery_locations_; 170 171 #if defined OS_CHROMEOS 172 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; 173 chromeos::ScopedTestCrosSettings test_cros_settings_; 174 chromeos::ScopedTestUserManager test_user_manager_; 175 #endif 176 177 storage_monitor::TestStorageMonitor monitor_; 178 scoped_ptr<TestingProfile> profile_; 179 scoped_ptr<MediaGalleriesPreferences> gallery_prefs_; 180 181 base::WeakPtrFactory<MediaGalleriesScanResultControllerTest> weak_factory_; 182 183 DISALLOW_COPY_AND_ASSIGN(MediaGalleriesScanResultControllerTest); 184 }; 185 186 TEST_F(MediaGalleriesScanResultControllerTest, EmptyDialog) { 187 StartDialog(); 188 EXPECT_TRUE(controller()); 189 EXPECT_TRUE(dialog()); 190 EXPECT_EQ(0U, GetFirstSectionSize()); 191 192 controller()->DialogFinished(true); 193 EXPECT_FALSE(controller()); 194 EXPECT_FALSE(dialog()); 195 EXPECT_EQ(0, dialog_update_count_at_destruction()); 196 } 197 198 TEST_F(MediaGalleriesScanResultControllerTest, AddScanResults) { 199 // Start with two scan results. 200 MediaGalleryPrefId scan_id = AddScanResult("scan_id", 1, 0, 0); 201 MediaGalleryPrefId auto_id = 202 AddGallery("auto_id", MediaGalleryPrefInfo::kAutoDetected, 2, 0, 0); 203 EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 204 205 // Show the dialog, but cancel it. 206 StartDialog(); 207 EXPECT_EQ(2U, GetFirstSectionSize()); 208 controller()->DialogFinished(false); 209 EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 210 211 // Show the dialog, unselect both and accept it. 212 StartDialog(); 213 EXPECT_EQ(2U, GetFirstSectionSize()); 214 controller()->DidToggleEntry(scan_id, false); 215 controller()->DidToggleEntry(auto_id, false); 216 controller()->DialogFinished(true); 217 EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 218 219 // Show the dialog, leave one selected and accept it. 220 StartDialog(); 221 EXPECT_EQ(2U, GetFirstSectionSize()); 222 controller()->DidToggleEntry(scan_id, false); 223 controller()->DialogFinished(true); 224 MediaGalleryPrefIdSet permitted = 225 gallery_prefs()->GalleriesForExtension(*extension()); 226 ASSERT_EQ(1U, permitted.size()); 227 EXPECT_EQ(auto_id, *permitted.begin()); 228 229 // Show the dialog, toggle the remaining entry twice and then accept it. 230 StartDialog(); 231 EXPECT_EQ(1U, GetFirstSectionSize()); 232 controller()->DidToggleEntry(scan_id, false); 233 controller()->DidToggleEntry(scan_id, true); 234 controller()->DialogFinished(true); 235 EXPECT_EQ(2U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 236 } 237 238 TEST_F(MediaGalleriesScanResultControllerTest, Blacklisted) { 239 // Start with two scan results. 240 MediaGalleryPrefId scan_id = AddScanResult("scan_id", 1, 0, 0); 241 MediaGalleryPrefId auto_id = 242 AddGallery("auto_id", MediaGalleryPrefInfo::kAutoDetected, 2, 0, 0); 243 EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 244 245 // Show the dialog, but cancel it. 246 StartDialog(); 247 EXPECT_EQ(2U, GetFirstSectionSize()); 248 controller()->DialogFinished(false); 249 EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 250 251 // Blacklist one and try again. 252 gallery_prefs()->ForgetGalleryById(scan_id); 253 StartDialog(); 254 EXPECT_EQ(1U, GetFirstSectionSize()); 255 controller()->DialogFinished(false); 256 257 // Adding it as a user gallery should change its type. 258 AddGallery("scan_id", MediaGalleryPrefInfo::kUserAdded, 1, 0, 0); 259 StartDialog(); 260 EXPECT_EQ(2U, GetFirstSectionSize()); 261 262 // Blacklisting the other while the dialog is open should remove it. 263 gallery_prefs()->ForgetGalleryById(auto_id); 264 EXPECT_EQ(1U, GetFirstSectionSize()); 265 controller()->DialogFinished(false); 266 EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 267 EXPECT_EQ(1, dialog_update_count_at_destruction()); 268 } 269 270 TEST_F(MediaGalleriesScanResultControllerTest, PrefUpdates) { 271 MediaGalleryPrefId selected = AddScanResult("selected", 1, 0, 0); 272 MediaGalleryPrefId unselected = AddScanResult("unselected", 1, 0, 0); 273 MediaGalleryPrefId selected_add_permission = 274 AddScanResult("selected_add_permission", 1, 0, 0); 275 MediaGalleryPrefId unselected_add_permission = 276 AddScanResult("unselected_add_permission", 1, 0, 0); 277 MediaGalleryPrefId selected_removed = 278 AddScanResult("selected_removed", 1, 0, 0); 279 MediaGalleryPrefId unselected_removed = 280 AddScanResult("unselected_removed", 1, 0, 0); 281 MediaGalleryPrefId selected_update = 282 AddScanResult("selected_update", 1, 0, 0); 283 MediaGalleryPrefId unselected_update = 284 AddScanResult("unselected_update", 1, 0, 0); 285 286 gallery_prefs()->AddGalleryByPath(MakeMediaGalleriesTestingPath("user"), 287 MediaGalleryPrefInfo::kUserAdded); 288 gallery_prefs()->AddGalleryByPath( 289 MakeMediaGalleriesTestingPath("auto_detected"), 290 MediaGalleryPrefInfo::kAutoDetected); 291 MediaGalleryPrefId blacklisted = gallery_prefs()->AddGalleryByPath( 292 MakeMediaGalleriesTestingPath("blacklisted"), 293 MediaGalleryPrefInfo::kAutoDetected); 294 gallery_prefs()->ForgetGalleryById(blacklisted); 295 EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 296 297 StartDialog(); 298 EXPECT_EQ(8U, GetFirstSectionSize()); 299 controller()->DidToggleEntry(unselected, false); 300 controller()->DidToggleEntry(unselected_add_permission, false); 301 controller()->DidToggleEntry(unselected_removed, false); 302 controller()->DidToggleEntry(unselected_update, false); 303 EXPECT_EQ(0, dialog()->update_count()); 304 EXPECT_EQ(8U, GetFirstSectionSize()); 305 306 // Add permission. 307 gallery_prefs()->SetGalleryPermissionForExtension(*extension(), 308 unselected_add_permission, 309 true); 310 EXPECT_EQ(1, dialog()->update_count()); 311 EXPECT_EQ(7U, GetFirstSectionSize()); 312 gallery_prefs()->SetGalleryPermissionForExtension(*extension(), 313 selected_add_permission, 314 true); 315 EXPECT_EQ(2, dialog()->update_count()); 316 EXPECT_EQ(6U, GetFirstSectionSize()); 317 318 // Blacklist scan results. 319 gallery_prefs()->ForgetGalleryById(unselected_removed); 320 EXPECT_EQ(3, dialog()->update_count()); 321 EXPECT_EQ(5U, GetFirstSectionSize()); 322 gallery_prefs()->ForgetGalleryById(selected_removed); 323 EXPECT_EQ(4, dialog()->update_count()); 324 EXPECT_EQ(4U, GetFirstSectionSize()); 325 326 // Update names. 327 const MediaGalleryPrefInfo& unselected_update_info = 328 gallery_prefs()->known_galleries().find(unselected_update)->second; 329 gallery_prefs()->AddGallery( 330 unselected_update_info.device_id, base::FilePath(), 331 MediaGalleryPrefInfo::kScanResult, 332 base::ASCIIToUTF16("Updated & Unselected"), 333 base::string16(), base::string16(), 0, base::Time(), 1, 0, 0); 334 EXPECT_EQ(5, dialog()->update_count()); 335 EXPECT_EQ(4U, GetFirstSectionSize()); 336 const MediaGalleryPrefInfo& selected_update_info = 337 gallery_prefs()->known_galleries().find(selected_update)->second; 338 gallery_prefs()->AddGallery( 339 selected_update_info.device_id, base::FilePath(), 340 MediaGalleryPrefInfo::kScanResult, 341 base::ASCIIToUTF16("Updated & Selected"), 342 base::string16(), base::string16(), 0, base::Time(), 1, 0, 0); 343 EXPECT_EQ(6, dialog()->update_count()); 344 EXPECT_EQ(4U, GetFirstSectionSize()); 345 346 MediaGalleriesDialogController::Entries results = 347 controller()->GetSectionEntries(0); 348 EXPECT_EQ(selected, results[0].pref_info.pref_id); 349 EXPECT_TRUE(results[0].selected); 350 EXPECT_EQ(selected_update, results[1].pref_info.pref_id); 351 EXPECT_TRUE(results[1].selected); 352 EXPECT_EQ(base::ASCIIToUTF16("Updated & Selected"), 353 results[1].pref_info.volume_label); 354 EXPECT_EQ(unselected, results[2].pref_info.pref_id); 355 EXPECT_FALSE(results[2].selected); 356 EXPECT_EQ(unselected_update, results[3].pref_info.pref_id); 357 EXPECT_FALSE(results[3].selected); 358 EXPECT_EQ(base::ASCIIToUTF16("Updated & Unselected"), 359 results[3].pref_info.volume_label); 360 361 controller()->DialogFinished(true); 362 EXPECT_EQ(4U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 363 StartDialog(); 364 EXPECT_EQ(2U, GetFirstSectionSize()); 365 controller()->DialogFinished(false); 366 } 367 368 TEST_F(MediaGalleriesScanResultControllerTest, ForgetGallery) { 369 // Start with two scan results. 370 MediaGalleryPrefId scan1 = AddScanResult("scan1", 1, 0, 0); 371 MediaGalleryPrefId scan2 = AddScanResult("scan2", 2, 0, 0); 372 EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 373 374 // Remove one and then cancel. 375 StartDialog(); 376 EXPECT_EQ(2U, GetFirstSectionSize()); 377 controller()->DidForgetEntry(scan1); 378 controller()->DialogFinished(false); 379 EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 380 381 // Remove one and then have it blacklisted from prefs. 382 StartDialog(); 383 EXPECT_EQ(2U, GetFirstSectionSize()); 384 controller()->DidForgetEntry(scan1); 385 EXPECT_EQ(1, dialog()->update_count()); 386 controller()->DidToggleEntry(scan2, false); // Uncheck the second. 387 gallery_prefs()->ForgetGalleryById(scan1); 388 controller()->DialogFinished(true); 389 EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 390 EXPECT_EQ(2, dialog_update_count_at_destruction()); 391 392 // Remove the other. 393 StartDialog(); 394 EXPECT_EQ(1U, GetFirstSectionSize()); 395 controller()->DidForgetEntry(scan2); 396 controller()->DialogFinished(true); 397 EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size()); 398 399 // Check that nothing shows up. 400 StartDialog(); 401 EXPECT_EQ(0U, GetFirstSectionSize()); 402 controller()->DialogFinished(false); 403 } 404 405 TEST_F(MediaGalleriesScanResultControllerTest, SortOrder) { 406 // Intentionally out of order numerically and alphabetically. 407 MediaGalleryPrefId third = AddScanResult("third", 2, 2, 2); 408 MediaGalleryPrefId second = 409 AddGallery("second", MediaGalleryPrefInfo::kAutoDetected, 9, 0, 0); 410 MediaGalleryPrefId first = AddScanResult("first", 8, 2, 3); 411 MediaGalleryPrefId fifth = AddScanResult("abb", 3, 0, 0); 412 MediaGalleryPrefId fourth = AddScanResult("aaa", 3, 0, 0); 413 414 StartDialog(); 415 MediaGalleriesDialogController::Entries results = 416 controller()->GetSectionEntries(0); 417 ASSERT_EQ(5U, results.size()); 418 EXPECT_EQ(first, results[0].pref_info.pref_id); 419 EXPECT_EQ(second, results[1].pref_info.pref_id); 420 EXPECT_EQ(third, results[2].pref_info.pref_id); 421 EXPECT_EQ(fourth, results[3].pref_info.pref_id); 422 EXPECT_EQ(fifth, results[4].pref_info.pref_id); 423 controller()->DialogFinished(false); 424 } 425