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