diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index f4df74299781c8..b1ec427573f100 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -164,6 +164,7 @@ inline napi_status ConcludeDeferred(napi_env env, napi_value result, bool is_resolved) { NAPI_PREAMBLE(env); + CHECK_ARG(env, deferred); CHECK_ARG(env, result); v8::Local context = env->context(); diff --git a/test/js-native-api/test_promise/binding.gyp b/test/js-native-api/test_promise/binding.gyp index fd777daf5e02cc..42276e53653e6f 100644 --- a/test/js-native-api/test_promise/binding.gyp +++ b/test/js-native-api/test_promise/binding.gyp @@ -3,7 +3,9 @@ { "target_name": "test_promise", "sources": [ + "../common.c", "../entry_point.c", + "test_null.c", "test_promise.c" ] } diff --git a/test/js-native-api/test_promise/test_null.c b/test/js-native-api/test_promise/test_null.c new file mode 100644 index 00000000000000..841dff45691b1f --- /dev/null +++ b/test/js-native-api/test_promise/test_null.c @@ -0,0 +1,95 @@ +#include + +#include "../common.h" +#include "test_null.h" + +static napi_value CreatePromise(napi_env env, napi_callback_info info) { + napi_value return_value, promise; + napi_deferred deferred; + + NODE_API_CALL(env, napi_create_object(env, &return_value)); + + add_returned_status(env, + "envIsNull", + return_value, + "Invalid argument", + napi_invalid_arg, + napi_create_promise(NULL, &deferred, &promise)); + + napi_create_promise(env, NULL, &promise); + add_last_status(env, "deferredIsNull", return_value); + + napi_create_promise(env, &deferred, NULL); + add_last_status(env, "promiseIsNull", return_value); + + return return_value; +} + +static napi_value test_resolution_api(napi_env env, + napi_callback_info info, + napi_status (*api)(napi_env, + napi_deferred, + napi_value)) { + napi_value return_value, promise, undefined; + napi_deferred deferred; + + NODE_API_CALL(env, napi_create_object(env, &return_value)); + NODE_API_CALL(env, napi_create_promise(env, &deferred, &promise)); + NODE_API_CALL(env, napi_get_undefined(env, &undefined)); + + add_returned_status(env, + "envIsNull", + return_value, + "Invalid argument", + napi_invalid_arg, + api(NULL, deferred, undefined)); + + api(env, NULL, undefined); + add_last_status(env, "deferredIsNull", return_value); + + api(env, deferred, NULL); + add_last_status(env, "valueIsNull", return_value); + + // We need to call the api will all parameters given because doing so frees a + // reference the implementation keeps internally. + napi_status status = api(env, deferred, undefined); + if (status != napi_ok) { + // This will make the test fail since the test doesn't expect that the + // nothing-is-null case will be recorded. + add_last_status(env, "nothingIsNull", return_value); + } + + NODE_API_CALL(env, + napi_set_named_property(env, return_value, "promise", promise)); + + return return_value; +} + +static napi_value ResolveDeferred(napi_env env, napi_callback_info info) { + return test_resolution_api(env, info, napi_resolve_deferred); +} + +static napi_value RejectDeferred(napi_env env, napi_callback_info info) { + return test_resolution_api(env, info, napi_reject_deferred); +} + +void init_test_null(napi_env env, napi_value exports) { + napi_value test_null; + + const napi_property_descriptor test_null_props[] = { + DECLARE_NODE_API_PROPERTY("createPromise", CreatePromise), + DECLARE_NODE_API_PROPERTY("resolveDeferred", ResolveDeferred), + DECLARE_NODE_API_PROPERTY("rejectDeferred", RejectDeferred), + }; + + NODE_API_CALL_RETURN_VOID(env, napi_create_object(env, &test_null)); + NODE_API_CALL_RETURN_VOID( + env, + napi_define_properties(env, + test_null, + sizeof(test_null_props) / sizeof(*test_null_props), + test_null_props)); + + NODE_API_CALL_RETURN_VOID( + env, napi_set_named_property(env, exports, "testNull", test_null)); +} diff --git a/test/js-native-api/test_promise/test_null.h b/test/js-native-api/test_promise/test_null.h new file mode 100644 index 00000000000000..f43e6b19acbbdb --- /dev/null +++ b/test/js-native-api/test_promise/test_null.h @@ -0,0 +1,8 @@ +#ifndef TEST_JS_NATIVE_API_TEST_PROMISE_TEST_NULL_H_ +#define TEST_JS_NATIVE_API_TEST_PROMISE_TEST_NULL_H_ + +#include + +void init_test_null(napi_env env, napi_value exports); + +#endif // TEST_JS_NATIVE_API_TEST_PROMISE_TEST_NULL_H_ diff --git a/test/js-native-api/test_promise/test_null.js b/test/js-native-api/test_promise/test_null.js new file mode 100644 index 00000000000000..ad1e1727cb306c --- /dev/null +++ b/test/js-native-api/test_promise/test_null.js @@ -0,0 +1,31 @@ +'use strict'; +const common = require('../../common'); +const assert = require('assert'); + +// Test passing NULL to object-related N-APIs. +const { testNull } = require(`./build/${common.buildType}/test_promise`); + +const expectedForCreatePromise = { + envIsNull: 'Invalid argument', + deferredIsNull: 'Invalid argument', + promiseIsNull: 'Invalid argument', +}; +assert.deepStrictEqual(testNull.createPromise(), expectedForCreatePromise); + +function testPromiseResolution(resultObject) { + const expectedForResolution = { + envIsNull: 'Invalid argument', + deferredIsNull: 'Invalid argument', + valueIsNull: 'Invalid argument', + }; + const promise = resultObject.promise; + + delete resultObject.promise; + assert.deepStrictEqual(resultObject, expectedForResolution); + + // Must avoid an unhandled rejection. + promise.catch(() => {}); +} + +testPromiseResolution(testNull.resolveDeferred()); +testPromiseResolution(testNull.rejectDeferred()); diff --git a/test/js-native-api/test_promise/test_promise.c b/test/js-native-api/test_promise/test_promise.c index 488ecea7853601..57dafc1f6a960c 100644 --- a/test/js-native-api/test_promise/test_promise.c +++ b/test/js-native-api/test_promise/test_promise.c @@ -1,5 +1,6 @@ #include #include "../common.h" +#include "test_null.h" napi_deferred deferred = NULL; @@ -58,6 +59,8 @@ napi_value Init(napi_env env, napi_value exports) { NODE_API_CALL(env, napi_define_properties( env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors)); + init_test_null(env, exports); + return exports; } EXTERN_C_END