Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
"use strict";
ChromeUtils.defineESModuleGetters(this, {
ShellService: "moz-src:///browser/components/shell/ShellService.sys.mjs",
TaskbarTabsPin: "resource:///modules/taskbartabs/TaskbarTabsPin.sys.mjs",
TaskbarTabsRegistry:
"resource:///modules/taskbartabs/TaskbarTabsRegistry.sys.mjs",
TaskbarTabsUtils: "resource:///modules/taskbartabs/TaskbarTabsUtils.sys.mjs",
XPCOMUtils: "resource://gre/modules/XPCOMUtils.sys.mjs",
});
XPCOMUtils.defineLazyServiceGetters(this, {
imgTools: ["@mozilla.org/image/tools;1", Ci.imgITools],
});
// We want to mock the native XPCOM interfaces of the initialized
// `ShellService.shellService`, but those interfaces are frozen. Instead we
// proxy `ShellService.shellService` and mock it.
const kMockNativeShellService = {
...ShellService.shellService,
createShortcut: sinon.stub().resolves("dummy_path"),
deleteShortcut: sinon.stub().resolves("dummy_path"),
pinShortcutToTaskbar: sinon.stub().resolves(),
unpinShortcutFromTaskbar: sinon.stub(),
};
sinon.stub(ShellService, "shellService").value(kMockNativeShellService);
sinon.stub(ShellService, "writeShortcutIcon");
sinon.stub(TaskbarTabsPin, "_getLocalization").returns({
formatValue(msg) {
// Slash must also be sanitized, so it should appear as '_' in paths.
return `[formatValue/${msg}]`;
},
});
registerCleanupFunction(() => {
sinon.restore();
});
// Favicons are written to the profile directory, ensure it exists.
do_get_profile();
function shellPinCalled(aTaskbarTab, destFolder, shortcutRelativePath) {
ok(
ShellService.writeShortcutIcon.calledOnce,
`Icon creation should have been called.`
);
ok(
kMockNativeShellService.createShortcut.calledOnce,
`Shortcut creation should have been called.`
);
Assert.equal(
kMockNativeShellService.createShortcut.firstCall.args[6],
destFolder,
"The shortcut should go into the expected destination."
);
Assert.equal(
kMockNativeShellService.createShortcut.firstCall.args[7],
shortcutRelativePath,
"The shortcut path should match the expected result."
);
ok(
kMockNativeShellService.pinShortcutToTaskbar.calledOnce,
`Pin to taskbar should have been called.`
);
Assert.equal(
kMockNativeShellService.pinShortcutToTaskbar.firstCall.args[1],
kMockNativeShellService.createShortcut.firstCall.args[6],
`The created and pinned shortcuts should be in the same folder.`
);
Assert.equal(
kMockNativeShellService.pinShortcutToTaskbar.firstCall.args[2],
kMockNativeShellService.createShortcut.firstCall.args[7],
`The created and pinned shortcuts should be the same file.`
);
Assert.equal(
kMockNativeShellService.pinShortcutToTaskbar.firstCall.args[2],
aTaskbarTab.shortcutRelativePath,
`The pinned shortcut should be the saved shortcut.`
);
Assert.equal(patchedSpy.callCount, 1, "A single patched event was emitted");
}
function shellUnpinCalled(aShortcutRelativePath) {
ok(
kMockNativeShellService.deleteShortcut.calledOnce,
`Unpin from taskbar should have been called.`
);
Assert.equal(
kMockNativeShellService.deleteShortcut.firstCall.args[1],
aShortcutRelativePath,
"shortcutRelativePath was deleted."
);
ok(
kMockNativeShellService.unpinShortcutFromTaskbar.calledOnce,
`Unpin from taskbar should have been called.`
);
Assert.equal(
kMockNativeShellService.unpinShortcutFromTaskbar.firstCall.args[1],
aShortcutRelativePath,
"shortcutRelativePath was deleted."
);
}
async function pinTaskbarTabDefaultIcon(aTaskbarTab, aRegistry) {
return TaskbarTabsPin.pinTaskbarTab(
aTaskbarTab,
aRegistry,
await TaskbarTabsUtils.getDefaultIcon()
);
}
const registry = new TaskbarTabsRegistry();
const patchedSpy = sinon.stub();
registry.on(TaskbarTabsRegistry.events.patched, patchedSpy);
add_task(async function test_pin_location() {
const parsedURI = Services.io.newURI("https://www.example.com");
const taskbarTab = createTaskbarTab(registry, parsedURI, 0);
sinon.resetHistory();
await pinTaskbarTabDefaultIcon(taskbarTab, registry);
shellPinCalled(
taskbarTab,
"Programs",
`[formatValue_taskbar-tab-shortcut-folder]\\${taskbarTab.name}.lnk`
);
});
add_task(async function test_pin_location_dos_name() {
const parsedURI = Services.io.newURI("https://aux.test");
const invalidTaskbarTab = createTaskbarTab(registry, parsedURI, 0);
sinon.resetHistory();
await pinTaskbarTabDefaultIcon(invalidTaskbarTab, registry);
shellPinCalled(
invalidTaskbarTab,
"Programs",
// 'Untitled' is the default selected by the MIME code, since
// AUX is a reserved name on Windows.
"[formatValue_taskbar-tab-shortcut-folder]\\Untitled.lnk"
);
registry.removeTaskbarTab(invalidTaskbarTab.id);
});
add_task(async function test_pin_location_bad_characters() {
const parsedURI = Services.io.newURI("https://another.test");
const invalidTaskbarTab = createTaskbarTab(registry, parsedURI, 0, {
manifest: {
name: "** :\t\r\n \\\\ >> Not a valid. filename??! << // |||: **.",
},
});
sinon.resetHistory();
await pinTaskbarTabDefaultIcon(invalidTaskbarTab, registry);
shellPinCalled(
invalidTaskbarTab,
"Programs",
"[formatValue_taskbar-tab-shortcut-folder]\\__ ____ __ __ Not a valid. filename__! __ __ ____ __..lnk"
);
registry.removeTaskbarTab(invalidTaskbarTab.id);
});
add_task(async function test_pin_location_lnk_extension() {
const parsedURI = Services.io.newURI("https://another.test");
const invalidTaskbarTab = createTaskbarTab(registry, parsedURI, 0, {
manifest: {
name: "coolstartup.lnk",
},
});
sinon.resetHistory();
await pinTaskbarTabDefaultIcon(invalidTaskbarTab, registry);
shellPinCalled(
invalidTaskbarTab,
"Programs",
"[formatValue_taskbar-tab-shortcut-folder]\\coolstartup.lnk.lnk"
);
registry.removeTaskbarTab(invalidTaskbarTab.id);
});
add_task(async function test_unpin() {
const exampleUrl = Services.io.newURI("https://example.com");
const tt = createTaskbarTab(registry, exampleUrl, 0);
registry.patchTaskbarTab(tt, {
shortcutRelativePath: "somewhere else\\shortcut name.lnk",
});
sinon.resetHistory();
await TaskbarTabsPin.unpinTaskbarTab(tt, registry);
shellUnpinCalled("somewhere else\\shortcut name.lnk");
Assert.equal(
tt.shortcutRelativePath,
null,
"Shortcut relative path was removed from the taskbar tab"
);
Assert.equal(patchedSpy.callCount, 1, "A single patched event was emitted");
});