blob: a75581c52887f4eb1a596b4d31d55639d714e383 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
/**
* Mock Recent fake entry.
* @type {!FilesAppEntry}
*/
const recentFakeEntry =
/** @type {!FilesAppEntry} */ ({toURL: () => 'fake-entry://recent'});
/**
* Drive file system.
* @type {!MockFileSystem}
*/
var drive;
/**
* Removable volume file system.
* @type {!MockFileSystem}
*/
var hoge;
// Setup the test components.
function setUp() {
// Mock LoadTimeData strings.
window.loadTimeData.data = {
MY_FILES_VOLUME_ENABLED: false,
MY_FILES_ROOT_LABEL: 'My files',
DOWNLOADS_DIRECTORY_LABEL: 'Downloads',
DRIVE_DIRECTORY_LABEL: 'My Drive',
};
window.loadTimeData.getString = id => {
return window.loadTimeData.data_[id] || id;
};
// Mock chrome APIs.
new MockCommandLinePrivate();
// Override VolumeInfo.prototype.resolveDisplayRoot to be sync.
VolumeInfoImpl.prototype.resolveDisplayRoot = function(successCallback) {
this.displayRoot_ = this.fileSystem_.root;
successCallback(this.displayRoot_);
return Promise.resolve(this.fileSystem_.root);
};
// Create mock file systems.
drive = new MockFileSystem('drive');
hoge = new MockFileSystem('removable:hoge');
}
/**
* Tests model.
*/
function testModel() {
var volumeManager = new MockVolumeManager();
var shortcutListModel = new MockFolderShortcutDataModel(
[new MockFileEntry(drive, '/root/shortcut')]);
var recentItem = new NavigationModelFakeItem(
'recent-label', NavigationModelItemType.RECENT, recentFakeEntry);
var crostiniFakeItem = new NavigationModelFakeItem(
'linux-files-label', NavigationModelItemType.CROSTINI,
new FakeEntry(
'linux-files-label', VolumeManagerCommon.RootType.CROSTINI));
var model = new NavigationListModel(
volumeManager, shortcutListModel, recentItem, new MockDirectoryModel());
model.linuxFilesItem = crostiniFakeItem;
assertEquals(4, model.length);
assertEquals(
'fake-entry://recent', /** @type {!NavigationModelFakeItem} */
(model.item(0)).entry.toURL());
assertEquals(
'/root/shortcut', /** @type {!NavigationModelShortcutItem} */
(model.item(1)).entry.fullPath);
assertEquals('My files', model.item(2).label);
assertEquals(
'drive', /** @type {!NavigationModelVolumeItem} */
(model.item(3)).volumeInfo.volumeId);
// Downloads and Crostini are displayed within My files.
const myFilesItem = /** @type NavigationModelFakeItem */ (model.item(2));
const myFilesEntryList = /** @type {!EntryList} */ (myFilesItem.entry);
assertEquals(2, myFilesEntryList.getUIChildren().length);
assertEquals('Downloads', myFilesEntryList.getUIChildren()[0].name);
assertEquals('linux-files-label', myFilesEntryList.getUIChildren()[1].name);
}
/**
* Tests model with no Recents, Linux files, Play files.
*/
function testNoRecentOrLinuxFiles() {
var volumeManager = new MockVolumeManager();
var shortcutListModel = new MockFolderShortcutDataModel(
[new MockFileEntry(drive, '/root/shortcut')]);
var recentItem = null;
var model = new NavigationListModel(
volumeManager, shortcutListModel, recentItem, new MockDirectoryModel());
assertEquals(3, model.length);
assertEquals(
'/root/shortcut', /** @type {!NavigationModelShortcutItem} */
(model.item(0)).entry.fullPath);
assertEquals('My files', model.item(1).label);
assertEquals(
'drive', /** @type {!NavigationModelVolumeItem} */
(model.item(2)).volumeInfo.volumeId);
}
/**
* Tests adding and removing shortcuts.
*/
function testAddAndRemoveShortcuts() {
var volumeManager = new MockVolumeManager();
var shortcutListModel = new MockFolderShortcutDataModel(
[new MockFileEntry(drive, '/root/shortcut')]);
var recentItem = null;
var model = new NavigationListModel(
volumeManager, shortcutListModel, recentItem, new MockDirectoryModel());
assertEquals(3, model.length);
// Add a shortcut at the tail, shortcuts are sorted by their label.
const addShortcut = new MockFileEntry(drive, '/root/shortcut2');
shortcutListModel.splice(1, 0, addShortcut);
assertEquals(4, model.length);
assertEquals(
'shortcut', /** @type {!NavigationModelShortcutItem} */
(model.item(0)).label);
assertEquals(
'shortcut2', /** @type {!NavigationModelShortcutItem} */
(model.item(1)).label);
// Add a shortcut at the head.
const headShortcut = new MockFileEntry(drive, '/root/head');
shortcutListModel.splice(0, 0, headShortcut);
assertEquals(5, model.length);
assertEquals(
'head', /** @type {!NavigationModelShortcutItem} */
(model.item(0)).label);
assertEquals(
'shortcut', /** @type {!NavigationModelShortcutItem} */
(model.item(1)).label);
assertEquals(
'shortcut2', /** @type {!NavigationModelShortcutItem} */
(model.item(2)).label);
// Remove the last shortcut.
shortcutListModel.splice(2, 1);
assertEquals(4, model.length);
assertEquals(
'head', /** @type {!NavigationModelShortcutItem} */
(model.item(0)).label);
assertEquals(
'shortcut', /** @type {!NavigationModelShortcutItem} */
(model.item(1)).label);
// Remove the first shortcut.
shortcutListModel.splice(0, 1);
assertEquals(3, model.length);
assertEquals(
'shortcut', /** @type {!NavigationModelShortcutItem} */
(model.item(0)).label);
}
/**
* Tests adding and removing volumes.
*/
function testAddAndRemoveVolumes() {
var volumeManager = new MockVolumeManager();
var shortcutListModel = new MockFolderShortcutDataModel(
[new MockFileEntry(drive, '/root/shortcut')]);
var recentItem = null;
var model = new NavigationListModel(
volumeManager, shortcutListModel, recentItem, new MockDirectoryModel());
assertEquals(3, model.length);
// Mount removable volume 'hoge'.
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.REMOVABLE, 'removable:hoge', '',
'device/path/1'));
assertEquals(4, model.length);
assertEquals(
'/root/shortcut', /** @type {!NavigationModelShortcutItem} */
(model.item(0)).entry.fullPath);
assertEquals('My files', model.item(1).label);
assertEquals(
'drive', /** @type {!NavigationModelVolumeItem} */
(model.item(2)).volumeInfo.volumeId);
assertEquals(
'removable:hoge', /** @type {!NavigationModelVolumeItem} */
(model.item(3)).volumeInfo.volumeId);
// Mount removable volume 'fuga'. Not a partition, so set a different device
// path to 'hoge'.
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.REMOVABLE, 'removable:fuga', '',
'device/path/2'));
assertEquals(5, model.length);
assertEquals(
'/root/shortcut', /** @type {!NavigationModelShortcutItem} */
(model.item(0)).entry.fullPath);
assertEquals('My files', model.item(1).label);
assertEquals(
'drive', /** @type {!NavigationModelVolumeItem} */
(model.item(2)).volumeInfo.volumeId);
assertEquals(
'removable:hoge', /** @type {!NavigationModelVolumeItem} */
(model.item(3)).volumeInfo.volumeId);
assertEquals(
'removable:fuga', /** @type {!NavigationModelVolumeItem} */
(model.item(4)).volumeInfo.volumeId);
// Create a shortcut on the 'hoge' volume.
shortcutListModel.splice(
1, 0, new MockFileEntry(hoge, '/shortcut2'));
assertEquals(6, model.length);
assertEquals(
'/root/shortcut', /** @type {!NavigationModelShortcutItem} */
(model.item(0)).entry.fullPath);
assertEquals(
'/shortcut2', /** @type {!NavigationModelShortcutItem} */
(model.item(1)).entry.fullPath);
assertEquals('My files', model.item(2).label);
assertEquals(
'drive', /** @type {!NavigationModelVolumeItem} */
(model.item(3)).volumeInfo.volumeId);
assertEquals(
'removable:hoge', /** @type {!NavigationModelVolumeItem} */
(model.item(4)).volumeInfo.volumeId);
assertEquals(
'removable:fuga', /** @type {!NavigationModelVolumeItem} */
(model.item(5)).volumeInfo.volumeId);
}
/**
* Tests that orderAndNestItems_ function does the following:
* 1. produces the expected order of volumes.
* 2. manages NavigationSection for the relevant volumes.
* 3. keeps MTP/Archive/Removable volumes on the original order.
*/
function testOrderAndNestItems() {
const volumeManager = new MockVolumeManager();
const shortcutListModel = new MockFolderShortcutDataModel([
new MockFileEntry(drive, '/root/shortcut'),
new MockFileEntry(drive, '/root/shortcut2')
]);
const recentItem = new NavigationModelFakeItem(
'recent-label', NavigationModelItemType.RECENT, recentFakeEntry);
// Create different volumes.
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.PROVIDED, 'provided:prov1'));
// Set the device paths of the removable volumes to different strings to
// test the behaviour of two physically separate external devices.
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.REMOVABLE, 'removable:hoge', '',
'device/path/1'));
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.REMOVABLE, 'removable:fuga', '',
'device/path/2'));
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.ARCHIVE, 'archive:a-rar'));
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.MTP, 'mtp:a-phone'));
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.PROVIDED, 'provided:prov2'));
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.ANDROID_FILES, 'android_files:droid'));
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.MEDIA_VIEW, 'media_view:images_root'));
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.MEDIA_VIEW, 'media_view:videos_root'));
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.MEDIA_VIEW, 'media_view:audio_root'));
// ZipArchiver mounts zip files as a PROVIDED volume type.
const zipVolumeId = 'provided:dmboannefpncccogfdikhmhpmdnddgoe:' +
'~%2FDownloads%2Fazip_file%2Ezip:' +
'096eaa592ea7e8ffb9a27435e50dabd6c809c125';
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.PROVIDED, zipVolumeId));
// Navigation items built above:
// 1. fake-entry://recent
// 2. media_view:images_root
// 3. media_view:videos_root
// 4. media_view:audio_root
// 5. /root/shortcut
// 6. /root/shortcut2
// 7. My files
// -> Downloads
// -> Play files
// -> Linux files
// 8. Drive - from setup()
// 9. provided:prov1
// 10. provided:prov2
//
// 11. removable:hoge
// 12. removable:fuga
// 13. archive:a-rar - mounted as archive
// 14. mtp:a-phone
// 15. provided:"zip" - mounted as provided: $zipVolumeId
// Constructor already calls orderAndNestItems_.
const model = new NavigationListModel(
volumeManager, shortcutListModel, recentItem, new MockDirectoryModel());
// Check items order and that MTP/Archive/Removable respect the original
// order.
assertEquals(15, model.length);
assertEquals('recent-label', model.item(0).label);
assertEquals('media_view:images_root', model.item(1).label);
assertEquals('media_view:videos_root', model.item(2).label);
assertEquals('media_view:audio_root', model.item(3).label);
assertEquals('shortcut', model.item(4).label);
assertEquals('shortcut2', model.item(5).label);
assertEquals('My files', model.item(6).label);
assertEquals('My Drive', model.item(7).label);
assertEquals('provided:prov1', model.item(8).label);
assertEquals('provided:prov2', model.item(9).label);
assertEquals('removable:hoge', model.item(10).label);
assertEquals('removable:fuga', model.item(11).label);
assertEquals('archive:a-rar', model.item(12).label);
assertEquals('mtp:a-phone', model.item(13).label);
assertEquals(zipVolumeId, model.item(14).label);
// Check NavigationSection, which defaults to TOP.
// recent-label.
assertEquals(NavigationSection.TOP, model.item(0).section);
// Media View.
// Images.
assertEquals(NavigationSection.TOP, model.item(1).section);
// Videos.
assertEquals(NavigationSection.TOP, model.item(2).section);
// Audio.
assertEquals(NavigationSection.TOP, model.item(3).section);
// shortcut.
assertEquals(NavigationSection.TOP, model.item(4).section);
// shortcut2.
assertEquals(NavigationSection.TOP, model.item(5).section);
// My Files.
assertEquals(NavigationSection.MY_FILES, model.item(6).section);
// Drive and FSP are grouped together.
// My Drive.
assertEquals(NavigationSection.CLOUD, model.item(7).section);
// provided:prov1.
assertEquals(NavigationSection.CLOUD, model.item(8).section);
// provided:prov2.
assertEquals(NavigationSection.CLOUD, model.item(9).section);
// MTP/Archive/Removable are grouped together.
// removable:hoge.
assertEquals(NavigationSection.REMOVABLE, model.item(10).section);
// removable:fuga.
assertEquals(NavigationSection.REMOVABLE, model.item(11).section);
// archive:a-rar.
assertEquals(NavigationSection.REMOVABLE, model.item(12).section);
// mtp:a-phone.
assertEquals(NavigationSection.REMOVABLE, model.item(13).section);
// archive:"zip" - $zipVolumeId
assertEquals(NavigationSection.REMOVABLE, model.item(14).section);
const myFilesModel = model.item(6);
// Re-order again: cast to allow calling this private model function.
/** @type {!Object} */ (model).orderAndNestItems_();
// Check if My Files is still in the same position.
assertEquals(NavigationSection.MY_FILES, model.item(6).section);
// Check if My Files model is still the same instance, because DirectoryTree
// expects it to be the same instance to be able to find it on the tree.
assertEquals(myFilesModel, model.item(6));
}
/**
* Tests model with My files enabled.
*/
function testMyFilesVolumeEnabled(callback) {
// Enable My files.
loadTimeData.data_['MY_FILES_VOLUME_ENABLED'] = true;
const volumeManager = new MockVolumeManager();
// Item 1 of the volume info list should have Downloads volume type.
assertEquals(
VolumeManagerCommon.VolumeType.DOWNLOADS,
volumeManager.volumeInfoList.item(1).volumeType);
// Create a downloads folder inside the item.
const downloadsVolume = volumeManager.volumeInfoList.item(1);
/** @type {!MockFileSystem} */ (downloadsVolume.fileSystem).populate([
'/Downloads/'
]);
const shortcutListModel = new MockFolderShortcutDataModel([]);
const recentItem = null;
// Create Android 'Play files' volume.
volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
VolumeManagerCommon.VolumeType.ANDROID_FILES, 'android_files:droid'));
const crostiniFakeItem = new NavigationModelFakeItem(
'linux-files-label', NavigationModelItemType.CROSTINI,
new FakeEntry(
'linux-files-label', VolumeManagerCommon.RootType.CROSTINI));
// Navigation items built above:
// 1. My files
// -> Play files
// -> Linux files
// 2. Drive - added by default by MockVolumeManager.
// Constructor already calls orderAndNestItems_.
const model = new NavigationListModel(
volumeManager, shortcutListModel, recentItem, new MockDirectoryModel());
model.linuxFilesItem = crostiniFakeItem;
assertEquals(2, model.length);
assertEquals('My files', model.item(0).label);
assertEquals('My Drive', model.item(1).label);
// Android and Crostini are displayed within My files. And there is no
// Downloads volume inside it. Downloads should be a normal folder inside
// the My files volume.
const myFilesItem = /** @type NavigationModelFakeItem */ (model.item(0));
const myFilesEntryList = /** @type {!EntryList} */ (myFilesItem.entry);
assertEquals(2, myFilesEntryList.getUIChildren().length);
assertEquals('android_files:droid', myFilesEntryList.getUIChildren()[0].name);
assertEquals('linux-files-label', myFilesEntryList.getUIChildren()[1].name);
const reader = myFilesEntryList.createReader();
const foundEntries = [];
reader.readEntries((entries) => {
for (const entry of entries) {
foundEntries.push(entry);
}
});
reportPromise(
waitUntil(() => {
// Wait for Downloads folder to be read from My files volume.
return foundEntries.length >= 1;
}).then(() => {
assertEquals(foundEntries[0].name, 'Downloads');
assertTrue(foundEntries[0].isDirectory);
}),
callback);
}