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