Skip to content

Commit

Permalink
test: return napi_exception_pending on throwing proxy handlers (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
toyobayashi authored Oct 25, 2023
1 parent 5f6f207 commit 7d4fd78
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 5 deletions.
1 change: 1 addition & 0 deletions packages/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ add_test("string" "./string/binding.c;./string/test_null.c" OFF)
add_test("property" "./property/binding.c" OFF)
add_test("promise" "./promise/binding.c" OFF)
add_test("object" "./object/test_null.c;./object/test_object.c" OFF)
add_test("object_exception" "./object/test_exceptions.c" OFF)
add_test("objwrap" "./objwrap/myobject.cc" OFF)
add_test("bigint" "./bigint/binding.c" OFF)
add_test("fnwrap" "./fnwrap/myobject.cc;./fnwrap/binding.cc" OFF)
Expand Down
27 changes: 22 additions & 5 deletions packages/test/common-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,34 @@ inline void add_last_status(napi_env env,
const char* key,
napi_value return_value) {
napi_value prop_value;
napi_value exception;
const napi_extended_error_info* p_last_error;
NODE_API_CALL_RETURN_VOID(env, napi_get_last_error_info(env, &p_last_error));
// Content of p_last_error can be updated in subsequent node-api calls.
// Retrieve it immediately.
const char* error_message = p_last_error->error_message == NULL
? "napi_ok"
: p_last_error->error_message;

bool is_exception_pending;
NODE_API_CALL_RETURN_VOID(
env, napi_is_exception_pending(env, &is_exception_pending));
if (is_exception_pending) {
NODE_API_CALL_RETURN_VOID(
env, napi_get_and_clear_last_exception(env, &exception));
char exception_key[50];
#if !defined(__wasm__) || (defined(__EMSCRIPTEN__) || defined(__wasi__))
snprintf(exception_key, sizeof(exception_key), "%s%s", key, "Exception");
#endif
NODE_API_CALL_RETURN_VOID(
env,
napi_set_named_property(env, return_value, exception_key, exception));
}

NODE_API_CALL_RETURN_VOID(
env,
napi_create_string_utf8(
env,
(p_last_error->error_message == NULL ? "napi_ok"
: p_last_error->error_message),
NAPI_AUTO_LENGTH,
&prop_value));
env, error_message, NAPI_AUTO_LENGTH, &prop_value));
NODE_API_CALL_RETURN_VOID(
env, napi_set_named_property(env, return_value, key, prop_value));
}
Expand Down
22 changes: 22 additions & 0 deletions packages/test/object/object_exceptions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* eslint-disable symbol-description */
/* eslint-disable camelcase */
'use strict'
const { load } = require('../util')
const common = require('../common')

module.exports = load('object_exception').then(test_object => {
const { testExceptions } = test_object

function throws () {
throw new Error('foobar')
}
testExceptions(new Proxy({}, {
get: common.mustCallAtLeast(throws, 1),
getOwnPropertyDescriptor: common.mustCallAtLeast(throws, 1),
defineProperty: common.mustCallAtLeast(throws, 1),
deleteProperty: common.mustCallAtLeast(throws, 1),
has: common.mustCallAtLeast(throws, 1),
set: common.mustCallAtLeast(throws, 1),
ownKeys: common.mustCallAtLeast(throws, 1)
}))
})
82 changes: 82 additions & 0 deletions packages/test/object/test_exceptions.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// #include <assert.h>
#include <js_native_api.h>
// #include <string.h>
#include "../common.h"
#include "../entry_point.h"

static napi_value TestExceptions(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value args[1];
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));

napi_value target = args[0];
napi_value exception, key, value;
napi_status status;
bool is_exception_pending;
bool bool_result;

NODE_API_CALL(env,
napi_create_string_utf8(env, "key", NAPI_AUTO_LENGTH, &key));
NODE_API_CALL(
env, napi_create_string_utf8(env, "value", NAPI_AUTO_LENGTH, &value));

#define PROCEDURE(call) \
{ \
status = (call); \
NODE_API_ASSERT( \
env, status == napi_pending_exception, "expect exception pending"); \
NODE_API_CALL(env, napi_is_exception_pending(env, &is_exception_pending)); \
NODE_API_ASSERT(env, is_exception_pending, "expect exception pending"); \
NODE_API_CALL(env, napi_get_and_clear_last_exception(env, &exception)); \
}
// discard the exception values.

// properties
PROCEDURE(napi_set_property(env, target, key, value));
PROCEDURE(napi_set_named_property(env, target, "key", value));
PROCEDURE(napi_has_property(env, target, key, &bool_result));
PROCEDURE(napi_has_own_property(env, target, key, &bool_result));
PROCEDURE(napi_has_named_property(env, target, "key", &bool_result));
PROCEDURE(napi_get_property(env, target, key, &value));
PROCEDURE(napi_get_named_property(env, target, "key", &value));
PROCEDURE(napi_delete_property(env, target, key, &bool_result));

// elements
PROCEDURE(napi_set_element(env, target, 0, value));
PROCEDURE(napi_has_element(env, target, 0, &bool_result));
PROCEDURE(napi_get_element(env, target, 0, &value));
PROCEDURE(napi_delete_element(env, target, 0, &bool_result));

napi_property_descriptor descriptors[] = {
DECLARE_NODE_API_PROPERTY_VALUE("key", value),
};
PROCEDURE(napi_define_properties(
env, target, sizeof(descriptors) / sizeof(*descriptors), descriptors));

PROCEDURE(napi_get_all_property_names(env,
target,
napi_key_own_only,
napi_key_enumerable,
napi_key_keep_numbers,
&value));
PROCEDURE(napi_get_property_names(env, target, &value));

return NULL;
}

EXTERN_C_START
napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor descriptors[] = {
DECLARE_NODE_API_PROPERTY("testExceptions", TestExceptions),
};

NODE_API_CALL(
env,
napi_define_properties(env,
exports,
sizeof(descriptors) / sizeof(*descriptors),
descriptors));

return exports;
}
EXTERN_C_END

0 comments on commit 7d4fd78

Please sign in to comment.