Bug 576492 - Load default preferences from extension defaults, r=Mossop
authorBenjamin Smedberg <benjamin@smedbergs.us>
Fri, 02 Jul 2010 12:45:20 -0400
changeset 47142 a844e2a8c6544b9ac38ec966a8066b6dfe77d60c
parent 47141 c7ab03af9a3de1c5e43b2c4788bccdf67a97724e
child 47143 d261faaa483abfb55b30985f4d0bc9bad1064ce9
push idunknown
push userunknown
push dateunknown
reviewersMossop
bugs576492
milestone2.0b2pre
first release with
nightly linux32
a844e2a8c654 / 4.0b2pre / 20100702101220 / files
nightly linux64
a844e2a8c654 / 4.0b2pre / 20100702102138 / files
nightly mac
a844e2a8c654 / 4.0b2pre / 20100702102211 / files
nightly win32
a844e2a8c654 / 4.0b2pre / 20100702111754 / files
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 576492 - Load default preferences from extension defaults, r=Mossop
modules/libpref/src/nsPrefService.cpp
modules/libpref/test/unit/extdata/testExt.js
modules/libpref/test/unit/head_libPrefs.js
modules/libpref/test/unit/test_extprefs.js
modules/libpref/test/unit/test_libPrefs.js
toolkit/xre/nsXREDirProvider.cpp
--- a/modules/libpref/src/nsPrefService.cpp
+++ b/modules/libpref/src/nsPrefService.cpp
@@ -73,16 +73,17 @@
 #endif
 
 // Definitions
 #define INITIAL_PREF_FILES 10
 
 // Prototypes
 static nsresult openPrefFile(nsIFile* aFile);
 static nsresult pref_InitInitialObjects(void);
+static nsresult pref_LoadPrefsInDirList(const char *listId);
 
 //-----------------------------------------------------------------------------
 
 /*
  * Constructor/Destructor
  */
 
 nsPrefService::nsPrefService()
@@ -160,16 +161,18 @@ nsresult nsPrefService::Init()
   if (!observerService)
     return NS_ERROR_FAILURE;
 
   rv = observerService->AddObserver(this, "profile-before-change", PR_TRUE);
 
   if (NS_SUCCEEDED(rv))
     rv = observerService->AddObserver(this, "profile-do-change", PR_TRUE);
 
+  observerService->AddObserver(this, "load-extension-defaults", PR_TRUE);
+
   return(rv);
 }
 
 NS_IMETHODIMP nsPrefService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
 {
   nsresult rv = NS_OK;
 
   if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
@@ -179,16 +182,18 @@ NS_IMETHODIMP nsPrefService::Observe(nsI
         mCurrentFile = nsnull;
       }
     } else {
       rv = SavePrefFile(nsnull);
     }
   } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
     ResetUserPrefs();
     rv = ReadUserPrefs(nsnull);
+  } else if (!strcmp(aTopic, "load-extension-defaults")) {
+    pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
   } else if (!nsCRT::strcmp(aTopic, "reload-default-prefs")) {
     // Reload the default prefs from file.
     pref_InitInitialObjects();
   }
   return rv;
 }
 
 
new file mode 100644
--- /dev/null
+++ b/modules/libpref/test/unit/extdata/testExt.js
@@ -0,0 +1,2 @@
+pref("testPref.bool2", true);
+pref("testExtPref.bool", true);
--- a/modules/libpref/test/unit/head_libPrefs.js
+++ b/modules/libpref/test/unit/head_libPrefs.js
@@ -35,16 +35,31 @@
  * ***** END LICENSE BLOCK ***** */
 
 const NS_APP_USER_PROFILE_50_DIR = "ProfD";
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cr = Components.results;
 
+function do_check_throws(f, result, stack)
+{
+  if (!stack)
+    stack = Components.stack.caller;
+
+  try {
+    f();
+  } catch (exc) {
+    if (exc.result == result)
+      return;
+    do_throw("expected result " + result + ", caught " + exc, stack);
+  }
+  do_throw("expected result " + result + ", none thrown", stack);
+}
+
 var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
 
 // Register current test directory as provider for the profile directory.
 var provider = {
   getFile: function(prop, persistent) {
     persistent.value = true;
     if (prop == NS_APP_USER_PROFILE_50_DIR)
       return dirSvc.get("CurProcD", Ci.nsIFile);
new file mode 100644
--- /dev/null
+++ b/modules/libpref/test/unit/test_extprefs.js
@@ -0,0 +1,70 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/  */
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+// The profile directory is already set up in the head_ files.
+
+function arrayenumerator(a)
+{
+  return {
+    i_: 0,
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
+    hasMoreElements: function ae_hasMoreElements() {
+      return this.i_ < a.length;
+    },
+    getNext: function ae_getNext() {
+      return a[this.i_++];
+    }
+  };
+}
+
+function run_test() {
+  var ps = Cc["@mozilla.org/preferences-service;1"].
+    getService(Ci.nsIPrefService).QueryInterface(Ci.nsIPrefBranch);
+
+  var extprefs = [do_get_file("extdata")];
+  
+  var extProvider = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider,
+                                           Ci.nsIDirectoryServiceProvider2]),
+    getFile: function ep_getFile() {
+      throw Cr.NS_ERROR_FAILURE;
+    },
+    
+    getFiles: function ep_getFiles(key) {
+      if (key != "ExtPrefDL")
+        throw Cr.NS_ERROR_FAILURE;
+
+      return arrayenumerator(extprefs);
+    }
+  };
+  
+  let prefFile = do_get_file("data/testPref.js");
+
+  do_check_throws(function() {
+    ps.getBoolPref("testExtPref.bool");
+  }, Cr.NS_ERROR_UNEXPECTED);
+  do_check_throws(function() {
+    ps.getBoolPref("testPref.bool1");
+  }, Cr.NS_ERROR_UNEXPECTED);
+  
+  ps.readUserPrefs(prefFile);
+
+  do_check_true(ps.getBoolPref("testPref.bool1"));
+  ps.setBoolPref("testPref.bool1", false);
+  do_check_false(ps.getBoolPref("testPref.bool1"));
+  
+  dirSvc.registerProvider(extProvider);
+  Services.obs.notifyObservers(null, "load-extension-defaults", null);
+
+  // The extension default should be available.
+  do_check_true(ps.getBoolPref("testExtPref.bool"));
+
+  // The extension default should not override existing user prefs
+  do_check_false(ps.getBoolPref("testPref.bool2"));
+
+  // The extension default should not modify existing set values
+  do_check_false(ps.getBoolPref("testPref.bool1"));
+}
--- a/modules/libpref/test/unit/test_libPrefs.js
+++ b/modules/libpref/test/unit/test_libPrefs.js
@@ -34,31 +34,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 const PREF_INVALID = 0;
 const PREF_BOOL    = 128;
 const PREF_INT     = 64;
 const PREF_STRING  = 32;
 
-function do_check_throws(f, result, stack)
-{
-  if (!stack)
-    stack = Components.stack.caller;
-
-  try {
-    f();
-  } catch (exc) {
-    if (exc.result == result)
-      return;
-    do_throw("expected result " + result + ", caught " + exc, stack);
-  }
-  do_throw("expected result " + result + ", none thrown", stack);
-}
-
 function makeList(a)
 {
   var o = {};
   for(var i=0; i<a.length; i++)
   {
     o[a[i]] = '';
   }
   return o;
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -729,16 +729,17 @@ nsXREDirProvider::DoStartup()
     if (em) {
       em->Observe(nsnull, "addons-startup", nsnull);
     } else {
       NS_WARNING("Failed to create Addons Manager.");
     }
 
     LoadExtensionBundleDirectories();
 
+    obsSvc->NotifyObservers(nsnull, "load-extension-defaults", nsnull);
     obsSvc->NotifyObservers(nsnull, "profile-after-change", kStartup);
 
     // Any component that has registered for the profile-after-change category
     // should also be created at this time.
     (void)NS_CreateServicesFromCategory("profile-after-change", nsnull,
                                         "profile-after-change");
 
     obsSvc->NotifyObservers(nsnull, "profile-initial-state", nsnull);