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 <windows.h>
6 #include <dbt.h>
7 #include <stddef.h>
8
9 #include <memory>
10 #include <string>
11 #include <vector>
12
13 #include "base/macros.h"
14 #include "base/memory/free_deleter.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/run_loop.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "components/storage_monitor/mock_removable_storage_observer.h"
20 #include "components/storage_monitor/portable_device_watcher_win.h"
21 #include "components/storage_monitor/removable_device_constants.h"
22 #include "components/storage_monitor/storage_info.h"
23 #include "components/storage_monitor/storage_monitor_win.h"
24 #include "components/storage_monitor/test_portable_device_watcher_win.h"
25 #include "components/storage_monitor/test_storage_monitor.h"
26 #include "components/storage_monitor/test_storage_monitor_win.h"
27 #include "components/storage_monitor/test_volume_mount_watcher_win.h"
28 #include "components/storage_monitor/volume_mount_watcher_win.h"
29 #include "content/public/test/browser_task_environment.h"
30 #include "content/public/test/test_utils.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32
33 using base::ASCIIToUTF16;
34
35 typedef std::vector<int> DeviceIndices;
36
37 // StorageMonitorWinTest -------------------------------------------------------
38
39 namespace storage_monitor {
40
41 class StorageMonitorWinTest : public testing::Test {
42 public:
43 StorageMonitorWinTest();
44 ~StorageMonitorWinTest() override;
45
46 protected:
47 // testing::Test:
48 void SetUp() override;
49 void TearDown() override;
50
51 void PreAttachDevices();
52
53 void DoMassStorageDeviceAttachedTest(const DeviceIndices& device_indices);
54 void DoMassStorageDevicesDetachedTest(const DeviceIndices& device_indices);
55
56 // Injects a device attach or detach change (depending on the value of
57 // |test_attach|) and tests that the appropriate handler is called.
58 void DoMTPDeviceTest(const base::string16& pnp_device_id, bool test_attach);
59
60 // Gets the MTP details of the storage specified by the |storage_device_id|.
61 // On success, returns true and fills in |pnp_device_id| and
62 // |storage_object_id|.
63 bool GetMTPStorageInfo(const std::string& storage_device_id,
64 base::string16* pnp_device_id,
65 base::string16* storage_object_id);
66
67 std::unique_ptr<TestStorageMonitorWin> monitor_;
68
69 // Weak pointer; owned by the device notifications class.
70 TestVolumeMountWatcherWin* volume_mount_watcher_;
71
72 MockRemovableStorageObserver observer_;
73
74 private:
75 content::BrowserTaskEnvironment task_environment_;
76
77 DISALLOW_COPY_AND_ASSIGN(StorageMonitorWinTest);
78 };
79
StorageMonitorWinTest()80 StorageMonitorWinTest::StorageMonitorWinTest() {
81 }
82
~StorageMonitorWinTest()83 StorageMonitorWinTest::~StorageMonitorWinTest() {
84 }
85
SetUp()86 void StorageMonitorWinTest::SetUp() {
87 volume_mount_watcher_ = new TestVolumeMountWatcherWin;
88 monitor_.reset(new TestStorageMonitorWin(volume_mount_watcher_,
89 new TestPortableDeviceWatcherWin));
90
91 monitor_->Init();
92 content::RunAllTasksUntilIdle();
93 monitor_->AddObserver(&observer_);
94 }
95
TearDown()96 void StorageMonitorWinTest::TearDown() {
97 content::RunAllTasksUntilIdle();
98 monitor_->RemoveObserver(&observer_);
99
100 // Windows storage monitor must be destroyed on the same thread
101 // as construction.
102 monitor_.reset();
103 }
104
PreAttachDevices()105 void StorageMonitorWinTest::PreAttachDevices() {
106 monitor_.reset();
107 volume_mount_watcher_ = new TestVolumeMountWatcherWin;
108 volume_mount_watcher_->SetAttachedDevicesFake();
109
110 int expect_attach_calls = 0;
111 std::vector<base::FilePath> initial_devices =
112 volume_mount_watcher_->GetAttachedDevicesCallback().Run();
113 for (std::vector<base::FilePath>::const_iterator it = initial_devices.begin();
114 it != initial_devices.end(); ++it) {
115 bool removable;
116 ASSERT_TRUE(volume_mount_watcher_->GetDeviceRemovable(*it, &removable));
117 if (removable)
118 expect_attach_calls++;
119 }
120
121 monitor_.reset(new TestStorageMonitorWin(volume_mount_watcher_,
122 new TestPortableDeviceWatcherWin));
123
124 monitor_->AddObserver(&observer_);
125 monitor_->Init();
126
127 EXPECT_EQ(0u, volume_mount_watcher_->devices_checked().size());
128
129 content::RunAllTasksUntilIdle();
130
131 std::vector<base::FilePath> checked_devices =
132 volume_mount_watcher_->devices_checked();
133 sort(checked_devices.begin(), checked_devices.end());
134 EXPECT_EQ(initial_devices, checked_devices);
135 EXPECT_EQ(expect_attach_calls, observer_.attach_calls());
136 EXPECT_EQ(0, observer_.detach_calls());
137 }
138
DoMassStorageDeviceAttachedTest(const DeviceIndices & device_indices)139 void StorageMonitorWinTest::DoMassStorageDeviceAttachedTest(
140 const DeviceIndices& device_indices) {
141 DEV_BROADCAST_VOLUME volume_broadcast;
142 volume_broadcast.dbcv_size = sizeof(volume_broadcast);
143 volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME;
144 volume_broadcast.dbcv_unitmask = 0x0;
145 volume_broadcast.dbcv_flags = 0x0;
146
147 int expect_attach_calls = observer_.attach_calls();
148 for (DeviceIndices::const_iterator it = device_indices.begin();
149 it != device_indices.end(); ++it) {
150 volume_broadcast.dbcv_unitmask |= 0x1 << *it;
151 bool removable;
152 ASSERT_TRUE(volume_mount_watcher_->GetDeviceRemovable(
153 VolumeMountWatcherWin::DriveNumberToFilePath(*it), &removable));
154 if (removable)
155 expect_attach_calls++;
156 }
157 monitor_->InjectDeviceChange(DBT_DEVICEARRIVAL,
158 reinterpret_cast<LPARAM>(&volume_broadcast));
159
160 content::RunAllTasksUntilIdle();
161
162 EXPECT_EQ(expect_attach_calls, observer_.attach_calls());
163 EXPECT_EQ(0, observer_.detach_calls());
164 }
165
DoMassStorageDevicesDetachedTest(const DeviceIndices & device_indices)166 void StorageMonitorWinTest::DoMassStorageDevicesDetachedTest(
167 const DeviceIndices& device_indices) {
168 DEV_BROADCAST_VOLUME volume_broadcast;
169 volume_broadcast.dbcv_size = sizeof(volume_broadcast);
170 volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME;
171 volume_broadcast.dbcv_unitmask = 0x0;
172 volume_broadcast.dbcv_flags = 0x0;
173
174 int pre_attach_calls = observer_.attach_calls();
175 int expect_detach_calls = 0;
176 for (DeviceIndices::const_iterator it = device_indices.begin();
177 it != device_indices.end(); ++it) {
178 volume_broadcast.dbcv_unitmask |= 0x1 << *it;
179 StorageInfo info;
180 ASSERT_TRUE(volume_mount_watcher_->GetDeviceInfo(
181 VolumeMountWatcherWin::DriveNumberToFilePath(*it), &info));
182 if (StorageInfo::IsRemovableDevice(info.device_id()))
183 ++expect_detach_calls;
184 }
185 monitor_->InjectDeviceChange(DBT_DEVICEREMOVECOMPLETE,
186 reinterpret_cast<LPARAM>(&volume_broadcast));
187 content::RunAllTasksUntilIdle();
188 EXPECT_EQ(pre_attach_calls, observer_.attach_calls());
189 EXPECT_EQ(expect_detach_calls, observer_.detach_calls());
190 }
191
DoMTPDeviceTest(const base::string16 & pnp_device_id,bool test_attach)192 void StorageMonitorWinTest::DoMTPDeviceTest(const base::string16& pnp_device_id,
193 bool test_attach) {
194 GUID guidDevInterface = GUID_NULL;
195 HRESULT hr = CLSIDFromString(kWPDDevInterfaceGUID, &guidDevInterface);
196 if (FAILED(hr))
197 return;
198
199 size_t device_id_size = pnp_device_id.size() * sizeof(base::char16);
200 size_t size = sizeof(DEV_BROADCAST_DEVICEINTERFACE) + device_id_size;
201 std::unique_ptr<DEV_BROADCAST_DEVICEINTERFACE, base::FreeDeleter>
202 dev_interface_broadcast(
203 static_cast<DEV_BROADCAST_DEVICEINTERFACE*>(malloc(size)));
204 DCHECK(dev_interface_broadcast);
205 ZeroMemory(dev_interface_broadcast.get(), size);
206 dev_interface_broadcast->dbcc_size = size;
207 dev_interface_broadcast->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
208 dev_interface_broadcast->dbcc_classguid = guidDevInterface;
209 memcpy(dev_interface_broadcast->dbcc_name, pnp_device_id.data(),
210 device_id_size);
211
212 int expect_attach_calls = observer_.attach_calls();
213 int expect_detach_calls = observer_.detach_calls();
214 PortableDeviceWatcherWin::StorageObjectIDs storage_object_ids =
215 TestPortableDeviceWatcherWin::GetMTPStorageObjectIds(pnp_device_id);
216 for (PortableDeviceWatcherWin::StorageObjectIDs::const_iterator it =
217 storage_object_ids.begin(); it != storage_object_ids.end(); ++it) {
218 std::string unique_id;
219 base::string16 name;
220 base::string16 location;
221 TestPortableDeviceWatcherWin::GetMTPStorageDetails(pnp_device_id, *it,
222 &location, &unique_id,
223 &name);
224 if (test_attach && !name.empty() && !unique_id.empty())
225 expect_attach_calls++;
226 else if (!name.empty() && !unique_id.empty())
227 expect_detach_calls++;
228 }
229
230 monitor_->InjectDeviceChange(
231 test_attach ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE,
232 reinterpret_cast<LPARAM>(dev_interface_broadcast.get()));
233
234 content::RunAllTasksUntilIdle();
235 EXPECT_EQ(expect_attach_calls, observer_.attach_calls());
236 EXPECT_EQ(expect_detach_calls, observer_.detach_calls());
237 }
238
GetMTPStorageInfo(const std::string & storage_device_id,base::string16 * pnp_device_id,base::string16 * storage_object_id)239 bool StorageMonitorWinTest::GetMTPStorageInfo(
240 const std::string& storage_device_id,
241 base::string16* pnp_device_id,
242 base::string16* storage_object_id) {
243 return monitor_->GetMTPStorageInfoFromDeviceId(storage_device_id,
244 pnp_device_id,
245 storage_object_id);
246 }
247
TEST_F(StorageMonitorWinTest,RandomMessage)248 TEST_F(StorageMonitorWinTest, RandomMessage) {
249 monitor_->InjectDeviceChange(DBT_DEVICEQUERYREMOVE, NULL);
250 content::RunAllTasksUntilIdle();
251 }
252
TEST_F(StorageMonitorWinTest,DevicesAttached)253 TEST_F(StorageMonitorWinTest, DevicesAttached) {
254 DeviceIndices device_indices;
255 device_indices.push_back(1); // B
256 device_indices.push_back(5); // F
257 device_indices.push_back(7); // H
258 device_indices.push_back(13); // N
259 DoMassStorageDeviceAttachedTest(device_indices);
260
261 StorageInfo info;
262 EXPECT_TRUE(monitor_->volume_mount_watcher()->GetDeviceInfo(
263 base::FilePath(ASCIIToUTF16("F:\\")), &info));
264 EXPECT_EQ(ASCIIToUTF16("F:\\"), info.location());
265 EXPECT_EQ("dcim:\\\\?\\Volume{F0000000-0000-0000-0000-000000000000}\\",
266 info.device_id());
267 EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info.storage_label());
268
269 EXPECT_FALSE(monitor_->GetStorageInfoForPath(
270 base::FilePath(ASCIIToUTF16("G:\\")), &info));
271 EXPECT_TRUE(monitor_->GetStorageInfoForPath(
272 base::FilePath(ASCIIToUTF16("F:\\")), &info));
273 StorageInfo info1;
274 EXPECT_TRUE(monitor_->GetStorageInfoForPath(
275 base::FilePath(ASCIIToUTF16("F:\\subdir")), &info1));
276 StorageInfo info2;
277 EXPECT_TRUE(monitor_->GetStorageInfoForPath(
278 base::FilePath(ASCIIToUTF16("F:\\subdir\\sub")), &info2));
279 EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info.storage_label());
280 EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info1.storage_label());
281 EXPECT_EQ(ASCIIToUTF16("F:\\ Drive"), info2.storage_label());
282 }
283
TEST_F(StorageMonitorWinTest,PathMountDevices)284 TEST_F(StorageMonitorWinTest, PathMountDevices) {
285 PreAttachDevices();
286 size_t init_storages = monitor_->GetAllAvailableStorages().size();
287
288 volume_mount_watcher_->AddDeviceForTesting(
289 base::FilePath(FILE_PATH_LITERAL("F:\\mount1")),
290 "dcim:mount1", L"mount1", 100);
291 volume_mount_watcher_->AddDeviceForTesting(
292 base::FilePath(FILE_PATH_LITERAL("F:\\mount1\\subdir")),
293 "dcim:mount1subdir", L"mount1subdir", 100);
294 volume_mount_watcher_->AddDeviceForTesting(
295 base::FilePath(FILE_PATH_LITERAL("F:\\mount2")),
296 "dcim:mount2", L"mount2", 100);
297 content::RunAllTasksUntilIdle();
298 EXPECT_EQ(init_storages + 3, monitor_->GetAllAvailableStorages().size());
299
300 StorageInfo info;
301 EXPECT_TRUE(monitor_->GetStorageInfoForPath(
302 base::FilePath(ASCIIToUTF16("F:\\dir")), &info));
303 EXPECT_EQ(L"F:\\ Drive", info.GetDisplayName(false));
304 EXPECT_TRUE(monitor_->GetStorageInfoForPath(
305 base::FilePath(ASCIIToUTF16("F:\\mount1")), &info));
306 EXPECT_EQ(L"mount1", info.GetDisplayName(false));
307 EXPECT_TRUE(monitor_->GetStorageInfoForPath(
308 base::FilePath(ASCIIToUTF16("F:\\mount1\\dir")), &info));
309 EXPECT_EQ(L"mount1", info.GetDisplayName(false));
310 EXPECT_TRUE(monitor_->GetStorageInfoForPath(
311 base::FilePath(ASCIIToUTF16("F:\\mount2\\dir")), &info));
312 EXPECT_EQ(L"mount2", info.GetDisplayName(false));
313 EXPECT_TRUE(monitor_->GetStorageInfoForPath(
314 base::FilePath(ASCIIToUTF16("F:\\mount1\\subdir")), &info));
315 EXPECT_EQ(L"mount1subdir", info.GetDisplayName(false));
316 EXPECT_TRUE(monitor_->GetStorageInfoForPath(
317 base::FilePath(ASCIIToUTF16("F:\\mount1\\subdir\\dir")), &info));
318 EXPECT_EQ(L"mount1subdir", info.GetDisplayName(false));
319 EXPECT_TRUE(monitor_->GetStorageInfoForPath(
320 base::FilePath(ASCIIToUTF16("F:\\mount1\\subdir\\dir\\dir")), &info));
321 EXPECT_EQ(L"mount1subdir", info.GetDisplayName(false));
322 }
323
TEST_F(StorageMonitorWinTest,DevicesAttachedHighBoundary)324 TEST_F(StorageMonitorWinTest, DevicesAttachedHighBoundary) {
325 DeviceIndices device_indices;
326 device_indices.push_back(25);
327
328 DoMassStorageDeviceAttachedTest(device_indices);
329 }
330
TEST_F(StorageMonitorWinTest,DevicesAttachedLowBoundary)331 TEST_F(StorageMonitorWinTest, DevicesAttachedLowBoundary) {
332 DeviceIndices device_indices;
333 device_indices.push_back(0);
334
335 DoMassStorageDeviceAttachedTest(device_indices);
336 }
337
TEST_F(StorageMonitorWinTest,DevicesAttachedAdjacentBits)338 TEST_F(StorageMonitorWinTest, DevicesAttachedAdjacentBits) {
339 DeviceIndices device_indices;
340 device_indices.push_back(0);
341 device_indices.push_back(1);
342 device_indices.push_back(2);
343 device_indices.push_back(3);
344
345 DoMassStorageDeviceAttachedTest(device_indices);
346 }
347
TEST_F(StorageMonitorWinTest,DevicesDetached)348 TEST_F(StorageMonitorWinTest, DevicesDetached) {
349 PreAttachDevices();
350
351 DeviceIndices device_indices;
352 device_indices.push_back(1);
353 device_indices.push_back(5);
354 device_indices.push_back(7);
355 device_indices.push_back(13);
356
357 DoMassStorageDevicesDetachedTest(device_indices);
358 }
359
TEST_F(StorageMonitorWinTest,DevicesDetachedHighBoundary)360 TEST_F(StorageMonitorWinTest, DevicesDetachedHighBoundary) {
361 PreAttachDevices();
362
363 DeviceIndices device_indices;
364 device_indices.push_back(25);
365
366 DoMassStorageDevicesDetachedTest(device_indices);
367 }
368
TEST_F(StorageMonitorWinTest,DevicesDetachedLowBoundary)369 TEST_F(StorageMonitorWinTest, DevicesDetachedLowBoundary) {
370 PreAttachDevices();
371
372 DeviceIndices device_indices;
373 device_indices.push_back(0);
374
375 DoMassStorageDevicesDetachedTest(device_indices);
376 }
377
TEST_F(StorageMonitorWinTest,DevicesDetachedAdjacentBits)378 TEST_F(StorageMonitorWinTest, DevicesDetachedAdjacentBits) {
379 PreAttachDevices();
380
381 DeviceIndices device_indices;
382 device_indices.push_back(0);
383 device_indices.push_back(1);
384 device_indices.push_back(2);
385 device_indices.push_back(3);
386
387 DoMassStorageDevicesDetachedTest(device_indices);
388 }
389
TEST_F(StorageMonitorWinTest,DuplicateAttachCheckSuppressed)390 TEST_F(StorageMonitorWinTest, DuplicateAttachCheckSuppressed) {
391 // Make sure the original C: mount notification makes it all the
392 // way through.
393 content::RunAllTasksUntilIdle();
394
395 volume_mount_watcher_->BlockDeviceCheckForTesting();
396 base::FilePath kAttachedDevicePath =
397 VolumeMountWatcherWin::DriveNumberToFilePath(8); // I:
398
399 DEV_BROADCAST_VOLUME volume_broadcast;
400 volume_broadcast.dbcv_size = sizeof(volume_broadcast);
401 volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME;
402 volume_broadcast.dbcv_flags = 0x0;
403 volume_broadcast.dbcv_unitmask = 0x100; // I: drive
404 monitor_->InjectDeviceChange(DBT_DEVICEARRIVAL,
405 reinterpret_cast<LPARAM>(&volume_broadcast));
406
407 EXPECT_EQ(0u, volume_mount_watcher_->devices_checked().size());
408
409 // Re-attach the same volume. We haven't released the mock device check
410 // event, so there'll be pending calls in the UI thread to finish the
411 // device check notification, blocking the duplicate device injection.
412 monitor_->InjectDeviceChange(DBT_DEVICEARRIVAL,
413 reinterpret_cast<LPARAM>(&volume_broadcast));
414
415 EXPECT_EQ(0u, volume_mount_watcher_->devices_checked().size());
416 volume_mount_watcher_->ReleaseDeviceCheck();
417 content::RunAllTasksUntilIdle();
418 volume_mount_watcher_->ReleaseDeviceCheck();
419
420 // Now let all attach notifications finish running. We'll only get one
421 // finish-attach call.
422 content::RunAllTasksUntilIdle();
423
424 const std::vector<base::FilePath>& checked_devices =
425 volume_mount_watcher_->devices_checked();
426 ASSERT_EQ(1u, checked_devices.size());
427 EXPECT_EQ(kAttachedDevicePath, checked_devices[0]);
428
429 // We'll receive a duplicate check now that the first check has fully cleared.
430 monitor_->InjectDeviceChange(DBT_DEVICEARRIVAL,
431 reinterpret_cast<LPARAM>(&volume_broadcast));
432 content::RunAllTasksUntilIdle();
433 volume_mount_watcher_->ReleaseDeviceCheck();
434 content::RunAllTasksUntilIdle();
435
436 ASSERT_EQ(2u, checked_devices.size());
437 EXPECT_EQ(kAttachedDevicePath, checked_devices[0]);
438 EXPECT_EQ(kAttachedDevicePath, checked_devices[1]);
439 }
440
TEST_F(StorageMonitorWinTest,DeviceInfoForPath)441 TEST_F(StorageMonitorWinTest, DeviceInfoForPath) {
442 PreAttachDevices();
443
444 StorageInfo device_info;
445 // An invalid path.
446 EXPECT_FALSE(monitor_->GetStorageInfoForPath(base::FilePath(L"COM1:\\"),
447 &device_info));
448
449 // An unconnected removable device.
450 EXPECT_FALSE(monitor_->GetStorageInfoForPath(base::FilePath(L"E:\\"),
451 &device_info));
452
453 // A connected removable device.
454 base::FilePath removable_device(L"F:\\");
455 EXPECT_TRUE(monitor_->GetStorageInfoForPath(removable_device, &device_info));
456
457 StorageInfo info;
458 ASSERT_TRUE(volume_mount_watcher_->GetDeviceInfo(removable_device, &info));
459 EXPECT_TRUE(StorageInfo::IsRemovableDevice(info.device_id()));
460 EXPECT_EQ(info.device_id(), device_info.device_id());
461 EXPECT_EQ(info.GetDisplayName(false), device_info.GetDisplayName(false));
462 EXPECT_EQ(info.location(), device_info.location());
463 EXPECT_EQ(1000000u, info.total_size_in_bytes());
464
465 // A fixed device.
466 base::FilePath fixed_device(L"N:\\");
467 EXPECT_TRUE(monitor_->GetStorageInfoForPath(fixed_device, &device_info));
468
469 ASSERT_TRUE(volume_mount_watcher_->GetDeviceInfo(
470 fixed_device, &info));
471 EXPECT_FALSE(StorageInfo::IsRemovableDevice(info.device_id()));
472 EXPECT_EQ(info.device_id(), device_info.device_id());
473 EXPECT_EQ(info.GetDisplayName(false), device_info.GetDisplayName(false));
474 EXPECT_EQ(info.location(), device_info.location());
475 }
476
477 // Test to verify basic MTP storage attach and detach notifications.
TEST_F(StorageMonitorWinTest,MTPDeviceBasicAttachDetach)478 TEST_F(StorageMonitorWinTest, MTPDeviceBasicAttachDetach) {
479 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo, true);
480 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo, false);
481 }
482
483 // When a MTP storage device with invalid storage label and id is
484 // attached/detached, there should not be any device attach/detach
485 // notifications.
TEST_F(StorageMonitorWinTest,MTPDeviceWithInvalidInfo)486 TEST_F(StorageMonitorWinTest, MTPDeviceWithInvalidInfo) {
487 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithInvalidInfo,
488 true);
489 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithInvalidInfo,
490 false);
491 }
492
493 // Attach a device with two data partitions. Verify that attach/detach
494 // notifications are sent out for each removable storage.
TEST_F(StorageMonitorWinTest,MTPDeviceWithMultipleStorageObjects)495 TEST_F(StorageMonitorWinTest, MTPDeviceWithMultipleStorageObjects) {
496 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithMultipleStorages,
497 true);
498 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithMultipleStorages,
499 false);
500 }
501
TEST_F(StorageMonitorWinTest,DriveNumberToFilePath)502 TEST_F(StorageMonitorWinTest, DriveNumberToFilePath) {
503 EXPECT_EQ(L"A:\\", VolumeMountWatcherWin::DriveNumberToFilePath(0).value());
504 EXPECT_EQ(L"Y:\\", VolumeMountWatcherWin::DriveNumberToFilePath(24).value());
505 EXPECT_EQ(L"", VolumeMountWatcherWin::DriveNumberToFilePath(-1).value());
506 EXPECT_EQ(L"", VolumeMountWatcherWin::DriveNumberToFilePath(199).value());
507 }
508
509 // Given a MTP storage persistent id, GetMTPStorageInfo() should fetch the
510 // device interface path and local storage object identifier.
TEST_F(StorageMonitorWinTest,GetMTPStorageInfoFromDeviceId)511 TEST_F(StorageMonitorWinTest, GetMTPStorageInfoFromDeviceId) {
512 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo, true);
513 PortableDeviceWatcherWin::StorageObjects storage_objects =
514 TestPortableDeviceWatcherWin::GetDeviceStorageObjects(
515 TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo);
516 for (PortableDeviceWatcherWin::StorageObjects::const_iterator it =
517 storage_objects.begin();
518 it != storage_objects.end(); ++it) {
519 base::string16 pnp_device_id;
520 base::string16 storage_object_id;
521 ASSERT_TRUE(GetMTPStorageInfo(it->object_persistent_id, &pnp_device_id,
522 &storage_object_id));
523 base::string16 expected(
524 TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo);
525 EXPECT_EQ(expected, pnp_device_id);
526 EXPECT_EQ(it->object_persistent_id,
527 TestPortableDeviceWatcherWin::GetMTPStorageUniqueId(
528 pnp_device_id, storage_object_id));
529 }
530 DoMTPDeviceTest(TestPortableDeviceWatcherWin::kMTPDeviceWithValidInfo, false);
531 }
532
533 } // namespace storage_monitor
534