blob: fe0f48eaf1b822e3579a6b78903b48ca743b329e [file] [log] [blame]
// Copyright 2015 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.
window.metrics = {
recordEnum: function() {},
recordSmallCount: function() {},
};
var mockTaskHistory = {
getLastExecutedTime: function(id) {
return 0;
},
recordTaskExecuted: function(id) {}
};
loadTimeData.data = {
DRIVE_FS_ENABLED: false,
MORE_ACTIONS_BUTTON_LABEL: 'MORE_ACTIONS_BUTTON_LABEL',
NO_TASK_FOR_EXECUTABLE: 'NO_TASK_FOR_EXECUTABLE',
NO_TASK_FOR_FILE_URL: 'NO_TASK_FOR_FILE_URL',
NO_TASK_FOR_FILE: 'NO_TASK_FOR_FILE',
NO_TASK_FOR_DMG: 'NO_TASK_FOR_DMG',
NO_TASK_FOR_CRX: 'NO_TASK_FOR_CRX',
NO_TASK_FOR_CRX_TITLE: 'NO_TASK_FOR_CRX_TITLE',
OPEN_WITH_BUTTON_LABEL: 'OPEN_WITH_BUTTON_LABEL',
TASK_INSTALL_LINUX_PACKAGE: 'TASK_INSTALL_LINUX_PACKAGE',
TASK_OPEN: 'TASK_OPEN',
UNABLE_TO_OPEN_CROSTINI_TITLE: 'UNABLE_TO_OPEN_CROSTINI_TITLE',
UNABLE_TO_OPEN_CROSTINI: 'UNABLE_TO_OPEN_CROSTINI',
};
function setUp() {
window.chrome = {
commandLinePrivate: {
hasSwitch: function(name, callback) {
callback(false);
}
},
fileManagerPrivate: {
getFileTasks: function(entries, callback) {
setTimeout(
callback.bind(null, [{
taskId: 'handler-extension-id|app|any',
isDefault: false,
isGenericFileHandler: true
}]),
0);
},
executeTask: function(taskId, entries, onViewFiles) {
onViewFiles('failed');
},
sharePathsWithCrostini: function(entries, persist, callback) {
callback();
},
},
runtime: {id: 'test-extension-id'},
};
}
/**
* Returns a mock file manager.
* @return {!FileManager}
*/
function getMockFileManager() {
const result = {
volumeManager: {
getLocationInfo: function(entry) {
return {rootType: VolumeManagerCommon.RootType.DRIVE};
},
getDriveConnectionState: function() {
return VolumeManagerCommon.DriveConnectionType.ONLINE;
},
getVolumeInfo: function(entry) {
return {
volumeType: VolumeManagerCommon.VolumeType.DRIVE
};
}
},
ui: {
alertDialog:
{showHtml: function(title, text, onOk, onCancel, onShow) {}}
},
metadataModel: {},
directoryModel: {
getCurrentRootType: function() {
return null;
}
},
crostini: new Crostini(),
};
result.crostini.init(result.volumeManager);
return result;
}
/**
* Returns a promise which is resolved when showHtml of alert dialog is called
* with expected title and text.
*
* @param {!Array<!Entry>} entries Entries.
* @param {string} expectedTitle An expected title.
* @param {string} expectedText An expected text.
* @return {!Promise}
*/
function showHtmlOfAlertDialogIsCalled(entries, expectedTitle, expectedText) {
return new Promise(function(resolve, reject) {
var fileManager = getMockFileManager();
fileManager.ui.alertDialog.showHtml =
function(title, text, onOk, onCancel, onShow) {
assertEquals(expectedTitle, title);
assertEquals(expectedText, text);
resolve();
};
FileTasks
.create(
fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, entries, [null],
mockTaskHistory, fileManager.crostini)
.then(function(tasks) {
tasks.executeDefault();
});
});
}
/**
* Returns a promise which is resolved when openSuggestAppsDialog is called.
*
* @param {!Array<!Entry>} entries Entries.
* @param {!Array<?string>} mimeTypes Mime types.
* @return {!Promise}
*/
function openSuggestAppsDialogIsCalled(entries, mimeTypes) {
return new Promise(function(resolve, reject) {
var fileManager = getMockFileManager();
fileManager.ui.suggestAppsDialog = {
showByExtensionAndMime: function(extension, mimeType, onDialogClosed) {
resolve();
}
};
FileTasks
.create(
fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, entries, mimeTypes,
mockTaskHistory, fileManager.crostini)
.then(function(tasks) {
tasks.executeDefault();
});
});
}
/**
* Returns a promise which is resolved when task picker is shown.
*
* @param {!Array<!Entry>} entries Entries.
* @param {!Array<?string>} mimeTypes Mime types.
* @return {!Promise}
*/
function showDefaultTaskDialogCalled(entries, mimeTypes) {
return new Promise(function(resolve, reject) {
var fileManager = getMockFileManager();
fileManager.ui.defaultTaskPicker = {
showDefaultTaskDialog: function(
title, message, items, defaultIdx, onSuccess) {
resolve();
}
};
FileTasks
.create(
fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, entries, mimeTypes,
mockTaskHistory, fileManager.crostini)
.then(function(tasks) {
tasks.executeDefault();
});
});
}
function testToOpenExeFile(callback) {
var mockFileSystem = new MockFileSystem('volumeId');
var mockEntry = new MockFileEntry(mockFileSystem, '/test.exe');
reportPromise(showHtmlOfAlertDialogIsCalled(
[mockEntry], 'test.exe', 'NO_TASK_FOR_EXECUTABLE'), callback);
}
function testToOpenDmgFile(callback) {
var mockFileSystem = new MockFileSystem('volumeId');
var mockEntry = new MockFileEntry(mockFileSystem, '/test.dmg');
reportPromise(showHtmlOfAlertDialogIsCalled(
[mockEntry], 'test.dmg', 'NO_TASK_FOR_DMG'), callback);
}
function testToOpenCrxFile(callback) {
var mockFileSystem = new MockFileSystem('volumeId');
var mockEntry = new MockFileEntry(mockFileSystem, '/test.crx');
reportPromise(showHtmlOfAlertDialogIsCalled(
[mockEntry], 'NO_TASK_FOR_CRX_TITLE', 'NO_TASK_FOR_CRX'), callback);
}
function testToOpenRtfFile(callback) {
var mockFileSystem = new MockFileSystem('volumeId');
var mockEntry = new MockFileEntry(mockFileSystem, '/test.rtf');
reportPromise(openSuggestAppsDialogIsCalled(
[mockEntry], ['application/rtf']), callback);
}
/**
* Test case for openSuggestAppsDialog with an entry which has external type of
* metadata.
*/
function testOpenSuggestAppsDialogWithMetadata(callback) {
var showByExtensionAndMimeIsCalled = new Promise(function(resolve, reject) {
var fileSystem = new MockFileSystem('volumeId');
var entry = new MockFileEntry(fileSystem, '/test.rtf');
var fileManager = getMockFileManager();
FileTasks
.create(
fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, {
taskMenuButton: document.createElement('button'),
fileContextMenu:
{defaultActionMenuItem: document.createElement('div')},
suggestAppsDialog: {
showByExtensionAndMime: function(
extension, mimeType, onDialogClosed) {
assertEquals('.rtf', extension);
assertEquals('application/rtf', mimeType);
resolve();
}
}
},
[entry], ['application/rtf'], mockTaskHistory, fileManager.crostini)
.then(function(tasks) {
tasks.openSuggestAppsDialog(
function() {}, function() {}, function() {});
});
});
reportPromise(showByExtensionAndMimeIsCalled, callback);
}
/**
* Test case for openSuggestAppsDialog with an entry which doesn't have
* extension. Since both extension and MIME type are required for
* openSuggestAppsDialogopen, onFalure should be called for this test case.
*/
function testOpenSuggestAppsDialogFailure(callback) {
var onFailureIsCalled = new Promise(function(resolve, reject) {
var fileSystem = new MockFileSystem('volumeId');
var entry = new MockFileEntry(fileSystem, '/test');
var fileManager = getMockFileManager();
FileTasks
.create(
fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, [entry], [null],
mockTaskHistory, fileManager.crostini)
.then(function(tasks) {
tasks.openSuggestAppsDialog(function() {}, function() {}, resolve);
});
});
reportPromise(onFailureIsCalled, callback);
}
/**
* Test case for opening task picker with an entry which doesn't have default
* app but multiple apps that can open it.
*/
function testOpenTaskPicker(callback) {
window.chrome.fileManagerPrivate.getFileTasks = function(entries, callback) {
setTimeout(
callback.bind(
null,
[
{
taskId: 'handler-extension-id1|app|any',
isDefault: false,
isGenericFileHandler: false,
title: 'app 1',
},
{
taskId: 'handler-extension-id2|app|any',
isDefault: false,
isGenericFileHandler: false,
title: 'app 2',
}
]),
0);
};
var mockFileSystem = new MockFileSystem('volumeId');
var mockEntry = new MockFileEntry(mockFileSystem, '/test.tiff');
reportPromise(
showDefaultTaskDialogCalled([mockEntry], ['image/tiff']), callback);
}
function testOpenWithMostRecentlyExecuted(callback) {
const latestTaskId = 'handler-extension-most-recently-executed|app|any';
const oldTaskId = 'handler-extension-executed-before|app|any';
window.chrome.fileManagerPrivate.getFileTasks = function(entries, callback) {
setTimeout(
callback.bind(
null,
// File tasks is sorted by last executed time, latest first.
[
{
taskId: latestTaskId,
isDefault: false,
isGenericFileHandler: false,
title: 'app 1',
},
{
taskId: oldTaskId,
isDefault: false,
isGenericFileHandler: false,
title: 'app 2',
},
{
taskId: 'handler-extension-never-executed|app|any',
isDefault: false,
isGenericFileHandler: false,
title: 'app 3',
},
]),
0);
};
var taskHistory = {
getLastExecutedTime: function(id) {
if (id == oldTaskId)
return 10000;
else if (id == latestTaskId)
return 20000;
return 0;
},
recordTaskExecuted: function(taskId) {}
};
var executedTask = null;
window.chrome.fileManagerPrivate.executeTask = function(
taskId, entries, onViewFiles) {
executedTask = taskId;
onViewFiles('success');
};
var mockFileSystem = new MockFileSystem('volumeId');
var mockEntry = new MockFileEntry(mockFileSystem, '/test.tiff');
var entries = [mockEntry];
var promise = new Promise(function(resolve, reject) {
var fileManager = getMockFileManager();
fileManager.ui.defaultTaskPicker = {
showDefaultTaskDialog: function(
title, message, items, defaultIdx, onSuccess) {
failWithMessage('should not show task picker');
}
};
FileTasks
.create(
fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, [mockEntry], [null],
taskHistory, fileManager.crostini)
.then(function(tasks) {
tasks.executeDefault();
assertEquals(latestTaskId, executedTask);
resolve();
});
});
reportPromise(promise, callback);
}
function testOpenZipWithZipArchiver(callback) {
var zipArchiverTaskId = 'dmboannefpncccogfdikhmhpmdnddgoe|app|open';
chrome.commandLinePrivate.hasSwitch = function(name, callback) {
if (name == 'enable-zip-archiver-unpacker') {
// This flag used to exist and was used to switch between the "Zip
// Unpacker" and "Zip Archiver" component extensions.
failWithMessage('run zip archiver', 'zip archiver flags checked');
}
callback(false);
};
window.chrome.fileManagerPrivate.getFileTasks = function(entries, callback) {
setTimeout(
callback.bind(
null,
[
{
taskId: zipArchiverTaskId,
isDefault: false,
isGenericFileHandler: false,
title: 'Zip Archiver',
},
]),
0);
};
// None of the tasks has ever been executed.
var taskHistory = {
getLastExecutedTime: function(id) {
return 0;
},
recordTaskExecuted: function(taskId) {}
};
var executedTask = null;
window.chrome.fileManagerPrivate.executeTask = function(
taskId, entries, onViewFiles) {
executedTask = taskId;
onViewFiles('success');
};
var mockFileSystem = new MockFileSystem('volumeId');
var mockEntry = new MockFileEntry(mockFileSystem, '/test.zip');
var promise = new Promise(function(resolve, reject) {
var fileManager = getMockFileManager();
fileManager.ui.defaultTaskPicker = {
showDefaultTaskDialog: function(
title, message, items, defaultIdx, onSuccess) {
failWithMessage('run zip archiver', 'default task picker was shown');
}
};
FileTasks
.create(
fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, [mockEntry], [null],
taskHistory, fileManager.crostini)
.then(function(tasks) {
tasks.executeDefault();
assertEquals(zipArchiverTaskId, executedTask);
resolve();
});
});
reportPromise(promise, callback);
}
function testOpenInstallLinuxPackageDialog(callback) {
window.chrome.fileManagerPrivate.getFileTasks = function(entries, callback) {
setTimeout(
callback.bind(
null,
[
{
taskId: 'test-extension-id|file|install-linux-package',
isDefault: false,
isGenericFileHandler: false,
title: '__MSG_INSTALL_LINUX_PACKAGE__',
},
]),
0);
};
var mockFileSystem = new MockFileSystem('volumeId');
var mockEntry = new MockFileEntry(mockFileSystem, '/test.deb');
var promise = new Promise(function(resolve, reject) {
var fileManager = getMockFileManager();
fileManager.ui.installLinuxPackageDialog = {
showInstallLinuxPackageDialog: function(entry) {
resolve();
}
};
fileManager.volumeManager.getLocationInfo = function(entry) {
return {rootType: VolumeManagerCommon.RootType.CROSTINI};
};
FileTasks
.create(
fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, [mockEntry], [null],
mockTaskHistory, fileManager.crostini)
.then(function(tasks) {
tasks.executeDefault();
});
});
reportPromise(promise, callback);
}
function testMaybeShareCrostiniOrShowDialog() {
const volumeManagerDownloads = {
getLocationInfo: (entry) => {
return {rootType: entry.filesystem.name};
}
};
const mockFsDownloads = new MockFileSystem('downloads');
const sharedDir = new MockDirectoryEntry(mockFsDownloads, '/shared');
const shared = new MockFileEntry(mockFsDownloads, '/shared/file');
const crostini = new Crostini();
crostini.init(volumeManagerDownloads);
crostini.setEnabled(true);
crostini.registerSharedPath(sharedDir, volumeManagerDownloads);
const notShared1 = new MockFileEntry(mockFsDownloads, '/notShared/file1');
const notShared2 = new MockFileEntry(mockFsDownloads, '/notShared/file2');
const otherNotShared =
new MockFileEntry(mockFsDownloads, '/otherNotShared/file');
const mockFsUnsharable = new MockFileSystem('unsharable');
const unsharable = new MockDirectoryEntry(mockFsUnsharable, '/unsharable');
function expect(
comment, entries, expectSuccess, expectedDialogTitle,
expectedDialogMessage) {
let showHtmlCalled = false;
function showHtml(title, message) {
showHtmlCalled = true;
assertEquals(
expectedDialogTitle, title,
'crostini share dialog title: ' + comment);
assertEquals(
expectedDialogMessage, message,
'crostini share dialog message: ' + comment);
}
const fakeFilesTask = {
entries_: entries,
crostini_: crostini,
ui_: {
alertDialog: {showHtml: showHtml},
confirmDialog: {showHtml: showHtml},
},
volumeManager_: volumeManagerDownloads,
};
const crostiniTask = {taskId: '|crostini|'};
let success = false;
FileTasks.prototype.maybeShareWithCrostiniOrShowDialog_.call(
fakeFilesTask, crostiniTask, () => {
success = true;
});
assertEquals(expectSuccess, success, 'success: ' + comment);
assertEquals(expectSuccess, !showHtmlCalled, 'showHtml called:' + comment);
}
expect('No entries', [], true, '', '');
crostini.setEnabled(false);
expect(
'Single entry, crostini-files not enabled', [notShared1], false,
'UNABLE_TO_OPEN_CROSTINI_TITLE', 'UNABLE_TO_OPEN_CROSTINI');
crostini.setEnabled(true);
expect('Single entry, not shared', [notShared1], true, '', '');
expect('Single entry, shared', [shared], true, '', '');
expect(
'2 entries, not shared, same dir', [notShared1, notShared2], true, '',
'');
expect(
'2 entries, not shared, different dir', [notShared1, otherNotShared],
true, '', '');
expect(
'2 entries, 1 not shared, different dir, not shared first',
[notShared1, shared], true, '', '');
expect(
'2 entries, 1 not shared, different dir, shared first',
[shared, notShared1], true, '', '');
expect(
'3 entries, 2 not shared, different dir',
[shared, notShared1, notShared2], true, '', '');
expect(
'2 entries, 1 not sharable', [notShared1, unsharable], false,
'UNABLE_TO_OPEN_CROSTINI_TITLE', 'UNABLE_TO_OPEN_CROSTINI');
}
function task(id) {
return /** @type{!chrome.fileManagerPrivate.FileTask} */ ({taskId: id});
}
function testTaskRequiresCrostiniSharing() {
assertTrue(
FileTasks.taskRequiresCrostiniSharing(task('app|crostini|open-with')));
assertTrue(FileTasks.taskRequiresCrostiniSharing(
task('appId|x|install-linux-package')));
assertFalse(FileTasks.taskRequiresCrostiniSharing(task('appId|x|open-with')));
}