From af07a2141ad3951e146691a87fce25702a954c08 Mon Sep 17 00:00:00 2001
From: Zidong Jiang <zidong.jiang@intel.com>
Date: Tue, 2 May 2017 14:19:17 +0800
Subject: [PATCH] Add promise C API

related issue: 1794

JerryScript-DCO-1.0-Signed-off-by: Zidong Jiang zidong.jiang@intel.com
---
 docs/02.API-REFERENCE.md                      | 138 ++++++++++++++-
 .../builtin-objects/ecma-builtin-promise.c    |   2 +-
 jerry-core/ecma/operations/ecma-jobqueue.c    |  15 +-
 .../ecma/operations/ecma-promise-object.c     |  31 +++-
 .../ecma/operations/ecma-promise-object.h     |  15 +-
 jerry-core/jerry.c                            |  78 +++++++++
 jerry-core/jerryscript.h                      |   7 +
 jerry-core/lit/lit-magic-strings.h            |   2 +
 tests/unit-core/CMakeLists.txt                |   4 +-
 tests/unit-core/test-promise.c                | 162 ++++++++++++++++++
 tools/run-tests.py                            |   4 +-
 11 files changed, 435 insertions(+), 23 deletions(-)
 create mode 100644 tests/unit-core/test-promise.c

diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md
index 8cf416e2c0..06b2a2e58f 100644
--- a/docs/02.API-REFERENCE.md
+++ b/docs/02.API-REFERENCE.md
@@ -1072,6 +1072,47 @@ jerry_value_is_object (const jerry_value_t value)
 - [jerry_release_value](#jerry_release_value)
 
 
+## jerry_value_is_promise
+
+**Summary**
+
+Returns whether the given `jerry_value_t` is a promise value.
+
+*Note*: This API depends on the ES2015-subset profile.
+
+**Prototype**
+
+```c
+bool
+jerry_value_is_promise (const jerry_value_t value)
+```
+
+- `value` - api value
+- return value
+  - true, if the given `jerry_value_t` is a promise
+  - false, otherwise
+
+**Example**
+
+```c
+{
+  jerry_value_t value;
+  ... // create or acquire value
+
+  if (jerry_value_is_promise (value))
+  {
+    ...
+  }
+
+  jerry_release_value (value);
+}
+```
+
+**See also**
+
+- [jerry_release_value](#jerry_release_value)
+
+
 ## jerry_value_is_string
 
 **Summary**
@@ -1980,6 +2021,64 @@ jerry_value_to_string (const jerry_value_t value);
 - [jerry_value_to_primitive](#jerry_value_to_primitive)
 
 
+# Functions for promise objects
+
+These APIs all depends on the ES2015-subset profile.
+
+## jerry_resolve_or_reject_promise
+
+**Summary**
+
+Resolve or reject the promise with an argument.
+
+**Prototype**
+
+```c
+jerry_value_t
+jerry_resolve_or_reject_promise (jerry_value_t promise,
+                                 jerry_value_t argument,
+                                 bool is_resolve)
+```
+
+- `promise` - the promise value
+- `argument` - the argument for resolve or reject
+- `is_resolve` - whether the promise should be resolved or rejected
+- return value
+  - undefined jerry value - resolve or reject successed
+  - jerry value with error flag - otherwise
+
+**Example**
+
+```c
+{
+  jerry_value_t promise = ... // acquire/create a promise object.
+
+  ...
+
+  bool is_resolve = ... // whether the promise should be resolved or rejected
+  jerry_value_t argument = ... // prepare the argumnent for the resolve or reject.
+
+  jerry_value_t is_ok = jerry_resolve_or_reject_promise (promise,
+                                                         argument,
+                                                         is_resolve);
+
+  if (jerry_value_has_error_flag (is_ok))
+  {
+    // handle the error.
+  }
+
+  jerry_release_value (is_ok);
+  jerry_release_value (argument);
+  jerry_release_value (promise);
+}
+```
+
+**See also**
+
+- [jerry_release_value](#jerry_release_value)
+- [jerry_value_has_error_flag](#jerry_value_has_error_flag)
+
+
 # Acquire and release API values
 
 ## jerry_acquire_value
@@ -2425,6 +2524,41 @@ jerry_create_object (void);
 - [jerry_release_value](#jerry_release_value)
 
 
+## jerry_create_promise
+
+**Summary**
+
+Create an empty promise object which can be resolved or rejected later
+by calling jerry_resolve_or_reject_promise.
+
+*Note*: This API depends on the ES2015-subset profile.
+
+**Prototype**
+
+```c
+jerry_value_t
+jerry_create_promise (void)
+```
+
+- return value - value of the newly created promise
+
+**Example**
+
+```c
+{
+  jerry_value_t p = jerry_create_promise ();
+
+  ...// usage of the promise
+
+  jerry_release_value (p);
+}
+
+**See also**
+
+- [jerry_resolve_or_reject_promise](#jerry_resolve_or_reject_promise)
+- [jerry_release_value](#jerry_release_value)
+
+
 ## jerry_create_string
 
 **Summary**
@@ -3528,7 +3662,7 @@ static const jerry_object_native_info_t native_obj_type_info =
     {
       // The type of this's native pointer matches what is expected.
       // Only now is it safe to cast to native_obj_t * and dereference the
-      // pointer: 
+      // pointer:
       native_obj_t *native_obj = native_p;
       native_obj->bar = ...; // Safe to access now!
     }
@@ -3582,7 +3716,7 @@ jerry_set_object_native_pointer (const jerry_value_t obj_val,
 **Example**
 
 See [jerry_get_object_native_pointer](#jerry_get_object_native_pointer) for a
-best-practice example. 
+best-practice example.
 
 **See also**
 
diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c
index 24cb4de001..f8e4ca4ed3 100644
--- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c
+++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c
@@ -683,7 +683,7 @@ ecma_builtin_promise_dispatch_construct (const ecma_value_t *arguments_list_p, /
     return ecma_raise_type_error (ECMA_ERR_MSG ("First parameter must be callable."));
   }
 
-  return ecma_op_create_promise_object (arguments_list_p[0], true);
+  return ecma_op_create_promise_object (arguments_list_p[0], ECMA_PROMISE_EXECUTOR_FUNCTION);
 } /* ecma_builtin_promise_dispatch_construct */
 
 /**
diff --git a/jerry-core/ecma/operations/ecma-jobqueue.c b/jerry-core/ecma/operations/ecma-jobqueue.c
index afe8dcb61e..1fc69fa3bc 100644
--- a/jerry-core/ecma/operations/ecma-jobqueue.c
+++ b/jerry-core/ecma/operations/ecma-jobqueue.c
@@ -223,10 +223,14 @@ ecma_process_promise_resolve_thenable_job (void *obj_p) /**< the job to be opera
 {
   ecma_job_promise_resolve_thenable_t *job_p = (ecma_job_promise_resolve_thenable_t *) obj_p;
   ecma_object_t *promise_p = ecma_get_object_from_value (job_p->promise);
-  ecma_promise_resolving_functions_t *funcs;
-  funcs = ecma_promise_create_resolving_functions (promise_p);
+  ecma_string_t str_resolve, str_reject;
+  ecma_init_ecma_magic_string (&str_resolve, LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION);
+  ecma_init_ecma_magic_string (&str_reject, LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION);
 
-  ecma_value_t argv[] = { funcs->resolve, funcs->reject };
+  ecma_value_t resolve = ecma_op_object_get (promise_p, &str_resolve);
+  ecma_value_t reject = ecma_op_object_get (promise_p, &str_reject);
+
+  ecma_value_t argv[] = { resolve, reject };
   ecma_value_t ret;
   ecma_value_t then_call_result = ecma_op_function_call (ecma_get_object_from_value (job_p->then),
                                                          job_p->thenable,
@@ -237,7 +241,7 @@ ecma_process_promise_resolve_thenable_job (void *obj_p) /**< the job to be opera
 
   if (ECMA_IS_VALUE_ERROR (then_call_result))
   {
-    ret = ecma_op_function_call (ecma_get_object_from_value (funcs->reject),
+    ret = ecma_op_function_call (ecma_get_object_from_value (reject),
                                  ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED),
                                  &then_call_result,
                                  1);
@@ -245,7 +249,8 @@ ecma_process_promise_resolve_thenable_job (void *obj_p) /**< the job to be opera
     ecma_free_value (then_call_result);
   }
 
-  ecma_promise_free_resolving_functions (funcs);
+  ecma_free_value (resolve);
+  ecma_free_value (reject);
   ecma_free_promise_resolve_thenable_job (job_p);
 
   return ret;
diff --git a/jerry-core/ecma/operations/ecma-promise-object.c b/jerry-core/ecma/operations/ecma-promise-object.c
index 0dc43ca270..321e351d8d 100644
--- a/jerry-core/ecma/operations/ecma-promise-object.c
+++ b/jerry-core/ecma/operations/ecma-promise-object.c
@@ -404,7 +404,7 @@ ecma_call_builtin_executor (ecma_object_t *executor_p, /**< the executor object
  *
  * @return pointer to the resolving functions
  */
-ecma_promise_resolving_functions_t *
+static ecma_promise_resolving_functions_t *
 ecma_promise_create_resolving_functions (ecma_object_t *object_p) /**< the promise object */
 {
   /* 1. */
@@ -455,7 +455,7 @@ ecma_promise_create_resolving_functions (ecma_object_t *object_p) /**< the promi
 /**
  * Free the heap and the member of the resolving functions.
  */
-void
+static void
 ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs) /**< points to the functions */
 {
   ecma_free_value (funcs->resolve);
@@ -473,7 +473,7 @@ ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs
  */
 ecma_value_t
 ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function or object */
-                               bool is_func) /**< indicates whether executor is a function */
+                               ecma_promise_executor_type_t type) /**< indicates the type of executor */
 {
   /* 3. */
   ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE_PROTOTYPE);
@@ -496,10 +496,22 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function
   /* 8. */
   ecma_promise_resolving_functions_t *funcs = ecma_promise_create_resolving_functions (object_p);
 
+  ecma_string_t str_resolve, str_reject;
+  ecma_init_ecma_magic_string (&str_resolve, LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION);
+  ecma_init_ecma_magic_string (&str_reject, LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION);
+  ecma_op_object_put (object_p,
+                      &str_resolve,
+                      funcs->resolve,
+                      false);
+  ecma_op_object_put (object_p,
+                      &str_reject,
+                      funcs->reject,
+                      false);
+
   /* 9. */
-  ecma_value_t completion;
+  ecma_value_t completion = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
 
-  if (is_func)
+  if (type == ECMA_PROMISE_EXECUTOR_FUNCTION)
   {
     JERRY_ASSERT (ecma_op_is_callable (executor));
 
@@ -509,7 +521,7 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function
                                         argv,
                                         2);
   }
-  else
+  else if (type == ECMA_PROMISE_EXECUTOR_OBJECT)
   {
     JERRY_ASSERT (ecma_is_value_object (executor));
 
@@ -517,6 +529,11 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function
                                              funcs->resolve,
                                              funcs->reject);
   }
+  else
+  {
+    JERRY_ASSERT (type == ECMA_PROMISE_EXECUTOR_EMPTY);
+    JERRY_UNUSED (executor);
+  }
 
   ecma_value_t status = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);
 
@@ -572,7 +589,7 @@ ecma_promise_new_capability (void)
                       false);
 
   /* 6. */
-  ecma_value_t promise = ecma_op_create_promise_object (executor, false);
+  ecma_value_t promise = ecma_op_create_promise_object (executor, ECMA_PROMISE_EXECUTOR_OBJECT);
 
   /* 10. */
   ecma_op_object_put (capability_p,
diff --git a/jerry-core/ecma/operations/ecma-promise-object.h b/jerry-core/ecma/operations/ecma-promise-object.h
index 9873f26571..c4422bd571 100644
--- a/jerry-core/ecma/operations/ecma-promise-object.h
+++ b/jerry-core/ecma/operations/ecma-promise-object.h
@@ -37,6 +37,16 @@ typedef enum
   ECMA_PROMISE_STATE__COUNT /**< number of states */
 } ecma_promise_state_t;
 
+/**
+ * Indicates the type of the executor in promise construct.
+ */
+typedef enum
+{
+  ECMA_PROMISE_EXECUTOR_FUNCTION, /**< the executor is a function, it is for the usual constructor */
+  ECMA_PROMISE_EXECUTOR_OBJECT, /**< the executor is an object, it is for the `then` routine */
+  ECMA_PROMISE_EXECUTOR_EMPTY /**< the executor is empty, it is for external C API */
+} ecma_promise_executor_type_t;
+
 /**
  * Description of the promise resolving functions.
  */
@@ -81,10 +91,7 @@ void ecma_promise_set_result (ecma_object_t *obj_p, ecma_value_t result);
 uint8_t ecma_promise_get_state (ecma_object_t *obj_p);
 void ecma_promise_set_state (ecma_object_t *obj_p, uint8_t state);
 ecma_value_t
-ecma_op_create_promise_object (ecma_value_t executor, bool is_func);
-ecma_promise_resolving_functions_t *
-ecma_promise_create_resolving_functions (ecma_object_t *obj_p);
-void ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs);
+ecma_op_create_promise_object (ecma_value_t executor, ecma_promise_executor_type_t type);
 ecma_value_t ecma_promise_new_capability (void);
 ecma_value_t
 ecma_promise_then (ecma_value_t promise,
diff --git a/jerry-core/jerry.c b/jerry-core/jerry.c
index fcca46bfd2..43fcc16d61 100644
--- a/jerry-core/jerry.c
+++ b/jerry-core/jerry.c
@@ -29,6 +29,7 @@
 #include "ecma-literal-storage.h"
 #include "ecma-objects.h"
 #include "ecma-objects-general.h"
+#include "ecma-promise-object.h"
 #include "jcontext.h"
 #include "jerryscript.h"
 #include "jerry-debugger.h"
@@ -2175,6 +2176,83 @@ jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, /**< per
 #endif /* JERRY_VM_EXEC_STOP */
 } /* jerry_set_vm_exec_stop_callback */
 
+#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
+
+/**
+ * Check if the specified value is promise.
+ *
+ * @return true  - if the specified value is promise,
+ *         false - otherwise
+ */
+bool
+jerry_value_is_promise (const jerry_value_t value) /**< api value */
+{
+  jerry_assert_api_available ();
+
+  return (ecma_is_value_object (value)
+          && ecma_is_promise (ecma_get_object_from_value (value)));
+} /* jerry_value_is_promise */
+
+/**
+ * Create an empty Promise object which can be resolve/reject later
+ * by calling jerry_resolve_or_reject_promise.
+ *
+ * Note:
+ *      returned value must be freed with jerry_release_value, when it is no longer needed.
+ *
+ * @return value of the created object
+ */
+jerry_value_t
+jerry_create_promise (void)
+{
+  jerry_assert_api_available ();
+
+  return ecma_op_create_promise_object (ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY), ECMA_PROMISE_EXECUTOR_EMPTY);
+} /* jerry_create_promise */
+
+/**
+ * Resolve or reject the promise with an argument.
+ *
+ * @return undefined value - if success
+ *         value marked with error flag - otherwise
+ */
+jerry_value_t
+jerry_resolve_or_reject_promise (jerry_value_t promise, /**< the promise value */
+                                 jerry_value_t argument, /**< the argument */
+                                 bool is_resolve) /**< whether the promise should be resolved or rejected */
+{
+  jerry_assert_api_available ();
+
+  if (!ecma_is_value_object (promise) || !ecma_is_promise (ecma_get_object_from_value (promise)))
+  {
+    return ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p));
+  }
+
+  ecma_string_t str;
+
+  if (is_resolve)
+  {
+    ecma_init_ecma_magic_string (&str, LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION);
+  }
+  else
+  {
+    ecma_init_ecma_magic_string (&str, LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION);
+  }
+
+  ecma_value_t function = ecma_op_object_get (ecma_get_object_from_value (promise), &str);
+
+  ecma_value_t ret = ecma_op_function_call (ecma_get_object_from_value (function),
+                                            ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED),
+                                            &argument,
+                                            1);
+
+  ecma_free_value (function);
+
+  return ret;
+} /* jerry_resolve_or_reject_promise */
+
+#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
+
 /**
  * @}
  */
diff --git a/jerry-core/jerryscript.h b/jerry-core/jerryscript.h
index be9d4a53e3..f4a9fbc26d 100644
--- a/jerry-core/jerryscript.h
+++ b/jerry-core/jerryscript.h
@@ -251,6 +251,7 @@ bool jerry_value_is_function (const jerry_value_t value);
 bool jerry_value_is_number (const jerry_value_t value);
 bool jerry_value_is_null (const jerry_value_t value);
 bool jerry_value_is_object (const jerry_value_t value);
+bool jerry_value_is_promise (const jerry_value_t value);
 bool jerry_value_is_string (const jerry_value_t value);
 bool jerry_value_is_undefined (const jerry_value_t value);
 
@@ -332,6 +333,7 @@ jerry_value_t jerry_create_number_infinity (bool sign);
 jerry_value_t jerry_create_number_nan (void);
 jerry_value_t jerry_create_null (void);
 jerry_value_t jerry_create_object (void);
+jerry_value_t jerry_create_promise (void);
 jerry_value_t jerry_create_string_from_utf8 (const jerry_char_t *str_p);
 jerry_value_t jerry_create_string_sz_from_utf8 (const jerry_char_t *str_p, jerry_size_t str_size);
 jerry_value_t jerry_create_string (const jerry_char_t *str_p);
@@ -387,6 +389,11 @@ void jerry_set_object_native_pointer (const jerry_value_t obj_val,
 bool jerry_foreach_object_property (const jerry_value_t obj_val, jerry_object_property_foreach_t foreach_p,
                                     void *user_data_p);
 
+/**
+ * Promise resolve/reject functions.
+ */
+jerry_value_t jerry_resolve_or_reject_promise (jerry_value_t promise, jerry_value_t argument, bool is_resolve);
+
 /**
  * Input validator functions.
  */
diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h
index fc1752c329..940330e1d5 100644
--- a/jerry-core/lit/lit-magic-strings.h
+++ b/jerry-core/lit/lit-magic-strings.h
@@ -38,6 +38,8 @@ typedef enum
   LIT_INTERNAL_MAGIC_STRING_PROMISE = LIT_NON_INTERNAL_MAGIC_STRING__COUNT, /**<  [[Promise]] of promise
                                                                              *    reject or resolve functions */
   LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED, /**< [[AlreadyResolved]] of promise reject or resolve functions */
+  LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION, /**< the resolve funtion of the promise object */
+  LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION, /**< the reject function of the promise object */
   LIT_NEED_MARK_MAGIC_STRING__COUNT,  /**< number of internal magic strings which will be used as properties' names,
                                        *   and the properties need to be marked during gc. */
   LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE = LIT_NEED_MARK_MAGIC_STRING__COUNT, /**< native handle package
diff --git a/tests/unit-core/CMakeLists.txt b/tests/unit-core/CMakeLists.txt
index 3ffaaa394a..60053486ee 100644
--- a/tests/unit-core/CMakeLists.txt
+++ b/tests/unit-core/CMakeLists.txt
@@ -19,8 +19,8 @@ if (NOT IS_ABSOLUTE ${FEATURE_PROFILE})
   set(FEATURE_PROFILE "${CMAKE_SOURCE_DIR}/jerry-core/profiles/${FEATURE_PROFILE}.profile")
 endif()
 
-if(NOT ${FEATURE_PROFILE} STREQUAL "${CMAKE_SOURCE_DIR}/jerry-core/profiles/es5.1.profile")
-  message(FATAL_ERROR "FEATURE_PROFILE='${FEATURE_PROFILE}' isn't supported with UNITTESTS=ON")
+if(${FEATURE_PROFILE} STREQUAL "${CMAKE_SOURCE_DIR}/jerry-core/profiles/minimal.profile")
+  message(FATAL_ERROR "minimal profile isn't supported in unit-core")
 endif()
 
 # Unit tests main modules
diff --git a/tests/unit-core/test-promise.c b/tests/unit-core/test-promise.c
new file mode 100644
index 0000000000..117ec1416a
--- /dev/null
+++ b/tests/unit-core/test-promise.c
@@ -0,0 +1,162 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jerryscript.h"
+#include "jerryscript-port.h"
+#include "jerryscript-port-default.h"
+#include "test-common.h"
+
+#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
+
+const char *test_source = (
+                           "var p1 = create_promise1();"
+                           "var p2 = create_promise2();"
+                           "p1.then(function(x) { "
+                           "  assert(x==='resolved'); "
+                           "}); "
+                           "p2.catch(function(x) { "
+                           "  assert(x==='rejected'); "
+                           "}); "
+                           );
+
+static int count_in_assert = 0;
+static jerry_value_t my_promise1;
+static jerry_value_t my_promise2;
+const jerry_char_t s1[] = "resolved";
+const jerry_char_t s2[] = "rejected";
+
+static jerry_value_t
+create_promise1_handler (const jerry_value_t func_obj_val __attribute__((unused)), /**< function object */
+                         const jerry_value_t this_val __attribute__((unused)), /**< this value */
+                         const jerry_value_t args_p[] __attribute__((unused)), /**< arguments list */
+                         const jerry_length_t args_cnt __attribute__((unused))) /**< arguments length */
+{
+  jerry_value_t ret =  jerry_create_promise ();
+  my_promise1 = jerry_acquire_value (ret);
+
+  return ret;
+} /* create_promise1_handler */
+
+static jerry_value_t
+create_promise2_handler (const jerry_value_t func_obj_val __attribute__((unused)), /**< function object */
+                         const jerry_value_t this_val __attribute__((unused)), /**< this value */
+                         const jerry_value_t args_p[] __attribute__((unused)), /**< arguments list */
+                         const jerry_length_t args_cnt __attribute__((unused))) /**< arguments length */
+{
+  jerry_value_t ret =  jerry_create_promise ();
+  my_promise2 = jerry_acquire_value (ret);
+
+  return ret;
+} /* create_promise2_handler */
+
+static jerry_value_t
+assert_handler (const jerry_value_t func_obj_val __attribute__((unused)), /**< function object */
+                const jerry_value_t this_p __attribute__((unused)), /**< this arg */
+                const jerry_value_t args_p[], /**< function arguments */
+                const jerry_length_t args_cnt) /**< number of function arguments */
+{
+  count_in_assert++;
+
+  if (args_cnt == 1
+      && jerry_value_is_boolean (args_p[0])
+      && jerry_get_boolean_value (args_p[0]))
+  {
+    return jerry_create_boolean (true);
+  }
+  else
+  {
+    TEST_ASSERT (false);
+  }
+} /* assert_handler */
+
+/**
+ * Register a JavaScript function in the global object.
+ */
+static void
+register_js_function (const char *name_p, /**< name of the function */
+                      jerry_external_handler_t handler_p) /**< function callback */
+{
+  jerry_value_t global_obj_val = jerry_get_global_object ();
+
+  jerry_value_t function_val = jerry_create_external_function (handler_p);
+  jerry_value_t function_name_val = jerry_create_string ((const jerry_char_t *) name_p);
+  jerry_value_t result_val = jerry_set_property (global_obj_val, function_name_val, function_val);
+
+  jerry_release_value (function_name_val);
+  jerry_release_value (function_val);
+  jerry_release_value (global_obj_val);
+
+  jerry_release_value (result_val);
+} /* register_js_function */
+
+int
+main (void)
+{
+  jerry_port_default_jobqueue_init ();
+  jerry_init (JERRY_INIT_EMPTY);
+
+  register_js_function ("create_promise1", create_promise1_handler);
+  register_js_function ("create_promise2", create_promise2_handler);
+  register_js_function ("assert", assert_handler);
+
+  jerry_value_t parsed_code_val = jerry_parse ((jerry_char_t *) test_source, strlen (test_source), false);
+  TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
+
+  jerry_value_t res = jerry_run (parsed_code_val);
+  TEST_ASSERT (!jerry_value_has_error_flag (res));
+
+  jerry_release_value (res);
+  jerry_release_value (parsed_code_val);
+
+  /* Test jerry_create_promise and jerry_value_is_promise. */
+  TEST_ASSERT (jerry_value_is_promise (my_promise1));
+  TEST_ASSERT (jerry_value_is_promise (my_promise2));
+
+  TEST_ASSERT (count_in_assert == 0);
+
+  /* Test jerry_resolve_or_reject_promise. */
+  jerry_value_t str_resolve = jerry_create_string (s1);
+  jerry_value_t str_reject = jerry_create_string (s2);
+
+  jerry_resolve_or_reject_promise (my_promise1, str_resolve, true);
+  jerry_resolve_or_reject_promise (my_promise2, str_reject, false);
+
+  /* The resolve/reject function should be invalid after the promise has the result. */
+  jerry_resolve_or_reject_promise (my_promise2, str_resolve, true);
+  jerry_resolve_or_reject_promise (my_promise1, str_reject, false);
+
+  /* Run the jobqueue. */
+  res = jerry_port_default_jobqueue_run ();
+
+  TEST_ASSERT (!jerry_value_has_error_flag (res));
+  TEST_ASSERT (count_in_assert == 2);
+
+  jerry_release_value (my_promise1);
+  jerry_release_value (my_promise2);
+  jerry_release_value (str_resolve);
+  jerry_release_value (str_reject);
+
+  jerry_cleanup ();
+} /* main */
+
+#else /* CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
+
+int
+main (void)
+{
+  return 0;
+} /* main */
+
+#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
diff --git a/tools/run-tests.py b/tools/run-tests.py
index 2ff6fe0c28..d7790d9e56 100755
--- a/tools/run-tests.py
+++ b/tools/run-tests.py
@@ -42,9 +42,9 @@ def get_binary_path(bin_dir_path):
 # Test options for unittests
 JERRY_UNITTESTS_OPTIONS = [
     Options('unittests',
-            ['--unittests', '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on']),
+            ['--unittests', '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es2015-subset']),
     Options('unittests-debug',
-            ['--unittests', '--debug', '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on'])
+            ['--unittests', '--debug', '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es2015-subset'])
 ]
 
 # Test options for jerry-tests