Bug 1081689 - Allow unregistration of a protocol.js type. r=paul
authorDave Camp <dcamp@mozilla.com>
Sun, 12 Oct 2014 09:18:00 +0300
changeset 233703 f4938adf5962087879e91dea1404bf98518ebe5a
parent 233702 ed70c889afe8c62151e1cbb6f8e1f103b2b6cc95
child 233704 cfc1be82cd6deb89c59b39e1c426058339a59df3
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspaul
bugs1081689
milestone35.0a2
Bug 1081689 - Allow unregistration of a protocol.js type. r=paul
toolkit/devtools/server/protocol.js
toolkit/devtools/server/tests/unit/test_protocol_unregister.js
toolkit/devtools/server/tests/unit/xpcshell.ini
--- a/toolkit/devtools/server/protocol.js
+++ b/toolkit/devtools/server/protocol.js
@@ -149,24 +149,37 @@ types.addType = function(name, typeObjec
     name: name,
     primitive: !(typeObject.read || typeObject.write),
     read: identityWrite,
     write: identityWrite
   }, typeObject);
 
   registeredTypes.set(name, type);
 
-  if (!options.thawed) {
-    Object.freeze(type);
-  }
-
   return type;
 };
 
 /**
+ * Remove a type previously registered with the system.
+ * Primarily useful for types registered by addons.
+ */
+types.removeType = function(name) {
+  // This type may still be referenced by other types, make sure
+  // those references don't work.
+  let type = registeredTypes.get(name);
+
+  type.name = "DEFUNCT:" + name;
+  type.category = "defunct";
+  type.primitive = false;
+  type.read = type.write = function() { throw new Error("Using defunct type: " + name); };
+
+  registeredTypes.delete(name);
+}
+
+/**
  * Add an array type to the type system.
  *
  * getType() will call this function if provided an "array:<type>"
  * typestring.
  *
  * @param type subtype
  *    The subtype to be held by the array.
  */
@@ -294,20 +307,16 @@ types.addActorType = function(name) {
       }
 
       if (!(formAttr in type.actorSpec)) {
         throw new Error("No type defined for " + formAttr);
       }
 
       return type.actorSpec[formAttr];
     }
-  }, {
-    // We usually freeze types, but actor types are updated when clients are
-    // created, so don't freeze yet.
-    thawed: true
   });
   return type;
 }
 
 types.addNullableType = function(subtype) {
   subtype = types.getType(subtype);
   return types.addType("nullable:" + subtype.name, {
     category: "nullable",
@@ -365,16 +374,24 @@ types.addActorDetail = function(name, ac
 types.addLifetime = function(name, prop) {
   if (registeredLifetimes.has(name)) {
     throw Error("Lifetime '" + name + "' already registered.");
   }
   registeredLifetimes.set(name, prop);
 }
 
 /**
+ * Remove a previously-registered lifetime.  Useful for lifetimes registered
+ * in addons.
+ */
+types.removeLifetime = function(name) {
+  registeredLifetimes.delete(name);
+}
+
+/**
  * Register a lifetime type.  This creates an actor type tied to the given
  * lifetime.
  *
  * This is called by getType() when passed a '<lifetimeType>:<actorType>'
  * typestring.
  *
  * @param string lifetime
  *    A lifetime string previously regisered with addLifetime()
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/unit/test_protocol_unregister.js
@@ -0,0 +1,44 @@
+const {types} = devtools.require("devtools/server/protocol");
+
+
+function run_test()
+{
+  types.addType("test", {
+    read: (v) => { return "successful read: " + v },
+    write: (v) => { return "successful write: " + v }
+  });
+
+  // Verify the type registered correctly.
+
+  let type = types.getType("test");
+  let arrayType = types.getType("array:test");
+  do_check_eq(type.read("foo"), "successful read: foo");
+  do_check_eq(arrayType.read(["foo"])[0], "successful read: foo");
+
+  types.removeType("test");
+
+  do_check_eq(type.name, "DEFUNCT:test");
+  try {
+    types.getType("test");
+    do_check_true(false, "getType should fail");
+  } catch(ex) {
+    do_check_eq(ex.toString(), "Error: Unknown type: test");
+  }
+
+  try {
+    type.read("foo");
+    do_check_true(false, "type.read should have thrown an exception.");
+  } catch(ex) {
+    do_check_eq(ex.toString(), "Error: Using defunct type: test");
+  }
+
+  try {
+    arrayType.read(["foo"]);
+    do_check_true(false, "array:test.read should have thrown an exception.");
+  } catch(ex) {
+    do_check_eq(ex.toString(), "Error: Using defunct type: test");
+  }
+
+}
+
+
--- a/toolkit/devtools/server/tests/unit/xpcshell.ini
+++ b/toolkit/devtools/server/tests/unit/xpcshell.ini
@@ -57,20 +57,21 @@ support-files =
 [test_nativewrappers.js]
 [test_nodelistactor.js]
 [test_eval-01.js]
 [test_eval-02.js]
 [test_eval-03.js]
 [test_eval-04.js]
 [test_eval-05.js]
 [test_protocol_async.js]
-[test_protocol_simple.js]
-[test_protocol_longstring.js]
 [test_protocol_children.js]
 [test_protocol_formtype.js]
+[test_protocol_longstring.js]
+[test_protocol_simple.js]
+[test_protocol_unregister.js]
 [test_breakpoint-01.js]
 [test_register_actor.js]
 skip-if = toolkit == "gonk"
 reason = bug 820380
 [test_breakpoint-02.js]
 skip-if = toolkit == "gonk"
 reason = bug 820380
 [test_breakpoint-03.js]