Browse Source

Allow async. functions to trigger an exception at the sync. function caller by doing onComplete.fail().

Edward Lee 15 years ago
parent
commit
4274660782
2 changed files with 65 additions and 0 deletions
  1. 12 0
      Sync.js
  2. 53 0
      test/unit/test_Sync.js

+ 12 - 0
Sync.js

@@ -46,6 +46,7 @@ const Cu = Components.utils;
 // Define some constants to specify various sync. callback states
 const CB_READY = {};
 const CB_COMPLETE = {};
+const CB_FAIL = {};
 
 // Share a secret only for functions in this file to prevent outside access
 const SECRET = {};
@@ -69,6 +70,12 @@ function makeCallback() {
   // Only allow access to the private data if the secret matches
   onComplete._ = function onComplete__(secret) secret == SECRET ? _ : {};
 
+  // Allow an alternate callback to trigger an exception to be thrown
+  onComplete.fail = function onComplete_fail(data) {
+    _.state = CB_FAIL;
+    _.value = data;
+  };
+
   return onComplete;
 }
 
@@ -111,8 +118,13 @@ function Sync(func, thisArg, callback) {
       thread.processNextEvent(true);
 
     // Reset the state of the callback to prepare for another call
+    let state = callbackData.state;
     callbackData.state = CB_READY;
 
+    // Throw the value the callback decided to fail with
+    if (state == CB_FAIL)
+      throw callbackData.value;
+
     // Return the value passed to the callback
     return callbackData.value;
   };

+ 53 - 0
test/unit/test_Sync.js

@@ -60,6 +60,59 @@ function test_Sync_this() {
   }, 100);
 }
 
+// Async. functions that throw before going async should appear like normal
+function test_Sync_exception() {
+  try {
+    Sync(function(cb) {
+      throw "EARLY!";
+    })();
+    do_throw("Async. function should have thrown");
+  }
+  catch(ex) {
+    do_check_eq(ex, "EARLY!");
+  }
+}
+
+// Check that sync. callbacks can throw an exception to the sync. caller
+function test_Sync_fail() {
+  try {
+    Sync(function(cb) {
+      cb.fail("FAIL!");
+    })();
+    do_throw("Sync. callback should have thrown");
+  }
+  catch(ex) {
+    do_check_eq(ex, "FAIL!");
+  }
+}
+
+// Async. functions that throw go unnoticed
+function test_Sync_async_exception() {
+  // XXX We can't detect if an async. function fails.. :(
+  return;
+
+  Sync(function(cb) {
+    setTimeout(function() {
+      throw "undetected";
+    }, 100);
+  })();
+}
+
+// Check that async. functions can trigger an exception to the sync. caller
+function test_Sync_async_fail() {
+  let startTime = new Date();
+  try {
+    Sync(function(cb) {
+      setTimeout(function() cb.fail("FAIL!"), 100)
+    })();
+    do_throw("Sync. callback should have thrown");
+  }
+  catch(ex) {
+    do_check_eq(ex, "FAIL!");
+    do_check_true(new Date() - startTime >= 95);
+  }
+}
+
 // Check that sync. function callbacks can be extracted
 function test_Sync_withCb() {
   let [add, cb] = Sync.withCb(slowAdd);