diff options
Diffstat (limited to 'modules/libpref/test/unit')
24 files changed, 1630 insertions, 0 deletions
diff --git a/modules/libpref/test/unit/data/testParser.js b/modules/libpref/test/unit/data/testParser.js new file mode 100644 index 0000000000..be29430b2a --- /dev/null +++ b/modules/libpref/test/unit/data/testParser.js @@ -0,0 +1,98 @@ +// Note: this file tests only valid syntax (of default pref files, not user +// pref files). See modules/libpref/test/gtest/Parser.cpp for tests of invalid +// syntax. + +# +# comment + # comment £
+//
+// comment + // comment £ +/**/ + /* comment £ */ +/* comment + * and +some
+ # more + // comment */ +// comment /* +# comment /* +/* /* /* /* /* ...no nesting of C-style comments... */ + +// The following four lines have whitespace: \t, \v, \f, \r + + + +
+ +// This comment has the same whitespace:
+# This comment has other stuff: \n \r \t \v \f \r \a \b \? \' \" \\ \@ +/* This comment has more stuff: \x61 \u0061 \u1234 \uXYZ */ + +/*0*/ pref /*1*/ ( /*2*/ "comment1" /*3*/ , /*4*/ true /*5*/ ) /*6*/ ; /*7*/ + +pref # foo +( // foo +"comment2" /* +foo +*/,/*foo*/ +true#foo +)// +; /*7*/ + +pref + ( + "spaced-out" + , + true + ) + ; + +pref("pref", true); +sticky_pref("sticky_pref", true); +user_pref("user_pref", true); +pref("sticky_pref2", true, sticky); +pref("locked_pref", true, locked); +pref("locked_sticky_pref", true, locked, sticky,sticky, + locked, locked, locked); + +pref("bool.true", true); +pref("bool.false", false); + +pref("int.0", 0); +pref("int.1", 1); +pref("int.123", 123); +pref("int.+234", +234); +pref("int.+ 345", + 345); +// Note that both the prefname and value have tabs in them +pref("int.-0", -0); +pref("int.-1", -1); +pref("int.- /* hmm */ 456", - /* hmm */ 456); +pref("int.-\n567", - +567); +pref("int.INT_MAX-1", 2147483646); +pref("int.INT_MAX", 2147483647); +pref("int.INT_MIN+2", -2147483646); +pref("int.INT_MIN+1", -2147483647); +pref("int.INT_MIN", -2147483648); +//pref("int.overflow.max", 2147483648); // overflows to -2147483648 +//pref("int.overflow.min", -2147483649); // overflows to 2147483647 +//pref("int.overflow.other", 4000000000); // overflows to -294967296 +//pref("int.overflow.another", 5000000000000000); // overflows to 937459712 + +pref("string.empty", ""); +pref("string.abc", "abc"); +pref("string.long", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); +pref('string.single-quotes', '"abc"'); +pref("string.double-quotes", "'abc'"); +pref("string.weird-chars", "
"); +pref("string.escapes", "\" \' \\ \n \r"); +pref("string.x-escapes1", "Mozilla0\x4d\x6F\x7a\x69\x6c\x6C\x610"); +pref("string.x-escapes2", "A\x41 A_umlaut\xc4 y_umlaut\xff"); +pref("string.u-escapes1", "A\u0041 A_umlaut\u00c4 y_umlaut\u00ff0"); +pref("string.u-escapes2", "S_acute\u015a y_grave\u1Ef3"); +// CYCLONE is 0x1f300, GRINNING FACE is 0x1f600. We have to represent them via +// surrogate pairs. +pref("string.u-surrogates", + "cyclone\uD83C\uDF00 grinning_face\uD83D\uDE00"); + diff --git a/modules/libpref/test/unit/data/testPref.js b/modules/libpref/test/unit/data/testPref.js new file mode 100644 index 0000000000..0864e7ce8b --- /dev/null +++ b/modules/libpref/test/unit/data/testPref.js @@ -0,0 +1,6 @@ +user_pref("testPref.bool1", true); +user_pref("testPref.bool2", false); +user_pref("testPref.int1", 23); +user_pref("testPref.int2", -1236); +user_pref("testPref.char1", "_testPref"); +user_pref("testPref.char2", "älskar");
\ No newline at end of file diff --git a/modules/libpref/test/unit/data/testPrefLocked.js b/modules/libpref/test/unit/data/testPrefLocked.js new file mode 100644 index 0000000000..001b65122b --- /dev/null +++ b/modules/libpref/test/unit/data/testPrefLocked.js @@ -0,0 +1,2 @@ +pref("testPref.unlocked.int", 333); +pref("testPref.locked.int", 444, locked); diff --git a/modules/libpref/test/unit/data/testPrefLockedUser.js b/modules/libpref/test/unit/data/testPrefLockedUser.js new file mode 100644 index 0000000000..4da40b7abc --- /dev/null +++ b/modules/libpref/test/unit/data/testPrefLockedUser.js @@ -0,0 +1,3 @@ +// testPrefLocked.js defined this pref as a locked pref. +// Changing a locked pref has no effect. +user_pref("testPref.locked.int", 555); diff --git a/modules/libpref/test/unit/data/testPrefSticky.js b/modules/libpref/test/unit/data/testPrefSticky.js new file mode 100644 index 0000000000..ef1a02adfd --- /dev/null +++ b/modules/libpref/test/unit/data/testPrefSticky.js @@ -0,0 +1,2 @@ +pref("testPref.unsticky.bool", true); +pref("testPref.sticky.bool", false, sticky); diff --git a/modules/libpref/test/unit/data/testPrefStickyUser.js b/modules/libpref/test/unit/data/testPrefStickyUser.js new file mode 100644 index 0000000000..d929c670ad --- /dev/null +++ b/modules/libpref/test/unit/data/testPrefStickyUser.js @@ -0,0 +1,5 @@ +// testPrefSticky.js defined this pref as sticky. Once a sticky +// pref has been changed, it's written as a user_pref(). +// So this test file reflects that scenario. +// Note the default in testPrefSticky.js is also false. +user_pref("testPref.sticky.bool", false); diff --git a/modules/libpref/test/unit/data/testPrefUTF8.js b/modules/libpref/test/unit/data/testPrefUTF8.js new file mode 100644 index 0000000000..a409c4eb72 --- /dev/null +++ b/modules/libpref/test/unit/data/testPrefUTF8.js @@ -0,0 +1,6 @@ +user_pref("testPref.bool1", true); +user_pref("testPref.bool2", false); +user_pref("testPref.int1", 23); +user_pref("testPref.int2", -1236); +user_pref("testPref.char1", "_testPref"); +user_pref("testPref.char2", "älskar"); diff --git a/modules/libpref/test/unit/extdata/testExt.js b/modules/libpref/test/unit/extdata/testExt.js new file mode 100644 index 0000000000..17c6849692 --- /dev/null +++ b/modules/libpref/test/unit/extdata/testExt.js @@ -0,0 +1,2 @@ +pref("testPref.bool2", true); +pref("testExtPref.bool", true); diff --git a/modules/libpref/test/unit/head_libPrefs.js b/modules/libpref/test/unit/head_libPrefs.js new file mode 100644 index 0000000000..ef7044a641 --- /dev/null +++ b/modules/libpref/test/unit/head_libPrefs.js @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const NS_APP_USER_PROFILE_50_DIR = "ProfD"; + +function do_check_throws(f, result, stack) { + if (!stack) { + stack = Components.stack.caller; + } + + try { + f(); + } catch (exc) { + equal(exc.result, result, "Correct exception was thrown"); + return; + } + ok(false, "expected result " + result + ", none thrown"); +} + +// Register current test directory as provider for the profile directory. +var provider = { + getFile(prop, persistent) { + persistent.value = true; + if (prop == NS_APP_USER_PROFILE_50_DIR) { + return Services.dirsvc.get("CurProcD", Ci.nsIFile); + } + throw Components.Exception( + "Tried to get test directory '" + prop + "'", + Cr.NS_ERROR_FAILURE + ); + }, + QueryInterface: ChromeUtils.generateQI(["nsIDirectoryServiceProvider"]), +}; +Services.dirsvc + .QueryInterface(Ci.nsIDirectoryService) + .registerProvider(provider); diff --git a/modules/libpref/test/unit/test_bug1354613.js b/modules/libpref/test/unit/test_bug1354613.js new file mode 100644 index 0000000000..e609c6805a --- /dev/null +++ b/modules/libpref/test/unit/test_bug1354613.js @@ -0,0 +1,21 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +function run_test() { + const BRANCH = "foo."; + const PREF_NAME = "testPref"; + const FULL_PREF_NAME = BRANCH + PREF_NAME; + + const FLOAT = 9.674; + const FUDGE = 0.001; + + let prefs = Services.prefs.getDefaultBranch(null); + + /* Test with a non-default branch */ + prefs.setCharPref(FULL_PREF_NAME, FLOAT); + let pb = Services.prefs.getBranch(BRANCH); + + let floatPref = pb.getFloatPref(PREF_NAME); + Assert.ok(FLOAT + FUDGE >= floatPref); + Assert.ok(FLOAT - FUDGE <= floatPref); +} diff --git a/modules/libpref/test/unit/test_bug345529.js b/modules/libpref/test/unit/test_bug345529.js new file mode 100644 index 0000000000..05fce35f57 --- /dev/null +++ b/modules/libpref/test/unit/test_bug345529.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Regression test for bug 345529 - crash removing an observer during an +// nsPref:changed notification. +function run_test() { + const PREF_NAME = "testPref"; + + var observer = { + QueryInterface: ChromeUtils.generateQI(["nsIObserver"]), + + observe: function observe(aSubject, aTopic, aState) { + Services.prefs.removeObserver(PREF_NAME, observer); + }, + }; + Services.prefs.addObserver(PREF_NAME, observer); + + Services.prefs.setCharPref(PREF_NAME, "test0"); + // This second call isn't needed on a clean profile: it makes sure + // the observer gets called even if the pref already had the value + // "test0" before this test. + Services.prefs.setCharPref(PREF_NAME, "test1"); + + Assert.ok(true); +} diff --git a/modules/libpref/test/unit/test_bug506224.js b/modules/libpref/test/unit/test_bug506224.js new file mode 100644 index 0000000000..033c5acc6e --- /dev/null +++ b/modules/libpref/test/unit/test_bug506224.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +function run_test() { + const PREF_NAME = "testPref"; + + var prefs = Services.prefs.getDefaultBranch(null); + var userprefs = Services.prefs.getBranch(null); + + prefs.setCharPref(PREF_NAME, "test0"); + prefs.lockPref(PREF_NAME); + Assert.equal("test0", userprefs.getCharPref(PREF_NAME)); + Assert.equal(false, userprefs.prefHasUserValue(PREF_NAME)); + + var file = do_get_profile(); + file.append("prefs.js"); + Services.prefs.savePrefFile(file); + + prefs.unlockPref(PREF_NAME); + prefs.setCharPref(PREF_NAME, "test1"); + Services.prefs.readUserPrefsFromFile(file); + + Assert.equal("test1", userprefs.getCharPref(PREF_NAME)); + Assert.equal(false, userprefs.prefHasUserValue(PREF_NAME)); +} diff --git a/modules/libpref/test/unit/test_bug577950.js b/modules/libpref/test/unit/test_bug577950.js new file mode 100644 index 0000000000..f9106a349f --- /dev/null +++ b/modules/libpref/test/unit/test_bug577950.js @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function run_test() { + var observer = { + QueryInterface: ChromeUtils.generateQI(["nsIObserver"]), + + observe: function observe(aSubject, aTopic, aState) { + // Don't do anything. + }, + }; + + /* Set the same pref twice. This shouldn't leak. */ + Services.prefs.addObserver("UserPref.nonexistent.setIntPref", observer); + Services.prefs.addObserver("UserPref.nonexistent.setIntPref", observer); +} diff --git a/modules/libpref/test/unit/test_bug790374.js b/modules/libpref/test/unit/test_bug790374.js new file mode 100644 index 0000000000..d4271a7ff7 --- /dev/null +++ b/modules/libpref/test/unit/test_bug790374.js @@ -0,0 +1,50 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +function run_test() { + const PREF_NAME = "testPref"; + + var prefs = Services.prefs.getDefaultBranch(null); + var userprefs = Services.prefs.getBranch(null); + + /* First, test to make sure we can parse a float from a string properly. */ + prefs.setCharPref(PREF_NAME, "9.674"); + prefs.lockPref(PREF_NAME); + var myFloat = 9.674; + var fudge = 0.001; + var floatPref = userprefs.getFloatPref(PREF_NAME); + Assert.ok(myFloat + fudge >= floatPref); + Assert.ok(myFloat - fudge <= floatPref); + + /* Now test some failure conditions. */ + prefs.unlockPref(PREF_NAME); + prefs.setCharPref(PREF_NAME, ""); + prefs.lockPref(PREF_NAME); + do_check_throws(function () { + userprefs.getFloatPref(PREF_NAME); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + prefs.unlockPref(PREF_NAME); + prefs.setCharPref(PREF_NAME, "18.0a1"); + prefs.lockPref(PREF_NAME); + + do_check_throws(function () { + userprefs.getFloatPref(PREF_NAME); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + prefs.unlockPref(PREF_NAME); + prefs.setCharPref(PREF_NAME, "09.25.2012"); + prefs.lockPref(PREF_NAME); + + do_check_throws(function () { + userprefs.getFloatPref(PREF_NAME); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + prefs.unlockPref(PREF_NAME); + prefs.setCharPref(PREF_NAME, "aString"); + prefs.lockPref(PREF_NAME); + + do_check_throws(function () { + userprefs.getFloatPref(PREF_NAME); + }, Cr.NS_ERROR_ILLEGAL_VALUE); +} diff --git a/modules/libpref/test/unit/test_changeType.js b/modules/libpref/test/unit/test_changeType.js new file mode 100644 index 0000000000..94f3a84f13 --- /dev/null +++ b/modules/libpref/test/unit/test_changeType.js @@ -0,0 +1,164 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Tests for changing the type of a preference (bug 985998) */ + +function run_test() { + var ps = Services.prefs; + + let defaultBranch = ps.getDefaultBranch(""); + let userBranch = ps.getBranch(""); + + // Prefs that only have a default value -- we can't change their type. + defaultBranch.setBoolPref("TypeTest.default.bool", true); + defaultBranch.setIntPref("TypeTest.default.int", 23); + defaultBranch.setCharPref("TypeTest.default.char", "hey"); + + Assert.equal(userBranch.getBoolPref("TypeTest.default.bool"), true); + Assert.equal(userBranch.getIntPref("TypeTest.default.int"), 23); + Assert.equal(userBranch.getCharPref("TypeTest.default.char"), "hey"); + + // Prefs that only have a user value -- we can change their type, but only + // when we set the user value. + userBranch.setBoolPref("TypeTest.user.bool", false); + userBranch.setIntPref("TypeTest.user.int", 24); + userBranch.setCharPref("TypeTest.user.char", "hi"); + + Assert.equal(userBranch.getBoolPref("TypeTest.user.bool"), false); + Assert.equal(userBranch.getIntPref("TypeTest.user.int"), 24); + Assert.equal(userBranch.getCharPref("TypeTest.user.char"), "hi"); + + // Prefs that have both a default and a user value -- we can't change their + // type. + defaultBranch.setBoolPref("TypeTest.both.bool", true); + userBranch.setBoolPref("TypeTest.both.bool", false); + defaultBranch.setIntPref("TypeTest.both.int", 25); + userBranch.setIntPref("TypeTest.both.int", 26); + defaultBranch.setCharPref("TypeTest.both.char", "yo"); + userBranch.setCharPref("TypeTest.both.char", "ya"); + + Assert.equal(userBranch.getBoolPref("TypeTest.both.bool"), false); + Assert.equal(userBranch.getIntPref("TypeTest.both.int"), 26); + Assert.equal(userBranch.getCharPref("TypeTest.both.char"), "ya"); + + // We only have a default value, and we try to set a default value of a + // different type --> fails. + do_check_throws(function () { + defaultBranch.setCharPref("TypeTest.default.bool", "boo"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setIntPref("TypeTest.default.bool", 5); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setCharPref("TypeTest.default.int", "boo"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setBoolPref("TypeTest.default.int", true); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setBoolPref("TypeTest.default.char", true); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setIntPref("TypeTest.default.char", 6); + }, Cr.NS_ERROR_UNEXPECTED); + + // We only have a default value, and we try to set a user value of a + // different type --> fails. + do_check_throws(function () { + userBranch.setCharPref("TypeTest.default.bool", "boo"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + userBranch.setIntPref("TypeTest.default.bool", 5); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + userBranch.setCharPref("TypeTest.default.int", "boo"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + userBranch.setBoolPref("TypeTest.default.int", true); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + userBranch.setBoolPref("TypeTest.default.char", true); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + userBranch.setIntPref("TypeTest.default.char", 6); + }, Cr.NS_ERROR_UNEXPECTED); + + // We only have a user value, and we try to set a default value of a + // different type --> fails. + do_check_throws(function () { + defaultBranch.setCharPref("TypeTest.user.bool", "boo"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setIntPref("TypeTest.user.bool", 5); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setCharPref("TypeTest.user.int", "boo"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setBoolPref("TypeTest.user.int", true); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setBoolPref("TypeTest.user.char", true); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setIntPref("TypeTest.user.char", 6); + }, Cr.NS_ERROR_UNEXPECTED); + + // We only have a user value, and we try to set a user value of a + // different type --> SUCCEEDS. + userBranch.setCharPref("TypeTest.user.bool", "boo"); + Assert.equal(userBranch.getCharPref("TypeTest.user.bool"), "boo"); + userBranch.setIntPref("TypeTest.user.bool", 5); + Assert.equal(userBranch.getIntPref("TypeTest.user.bool"), 5); + userBranch.setCharPref("TypeTest.user.int", "boo"); + Assert.equal(userBranch.getCharPref("TypeTest.user.int"), "boo"); + userBranch.setBoolPref("TypeTest.user.int", true); + Assert.equal(userBranch.getBoolPref("TypeTest.user.int"), true); + userBranch.setBoolPref("TypeTest.user.char", true); + Assert.equal(userBranch.getBoolPref("TypeTest.user.char"), true); + userBranch.setIntPref("TypeTest.user.char", 6); + Assert.equal(userBranch.getIntPref("TypeTest.user.char"), 6); + + // We have both a default value and user value, and we try to set a default + // value of a different type --> fails. + do_check_throws(function () { + defaultBranch.setCharPref("TypeTest.both.bool", "boo"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setIntPref("TypeTest.both.bool", 5); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setCharPref("TypeTest.both.int", "boo"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setBoolPref("TypeTest.both.int", true); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setBoolPref("TypeTest.both.char", true); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + defaultBranch.setIntPref("TypeTest.both.char", 6); + }, Cr.NS_ERROR_UNEXPECTED); + + // We have both a default value and user value, and we try to set a user + // value of a different type --> fails. + do_check_throws(function () { + userBranch.setCharPref("TypeTest.both.bool", "boo"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + userBranch.setIntPref("TypeTest.both.bool", 5); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + userBranch.setCharPref("TypeTest.both.int", "boo"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + userBranch.setBoolPref("TypeTest.both.int", true); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + userBranch.setBoolPref("TypeTest.both.char", true); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + userBranch.setIntPref("TypeTest.both.char", 6); + }, Cr.NS_ERROR_UNEXPECTED); +} diff --git a/modules/libpref/test/unit/test_defaultValues.js b/modules/libpref/test/unit/test_defaultValues.js new file mode 100644 index 0000000000..905675a1cf --- /dev/null +++ b/modules/libpref/test/unit/test_defaultValues.js @@ -0,0 +1,59 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Tests for providing a default value to get{Bool,Char,Float,Int}Pref */ + +function run_test() { + const ps = Services.prefs; + let prefName = "test.default.values.bool"; + do_check_throws(function () { + ps.getBoolPref(prefName); + }, Cr.NS_ERROR_UNEXPECTED); + strictEqual(ps.getBoolPref(prefName, false), false); + strictEqual(ps.getBoolPref(prefName, true), true); + ps.setBoolPref(prefName, true); + strictEqual(ps.getBoolPref(prefName), true); + strictEqual(ps.getBoolPref(prefName, false), true); + strictEqual(ps.getBoolPref(prefName, true), true); + + prefName = "test.default.values.char"; + do_check_throws(function () { + ps.getCharPref(prefName); + }, Cr.NS_ERROR_UNEXPECTED); + strictEqual(ps.getCharPref(prefName, ""), ""); + strictEqual(ps.getCharPref(prefName, "string"), "string"); + ps.setCharPref(prefName, "foo"); + strictEqual(ps.getCharPref(prefName), "foo"); + strictEqual(ps.getCharPref(prefName, "string"), "foo"); + + prefName = "test.default.values.string"; + do_check_throws(function () { + ps.getCharPref(prefName); + }, Cr.NS_ERROR_UNEXPECTED); + strictEqual(ps.getStringPref(prefName, ""), ""); + strictEqual(ps.getStringPref(prefName, "éèçà ê€"), "éèçà ê€"); + ps.setStringPref(prefName, "éèçà ê€"); + strictEqual(ps.getStringPref(prefName), "éèçà ê€"); + strictEqual(ps.getStringPref(prefName, "string"), "éèçà ê€"); + + prefName = "test.default.values.float"; + do_check_throws(function () { + ps.getFloatPref(prefName); + }, Cr.NS_ERROR_UNEXPECTED); + strictEqual(ps.getFloatPref(prefName, 3.5), 3.5); + strictEqual(ps.getFloatPref(prefName, 0), 0); + ps.setCharPref(prefName, 1.75); + strictEqual(ps.getFloatPref(prefName), 1.75); + strictEqual(ps.getFloatPref(prefName, 3.5), 1.75); + + prefName = "test.default.values.int"; + do_check_throws(function () { + ps.getIntPref(prefName); + }, Cr.NS_ERROR_UNEXPECTED); + strictEqual(ps.getIntPref(prefName, 3), 3); + strictEqual(ps.getIntPref(prefName, 0), 0); + ps.setIntPref(prefName, 42); + strictEqual(ps.getIntPref(prefName), 42); + strictEqual(ps.getIntPref(prefName, 3), 42); +} diff --git a/modules/libpref/test/unit/test_dirtyPrefs.js b/modules/libpref/test/unit/test_dirtyPrefs.js new file mode 100644 index 0000000000..e107bef363 --- /dev/null +++ b/modules/libpref/test/unit/test_dirtyPrefs.js @@ -0,0 +1,69 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Tests for handling of the preferences 'dirty' flag (bug 985998) */ + +function run_test() { + const ps = Services.prefs; + + let defaultBranch = ps.getDefaultBranch(""); + let userBranch = ps.getBranch(""); + + let prefFile = do_get_profile(); + prefFile.append("prefs.js"); + + //* *************************************************************************// + // prefs are not dirty after a write + ps.savePrefFile(null); + Assert.ok(!ps.dirty); + + // set a new a user value, we should become dirty + userBranch.setBoolPref("DirtyTest.new.bool", true); + Assert.ok(ps.dirty); + ps.savePrefFile(null); + // Overwrite a pref with the same value => not dirty + userBranch.setBoolPref("DirtyTest.new.bool", true); + Assert.ok(!ps.dirty); + + // Repeat for the other two types + userBranch.setIntPref("DirtyTest.new.int", 1); + Assert.ok(ps.dirty); + ps.savePrefFile(null); + // Overwrite a pref with the same value => not dirty + userBranch.setIntPref("DirtyTest.new.int", 1); + Assert.ok(!ps.dirty); + + userBranch.setCharPref("DirtyTest.new.char", "oop"); + Assert.ok(ps.dirty); + ps.savePrefFile(null); + // Overwrite a pref with the same value => not dirty + userBranch.setCharPref("DirtyTest.new.char", "oop"); + Assert.ok(!ps.dirty); + + // change *type* of a user value -> dirty + userBranch.setBoolPref("DirtyTest.new.char", false); + Assert.ok(ps.dirty); + ps.savePrefFile(null); + + // Set a default pref => not dirty (defaults don't go into prefs.js) + defaultBranch.setBoolPref("DirtyTest.existing.bool", true); + Assert.ok(!ps.dirty); + // Fail to change type of a pref with default value -> not dirty + do_check_throws(function () { + userBranch.setCharPref("DirtyTest.existing.bool", "boo"); + }, Cr.NS_ERROR_UNEXPECTED); + Assert.ok(!ps.dirty); + + // Set user value same as default, not dirty + userBranch.setBoolPref("DirtyTest.existing.bool", true); + Assert.ok(!ps.dirty); + // User value different from default, dirty + userBranch.setBoolPref("DirtyTest.existing.bool", false); + Assert.ok(ps.dirty); + ps.savePrefFile(null); + // Back to default value, dirty again + userBranch.setBoolPref("DirtyTest.existing.bool", true); + Assert.ok(ps.dirty); + ps.savePrefFile(null); +} diff --git a/modules/libpref/test/unit/test_libPrefs.js b/modules/libpref/test/unit/test_libPrefs.js new file mode 100644 index 0000000000..93651568be --- /dev/null +++ b/modules/libpref/test/unit/test_libPrefs.js @@ -0,0 +1,450 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// It is necessary to manually disable `xpc::IsInAutomation` since +// `resetPrefs` will flip the preference to re-enable `once`-synced +// preference change assertions, and also change the value of those +// preferences. +Services.prefs.setBoolPref( + "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", + false +); + +const PREF_INVALID = 0; +const PREF_BOOL = 128; +const PREF_INT = 64; +const PREF_STRING = 32; + +const MAX_PREF_LENGTH = 1 * 1024 * 1024; + +function makeList(a) { + var o = {}; + for (var i = 0; i < a.length; i++) { + o[a[i]] = ""; + } + return o; +} + +function run_test() { + const ps = Services.prefs; + + //* *************************************************************************// + // Nullsafety + + do_check_throws(function () { + ps.getPrefType(null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.getBoolPref(null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.setBoolPref(null, false); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.getIntPref(null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.setIntPref(null, 0); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.getCharPref(null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.setCharPref(null, null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.getStringPref(null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.setStringPref(null, null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.clearUserPref(null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.prefHasUserValue(null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.lockPref(null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.prefIsLocked(null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.unlockPref(null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.deleteBranch(null); + }, Cr.NS_ERROR_INVALID_ARG); + do_check_throws(function () { + ps.getChildList(null); + }, Cr.NS_ERROR_INVALID_ARG); + + //* *************************************************************************// + // Nonexisting user preferences + + Assert.equal(ps.prefHasUserValue("UserPref.nonexistent.hasUserValue"), false); + ps.clearUserPref("UserPref.nonexistent.clearUserPref"); // shouldn't throw + Assert.equal( + ps.getPrefType("UserPref.nonexistent.getPrefType"), + PREF_INVALID + ); + Assert.equal(ps.root, ""); + + // bool... + do_check_throws(function () { + ps.getBoolPref("UserPref.nonexistent.getBoolPref"); + }, Cr.NS_ERROR_UNEXPECTED); + ps.setBoolPref("UserPref.nonexistent.setBoolPref", false); + Assert.equal(ps.getBoolPref("UserPref.nonexistent.setBoolPref"), false); + + // int... + do_check_throws(function () { + ps.getIntPref("UserPref.nonexistent.getIntPref"); + }, Cr.NS_ERROR_UNEXPECTED); + ps.setIntPref("UserPref.nonexistent.setIntPref", 5); + Assert.equal(ps.getIntPref("UserPref.nonexistent.setIntPref"), 5); + + // char + do_check_throws(function () { + ps.getCharPref("UserPref.nonexistent.getCharPref"); + }, Cr.NS_ERROR_UNEXPECTED); + ps.setCharPref("UserPref.nonexistent.setCharPref", "_test"); + Assert.equal(ps.getCharPref("UserPref.nonexistent.setCharPref"), "_test"); + + //* *************************************************************************// + // Existing user Prefs and data integrity test (round-trip match) + + ps.setBoolPref("UserPref.existing.bool", true); + ps.setIntPref("UserPref.existing.int", 23); + ps.setCharPref("UserPref.existing.char", "hey"); + + // getPref should return the pref value + Assert.equal(ps.getBoolPref("UserPref.existing.bool"), true); + Assert.equal(ps.getIntPref("UserPref.existing.int"), 23); + Assert.equal(ps.getCharPref("UserPref.existing.char"), "hey"); + + // setPref should not complain and should change the value of the pref + ps.setBoolPref("UserPref.existing.bool", false); + Assert.equal(ps.getBoolPref("UserPref.existing.bool"), false); + ps.setIntPref("UserPref.existing.int", 24); + Assert.equal(ps.getIntPref("UserPref.existing.int"), 24); + ps.setCharPref("UserPref.existing.char", "hej då!"); + Assert.equal(ps.getCharPref("UserPref.existing.char"), "hej då!"); + + // prefHasUserValue should return true now + Assert.ok(ps.prefHasUserValue("UserPref.existing.bool")); + Assert.ok(ps.prefHasUserValue("UserPref.existing.int")); + Assert.ok(ps.prefHasUserValue("UserPref.existing.char")); + + // clearUserPref should remove the pref + ps.clearUserPref("UserPref.existing.bool"); + Assert.ok(!ps.prefHasUserValue("UserPref.existing.bool")); + ps.clearUserPref("UserPref.existing.int"); + Assert.ok(!ps.prefHasUserValue("UserPref.existing.int")); + ps.clearUserPref("UserPref.existing.char"); + Assert.ok(!ps.prefHasUserValue("UserPref.existing.char")); + + //* *************************************************************************// + // Large value test + + let largeStr = new Array(MAX_PREF_LENGTH + 1).join("x"); + ps.setCharPref("UserPref.large.char", largeStr); + largeStr += "x"; + do_check_throws(function () { + ps.setCharPref("UserPref.large.char", largeStr); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + //* *************************************************************************// + // getPrefType test + + // bool... + ps.setBoolPref("UserPref.getPrefType.bool", true); + Assert.equal(ps.getPrefType("UserPref.getPrefType.bool"), PREF_BOOL); + + // int... + ps.setIntPref("UserPref.getPrefType.int", -234); + Assert.equal(ps.getPrefType("UserPref.getPrefType.int"), PREF_INT); + + // char... + ps.setCharPref("UserPref.getPrefType.char", "testing1..2"); + Assert.equal(ps.getPrefType("UserPref.getPrefType.char"), PREF_STRING); + + //* *************************************************************************// + // getBranch tests + + Assert.equal(ps.root, ""); + + // bool ... + ps.setBoolPref("UserPref.root.boolPref", true); + let pb_1 = ps.getBranch("UserPref.root."); + Assert.equal(pb_1.getBoolPref("boolPref"), true); + let pb_2 = ps.getBranch("UserPref.root.boolPref"); + Assert.equal(pb_2.getBoolPref(""), true); + pb_2.setBoolPref(".anotherPref", false); + let pb_3 = ps.getBranch("UserPref.root.boolPre"); + Assert.equal(pb_3.getBoolPref("f.anotherPref"), false); + + // int ... + ps.setIntPref("UserPref.root.intPref", 23); + pb_1 = ps.getBranch("UserPref.root."); + Assert.equal(pb_1.getIntPref("intPref"), 23); + pb_2 = ps.getBranch("UserPref.root.intPref"); + Assert.equal(pb_2.getIntPref(""), 23); + pb_2.setIntPref(".anotherPref", 69); + pb_3 = ps.getBranch("UserPref.root.intPre"); + Assert.equal(pb_3.getIntPref("f.anotherPref"), 69); + + // char... + ps.setCharPref("UserPref.root.charPref", "_char"); + pb_1 = ps.getBranch("UserPref.root."); + Assert.equal(pb_1.getCharPref("charPref"), "_char"); + pb_2 = ps.getBranch("UserPref.root.charPref"); + Assert.equal(pb_2.getCharPref(""), "_char"); + pb_2.setCharPref(".anotherPref", "_another"); + pb_3 = ps.getBranch("UserPref.root.charPre"); + Assert.equal(pb_3.getCharPref("f.anotherPref"), "_another"); + + //* *************************************************************************// + // getChildlist tests + + // get an already set prefBranch + let pb1 = ps.getBranch("UserPref.root."); + let prefList = pb1.getChildList(""); + Assert.equal(prefList.length, 6); + + // check for specific prefs in the array : the order is not important + Assert.ok("boolPref" in makeList(prefList)); + Assert.ok("intPref" in makeList(prefList)); + Assert.ok("charPref" in makeList(prefList)); + Assert.ok("boolPref.anotherPref" in makeList(prefList)); + Assert.ok("intPref.anotherPref" in makeList(prefList)); + Assert.ok("charPref.anotherPref" in makeList(prefList)); + + //* *************************************************************************// + // Default branch tests + + // bool... + pb1 = ps.getDefaultBranch(""); + pb1.setBoolPref("DefaultPref.bool", true); + Assert.equal(pb1.getBoolPref("DefaultPref.bool"), true); + Assert.ok(!pb1.prefHasUserValue("DefaultPref.bool")); + ps.setBoolPref("DefaultPref.bool", false); + Assert.ok(pb1.prefHasUserValue("DefaultPref.bool")); + Assert.equal(ps.getBoolPref("DefaultPref.bool"), false); + + // int... + pb1 = ps.getDefaultBranch(""); + pb1.setIntPref("DefaultPref.int", 100); + Assert.equal(pb1.getIntPref("DefaultPref.int"), 100); + Assert.ok(!pb1.prefHasUserValue("DefaultPref.int")); + ps.setIntPref("DefaultPref.int", 50); + Assert.ok(pb1.prefHasUserValue("DefaultPref.int")); + Assert.equal(ps.getIntPref("DefaultPref.int"), 50); + + // char... + pb1 = ps.getDefaultBranch(""); + pb1.setCharPref("DefaultPref.char", "_default"); + Assert.equal(pb1.getCharPref("DefaultPref.char"), "_default"); + Assert.ok(!pb1.prefHasUserValue("DefaultPref.char")); + ps.setCharPref("DefaultPref.char", "_user"); + Assert.ok(pb1.prefHasUserValue("DefaultPref.char")); + Assert.equal(ps.getCharPref("DefaultPref.char"), "_user"); + + //* *************************************************************************// + // pref Locking/Unlocking tests + + // locking and unlocking a nonexistent pref should throw + do_check_throws(function () { + ps.lockPref("DefaultPref.nonexistent"); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + do_check_throws(function () { + ps.unlockPref("DefaultPref.nonexistent"); + }, Cr.NS_ERROR_ILLEGAL_VALUE); + + // getting a locked pref branch should return the "default" value + Assert.ok(!ps.prefIsLocked("DefaultPref.char")); + ps.lockPref("DefaultPref.char"); + Assert.equal(ps.getCharPref("DefaultPref.char"), "_default"); + Assert.ok(ps.prefIsLocked("DefaultPref.char")); + + // getting an unlocked pref branch should return the "user" value + ps.unlockPref("DefaultPref.char"); + Assert.equal(ps.getCharPref("DefaultPref.char"), "_user"); + Assert.ok(!ps.prefIsLocked("DefaultPref.char")); + + // setting the "default" value to a user pref branch should + // make prefHasUserValue return false (documented behavior) + ps.setCharPref("DefaultPref.char", "_default"); + Assert.ok(!pb1.prefHasUserValue("DefaultPref.char")); + + // unlocking and locking multiple times shouldn't throw + ps.unlockPref("DefaultPref.char"); + ps.lockPref("DefaultPref.char"); + ps.lockPref("DefaultPref.char"); + + //* *************************************************************************// + // resetBranch test + + // NOT IMPLEMENTED YET in module/libpref. So we're not testing ! + // uncomment the following if resetBranch ever gets implemented. + /* ps.resetBranch("DefaultPref"); + do_check_eq(ps.getBoolPref("DefaultPref.bool"), true); + do_check_eq(ps.getIntPref("DefaultPref.int"), 100); + do_check_eq(ps.getCharPref("DefaultPref.char"), "_default");*/ + + //* *************************************************************************// + // deleteBranch tests + + // TODO : Really, this should throw!, by documentation. + // do_check_throws(function() { + // ps.deleteBranch("UserPref.nonexistent.deleteBranch");}, Cr.NS_ERROR_UNEXPECTED); + + ps.deleteBranch("DefaultPref"); + let pb = ps.getBranch("DefaultPref"); + pb1 = ps.getDefaultBranch("DefaultPref"); + + // getting prefs on deleted user branches should throw + do_check_throws(function () { + pb.getBoolPref("DefaultPref.bool"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + pb.getIntPref("DefaultPref.int"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + pb.getCharPref("DefaultPref.char"); + }, Cr.NS_ERROR_UNEXPECTED); + + // getting prefs on deleted default branches should throw + do_check_throws(function () { + pb1.getBoolPref("DefaultPref.bool"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + pb1.getIntPref("DefaultPref.int"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + pb1.getCharPref("DefaultPref.char"); + }, Cr.NS_ERROR_UNEXPECTED); + + //* *************************************************************************// + // savePrefFile & readPrefFile tests + + // set some prefs + ps.setBoolPref("ReadPref.bool", true); + ps.setIntPref("ReadPref.int", 230); + ps.setCharPref("ReadPref.char", "hello"); + + // save those prefs in a file + let savePrefFile = do_get_cwd(); + savePrefFile.append("data"); + savePrefFile.append("savePref.js"); + + if (savePrefFile.exists()) { + savePrefFile.remove(false); + } + savePrefFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); + ps.savePrefFile(savePrefFile); + ps.resetPrefs(); + + // load a preexisting pref file + let prefFile = do_get_file("data/testPref.js"); + ps.readUserPrefsFromFile(prefFile); + + // former prefs should have been replaced/lost + do_check_throws(function () { + pb.getBoolPref("ReadPref.bool"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + pb.getIntPref("ReadPref.int"); + }, Cr.NS_ERROR_UNEXPECTED); + do_check_throws(function () { + pb.getCharPref("ReadPref.char"); + }, Cr.NS_ERROR_UNEXPECTED); + + // loaded prefs should read ok. + pb = ps.getBranch("testPref."); + Assert.equal(pb.getBoolPref("bool1"), true); + Assert.equal(pb.getBoolPref("bool2"), false); + Assert.equal(pb.getIntPref("int1"), 23); + Assert.equal(pb.getIntPref("int2"), -1236); + Assert.equal(pb.getCharPref("char1"), "_testPref"); + Assert.equal(pb.getCharPref("char2"), "älskar"); + + // loading our former savePrefFile should allow us to read former prefs + + // Hack alert: on Windows nsLocalFile caches the size of savePrefFile from + // the .create() call above as 0. We call .exists() to reset the cache. + savePrefFile.exists(); + + ps.readUserPrefsFromFile(savePrefFile); + // cleanup the file now we don't need it + savePrefFile.remove(false); + Assert.equal(ps.getBoolPref("ReadPref.bool"), true); + Assert.equal(ps.getIntPref("ReadPref.int"), 230); + Assert.equal(ps.getCharPref("ReadPref.char"), "hello"); + + // ... and still be able to access "prior-to-readUserPrefs" preferences + Assert.equal(pb.getBoolPref("bool1"), true); + Assert.equal(pb.getBoolPref("bool2"), false); + Assert.equal(pb.getIntPref("int1"), 23); + + //* *************************************************************************// + // preference Observers + + class PrefObserver { + /** + * Creates and registers a pref observer. + * + * @param prefBranch The preference branch instance to observe. + * @param expectedName The pref name we expect to receive. + * @param expectedValue The int pref value we expect to receive. + */ + constructor(prefBranch, expectedName, expectedValue) { + this.pb = prefBranch; + this.name = expectedName; + this.value = expectedValue; + + prefBranch.addObserver(expectedName, this); + } + + QueryInterface(aIID) { + if (aIID.equals(Ci.nsIObserver) || aIID.equals(Ci.nsISupports)) { + return this; + } + throw Components.Exception("", Cr.NS_NOINTERFACE); + } + + observe(aSubject, aTopic, aState) { + Assert.equal(aTopic, "nsPref:changed"); + Assert.equal(aState, this.name); + Assert.equal(this.pb.getIntPref(aState), this.value); + pb.removeObserver(aState, this); + + // notification received, we may go on... + do_test_finished(); + } + } + + // Indicate that we'll have 3 more async tests pending so that they all + // actually get a chance to run. + do_test_pending(); + do_test_pending(); + do_test_pending(); + + let observer = new PrefObserver(ps, "ReadPref.int", 76); + ps.setIntPref("ReadPref.int", 76); + + // removed observer should not fire + ps.removeObserver("ReadPref.int", observer); + ps.setIntPref("ReadPref.int", 32); + + // let's test observers once more with a non-root prefbranch + pb = ps.getBranch("ReadPref."); + observer = new PrefObserver(pb, "int", 76); + ps.setIntPref("ReadPref.int", 76); + + // Let's try that again with different pref. + observer = new PrefObserver(pb, "another_int", 76); + ps.setIntPref("ReadPref.another_int", 76); +} diff --git a/modules/libpref/test/unit/test_locked_file_prefs.js b/modules/libpref/test/unit/test_locked_file_prefs.js new file mode 100644 index 0000000000..29b5270df5 --- /dev/null +++ b/modules/libpref/test/unit/test_locked_file_prefs.js @@ -0,0 +1,51 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// This file tests the `locked` attribute in default pref files. + +const ps = Services.prefs; + +// It is necessary to manually disable `xpc::IsInAutomation` since +// `resetPrefs` will flip the preference to re-enable `once`-synced +// preference change assertions, and also change the value of those +// preferences. +Services.prefs.setBoolPref( + "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", + false +); + +add_test(function notChangedFromAPI() { + ps.resetPrefs(); + ps.readDefaultPrefsFromFile(do_get_file("data/testPrefLocked.js")); + Assert.strictEqual(ps.getIntPref("testPref.unlocked.int"), 333); + Assert.strictEqual(ps.getIntPref("testPref.locked.int"), 444); + + // Unlocked pref: can set the user value, which is used upon reading. + ps.setIntPref("testPref.unlocked.int", 334); + Assert.ok(ps.prefHasUserValue("testPref.unlocked.int"), "has a user value"); + Assert.strictEqual(ps.getIntPref("testPref.unlocked.int"), 334); + + // Locked pref: can set the user value, but the default value is used upon + // reading. + ps.setIntPref("testPref.locked.int", 445); + Assert.ok(ps.prefHasUserValue("testPref.locked.int"), "has a user value"); + Assert.strictEqual(ps.getIntPref("testPref.locked.int"), 444); + + // After unlocking, the user value is used. + ps.unlockPref("testPref.locked.int"); + Assert.ok(ps.prefHasUserValue("testPref.locked.int"), "has a user value"); + Assert.strictEqual(ps.getIntPref("testPref.locked.int"), 445); + + run_next_test(); +}); + +add_test(function notChangedFromUserPrefs() { + ps.resetPrefs(); + ps.readDefaultPrefsFromFile(do_get_file("data/testPrefLocked.js")); + ps.readUserPrefsFromFile(do_get_file("data/testPrefLockedUser.js")); + + Assert.strictEqual(ps.getIntPref("testPref.unlocked.int"), 333); + Assert.strictEqual(ps.getIntPref("testPref.locked.int"), 444); + + run_next_test(); +}); diff --git a/modules/libpref/test/unit/test_parsePrefs.js b/modules/libpref/test/unit/test_parsePrefs.js new file mode 100644 index 0000000000..53bb55dc7e --- /dev/null +++ b/modules/libpref/test/unit/test_parsePrefs.js @@ -0,0 +1,136 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +"use strict"; + +// // This undoes some of the configuration from +// Services.dirsvc +// .QueryInterface(Ci.nsIDirectoryService) +// .unregisterProvider(provider); + +class PrefObserver { + constructor() { + this.events = []; + } + + onStringPref(...args) { + // // What happens with an exception here? + // throw new Error(`foo ${args[1]}`); + this.events.push(["string", ...args]); + } + + onIntPref(...args) { + this.events.push(["int", ...args]); + } + + onBoolPref(...args) { + this.events.push(["bool", ...args]); + } + + onError(message) { + this.events.push(["error", message]); + } +} + +const TESTS = { + "data/testPrefSticky.js": [ + ["bool", "Default", "testPref.unsticky.bool", true, false, false], + ["bool", "Default", "testPref.sticky.bool", false, true, false], + ], + "data/testPrefStickyUser.js": [ + ["bool", "User", "testPref.sticky.bool", false, false, false], + ], + "data/testPrefLocked.js": [ + ["int", "Default", "testPref.unlocked.int", 333, false, false], + ["int", "Default", "testPref.locked.int", 444, false, true], + ], + // data/testPrefLockedUser is ASCII. + "data/testPrefLockedUser.js": [ + ["int", "User", "testPref.locked.int", 555, false, false], + ], + // data/testPref is ISO-8859. + "data/testPref.js": [ + ["bool", "User", "testPref.bool1", true, false, false], + ["bool", "User", "testPref.bool2", false, false, false], + ["int", "User", "testPref.int1", 23, false, false], + ["int", "User", "testPref.int2", -1236, false, false], + ["string", "User", "testPref.char1", "_testPref", false, false], + ["string", "User", "testPref.char2", "älskar", false, false], + ], + // data/testParsePrefs is data/testPref.js as UTF-8. + "data/testPrefUTF8.js": [ + ["bool", "User", "testPref.bool1", true, false, false], + ["bool", "User", "testPref.bool2", false, false, false], + ["int", "User", "testPref.int1", 23, false, false], + ["int", "User", "testPref.int2", -1236, false, false], + ["string", "User", "testPref.char1", "_testPref", false, false], + // Observe that this is the ISO-8859/Latin-1 encoding of the UTF-8 bytes. + // (Note that this source file is encoded as UTF-8.) This appears to just + // be how libpref handles this case. This test serves as documentation of + // this infelicity. + ["string", "User", "testPref.char2", "älskar", false, false], + ], +}; + +add_task(async function test_success() { + for (let [path, expected] of Object.entries(TESTS)) { + let prefObserver = new PrefObserver(); + + let prefsFile = do_get_file(path); + let data = await IOUtils.read(prefsFile.path); + + Services.prefs.parsePrefsFromBuffer(data, prefObserver, path); + Assert.deepEqual( + prefObserver.events, + expected, + `Observations from ${path} are as expected` + ); + } +}); + +add_task(async function test_exceptions() { + const { AddonTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/AddonTestUtils.sys.mjs" + ); + + let s = `user_pref("testPref.bool1", true); + user_pref("testPref.bool2", false); + user_pref("testPref.int1", 23); + user_pref("testPref.int2", -1236); + `; + + let onErrorCount = 0; + let addPrefCount = 0; + + let marker = "2fc599a1-433b-4de7-bd63-3e69c3bbad5b"; + let addPref = (...args) => { + addPrefCount += 1; + throw new Error(`${marker}${JSON.stringify(args)}${marker}`); + }; + + let { messages } = await AddonTestUtils.promiseConsoleOutput(() => { + Services.prefs.parsePrefsFromBuffer(new TextEncoder().encode(s), { + onStringPref: addPref, + onIntPref: addPref, + onBoolPref: addPref, + onError(message) { + onErrorCount += 1; + console.error(message); + }, + }); + }); + + Assert.equal(addPrefCount, 4); + Assert.equal(onErrorCount, 0); + + // This is fragile but mercifully simple. + Assert.deepEqual( + messages.map(m => JSON.parse(m.message.split(marker)[1])), + [ + ["User", "testPref.bool1", true, false, false], + ["User", "testPref.bool2", false, false, false], + ["User", "testPref.int1", 23, false, false], + ["User", "testPref.int2", -1236, false, false], + ] + ); +}); diff --git a/modules/libpref/test/unit/test_parser.js b/modules/libpref/test/unit/test_parser.js new file mode 100644 index 0000000000..0b37eef47d --- /dev/null +++ b/modules/libpref/test/unit/test_parser.js @@ -0,0 +1,116 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// It is necessary to manually disable `xpc::IsInAutomation` since +// `resetPrefs` will flip the preference to re-enable `once`-synced +// preference change assertions, and also change the value of those +// preferences. +Services.prefs.setBoolPref( + "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", + false +); + +function run_test() { + const ps = Services.prefs; + + ps.resetPrefs(); + ps.readDefaultPrefsFromFile(do_get_file("data/testParser.js")); + + Assert.equal(ps.getBoolPref("comment1"), true); + Assert.equal(ps.getBoolPref("comment2"), true); + Assert.equal(ps.getBoolPref("spaced-out"), true); + + Assert.equal(ps.getBoolPref("pref"), true); + Assert.equal(ps.getBoolPref("sticky_pref"), true); + Assert.equal(ps.getBoolPref("user_pref"), true); + Assert.equal(ps.getBoolPref("sticky_pref2"), true); + Assert.equal(ps.getBoolPref("locked_pref"), true); + Assert.equal(ps.getBoolPref("locked_sticky_pref"), true); + Assert.equal(ps.prefIsLocked("locked_pref"), true); + Assert.equal(ps.prefIsLocked("locked_sticky_pref"), true); + + Assert.equal(ps.getBoolPref("bool.true"), true); + Assert.equal(ps.getBoolPref("bool.false"), false); + + Assert.equal(ps.getIntPref("int.0"), 0); + Assert.equal(ps.getIntPref("int.1"), 1); + Assert.equal(ps.getIntPref("int.123"), 123); + Assert.equal(ps.getIntPref("int.+234"), 234); + Assert.equal(ps.getIntPref("int.+ 345"), 345); + Assert.equal(ps.getIntPref("int.-0"), -0); + Assert.equal(ps.getIntPref("int.-1"), -1); + Assert.equal(ps.getIntPref("int.- /* hmm */\t456"), -456); + Assert.equal(ps.getIntPref("int.-\n567"), -567); + Assert.equal(ps.getIntPref("int.INT_MAX-1"), 2147483646); + Assert.equal(ps.getIntPref("int.INT_MAX"), 2147483647); + Assert.equal(ps.getIntPref("int.INT_MIN+2"), -2147483646); + Assert.equal(ps.getIntPref("int.INT_MIN+1"), -2147483647); + Assert.equal(ps.getIntPref("int.INT_MIN"), -2147483648); + + Assert.equal(ps.getCharPref("string.empty"), ""); + Assert.equal(ps.getCharPref("string.abc"), "abc"); + Assert.equal( + ps.getCharPref("string.long"), + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + ); + Assert.equal(ps.getCharPref("string.single-quotes"), '"abc"'); + Assert.equal(ps.getCharPref("string.double-quotes"), "'abc'"); + Assert.equal( + ps.getCharPref("string.weird-chars"), + "\x0d \x09 \x0b \x0c \x06 \x16" + ); + Assert.equal(ps.getCharPref("string.escapes"), "\" ' \\ \n \r"); + + // This one is ASCII, so we can use getCharPref() and getStringPref + // interchangeably. + Assert.equal( + ps.getCharPref("string.x-escapes1"), + "Mozilla0\x4d\x6F\x7a\x69\x6c\x6C\x610" + ); + Assert.equal(ps.getStringPref("string.x-escapes1"), "Mozilla0Mozilla0"); + + // This one has chars with value > 127, so it's not valid UTF8, so we can't + // use getStringPref on it. + Assert.equal( + ps.getCharPref("string.x-escapes2"), + "AA A_umlaut\xc4 y_umlaut\xff" + ); + + // The following strings use \uNNNN escapes, which are UTF16 code points. + // libpref stores them internally as UTF8 byte sequences. In each case we get + // the string in two ways: + // - getStringPref() interprets it as UTF8, which is then converted to UTF16 + // in JS. I.e. code points that are multiple bytes in UTF8 become a single + // 16-bit char in JS (except for the non-BMP chars, which become a 16-bit + // surrogate pair). + // - getCharPref() interprets it as Latin1, which is then converted to UTF16 + // in JS. I.e. code points that are multiple bytes in UTF8 become multiple + // 16-bit chars in JS. + + Assert.equal( + ps.getStringPref("string.u-escapes1"), + "A\u0041 A_umlaut\u00c4 y_umlaut\u00ff0" + ); + Assert.equal( + ps.getCharPref("string.u-escapes1"), + "A\x41 A_umlaut\xc3\x84 y_umlaut\xc3\xbf0" + ); + + Assert.equal( + ps.getStringPref("string.u-escapes2"), + "S_acute\u015a y_grave\u1Ef3" + ); + Assert.equal( + ps.getCharPref("string.u-escapes2"), + "S_acute\xc5\x9a y_grave\xe1\xbb\xb3" + ); + + Assert.equal( + ps.getStringPref("string.u-surrogates"), + "cyclone\uD83C\uDF00 grinning_face\uD83D\uDE00" + ); + Assert.equal( + ps.getCharPref("string.u-surrogates"), + "cyclone\xF0\x9F\x8C\x80 grinning_face\xF0\x9F\x98\x80" + ); +} diff --git a/modules/libpref/test/unit/test_stickyprefs.js b/modules/libpref/test/unit/test_stickyprefs.js new file mode 100644 index 0000000000..d344d208ab --- /dev/null +++ b/modules/libpref/test/unit/test_stickyprefs.js @@ -0,0 +1,196 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +const ps = Services.prefs; + +// It is necessary to manually disable `xpc::IsInAutomation` since +// `resetPrefs` will flip the preference to re-enable `once`-synced +// preference change assertions, and also change the value of those +// preferences. +Services.prefs.setBoolPref( + "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", + false +); + +// A little helper to reset the service and load one pref file. +function resetAndLoadDefaults() { + ps.resetPrefs(); + ps.readDefaultPrefsFromFile(do_get_file("data/testPrefSticky.js")); +} + +// A little helper to reset the service and load two pref files. +function resetAndLoadAll() { + ps.resetPrefs(); + ps.readDefaultPrefsFromFile(do_get_file("data/testPrefSticky.js")); + ps.readUserPrefsFromFile(do_get_file("data/testPrefStickyUser.js")); +} + +// A little helper that saves the current state to a file in the profile +// dir, then resets the service and re-reads the file it just saved. +// Used to test what gets actually written - things the pref service decided +// not to write don't exist at all after this call. +function saveAndReload() { + let file = do_get_profile(); + file.append("prefs.js"); + ps.savePrefFile(file); + + // Now reset the pref service and re-read what we saved. + ps.resetPrefs(); + + // Hack alert: on Windows nsLocalFile caches the size of savePrefFile from + // the .create() call above as 0. We call .exists() to reset the cache. + file.exists(); + + ps.readUserPrefsFromFile(file); +} + +// A sticky pref should not be written if the value is unchanged. +add_test(function notWrittenWhenUnchanged() { + resetAndLoadDefaults(); + Assert.strictEqual(ps.getBoolPref("testPref.unsticky.bool"), true); + Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false); + + // write prefs - but we haven't changed the sticky one, so it shouldn't be written. + saveAndReload(); + // sticky should not have been written to the new file. + try { + ps.getBoolPref("testPref.sticky.bool"); + Assert.ok(false, "expected failure reading this pref"); + } catch (ex) { + Assert.ok(ex, "exception reading regular pref"); + } + run_next_test(); +}); + +// Loading a sticky `pref` then a `user_pref` for the same pref means it should +// always be written. +add_test(function writtenOnceLoadedWithoutChange() { + // Load the same pref file *as well as* a pref file that has a user_pref for + // our sticky with the default value. It should be re-written without us + // touching it. + resetAndLoadAll(); + // reset and re-read what we just wrote - it should be written. + saveAndReload(); + Assert.strictEqual( + ps.getBoolPref("testPref.sticky.bool"), + false, + "user_pref was written with default value" + ); + run_next_test(); +}); + +// If a sticky pref is explicicitly changed, even to the default, it is written. +add_test(function writtenOnceLoadedWithChangeNonDefault() { + // Load the same pref file *as well as* a pref file that has a user_pref for + // our sticky - then change the pref. It should be written. + resetAndLoadAll(); + // Set a new val and check we wrote it. + ps.setBoolPref("testPref.sticky.bool", false); + saveAndReload(); + Assert.strictEqual( + ps.getBoolPref("testPref.sticky.bool"), + false, + "user_pref was written with custom value" + ); + run_next_test(); +}); + +// If a sticky pref is changed to the non-default value, it is written. +add_test(function writtenOnceLoadedWithChangeNonDefault() { + // Load the same pref file *as well as* a pref file that has a user_pref for + // our sticky - then change the pref. It should be written. + resetAndLoadAll(); + // Set a new val and check we wrote it. + ps.setBoolPref("testPref.sticky.bool", true); + saveAndReload(); + Assert.strictEqual( + ps.getBoolPref("testPref.sticky.bool"), + true, + "user_pref was written with custom value" + ); + run_next_test(); +}); + +// Test that prefHasUserValue always returns true whenever there is a sticky +// value, even when that value matches the default. This is mainly for +// about:config semantics - prefs with a sticky value always remain bold and +// always offer "reset" (which fully resets and drops the sticky value as if +// the pref had never changed.) +add_test(function hasUserValue() { + // sticky pref without user value. + resetAndLoadDefaults(); + Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false); + Assert.ok( + !ps.prefHasUserValue("testPref.sticky.bool"), + "should not initially reflect a user value" + ); + + ps.setBoolPref("testPref.sticky.bool", false); + Assert.ok( + ps.prefHasUserValue("testPref.sticky.bool"), + "should reflect a user value after set to default" + ); + + ps.setBoolPref("testPref.sticky.bool", true); + Assert.ok( + ps.prefHasUserValue("testPref.sticky.bool"), + "should reflect a user value after change to non-default" + ); + + ps.clearUserPref("testPref.sticky.bool"); + Assert.ok( + !ps.prefHasUserValue("testPref.sticky.bool"), + "should reset to no user value" + ); + ps.setBoolPref("testPref.sticky.bool", false, "expected default"); + + // And make sure the pref immediately reflects a user value after load. + resetAndLoadAll(); + Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false); + Assert.ok( + ps.prefHasUserValue("testPref.sticky.bool"), + "should have a user value when loaded value is the default" + ); + run_next_test(); +}); + +// Test that clearUserPref removes the "sticky" value. +add_test(function clearUserPref() { + // load things such that we have a sticky value which is the same as the + // default. + resetAndLoadAll(); + ps.clearUserPref("testPref.sticky.bool"); + + // Once we save prefs the sticky pref should no longer be written. + saveAndReload(); + try { + ps.getBoolPref("testPref.sticky.bool"); + Assert.ok(false, "expected failure reading this pref"); + } catch (ex) { + Assert.ok(ex, "pref doesn't have a sticky value"); + } + run_next_test(); +}); + +// Test that a pref observer gets a notification fired when a sticky pref +// has it's value changed to the same value as the default. The reason for +// this behaviour is that later we might have other code that cares about a +// pref being sticky (IOW, we notify due to the "state" of the pref changing +// even if the value has not) +add_test(function observerFires() { + // load things so there's no sticky value. + resetAndLoadDefaults(); + + function observe(subject, topic, data) { + Assert.equal(data, "testPref.sticky.bool"); + ps.removeObserver("testPref.sticky.bool", observe); + run_next_test(); + } + ps.addObserver("testPref.sticky.bool", observe); + + ps.setBoolPref( + "testPref.sticky.bool", + ps.getBoolPref("testPref.sticky.bool") + ); + // and the observer will fire triggering the next text. +}); diff --git a/modules/libpref/test/unit/test_warnings.js b/modules/libpref/test/unit/test_warnings.js new file mode 100644 index 0000000000..a6782f5c59 --- /dev/null +++ b/modules/libpref/test/unit/test_warnings.js @@ -0,0 +1,62 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function makeBuffer(length) { + return new Array(length + 1).join("x"); +} + +/** + * @resolves |true| if execution proceeded without warning, + * |false| if there was a warning. + */ +function checkWarning(pref, buffer) { + return new Promise(resolve => { + let complete = false; + let listener = { + observe(event) { + let message = event.message; + if ( + !( + message.startsWith("Warning: attempting to write") && + message.includes(pref) + ) + ) { + return; + } + if (complete) { + return; + } + complete = true; + info("Warning while setting " + pref); + Services.console.unregisterListener(listener); + resolve(true); + }, + }; + do_timeout(1000, function () { + if (complete) { + return; + } + complete = true; + info("No warning while setting " + pref); + Services.console.unregisterListener(listener); + resolve(false); + }); + Services.console.registerListener(listener); + Services.prefs.setCharPref(pref, buffer); + }); +} + +add_task(async function () { + // Simple change, shouldn't cause a warning + info("Checking that a simple change doesn't cause a warning"); + let buf = makeBuffer(100); + let warned = await checkWarning("string.accept", buf); + Assert.ok(!warned); + + // Large change, should cause a warning + info("Checking that a large change causes a warning"); + buf = makeBuffer(32 * 1024); + warned = await checkWarning("string.warn", buf); + Assert.ok(warned); +}); diff --git a/modules/libpref/test/unit/xpcshell.ini b/modules/libpref/test/unit/xpcshell.ini new file mode 100644 index 0000000000..0778b8659f --- /dev/null +++ b/modules/libpref/test/unit/xpcshell.ini @@ -0,0 +1,28 @@ +[DEFAULT] +head = head_libPrefs.js +support-files = + data/testPref.js + extdata/testExt.js + +[test_warnings.js] +[test_bug345529.js] +[test_bug506224.js] +[test_bug577950.js] +[test_bug790374.js] +[test_stickyprefs.js] +skip-if = (os == "win" && socketprocess_networking) +support-files = data/testPrefSticky.js data/testPrefStickyUser.js +[test_locked_file_prefs.js] +skip-if = (os == "win" && socketprocess_networking) +support-files = data/testPrefLocked.js data/testPrefLockedUser.js +[test_changeType.js] +[test_defaultValues.js] +[test_dirtyPrefs.js] +[test_libPrefs.js] +[test_bug1354613.js] +[test_parser.js] +support-files = data/testParser.js +[test_parsePrefs.js] +support-files = + data/testPrefUTF8.js +head = |