Bug 1093021 - Implemented PromiseUtils.defer; r=yoric
authorAkshendra Pratap <akshendra521994@gmail.com>
Mon, 10 Nov 2014 05:52:00 +0100
changeset 216359 8ab91f02f963ca92d0a332afc77d2f70985ef702
parent 216358 d6dbc6e05dce4e7e5499e394a392f098b2f78999
child 216360 888dd71a867f5cd900fcd250a61e404714873014
child 216449 aa72ddfe9f9365cf4e9e3a70ff639c0e5c3829b8
push id10035
push usercbook@mozilla.com
push dateWed, 19 Nov 2014 08:46:08 +0000
treeherderfx-team@8ab91f02f963 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyoric
bugs1093021
milestone36.0a1
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