Bug 568691 fixups: alter mockObjects.js so that it registers its mock by contractID but doesn't replace the CID. Fix the generic classinfo not to assert when code asks for the class description (which is no longer implemented).
authorBenjamin Smedberg <benjamin@smedbergs.us>
Wed, 23 Jun 2010 15:18:13 -0400
changeset 47036 d0799601db2c509d9e813bf3a55e23808c3165e8
parent 47035 c4fc378e08760db33dd62262df4ed22b7eb963a8
child 47037 acb4f43ba5ab89c32e25af340345a308dddb5f29
push id14223
push userbsmedberg@mozilla.com
push dateThu, 01 Jul 2010 18:30:48 +0000
treeherdermozilla-central@836fd3f8feba [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs568691
milestone1.9.3a6pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 568691 fixups: alter mockObjects.js so that it registers its mock by contractID but doesn't replace the CID. Fix the generic classinfo not to assert when code asks for the class description (which is no longer implemented).
toolkit/content/tests/browser/common/mockObjects.js
xpcom/components/nsComponentManager.cpp
xpcom/components/nsIComponentRegistrar.idl
xpcom/glue/nsClassInfoImpl.cpp
--- a/toolkit/content/tests/browser/common/mockObjects.js
+++ b/toolkit/content/tests/browser/common/mockObjects.js
@@ -60,71 +60,76 @@ MockObjectRegisterer.prototype = {
   /**
    * Replaces the current factory with one that returns a new mock object.
    *
    * After register() has been called, it is mandatory to call unregister() to
    * restore the original component. Usually, you should use a try-catch block
    * to ensure that unregister() is called.
    */
   register: function MOR_register() {
-    if (this._originalFactory)
+    if (this._originalCID)
       throw new Exception("Invalid object state when calling register()");
 
     // Define a factory that creates a new object using the given constructor.
     var providedConstructor = this._replacementCtor;
     this._mockFactory = {
       createInstance: function MF_createInstance(aOuter, aIid) {
         if (aOuter != null)
           throw Cr.NS_ERROR_NO_AGGREGATION;
         return new providedConstructor().QueryInterface(aIid);
       }
     };
 
-    // Preserve the original factory.
-    this._originalFactory = Cm.getClassObjectByContractID(this._contractID,
-                                                          Ci.nsIFactory);
+    this._cid = Components.classes["@mozilla.org/uuid-generator;1"].
+      getService(Components.interfaces.nsIUUIDGenerator).generateUUID();
+
+    // Preserve the original CID
+    var componentRegistrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
+    this._originalCID = componentRegistrar.contractIDToCID(this._contractID);
 
     // Replace the original factory with the mock one.
-    var classInfo = this._originalFactory.QueryInterface(Ci.nsIClassInfo);
-    var componentRegistrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
-    componentRegistrar.registerFactory(classInfo.classID,
-                                       "Mock " + classInfo.classDescription,
+    componentRegistrar.registerFactory(this._cid,
+                                       "",
                                        this._contractID,
                                        this._mockFactory);
   },
 
   /**
    * Restores the original factory.
    */
   unregister: function MOR_unregister() {
-    if (!this._originalFactory)
+    if (!this._originalCID)
       throw new Exception("Invalid object state when calling unregister()");
 
     // Free references to the mock factory.
-    var classInfo = this._originalFactory.QueryInterface(Ci.nsIClassInfo);
     var componentRegistrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
-    componentRegistrar.unregisterFactory(classInfo.classID,
+    componentRegistrar.unregisterFactory(this._cid,
                                          this._mockFactory);
 
     // Restore the original factory.
-    componentRegistrar.registerFactory(classInfo.classID,
-                                       classInfo.classDescription,
+    componentRegistrar.registerFactory(this._originalCID,
+                                       "",
                                        this._contractID,
-                                       this._originalFactory);
+                                       null);
 
     // Allow registering a mock factory again later.
-    this._originalFactory = null;
+    this._cid = null;
+    this._originalCID = null;
     this._mockFactory = null;
   },
 
   // --- Private methods and properties ---
 
   /**
-   * The original nsIFactory for the component being replaced, or null when the
-   *  original component is in place.
+   * The CID of the component being replaced.
    */
-  _originalFactory: null,
+  _originalCID: null,
+
+  /**
+   * The CID under which the mock contractID was registered.
+   */
+  _cid: null,
 
   /**
    * The nsIFactory that was automatically generated by this object.
    */
   _mockFactory: null
 }
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -1482,25 +1482,43 @@ nsComponentManagerImpl::LoaderForExtensi
 }
 
 NS_IMETHODIMP
 nsComponentManagerImpl::RegisterFactory(const nsCID& aClass,
                                         const char* aName,
                                         const char* aContractID,
                                         nsIFactory* aFactory)
 {
+    if (!aFactory) {
+        // If a null factory is passed in, this call just wants to reset
+        // the contract ID to point to an existing CID entry.
+        if (!aContractID)
+            return NS_ERROR_INVALID_ARG;
+
+        nsAutoMonitor mon(mMon);
+        nsFactoryEntry* oldf = mFactories.Get(aClass);
+        if (!oldf)
+            return NS_ERROR_FACTORY_NOT_REGISTERED;
+
+        mContractIDs.Put(nsDependentCString(aContractID), oldf);
+        return NS_OK;
+    }
+
     nsAutoPtr<nsFactoryEntry> f(new nsFactoryEntry(aFactory));
 
     nsAutoMonitor mon(mMon);
     nsFactoryEntry* oldf = mFactories.Get(aClass);
     if (oldf)
         return NS_ERROR_FACTORY_EXISTS;
 
     mFactories.Put(aClass, f.forget());
-    mContractIDs.Put(nsDependentCString(aContractID), f);
+
+    if (aContractID)
+        mContractIDs.Put(nsDependentCString(aContractID), f);
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass,
                                           nsIFactory* aFactory)
 {
     // Don't release the dying factory or service object until releasing
--- a/xpcom/components/nsIComponentRegistrar.idl
+++ b/xpcom/components/nsIComponentRegistrar.idl
@@ -49,18 +49,20 @@ interface nsIComponentRegistrar : nsISup
 {
     /**
      * registerFactory
      *
      * Register a factory with a given ContractID, CID and Class Name.
      *
      * @param aClass      : CID of object
      * @param aClassName  : Class Name of CID (unused)
-     * @param aContractID : ContractID associated with CID aClass
+     * @param aContractID : ContractID associated with CID aClass (optional)
      * @param aFactory    : Factory that will be registered for CID aClass
+     *                      If aFactory is null, the contract will be associated
+     *                      with a previously registered CID.
      */
     void registerFactory(in nsCIDRef aClass, 
                          in string aClassName,
                          in string aContractID, 
                          in nsIFactory aFactory);
 
     /**
      * unregisterFactory
--- a/xpcom/glue/nsClassInfoImpl.cpp
+++ b/xpcom/glue/nsClassInfoImpl.cpp
@@ -35,17 +35,16 @@ GenericClassInfo::GetContractID(char** c
   NS_ERROR("GetContractID not implemented");
   *contractid = NULL;
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 GenericClassInfo::GetClassDescription(char** description)
 {
-  NS_ERROR("GetClassDescription not implemented");
   *description = NULL;
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 GenericClassInfo::GetClassID(nsCID** classid)
 {
   NS_ERROR("GetClassID not implemented");