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