Bug 1093021 - Implemented PromiseUtils.defer; r=yoric
authorAkshendra Pratap <akshendra521994@gmail.com>
Mon, 10 Nov 2014 05:52:00 +0100
changeset 216447 8ab91f02f963ca92d0a332afc77d2f70985ef702
parent 216446 d6dbc6e05dce4e7e5499e394a392f098b2f78999
child 216448 aa72ddfe9f9365cf4e9e3a70ff639c0e5c3829b8
child 216528 888dd71a867f5cd900fcd250a61e404714873014
push id27850
push usercbook@mozilla.com
push dateWed, 19 Nov 2014 12:44:14 +0000
treeherdermozilla-central@aa72ddfe9f93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyoric
bugs1093021
milestone36.0a1
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 1093021 - Implemented PromiseUtils.defer; r=yoric
toolkit/modules/PromiseUtils.jsm
toolkit/modules/tests/xpcshell/test_PromiseUtils.js
--- a/toolkit/modules/PromiseUtils.jsm
+++ b/toolkit/modules/PromiseUtils.jsm
@@ -45,10 +45,52 @@ this.PromiseUtils = {
         try {
           rejection ? reject(rejection()) : reject(new Error("Promise Timeout"));
         } catch(ex) {
           reject(ex);
         }
         clearTimeout(id);
       }, delay);
     });
-  }
+  },
+
+  /*
+   * Creates a new pending Promise and provide methods to resolve and reject this Promise.
+   *
+   * @return {Deferred} an object consisting of a pending Promise "promise"
+   * and methods "resolve" and "reject" to change its state.
+   */
+  defer : function() {
+    return new Deferred();
+  },
+}
+
+/**
+ * The definition of Deferred object which is returned by PromiseUtils.defer(),
+ * It contains a Promise and methods to resolve/reject it.
+ */
+function Deferred() {
+  /* A method to resolve the associated Promise with the value passed.
+   * If the promise is already settled it does nothing.
+   *
+   * @param {anything} value : This value is used to resolve the promise
+   * If the value is a Promise then the associated promise assumes the state
+   * of Promise passed as value.
+   */
+  this.resolve = null;
+
+  /* A method to reject the assocaited Promise with the value passed.
+   * If the promise is already settled it does nothing.
+   *
+   * @param {anything} reason: The reason for the rejection of the Promise.
+   * Generally its an Error object. If however a Promise is passed, then the Promise
+   * itself will be the reason for rejection no matter the state of the Promise.
+   */
+  this.reject = null;
+
+  /* A newly created Pomise object.
+   * Initially in pending state.
+   */
+  this.promise = new Promise((resolve, reject) => {
+    this.resolve = resolve;
+    this.reject = reject;
+  });
 }
\ No newline at end of file
--- a/toolkit/modules/tests/xpcshell/test_PromiseUtils.js
+++ b/toolkit/modules/tests/xpcshell/test_PromiseUtils.js
@@ -6,16 +6,20 @@
 Components.utils.import("resource://gre/modules/PromiseUtils.jsm");
 Components.utils.import("resource://gre/modules/Timer.jsm");
 
 // Tests for PromiseUtils.jsm
 function run_test() {
   run_next_test();
 }
 
+///////////////////////////////////////////////////////////////////////////////////////////
+// Tests for PromiseUtils.resolveOrTimeout()
+///////////////////////////////////////////////////////////////////////////////////////////
+
 /* Tests for the case when arguments to resolveOrTimeout
  * are not of correct type */
 add_task(function* test_wrong_arguments() {
   let p = new Promise((resolve, reject) => {});
   // for the first argument
   Assert.throws(() => PromiseUtils.resolveOrTimeout("string", 200), /first argument <promise> must be a Promise object/,
                 "TypeError thrown because first argument is not a Promsie object");
   // for second argument
@@ -70,9 +74,102 @@ add_task(function* test_rejection_functi
 
 /* Tests for the case when the passed promise doesn't settles
  * and rejection throws an error */
 add_task(function* test_rejection_throw_error() {
   let p = new Promise((resolve, reject) => {});
   yield Assert.rejects(PromiseUtils.resolveOrTimeout(p, 200, () => {
     throw new Error("Rejection threw an Error");
   }), /Rejection threw an Error/, "Rejection threw an error");
+});
+
+///////////////////////////////////////////////////////////////////////////////////////
+// Tests for PromiseUtils.defer()
+///////////////////////////////////////////////////////////////////////////////////////
+
+/* Tests for checking the resolve method of the Deferred object
+ * returned by PromiseUtils.defer() */
+add_task(function* test_resolve_string() {
+  let def = PromiseUtils.defer();
+  let expected = "The promise is resolved " + Math.random();
+  def.resolve(expected);
+  let result = yield def.promise;
+  Assert.equal(result, expected, "def.resolve() resolves the promise");
+});
+
+/* Test for the case when undefined is passed to the resolve method
+ * of the Deferred object */
+add_task(function* test_resolve_undefined() {
+  let def = PromiseUtils.defer();
+  def.resolve();
+  let result = yield def.promise;
+  Assert.equal(result, undefined, "resolve works with undefined as well");
+});
+
+/* Test when a pending promise is passed to the resolve method
+ * of the Deferred object */
+add_task(function* test_resolve_pending_promise() {
+  let def = PromiseUtils.defer();
+  let expected = 100 + Math.random();
+  let p = new Promise((resolve, reject) => {
+    setTimeout(() => resolve(expected), 100);
+  });
+  def.resolve(p);
+  let result = yield def.promise;
+  Assert.equal(result, expected, "def.promise assumed the state of the passed promise");
+});
+
+/* Test when a resovled promise is passed
+ * to the resolve method of the Deferred object */
+add_task(function* test_resolve_resolved_promise() {
+  let def = PromiseUtils.defer();
+  let expected = "Yeah resolved" + Math.random();
+  let p = new Promise((resolve, reject) => resolve(expected));
+  def.resolve(p);
+  let result = yield def.promise;
+  Assert.equal(result, expected, "Resolved promise is passed to the resolve method");
+});
+
+/* Test for the case when a rejected promise is
+ * passed to the resolve method */
+add_task(function* test_resolve_rejected_promise() {
+  let def = PromiseUtils.defer();
+  let p = new Promise((resolve, reject) => reject(new Error("There its an rejection")));
+  def.resolve(p);
+  yield Assert.rejects(def.promise, /There its an rejection/, "Settled rejection promise passed to the resolve method");
+});
+
+/* Test for the checking the reject method of
+ * the Deferred object returned by PromiseUtils.defer() */
+add_task(function* test_reject_Error() {
+  let def = PromiseUtils.defer();
+  def.reject(new Error("This one rejects"));
+  yield Assert.rejects(def.promise, /This one rejects/, "reject method with Error for rejection");
+});
+
+/* Test for the case when a pending Promise is passed to
+ * the reject method of Deferred object */
+add_task(function* test_reject_pending_promise() {
+  let def = PromiseUtils.defer();
+  let p = new Promise((resolve, reject) => {
+    setTimeout(() => resolve(100), 100);
+  });
+  def.reject(p);
+  yield Assert.rejects(def.promise, Promise, "Rejection with a pending promise uses the passed promise itself as the reason of rejection");
+});
+
+/* Test for the case when a resolved Promise
+ * is passed to the reject method */
+add_task(function* test_reject_resolved_promise() {
+  let def = PromiseUtils.defer();
+  let p = new Promise((resolve, reject) => resolve("This resolved"));
+  def.reject(p);
+  yield Assert.rejects(def.promise, Promise, "Rejection with a resolved promise uses the passed promise itself as the reason of rejection");
+});
+
+/* Test for the case when a rejected Promise is
+ * passed to the reject method */
+add_task(function* test_reject_resolved_promise() {
+  let def = PromiseUtils.defer();
+  let p = new Promise((resolve, reject) => reject(new Error("This on rejects")));
+  def.reject(p);
+  yield Assert.rejects(def.promise, Promise, "Rejection with a rejected promise uses the passed promise itself as the reason of rejection");
 });
\ No newline at end of file