diff options
Diffstat (limited to 'toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js')
-rw-r--r-- | toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js | 598 |
1 files changed, 598 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js b/toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js new file mode 100644 index 000000000..61a46b251 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js @@ -0,0 +1,598 @@ +var Cc = Components.classes; +var Ci = Components.interfaces; + +const MANDATORY = ["id", "name", "headerURL"]; +const OPTIONAL = ["footerURL", "textcolor", "accentcolor", "iconURL", + "previewURL", "author", "description", "homepageURL", + "updateURL", "version"]; + +Components.utils.import("resource://gre/modules/Services.jsm"); + +function dummy(id) { + return { + id: id || Math.random().toString(), + name: Math.random().toString(), + headerURL: "http://lwttest.invalid/a.png", + footerURL: "http://lwttest.invalid/b.png", + textcolor: Math.random().toString(), + accentcolor: Math.random().toString() + }; +} + +function hasPermission(aAddon, aPerm) { + var perm = AddonManager["PERM_CAN_" + aPerm.toUpperCase()]; + return !!(aAddon.permissions & perm); +} + +function run_test() { + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9"); + startupManager(); + + Services.prefs.setIntPref("lightweightThemes.maxUsedThemes", 8); + + let {LightweightThemeManager: ltm} = Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", {}); + + do_check_eq(typeof ltm, "object"); + do_check_eq(typeof ltm.usedThemes, "object"); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + ltm.previewTheme(dummy("preview0")); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + ltm.previewTheme(dummy("preview1")); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + ltm.resetPreview(); + + ltm.currentTheme = dummy("x0"); + do_check_eq(ltm.usedThemes.length, 1); + do_check_eq(ltm.currentTheme.id, "x0"); + do_check_eq(ltm.usedThemes[0].id, "x0"); + do_check_eq(ltm.getUsedTheme("x0").id, "x0"); + + ltm.previewTheme(dummy("preview0")); + do_check_eq(ltm.usedThemes.length, 1); + do_check_eq(ltm.currentTheme.id, "x0"); + + ltm.resetPreview(); + do_check_eq(ltm.usedThemes.length, 1); + do_check_eq(ltm.currentTheme.id, "x0"); + + ltm.currentTheme = dummy("x1"); + do_check_eq(ltm.usedThemes.length, 2); + do_check_eq(ltm.currentTheme.id, "x1"); + do_check_eq(ltm.usedThemes[1].id, "x0"); + + ltm.currentTheme = dummy("x2"); + do_check_eq(ltm.usedThemes.length, 3); + do_check_eq(ltm.currentTheme.id, "x2"); + do_check_eq(ltm.usedThemes[1].id, "x1"); + do_check_eq(ltm.usedThemes[2].id, "x0"); + + ltm.currentTheme = dummy("x3"); + ltm.currentTheme = dummy("x4"); + ltm.currentTheme = dummy("x5"); + ltm.currentTheme = dummy("x6"); + ltm.currentTheme = dummy("x7"); + do_check_eq(ltm.usedThemes.length, 8); + do_check_eq(ltm.currentTheme.id, "x7"); + do_check_eq(ltm.usedThemes[1].id, "x6"); + do_check_eq(ltm.usedThemes[7].id, "x0"); + + ltm.currentTheme = dummy("x8"); + do_check_eq(ltm.usedThemes.length, 8); + do_check_eq(ltm.currentTheme.id, "x8"); + do_check_eq(ltm.usedThemes[1].id, "x7"); + do_check_eq(ltm.usedThemes[7].id, "x1"); + do_check_eq(ltm.getUsedTheme("x0"), null); + + ltm.forgetUsedTheme("nonexistent"); + do_check_eq(ltm.usedThemes.length, 8); + do_check_neq(ltm.currentTheme, null); + + ltm.forgetUsedTheme("x8"); + do_check_eq(ltm.usedThemes.length, 7); + do_check_eq(ltm.currentTheme, null); + do_check_eq(ltm.usedThemes[0].id, "x7"); + do_check_eq(ltm.usedThemes[6].id, "x1"); + + ltm.forgetUsedTheme("x7"); + ltm.forgetUsedTheme("x6"); + ltm.forgetUsedTheme("x5"); + ltm.forgetUsedTheme("x4"); + ltm.forgetUsedTheme("x3"); + do_check_eq(ltm.usedThemes.length, 2); + do_check_eq(ltm.currentTheme, null); + do_check_eq(ltm.usedThemes[0].id, "x2"); + do_check_eq(ltm.usedThemes[1].id, "x1"); + + ltm.currentTheme = dummy("x1"); + do_check_eq(ltm.usedThemes.length, 2); + do_check_eq(ltm.currentTheme.id, "x1"); + do_check_eq(ltm.usedThemes[0].id, "x1"); + do_check_eq(ltm.usedThemes[1].id, "x2"); + + ltm.currentTheme = dummy("x2"); + do_check_eq(ltm.usedThemes.length, 2); + do_check_eq(ltm.currentTheme.id, "x2"); + do_check_eq(ltm.usedThemes[0].id, "x2"); + do_check_eq(ltm.usedThemes[1].id, "x1"); + + ltm.currentTheme = ltm.getUsedTheme("x1"); + do_check_eq(ltm.usedThemes.length, 2); + do_check_eq(ltm.currentTheme.id, "x1"); + do_check_eq(ltm.usedThemes[0].id, "x1"); + do_check_eq(ltm.usedThemes[1].id, "x2"); + + ltm.forgetUsedTheme("x1"); + ltm.forgetUsedTheme("x2"); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + // Use chinese name to test utf-8, for bug #541943 + var chineseTheme = dummy("chinese0"); + chineseTheme.name = "笢恅0"; + chineseTheme.description = "笢恅1"; + ltm.currentTheme = chineseTheme; + do_check_eq(ltm.usedThemes.length, 1); + do_check_eq(ltm.currentTheme.name, "笢恅0"); + do_check_eq(ltm.currentTheme.description, "笢恅1"); + do_check_eq(ltm.usedThemes[0].name, "笢恅0"); + do_check_eq(ltm.usedThemes[0].description, "笢恅1"); + do_check_eq(ltm.getUsedTheme("chinese0").name, "笢恅0"); + do_check_eq(ltm.getUsedTheme("chinese0").description, "笢恅1"); + + // This name used to break the usedTheme JSON causing all LWTs to be lost + var chineseTheme1 = dummy("chinese1"); + chineseTheme1.name = "眵昜湮桵蔗坌~郔乾"; + chineseTheme1.description = "眵昜湮桵蔗坌~郔乾"; + ltm.currentTheme = chineseTheme1; + do_check_neq(ltm.currentTheme, null); + do_check_eq(ltm.usedThemes.length, 2); + do_check_eq(ltm.currentTheme.name, "眵昜湮桵蔗坌~郔乾"); + do_check_eq(ltm.currentTheme.description, "眵昜湮桵蔗坌~郔乾"); + do_check_eq(ltm.usedThemes[1].name, "笢恅0"); + do_check_eq(ltm.usedThemes[1].description, "笢恅1"); + do_check_eq(ltm.usedThemes[0].name, "眵昜湮桵蔗坌~郔乾"); + do_check_eq(ltm.usedThemes[0].description, "眵昜湮桵蔗坌~郔乾"); + + ltm.forgetUsedTheme("chinese0"); + do_check_eq(ltm.usedThemes.length, 1); + do_check_neq(ltm.currentTheme, null); + + ltm.forgetUsedTheme("chinese1"); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + do_check_eq(ltm.parseTheme("invalid json"), null); + do_check_eq(ltm.parseTheme('"json string"'), null); + + function roundtrip(data, secure) { + return ltm.parseTheme(JSON.stringify(data), + "http" + (secure ? "s" : "") + "://lwttest.invalid/"); + } + + var data = dummy(); + do_check_neq(roundtrip(data), null); + data.id = null; + do_check_eq(roundtrip(data), null); + data.id = 1; + do_check_eq(roundtrip(data), null); + data.id = 1.5; + do_check_eq(roundtrip(data), null); + data.id = true; + do_check_eq(roundtrip(data), null); + data.id = {}; + do_check_eq(roundtrip(data), null); + data.id = []; + do_check_eq(roundtrip(data), null); + + // Check whether parseTheme handles international characters right + var chineseTheme2 = dummy(); + chineseTheme2.name = "眵昜湮桵蔗坌~郔乾"; + chineseTheme2.description = "眵昜湮桵蔗坌~郔乾"; + do_check_neq(roundtrip(chineseTheme2), null); + do_check_eq(roundtrip(chineseTheme2).name, "眵昜湮桵蔗坌~郔乾"); + do_check_eq(roundtrip(chineseTheme2).description, "眵昜湮桵蔗坌~郔乾"); + + data = dummy(); + data.unknownProperty = "Foo"; + do_check_eq(typeof roundtrip(data).unknownProperty, "undefined"); + + data = dummy(); + data.unknownURL = "http://lwttest.invalid/"; + do_check_eq(typeof roundtrip(data).unknownURL, "undefined"); + + function roundtripSet(props, modify, test, secure) { + props.forEach(function (prop) { + var theme = dummy(); + modify(theme, prop); + test(roundtrip(theme, secure), prop, theme); + }); + } + + roundtripSet(MANDATORY, function (theme, prop) { + delete theme[prop]; + }, function (after) { + do_check_eq(after, null); + }); + + roundtripSet(OPTIONAL, function (theme, prop) { + delete theme[prop]; + }, function (after) { + do_check_neq(after, null); + }); + + roundtripSet(MANDATORY, function (theme, prop) { + theme[prop] = ""; + }, function (after) { + do_check_eq(after, null); + }); + + roundtripSet(OPTIONAL, function (theme, prop) { + theme[prop] = ""; + }, function (after, prop) { + do_check_eq(typeof after[prop], "undefined"); + }); + + roundtripSet(MANDATORY, function (theme, prop) { + theme[prop] = " "; + }, function (after) { + do_check_eq(after, null); + }); + + roundtripSet(OPTIONAL, function (theme, prop) { + theme[prop] = " "; + }, function (after, prop) { + do_check_neq(after, null); + do_check_eq(typeof after[prop], "undefined"); + }); + + function non_urls(props) { + return props.filter(prop => !/URL$/.test(prop)); + } + + function urls(props) { + return props.filter(prop => /URL$/.test(prop)); + } + + roundtripSet(non_urls(MANDATORY.concat(OPTIONAL)), function (theme, prop) { + theme[prop] = prop; + }, function (after, prop, before) { + do_check_eq(after[prop], before[prop]); + }); + + roundtripSet(non_urls(MANDATORY.concat(OPTIONAL)), function (theme, prop) { + theme[prop] = " " + prop + " "; + }, function (after, prop, before) { + do_check_eq(after[prop], before[prop].trim()); + }); + + roundtripSet(urls(MANDATORY.concat(OPTIONAL)), function (theme, prop) { + theme[prop] = Math.random().toString(); + }, function (after, prop, before) { + if (prop == "updateURL") + do_check_eq(typeof after[prop], "undefined"); + else + do_check_eq(after[prop], "http://lwttest.invalid/" + before[prop]); + }); + + roundtripSet(urls(MANDATORY.concat(OPTIONAL)), function (theme, prop) { + theme[prop] = Math.random().toString(); + }, function (after, prop, before) { + do_check_eq(after[prop], "https://lwttest.invalid/" + before[prop]); + }, true); + + roundtripSet(urls(MANDATORY.concat(OPTIONAL)), function (theme, prop) { + theme[prop] = "https://sub.lwttest.invalid/" + Math.random().toString(); + }, function (after, prop, before) { + do_check_eq(after[prop], before[prop]); + }); + + roundtripSet(urls(MANDATORY), function (theme, prop) { + theme[prop] = "ftp://lwttest.invalid/" + Math.random().toString(); + }, function (after) { + do_check_eq(after, null); + }); + + roundtripSet(urls(OPTIONAL), function (theme, prop) { + theme[prop] = "ftp://lwttest.invalid/" + Math.random().toString(); + }, function (after, prop) { + do_check_eq(typeof after[prop], "undefined"); + }); + + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + data = dummy(); + delete data.name; + try { + ltm.currentTheme = data; + do_throw("Should have rejected a theme with no name"); + } + catch (e) { + // Expected exception + } + + data = dummy(); + data.headerURL = "foo"; + try { + ltm.currentTheme = data; + do_throw("Should have rejected a theme with a bad headerURL"); + } + catch (e) { + // Expected exception + } + + data = dummy(); + data.headerURL = "ftp://lwtest.invalid/test.png"; + try { + ltm.currentTheme = data; + do_throw("Should have rejected a theme with a non-http(s) headerURL"); + } + catch (e) { + // Expected exception + } + + data = dummy(); + data.headerURL = "file:///test.png"; + try { + ltm.currentTheme = data; + do_throw("Should have rejected a theme with a non-http(s) headerURL"); + } + catch (e) { + // Expected exception + } + + data = dummy(); + data.updateURL = "file:///test.json"; + ltm.setLocalTheme(data); + do_check_eq(ltm.usedThemes.length, 1); + do_check_eq(ltm.currentTheme.updateURL, undefined); + ltm.forgetUsedTheme(ltm.currentTheme.id); + do_check_eq(ltm.usedThemes.length, 0); + + data = dummy(); + data.headerURL = "file:///test.png"; + ltm.setLocalTheme(data); + do_check_eq(ltm.usedThemes.length, 1); + do_check_eq(ltm.currentTheme.headerURL, "file:///test.png"); + ltm.forgetUsedTheme(ltm.currentTheme.id); + do_check_eq(ltm.usedThemes.length, 0); + + data = dummy(); + data.headerURL = "ftp://lwtest.invalid/test.png"; + try { + ltm.setLocalTheme(data); + do_throw("Should have rejected a theme with a non-http(s), non-file headerURL"); + } + catch (e) { + // Expected exception + } + + data = dummy(); + delete data.id; + try { + ltm.currentTheme = data; + do_throw("Should have rejected a theme with no ID"); + } + catch (e) { + // Expected exception + } + + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + // Force the theme into the prefs anyway + let prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefBranch); + let themes = [data]; + prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify(themes)); + do_check_eq(ltm.usedThemes.length, 1); + + // This should silently drop the bad theme. + ltm.currentTheme = dummy(); + do_check_eq(ltm.usedThemes.length, 1); + ltm.forgetUsedTheme(ltm.currentTheme.id); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + // Add one broken and some working. + themes = [data, dummy("x1"), dummy("x2")]; + prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify(themes)); + do_check_eq(ltm.usedThemes.length, 3); + + // Switching to an existing theme should drop the bad theme. + ltm.currentTheme = ltm.getUsedTheme("x1"); + do_check_eq(ltm.usedThemes.length, 2); + ltm.forgetUsedTheme("x1"); + ltm.forgetUsedTheme("x2"); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify(themes)); + do_check_eq(ltm.usedThemes.length, 3); + + // Forgetting an existing theme should drop the bad theme. + ltm.forgetUsedTheme("x1"); + do_check_eq(ltm.usedThemes.length, 1); + ltm.forgetUsedTheme("x2"); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + // Test whether a JSON set with setCharPref can be retrieved with usedThemes + ltm.currentTheme = dummy("x0"); + ltm.currentTheme = dummy("x1"); + prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify(ltm.usedThemes)); + do_check_eq(ltm.usedThemes.length, 2); + do_check_eq(ltm.currentTheme.id, "x1"); + do_check_eq(ltm.usedThemes[1].id, "x0"); + do_check_eq(ltm.usedThemes[0].id, "x1"); + + ltm.forgetUsedTheme("x0"); + do_check_eq(ltm.usedThemes.length, 1); + do_check_neq(ltm.currentTheme, null); + + ltm.forgetUsedTheme("x1"); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + Services.prefs.clearUserPref("lightweightThemes.maxUsedThemes"); + + ltm.currentTheme = dummy("x1"); + ltm.currentTheme = dummy("x2"); + ltm.currentTheme = dummy("x3"); + ltm.currentTheme = dummy("x4"); + ltm.currentTheme = dummy("x5"); + ltm.currentTheme = dummy("x6"); + ltm.currentTheme = dummy("x7"); + ltm.currentTheme = dummy("x8"); + ltm.currentTheme = dummy("x9"); + ltm.currentTheme = dummy("x10"); + ltm.currentTheme = dummy("x11"); + ltm.currentTheme = dummy("x12"); + ltm.currentTheme = dummy("x13"); + ltm.currentTheme = dummy("x14"); + ltm.currentTheme = dummy("x15"); + ltm.currentTheme = dummy("x16"); + ltm.currentTheme = dummy("x17"); + ltm.currentTheme = dummy("x18"); + ltm.currentTheme = dummy("x19"); + ltm.currentTheme = dummy("x20"); + ltm.currentTheme = dummy("x21"); + ltm.currentTheme = dummy("x22"); + ltm.currentTheme = dummy("x23"); + ltm.currentTheme = dummy("x24"); + ltm.currentTheme = dummy("x25"); + ltm.currentTheme = dummy("x26"); + ltm.currentTheme = dummy("x27"); + ltm.currentTheme = dummy("x28"); + ltm.currentTheme = dummy("x29"); + ltm.currentTheme = dummy("x30"); + + do_check_eq(ltm.usedThemes.length, 30); + + ltm.currentTheme = dummy("x31"); + + do_check_eq(ltm.usedThemes.length, 30); + do_check_eq(ltm.getUsedTheme("x1"), null); + + Services.prefs.setIntPref("lightweightThemes.maxUsedThemes", 15); + + do_check_eq(ltm.usedThemes.length, 15); + + Services.prefs.setIntPref("lightweightThemes.maxUsedThemes", 32); + + ltm.currentTheme = dummy("x1"); + ltm.currentTheme = dummy("x2"); + ltm.currentTheme = dummy("x3"); + ltm.currentTheme = dummy("x4"); + ltm.currentTheme = dummy("x5"); + ltm.currentTheme = dummy("x6"); + ltm.currentTheme = dummy("x7"); + ltm.currentTheme = dummy("x8"); + ltm.currentTheme = dummy("x9"); + ltm.currentTheme = dummy("x10"); + ltm.currentTheme = dummy("x11"); + ltm.currentTheme = dummy("x12"); + ltm.currentTheme = dummy("x13"); + ltm.currentTheme = dummy("x14"); + ltm.currentTheme = dummy("x15"); + ltm.currentTheme = dummy("x16"); + + ltm.currentTheme = dummy("x32"); + + do_check_eq(ltm.usedThemes.length, 32); + + ltm.currentTheme = dummy("x33"); + + do_check_eq(ltm.usedThemes.length, 32); + + Services.prefs.clearUserPref("lightweightThemes.maxUsedThemes"); + + do_check_eq(ltm.usedThemes.length, 30); + + let usedThemes = ltm.usedThemes; + for (let theme of usedThemes) { + ltm.forgetUsedTheme(theme.id); + } + + // Check builtInTheme functionality for Bug 1094821 + do_check_eq(ltm._builtInThemes.toString(), "[object Map]"); + do_check_eq([...ltm._builtInThemes.entries()].length, 0); + do_check_eq(ltm.usedThemes.length, 0); + + ltm.addBuiltInTheme(dummy("builtInTheme0")); + do_check_eq([...ltm._builtInThemes].length, 1); + do_check_eq(ltm.usedThemes.length, 1); + do_check_eq(ltm.usedThemes[0].id, "builtInTheme0"); + + ltm.addBuiltInTheme(dummy("builtInTheme1")); + do_check_eq([...ltm._builtInThemes].length, 2); + do_check_eq(ltm.usedThemes.length, 2); + do_check_eq(ltm.usedThemes[1].id, "builtInTheme1"); + + // Clear all and then re-add + ltm.clearBuiltInThemes(); + do_check_eq([...ltm._builtInThemes].length, 0); + do_check_eq(ltm.usedThemes.length, 0); + + ltm.addBuiltInTheme(dummy("builtInTheme0")); + ltm.addBuiltInTheme(dummy("builtInTheme1")); + do_check_eq([...ltm._builtInThemes].length, 2); + do_check_eq(ltm.usedThemes.length, 2); + + do_test_pending(); + + AddonManager.getAddonByID("builtInTheme0@personas.mozilla.org", builtInThemeAddon => { + // App specific theme can't be uninstalled or disabled, + // but can be enabled (since it isn't already applied). + do_check_eq(hasPermission(builtInThemeAddon, "uninstall"), false); + do_check_eq(hasPermission(builtInThemeAddon, "disable"), false); + do_check_eq(hasPermission(builtInThemeAddon, "enable"), true); + + ltm.currentTheme = dummy("x0"); + do_check_eq([...ltm._builtInThemes].length, 2); + do_check_eq(ltm.usedThemes.length, 3); + do_check_eq(ltm.usedThemes[0].id, "x0"); + do_check_eq(ltm.currentTheme.id, "x0"); + do_check_eq(ltm.usedThemes[1].id, "builtInTheme0"); + do_check_eq(ltm.usedThemes[2].id, "builtInTheme1"); + + Assert.throws(() => { ltm.addBuiltInTheme(dummy("builtInTheme0")) }, + "Exception is thrown adding a duplicate theme"); + Assert.throws(() => { ltm.addBuiltInTheme("not a theme object") }, + "Exception is thrown adding an invalid theme"); + + AddonManager.getAddonByID("x0@personas.mozilla.org", x0Addon => { + // Currently applied (non-app-specific) can be uninstalled or disabled, + // but can't be enabled (since it's already applied). + do_check_eq(hasPermission(x0Addon, "uninstall"), true); + do_check_eq(hasPermission(x0Addon, "disable"), true); + do_check_eq(hasPermission(x0Addon, "enable"), false); + + ltm.forgetUsedTheme("x0"); + do_check_eq(ltm.currentTheme, null); + + // Removing the currently applied app specific theme should unapply it + ltm.currentTheme = ltm.getUsedTheme("builtInTheme0"); + do_check_eq(ltm.currentTheme.id, "builtInTheme0"); + do_check_true(ltm.forgetBuiltInTheme("builtInTheme0")); + do_check_eq(ltm.currentTheme, null); + + do_check_eq([...ltm._builtInThemes].length, 1); + do_check_eq(ltm.usedThemes.length, 1); + + do_check_true(ltm.forgetBuiltInTheme("builtInTheme1")); + do_check_false(ltm.forgetBuiltInTheme("not-an-existing-theme-id")); + + do_check_eq([...ltm._builtInThemes].length, 0); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + do_test_finished(); + }); + }); +} |