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