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/run_loop.h"
9#include "base/strings/string16.h"
10#include "base/strings/string_util.h"
11#include "base/strings/utf_string_conversions.h"
12#include "chrome/browser/extensions/test_extension_system.h"
13#include "chrome/browser/media_galleries/media_galleries_dialog_controller_test_util.h"
14#include "chrome/browser/media_galleries/media_galleries_permission_controller.h"
15#include "chrome/browser/media_galleries/media_galleries_preferences.h"
16#include "chrome/browser/media_galleries/media_galleries_test_util.h"
17#include "chrome/test/base/testing_profile.h"
18#include "components/storage_monitor/storage_info.h"
19#include "components/storage_monitor/test_storage_monitor.h"
20#include "content/public/test/test_browser_thread_bundle.h"
21#include "extensions/common/permissions/media_galleries_permission.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24#if defined(OS_CHROMEOS)
25#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
26#include "chrome/browser/chromeos/settings/cros_settings.h"
27#include "chrome/browser/chromeos/settings/device_settings_service.h"
28#endif
29
30using storage_monitor::StorageInfo;
31using storage_monitor::TestStorageMonitor;
32
33namespace {
34
35std::string GalleryName(const MediaGalleryPrefInfo& gallery) {
36  base::string16 name = gallery.GetGalleryDisplayName();
37  return base::UTF16ToASCII(name);
38}
39
40}  // namespace
41
42class MediaGalleriesPermissionControllerTest : public ::testing::Test {
43 public:
44  MediaGalleriesPermissionControllerTest()
45      : dialog_(NULL),
46        dialog_update_count_at_destruction_(0),
47        controller_(NULL),
48        profile_(new TestingProfile()),
49        weak_factory_(this) {
50  }
51
52  virtual ~MediaGalleriesPermissionControllerTest() {
53    EXPECT_FALSE(controller_);
54    EXPECT_FALSE(dialog_);
55  }
56
57  virtual void SetUp() OVERRIDE {
58    ASSERT_TRUE(TestStorageMonitor::CreateAndInstall());
59
60    extensions::TestExtensionSystem* extension_system(
61        static_cast<extensions::TestExtensionSystem*>(
62            extensions::ExtensionSystem::Get(profile_.get())));
63    extension_system->CreateExtensionService(
64        CommandLine::ForCurrentProcess(), base::FilePath(), false);
65
66    gallery_prefs_.reset(new MediaGalleriesPreferences(profile_.get()));
67    base::RunLoop loop;
68    gallery_prefs_->EnsureInitialized(loop.QuitClosure());
69    loop.Run();
70
71    std::vector<std::string> read_permissions;
72    read_permissions.push_back(
73        extensions::MediaGalleriesPermission::kReadPermission);
74    extension_ = AddMediaGalleriesApp("read", read_permissions, profile_.get());
75  }
76
77  virtual void TearDown() OVERRIDE {
78    TestStorageMonitor::Destroy();
79  }
80
81  void StartDialog() {
82    ASSERT_FALSE(controller_);
83    controller_ = new MediaGalleriesPermissionController(
84        *extension_.get(),
85        gallery_prefs_.get(),
86        base::Bind(&MediaGalleriesPermissionControllerTest::CreateMockDialog,
87                   base::Unretained(this)),
88        base::Bind(
89            &MediaGalleriesPermissionControllerTest::OnControllerDone,
90            base::Unretained(this)));
91  }
92
93  MediaGalleriesPermissionController* controller() {
94    return controller_;
95  }
96
97  MockMediaGalleriesDialog* dialog() {
98    return dialog_;
99  }
100
101  int dialog_update_count_at_destruction() {
102    EXPECT_FALSE(dialog_);
103    return dialog_update_count_at_destruction_;
104  }
105
106  extensions::Extension* extension() {
107    return extension_.get();
108  }
109
110  MediaGalleriesPreferences* gallery_prefs() {
111    return gallery_prefs_.get();
112  }
113
114  GalleryDialogId GetDialogIdFromPrefId(MediaGalleryPrefId pref_id);
115
116  void TestForgottenType(MediaGalleryPrefInfo::Type type,
117                         bool forget_preserves_pref_id);
118
119 protected:
120  EnsureMediaDirectoriesExists mock_gallery_locations_;
121
122 private:
123  MediaGalleriesDialog* CreateMockDialog(
124      MediaGalleriesDialogController* controller) {
125    EXPECT_FALSE(dialog_);
126    dialog_update_count_at_destruction_ = 0;
127    dialog_ = new MockMediaGalleriesDialog(base::Bind(
128        &MediaGalleriesPermissionControllerTest::OnDialogDestroyed,
129        weak_factory_.GetWeakPtr()));
130    return dialog_;
131  }
132
133  void OnDialogDestroyed(int update_count) {
134    EXPECT_TRUE(dialog_);
135    dialog_update_count_at_destruction_ = update_count;
136    dialog_ = NULL;
137  }
138
139  void OnControllerDone() {
140    controller_ = NULL;
141  }
142
143  // Needed for extension service & friends to work.
144  content::TestBrowserThreadBundle thread_bundle_;
145
146  // The dialog is owned by the controller, but this pointer should only be
147  // valid while the dialog is live within the controller.
148  MockMediaGalleriesDialog* dialog_;
149  int dialog_update_count_at_destruction_;
150
151  // The controller owns itself.
152  MediaGalleriesPermissionController* controller_;
153
154  scoped_refptr<extensions::Extension> extension_;
155
156#if defined OS_CHROMEOS
157  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
158  chromeos::ScopedTestCrosSettings test_cros_settings_;
159  chromeos::ScopedTestUserManager test_user_manager_;
160#endif
161
162  TestStorageMonitor monitor_;
163  scoped_ptr<TestingProfile> profile_;
164  scoped_ptr<MediaGalleriesPreferences> gallery_prefs_;
165
166  base::WeakPtrFactory<MediaGalleriesPermissionControllerTest>
167      weak_factory_;
168
169  DISALLOW_COPY_AND_ASSIGN(MediaGalleriesPermissionControllerTest);
170};
171
172GalleryDialogId
173MediaGalleriesPermissionControllerTest::GetDialogIdFromPrefId(
174    MediaGalleryPrefId pref_id) {
175  return controller_->GetDialogId(pref_id);
176}
177
178void MediaGalleriesPermissionControllerTest::TestForgottenType(
179    MediaGalleryPrefInfo::Type type, bool forget_preserves_pref_id) {
180  EXPECT_EQ(0U, gallery_prefs()->GalleriesForExtension(*extension()).size());
181
182  MediaGalleryPrefId forgotten1 = gallery_prefs()->AddGalleryByPath(
183      MakeMediaGalleriesTestingPath("forgotten1"), type);
184  MediaGalleryPrefId forgotten2 = gallery_prefs()->AddGalleryByPath(
185      MakeMediaGalleriesTestingPath("forgotten2"), type);
186  // Show dialog and accept to verify 2 entries
187  StartDialog();
188  EXPECT_EQ(0U, controller()->GetSectionEntries(0).size());
189  EXPECT_EQ(mock_gallery_locations_.num_galleries() + 2U,
190            controller()->GetSectionEntries(1).size());
191  controller()->DidToggleEntry(GetDialogIdFromPrefId(forgotten1), true);
192  controller()->DidToggleEntry(GetDialogIdFromPrefId(forgotten2), true);
193  controller()->DialogFinished(true);
194  EXPECT_EQ(2U, gallery_prefs()->GalleriesForExtension(*extension()).size());
195
196  // Forget one and cancel to see that it's still there.
197  StartDialog();
198  EXPECT_EQ(2U, controller()->GetSectionEntries(0).size());
199  controller()->DidForgetEntry(GetDialogIdFromPrefId(forgotten1));
200  EXPECT_EQ(1U, controller()->GetSectionEntries(0).size());
201  controller()->DialogFinished(false);
202  EXPECT_EQ(2U, gallery_prefs()->GalleriesForExtension(*extension()).size());
203
204  // Forget one and confirm to see that it's gone.
205  StartDialog();
206  EXPECT_EQ(2U, controller()->GetSectionEntries(0).size());
207  controller()->DidForgetEntry(GetDialogIdFromPrefId(forgotten1));
208  EXPECT_EQ(1U, controller()->GetSectionEntries(0).size());
209  controller()->DialogFinished(true);
210  EXPECT_EQ(1U, gallery_prefs()->GalleriesForExtension(*extension()).size());
211
212  // Add back and test whether the same pref id is preserved.
213  StartDialog();
214  controller()->FileSelected(
215      MakeMediaGalleriesTestingPath("forgotten1"), 0, NULL);
216  controller()->DialogFinished(true);
217  EXPECT_EQ(2U, gallery_prefs()->GalleriesForExtension(*extension()).size());
218  MediaGalleryPrefInfo retrieved_info;
219  EXPECT_TRUE(gallery_prefs()->LookUpGalleryByPath(
220      MakeMediaGalleriesTestingPath("forgotten1"), &retrieved_info));
221  EXPECT_EQ(forget_preserves_pref_id, retrieved_info.pref_id == forgotten1);
222
223  // Add a new one and forget it & see that it's gone.
224  MediaGalleryPrefId forgotten3 = gallery_prefs()->AddGalleryByPath(
225      MakeMediaGalleriesTestingPath("forgotten3"), type);
226  StartDialog();
227  EXPECT_EQ(2U, controller()->GetSectionEntries(0).size());
228  EXPECT_EQ(mock_gallery_locations_.num_galleries() + 1U,
229            controller()->GetSectionEntries(1).size());
230  controller()->DidToggleEntry(GetDialogIdFromPrefId(forgotten3), true);
231  controller()->DidForgetEntry(GetDialogIdFromPrefId(forgotten3));
232  EXPECT_EQ(2U, controller()->GetSectionEntries(0).size());
233  EXPECT_EQ(static_cast<unsigned long>(mock_gallery_locations_.num_galleries()),
234            controller()->GetSectionEntries(1).size());
235  controller()->DialogFinished(true);
236  EXPECT_EQ(2U, gallery_prefs()->GalleriesForExtension(*extension()).size());
237}
238
239TEST_F(MediaGalleriesPermissionControllerTest, TestForgottenUserAdded) {
240  TestForgottenType(MediaGalleryPrefInfo::kUserAdded,
241                    false /* forget_preserves_pref_id */);
242}
243
244TEST_F(MediaGalleriesPermissionControllerTest, TestForgottenAutoDetected) {
245  TestForgottenType(MediaGalleryPrefInfo::kAutoDetected,
246                    true /* forget_preserves_pref_id */);
247}
248
249TEST_F(MediaGalleriesPermissionControllerTest, TestForgottenScanResult) {
250  TestForgottenType(MediaGalleryPrefInfo::kScanResult,
251                    true /* forget_preserves_pref_id */);
252}
253
254TEST_F(MediaGalleriesPermissionControllerTest, TestNameGeneration) {
255  MediaGalleryPrefInfo gallery;
256  gallery.pref_id = 1;
257  gallery.device_id = StorageInfo::MakeDeviceId(
258      StorageInfo::FIXED_MASS_STORAGE, "/path/to/gallery");
259  gallery.type = MediaGalleryPrefInfo::kAutoDetected;
260  std::string galleryName("/path/to/gallery");
261#if defined(OS_CHROMEOS)
262  galleryName = "gallery";
263#endif
264  EXPECT_EQ(galleryName, GalleryName(gallery));
265
266  gallery.display_name = base::ASCIIToUTF16("override");
267  EXPECT_EQ("override", GalleryName(gallery));
268
269  gallery.display_name = base::string16();
270  gallery.volume_label = base::ASCIIToUTF16("label");
271  EXPECT_EQ(galleryName, GalleryName(gallery));
272
273  gallery.path = base::FilePath(FILE_PATH_LITERAL("sub/gallery2"));
274  galleryName = "/path/to/gallery/sub/gallery2";
275#if defined(OS_CHROMEOS)
276  galleryName = "gallery2";
277#endif
278#if defined(OS_WIN)
279  galleryName = base::FilePath(FILE_PATH_LITERAL("/path/to/gallery"))
280                    .Append(gallery.path).MaybeAsASCII();
281#endif
282  EXPECT_EQ(galleryName, GalleryName(gallery));
283
284  gallery.path = base::FilePath();
285  gallery.device_id = StorageInfo::MakeDeviceId(
286      StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM,
287      "/path/to/dcim");
288  gallery.display_name = base::ASCIIToUTF16("override");
289  EXPECT_EQ("override", GalleryName(gallery));
290
291  gallery.volume_label = base::ASCIIToUTF16("volume");
292  gallery.vendor_name = base::ASCIIToUTF16("vendor");
293  gallery.model_name = base::ASCIIToUTF16("model");
294  EXPECT_EQ("override", GalleryName(gallery));
295
296  gallery.display_name = base::string16();
297  EXPECT_EQ("volume", GalleryName(gallery));
298
299  gallery.volume_label = base::string16();
300  EXPECT_EQ("vendor, model", GalleryName(gallery));
301
302  gallery.total_size_in_bytes = 1000000;
303  EXPECT_EQ("977 KB vendor, model", GalleryName(gallery));
304
305  gallery.path = base::FilePath(FILE_PATH_LITERAL("sub/path"));
306  EXPECT_EQ("path - 977 KB vendor, model", GalleryName(gallery));
307}
308