koffi 2.7.2 → 2.7.4-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/build/koffi/darwin_arm64/koffi.node +0 -0
  3. package/build/koffi/darwin_x64/koffi.node +0 -0
  4. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  5. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  6. package/build/koffi/freebsd_x64/koffi.node +0 -0
  7. package/build/koffi/linux_arm32hf/koffi.node +0 -0
  8. package/build/koffi/linux_arm64/koffi.node +0 -0
  9. package/build/koffi/linux_ia32/koffi.node +0 -0
  10. package/build/koffi/linux_riscv64hf64/koffi.node +0 -0
  11. package/build/koffi/linux_x64/koffi.node +0 -0
  12. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  13. package/build/koffi/openbsd_x64/koffi.node +0 -0
  14. package/build/koffi/win32_arm64/koffi.node +0 -0
  15. package/build/koffi/win32_ia32/koffi.node +0 -0
  16. package/build/koffi/win32_x64/koffi.node +0 -0
  17. package/doc/misc.md +1 -1
  18. package/index.js +2 -2
  19. package/indirect.js +2 -2
  20. package/package.json +2 -2
  21. package/src/koffi/src/abi_arm32.cc +4 -4
  22. package/src/koffi/src/abi_arm64.cc +4 -4
  23. package/src/koffi/src/abi_riscv64.cc +4 -4
  24. package/src/koffi/src/abi_x64_sysv.cc +4 -4
  25. package/src/koffi/src/abi_x64_win.cc +4 -4
  26. package/src/koffi/src/abi_x86.cc +4 -4
  27. package/src/koffi/src/call.cc +6 -6
  28. package/src/koffi/src/call.hh +2 -2
  29. package/src/koffi/src/ffi.cc +0 -9
  30. package/src/koffi/src/ffi.hh +0 -1
  31. package/src/koffi/src/util.cc +7 -13
  32. package/src/koffi/src/util.hh +9 -1
  33. package/vendor/node-addon-api/CHANGELOG.md +76 -0
  34. package/vendor/node-addon-api/LICENSE.md +2 -6
  35. package/vendor/node-addon-api/README.md +10 -9
  36. package/vendor/node-addon-api/benchmark/binding.gyp +4 -4
  37. package/vendor/node-addon-api/common.gypi +1 -2
  38. package/vendor/node-addon-api/doc/array.md +1 -1
  39. package/vendor/node-addon-api/doc/async_worker_variants.md +16 -16
  40. package/vendor/node-addon-api/doc/cmake-js.md +1 -1
  41. package/vendor/node-addon-api/doc/env.md +11 -0
  42. package/vendor/node-addon-api/doc/hierarchy.md +2 -0
  43. package/vendor/node-addon-api/doc/setup.md +53 -71
  44. package/vendor/node-addon-api/doc/syntax_error.md +66 -0
  45. package/vendor/node-addon-api/doc/value.md +2 -0
  46. package/vendor/node-addon-api/index.js +2 -1
  47. package/vendor/node-addon-api/napi-inl.h +68 -65
  48. package/vendor/node-addon-api/napi.h +15 -5
  49. package/vendor/node-addon-api/node_addon_api.gyp +32 -0
  50. package/vendor/node-addon-api/package.json +14 -3
  51. package/vendor/node-addon-api/test/addon.cc +7 -1
  52. package/vendor/node-addon-api/test/addon.js +5 -9
  53. package/vendor/node-addon-api/test/addon_data.cc +3 -3
  54. package/vendor/node-addon-api/test/addon_data.js +16 -38
  55. package/vendor/node-addon-api/test/bigint.cc +0 -1
  56. package/vendor/node-addon-api/test/binding.cc +12 -1
  57. package/vendor/node-addon-api/test/binding.gyp +10 -8
  58. package/vendor/node-addon-api/test/child_processes/addon.js +11 -0
  59. package/vendor/node-addon-api/test/child_processes/addon_data.js +24 -0
  60. package/vendor/node-addon-api/test/child_processes/objectwrap_function.js +22 -0
  61. package/vendor/node-addon-api/test/child_processes/threadsafe_function_exception.js +33 -0
  62. package/vendor/node-addon-api/test/child_processes/typed_threadsafe_function_exception.js +19 -0
  63. package/vendor/node-addon-api/test/common/index.js +57 -3
  64. package/vendor/node-addon-api/test/env_misc.cc +25 -0
  65. package/vendor/node-addon-api/test/env_misc.js +12 -0
  66. package/vendor/node-addon-api/test/error.cc +47 -0
  67. package/vendor/node-addon-api/test/error.js +16 -0
  68. package/vendor/node-addon-api/test/index.js +5 -0
  69. package/vendor/node-addon-api/test/objectwrap_function.cc +10 -12
  70. package/vendor/node-addon-api/test/objectwrap_function.js +4 -20
  71. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_exception.cc +50 -0
  72. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_exception.js +20 -0
  73. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_exception.cc +39 -0
  74. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_exception.js +13 -0
@@ -367,6 +367,10 @@ class Env {
367
367
  } * data;
368
368
  };
369
369
  #endif // NAPI_VERSION > 2
370
+
371
+ #if NAPI_VERSION > 8
372
+ const char* GetModuleFileName() const;
373
+ #endif // NAPI_VERSION > 8
370
374
  };
371
375
 
372
376
  /// A JavaScript value of unknown type.
@@ -1531,11 +1535,6 @@ class Buffer : public Uint8Array {
1531
1535
  T* Data() const;
1532
1536
 
1533
1537
  private:
1534
- mutable size_t _length;
1535
- mutable T* _data;
1536
-
1537
- Buffer(napi_env env, napi_value value, size_t length, T* data);
1538
- void EnsureInfo() const;
1539
1538
  };
1540
1539
 
1541
1540
  /// Holds a counted reference to a value; initially a weak reference unless
@@ -1853,6 +1852,17 @@ class RangeError : public Error {
1853
1852
  RangeError(napi_env env, napi_value value);
1854
1853
  };
1855
1854
 
1855
+ #if NAPI_VERSION > 8
1856
+ class SyntaxError : public Error {
1857
+ public:
1858
+ static SyntaxError New(napi_env env, const char* message);
1859
+ static SyntaxError New(napi_env env, const std::string& message);
1860
+
1861
+ SyntaxError();
1862
+ SyntaxError(napi_env env, napi_value value);
1863
+ };
1864
+ #endif // NAPI_VERSION > 8
1865
+
1856
1866
  class CallbackInfo {
1857
1867
  public:
1858
1868
  CallbackInfo(napi_env env, napi_callback_info info);
@@ -0,0 +1,32 @@
1
+ {
2
+ 'targets': [
3
+ {
4
+ 'target_name': 'node_addon_api',
5
+ 'type': 'none',
6
+ 'sources': [ 'napi.h', 'napi-inl.h' ],
7
+ 'direct_dependent_settings': {
8
+ 'include_dirs': [ '.' ],
9
+ 'includes': ['noexcept.gypi'],
10
+ }
11
+ },
12
+ {
13
+ 'target_name': 'node_addon_api_except',
14
+ 'type': 'none',
15
+ 'sources': [ 'napi.h', 'napi-inl.h' ],
16
+ 'direct_dependent_settings': {
17
+ 'include_dirs': [ '.' ],
18
+ 'includes': ['except.gypi'],
19
+ }
20
+ },
21
+ {
22
+ 'target_name': 'node_addon_api_maybe',
23
+ 'type': 'none',
24
+ 'sources': [ 'napi.h', 'napi-inl.h' ],
25
+ 'direct_dependent_settings': {
26
+ 'include_dirs': [ '.' ],
27
+ 'includes': ['noexcept.gypi'],
28
+ 'defines': ['NODE_ADDON_API_ENABLE_MAYBE']
29
+ }
30
+ },
31
+ ]
32
+ }
@@ -407,6 +407,14 @@
407
407
  {
408
408
  "name": "Caleb Hearon",
409
409
  "url": "https://github.com/chearon"
410
+ },
411
+ {
412
+ "name": "Marx",
413
+ "url": "https://github.com/MarxJiao"
414
+ },
415
+ {
416
+ "name": "Ömer AKGÜL",
417
+ "url": "https://github.com/tuhalf"
410
418
  }
411
419
  ],
412
420
  "description": "Node.js API (Node-API)",
@@ -420,7 +428,7 @@
420
428
  "eslint-plugin-import": "^2.24.2",
421
429
  "eslint-plugin-node": "^11.1.0",
422
430
  "eslint-plugin-promise": "^5.1.0",
423
- "fs-extra": "^9.0.1",
431
+ "fs-extra": "^11.1.1",
424
432
  "path": "^0.12.7",
425
433
  "pre-commit": "^1.2.2",
426
434
  "safe-buffer": "^5.1.1"
@@ -467,6 +475,9 @@
467
475
  "lint:fix": "node tools/clang-format --fix && node tools/eslint-format --fix"
468
476
  },
469
477
  "pre-commit": "lint",
470
- "version": "7.0.0",
471
- "support": true
478
+ "version": "7.1.0",
479
+ "support": true,
480
+ "engines": {
481
+ "node": "^16 || ^18 || >= 20"
482
+ }
472
483
  }
@@ -17,6 +17,8 @@ class TestAddon : public Napi::Addon<TestAddon> {
17
17
  {InstanceMethod("decrement", &TestAddon::Decrement)}))});
18
18
  }
19
19
 
20
+ ~TestAddon() { fprintf(stderr, "TestAddon::~TestAddon\n"); }
21
+
20
22
  private:
21
23
  Napi::Value Increment(const Napi::CallbackInfo& info) {
22
24
  return Napi::Number::New(info.Env(), ++value);
@@ -29,10 +31,14 @@ class TestAddon : public Napi::Addon<TestAddon> {
29
31
  uint32_t value = 42;
30
32
  };
31
33
 
34
+ Napi::Value CreateAddon(const Napi::CallbackInfo& info) {
35
+ return TestAddon::Init(info.Env(), Napi::Object::New(info.Env()));
36
+ }
37
+
32
38
  } // end of anonymous namespace
33
39
 
34
40
  Napi::Object InitAddon(Napi::Env env) {
35
- return TestAddon::Init(env, Napi::Object::New(env));
41
+ return Napi::Function::New<CreateAddon>(env, "CreateAddon");
36
42
  }
37
43
 
38
44
  #endif // (NAPI_VERSION > 5)
@@ -1,11 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const assert = require('assert');
4
-
5
- module.exports = require('./common').runTest(test);
6
-
7
- function test (binding) {
8
- assert.strictEqual(binding.addon.increment(), 43);
9
- assert.strictEqual(binding.addon.increment(), 44);
10
- assert.strictEqual(binding.addon.subObject.decrement(), 43);
11
- }
3
+ module.exports = require('./common').runTestInChildProcess({
4
+ suite: 'addon',
5
+ testName: 'workingCode',
6
+ expectedStderr: ['TestAddon::~TestAddon']
7
+ });
@@ -4,10 +4,10 @@
4
4
  #include "test_helper.h"
5
5
 
6
6
  // An overly elaborate way to get/set a boolean stored in the instance data:
7
- // 0. A boolean named "verbose" is stored in the instance data. The constructor
8
- // for JS `VerboseIndicator` instances is also stored in the instance data.
7
+ // 0. The constructor for JS `VerboseIndicator` instances, which have a private
8
+ // member named "verbose", is stored in the instance data.
9
9
  // 1. Add a property named "verbose" onto exports served by a getter/setter.
10
- // 2. The getter returns a object of type VerboseIndicator, which itself has a
10
+ // 2. The getter returns an object of type VerboseIndicator, which itself has a
11
11
  // property named "verbose", also served by a getter/setter:
12
12
  // * The getter returns a boolean, indicating whether "verbose" is set.
13
13
  // * The setter sets "verbose" on the instance data.
@@ -1,46 +1,24 @@
1
1
  'use strict';
2
2
 
3
- const assert = require('assert');
4
- const { spawn } = require('child_process');
5
- const readline = require('readline');
3
+ const common = require('./common');
6
4
 
7
- module.exports = require('./common').runTestWithBindingPath(test);
5
+ module.exports = common.runTest(test);
8
6
 
9
- // Make sure the instance data finalizer is called at process exit. If the hint
10
- // is non-zero, it will be printed out by the child process.
11
- function testFinalizer (bindingName, hint, expected) {
12
- return new Promise((resolve) => {
13
- bindingName = bindingName.split('\\').join('\\\\');
14
- const child = spawn(process.execPath, [
15
- '-e',
16
- `require('${bindingName}').addon_data(${hint}).verbose = true;`
17
- ]);
18
- const actual = [];
19
- readline
20
- .createInterface({ input: child.stderr })
21
- .on('line', (line) => {
22
- if (expected.indexOf(line) >= 0) {
23
- actual.push(line);
24
- }
25
- })
26
- .on('close', () => {
27
- assert.deepStrictEqual(expected, actual);
28
- resolve();
29
- });
7
+ async function test () {
8
+ await common.runTestInChildProcess({
9
+ suite: 'addon_data',
10
+ testName: 'workingCode'
30
11
  });
31
- }
32
-
33
- async function test (bindingName) {
34
- const binding = require(bindingName).addon_data(0);
35
12
 
36
- // Make sure it is possible to get/set instance data.
37
- assert.strictEqual(binding.verbose.verbose, false);
38
- binding.verbose = true;
39
- assert.strictEqual(binding.verbose.verbose, true);
40
- binding.verbose = false;
41
- assert.strictEqual(binding.verbose.verbose, false);
13
+ await common.runTestInChildProcess({
14
+ suite: 'addon_data',
15
+ testName: 'cleanupWithoutHint',
16
+ expectedStderr: ['addon_data: Addon::~Addon']
17
+ });
42
18
 
43
- await testFinalizer(bindingName, 0, ['addon_data: Addon::~Addon']);
44
- await testFinalizer(bindingName, 42,
45
- ['addon_data: Addon::~Addon', 'hint: 42']);
19
+ await common.runTestInChildProcess({
20
+ suite: 'addon_data',
21
+ testName: 'cleanupWithHint',
22
+ expectedStderr: ['addon_data: Addon::~Addon', 'hint: 42']
23
+ });
46
24
  }
@@ -1,6 +1,5 @@
1
1
  #if (NAPI_VERSION > 5)
2
2
 
3
- #define NAPI_EXPERIMENTAL
4
3
  #include "napi.h"
5
4
 
6
5
  #include "test_helper.h"
@@ -50,12 +50,14 @@ Object InitPromise(Env env);
50
50
  Object InitRunScript(Env env);
51
51
  #if (NAPI_VERSION > 3)
52
52
  Object InitThreadSafeFunctionCtx(Env env);
53
+ Object InitThreadSafeFunctionException(Env env);
53
54
  Object InitThreadSafeFunctionExistingTsfn(Env env);
54
55
  Object InitThreadSafeFunctionPtr(Env env);
55
56
  Object InitThreadSafeFunctionSum(Env env);
56
57
  Object InitThreadSafeFunctionUnref(Env env);
57
58
  Object InitThreadSafeFunction(Env env);
58
59
  Object InitTypedThreadSafeFunctionCtx(Env env);
60
+ Object InitTypedThreadSafeFunctionException(Env env);
59
61
  Object InitTypedThreadSafeFunctionExistingTsfn(Env env);
60
62
  Object InitTypedThreadSafeFunctionPtr(Env env);
61
63
  Object InitTypedThreadSafeFunctionSum(Env env);
@@ -78,7 +80,9 @@ Object InitThunkingManual(Env env);
78
80
  Object InitObjectFreezeSeal(Env env);
79
81
  Object InitTypeTaggable(Env env);
80
82
  #endif
81
-
83
+ #if (NAPI_VERSION > 8)
84
+ Object InitEnvMiscellaneous(Env env);
85
+ #endif
82
86
  #if defined(NODE_ADDON_API_ENABLE_MAYBE)
83
87
  Object InitMaybeCheck(Env env);
84
88
  #endif
@@ -137,6 +141,8 @@ Object Init(Env env, Object exports) {
137
141
  exports.Set("symbol", InitSymbol(env));
138
142
  #if (NAPI_VERSION > 3)
139
143
  exports.Set("threadsafe_function_ctx", InitThreadSafeFunctionCtx(env));
144
+ exports.Set("threadsafe_function_exception",
145
+ InitThreadSafeFunctionException(env));
140
146
  exports.Set("threadsafe_function_existing_tsfn",
141
147
  InitThreadSafeFunctionExistingTsfn(env));
142
148
  exports.Set("threadsafe_function_ptr", InitThreadSafeFunctionPtr(env));
@@ -145,6 +151,8 @@ Object Init(Env env, Object exports) {
145
151
  exports.Set("threadsafe_function", InitThreadSafeFunction(env));
146
152
  exports.Set("typed_threadsafe_function_ctx",
147
153
  InitTypedThreadSafeFunctionCtx(env));
154
+ exports.Set("typed_threadsafe_function_exception",
155
+ InitTypedThreadSafeFunctionException(env));
148
156
  exports.Set("typed_threadsafe_function_existing_tsfn",
149
157
  InitTypedThreadSafeFunctionExistingTsfn(env));
150
158
  exports.Set("typed_threadsafe_function_ptr",
@@ -171,6 +179,9 @@ Object Init(Env env, Object exports) {
171
179
  exports.Set("object_freeze_seal", InitObjectFreezeSeal(env));
172
180
  exports.Set("type_taggable", InitTypeTaggable(env));
173
181
  #endif
182
+ #if (NAPI_VERSION > 8)
183
+ exports.Set("env_misc", InitEnvMiscellaneous(env));
184
+ #endif
174
185
 
175
186
  #if defined(NODE_ADDON_API_ENABLE_MAYBE)
176
187
  exports.Set("maybe_check", InitMaybeCheck(env));
@@ -26,6 +26,7 @@
26
26
  'dataview/dataview.cc',
27
27
  'dataview/dataview_read_write.cc',
28
28
  'env_cleanup.cc',
29
+ 'env_misc.cc',
29
30
  'error.cc',
30
31
  'error_handling_for_primitives.cc',
31
32
  'external.cc',
@@ -54,6 +55,7 @@
54
55
  'run_script.cc',
55
56
  'symbol.cc',
56
57
  'threadsafe_function/threadsafe_function_ctx.cc',
58
+ 'threadsafe_function/threadsafe_function_exception.cc',
57
59
  'threadsafe_function/threadsafe_function_existing_tsfn.cc',
58
60
  'threadsafe_function/threadsafe_function_ptr.cc',
59
61
  'threadsafe_function/threadsafe_function_sum.cc',
@@ -61,6 +63,7 @@
61
63
  'threadsafe_function/threadsafe_function.cc',
62
64
  'type_taggable.cc',
63
65
  'typed_threadsafe_function/typed_threadsafe_function_ctx.cc',
66
+ 'typed_threadsafe_function/typed_threadsafe_function_exception.cc',
64
67
  'typed_threadsafe_function/typed_threadsafe_function_existing_tsfn.cc',
65
68
  'typed_threadsafe_function/typed_threadsafe_function_ptr.cc',
66
69
  'typed_threadsafe_function/typed_threadsafe_function_sum.cc',
@@ -94,41 +97,40 @@
94
97
  'targets': [
95
98
  {
96
99
  'target_name': 'binding',
97
- 'includes': ['../except.gypi'],
100
+ 'dependencies': ['../node_addon_api.gyp:node_addon_api_except'],
98
101
  'sources': ['>@(build_sources)']
99
102
  },
100
103
  {
101
104
  'target_name': 'binding_noexcept',
102
- 'includes': ['../noexcept.gypi'],
105
+ 'dependencies': ['../node_addon_api.gyp:node_addon_api'],
103
106
  'sources': ['>@(build_sources)']
104
107
  },
105
108
  {
106
109
  'target_name': 'binding_noexcept_maybe',
107
- 'includes': ['../noexcept.gypi'],
110
+ 'dependencies': ['../node_addon_api.gyp:node_addon_api_maybe'],
108
111
  'sources': ['>@(build_sources)'],
109
- 'defines': ['NODE_ADDON_API_ENABLE_MAYBE']
110
112
  },
111
113
  {
112
114
  'target_name': 'binding_swallowexcept',
113
- 'includes': ['../except.gypi'],
115
+ 'dependencies': ['../node_addon_api.gyp:node_addon_api_except'],
114
116
  'sources': [ '>@(build_sources_swallowexcept)'],
115
117
  'defines': ['NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS']
116
118
  },
117
119
  {
118
120
  'target_name': 'binding_swallowexcept_noexcept',
119
- 'includes': ['../noexcept.gypi'],
121
+ 'dependencies': ['../node_addon_api.gyp:node_addon_api'],
120
122
  'sources': ['>@(build_sources_swallowexcept)'],
121
123
  'defines': ['NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS']
122
124
  },
123
125
  {
124
126
  'target_name': 'binding_type_check',
125
- 'includes': ['../noexcept.gypi'],
127
+ 'dependencies': ['../node_addon_api.gyp:node_addon_api'],
126
128
  'sources': ['>@(build_sources_type_check)'],
127
129
  'defines': ['NODE_ADDON_API_ENABLE_TYPE_CHECK_ON_AS']
128
130
  },
129
131
  {
130
132
  'target_name': 'binding_custom_namespace',
131
- 'includes': ['../noexcept.gypi'],
133
+ 'dependencies': ['../node_addon_api.gyp:node_addon_api'],
132
134
  'sources': ['>@(build_sources)'],
133
135
  'defines': ['NAPI_CPP_CUSTOM_NAMESPACE=cstm']
134
136
  },
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+ const assert = require('assert');
3
+
4
+ module.exports = {
5
+ workingCode: binding => {
6
+ const addon = binding.addon();
7
+ assert.strictEqual(addon.increment(), 43);
8
+ assert.strictEqual(addon.increment(), 44);
9
+ assert.strictEqual(addon.subObject.decrement(), 43);
10
+ }
11
+ };
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ const assert = require('assert');
4
+
5
+ // Make sure the instance data finalizer is called at process exit. If the hint
6
+ // is non-zero, it will be printed out by the child process.
7
+ const cleanupTest = (binding, hint) => {
8
+ binding.addon_data(hint).verbose = true;
9
+ };
10
+
11
+ module.exports = {
12
+ workingCode: binding => {
13
+ const addonData = binding.addon_data(0);
14
+
15
+ // Make sure it is possible to get/set instance data.
16
+ assert.strictEqual(addonData.verbose.verbose, false);
17
+ addonData.verbose = true;
18
+ assert.strictEqual(addonData.verbose.verbose, true);
19
+ addonData.verbose = false;
20
+ assert.strictEqual(addonData.verbose.verbose, false);
21
+ },
22
+ cleanupWithHint: binding => cleanupTest(binding, 42),
23
+ cleanupWithoutHint: binding => cleanupTest(binding, 0)
24
+ };
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ const assert = require('assert');
4
+ const testUtil = require('../testUtil');
5
+
6
+ module.exports = {
7
+ runTest: function (binding) {
8
+ return testUtil.runGCTests([
9
+ 'objectwrap function',
10
+ () => {
11
+ const { FunctionTest } = binding.objectwrap_function();
12
+ const newConstructed = new FunctionTest();
13
+ const functionConstructed = FunctionTest();
14
+ assert(newConstructed instanceof FunctionTest);
15
+ assert(functionConstructed instanceof FunctionTest);
16
+ assert.throws(() => (FunctionTest(true)), /an exception/);
17
+ },
18
+ // Do one gc before returning.
19
+ () => {}
20
+ ]);
21
+ }
22
+ };
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ const assert = require('assert');
4
+ const common = require('../common');
5
+
6
+ module.exports = {
7
+ testCall: async binding => {
8
+ const { testCall } = binding.threadsafe_function_exception;
9
+
10
+ await new Promise(resolve => {
11
+ process.once('uncaughtException', common.mustCall(err => {
12
+ assert.strictEqual(err.message, 'test');
13
+ resolve();
14
+ }, 1));
15
+
16
+ testCall(common.mustCall(() => {
17
+ throw new Error('test');
18
+ }, 1));
19
+ });
20
+ },
21
+ testCallWithNativeCallback: async binding => {
22
+ const { testCallWithNativeCallback } = binding.threadsafe_function_exception;
23
+
24
+ await new Promise(resolve => {
25
+ process.once('uncaughtException', common.mustCall(err => {
26
+ assert.strictEqual(err.message, 'test-from-native');
27
+ resolve();
28
+ }, 1));
29
+
30
+ testCallWithNativeCallback();
31
+ });
32
+ }
33
+ };
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ const assert = require('assert');
4
+ const common = require('../common');
5
+
6
+ module.exports = {
7
+ testCall: async binding => {
8
+ const { testCall } = binding.typed_threadsafe_function_exception;
9
+
10
+ await new Promise(resolve => {
11
+ process.once('uncaughtException', common.mustCall(err => {
12
+ assert.strictEqual(err.message, 'test-from-native');
13
+ resolve();
14
+ }, 1));
15
+
16
+ testCall();
17
+ });
18
+ }
19
+ };
@@ -3,6 +3,11 @@
3
3
  const assert = require('assert');
4
4
  const path = require('path');
5
5
  const { access } = require('node:fs/promises');
6
+ const { spawn } = require('child_process');
7
+ const { EOL } = require('os');
8
+ const readline = require('readline');
9
+
10
+ const escapeBackslashes = (pathString) => pathString.split('\\').join('\\\\');
6
11
 
7
12
  const noop = () => {};
8
13
 
@@ -26,7 +31,7 @@ function runCallChecks (exitCode) {
26
31
  context.name,
27
32
  context.messageSegment,
28
33
  context.actual);
29
- console.log(context.stack.split('\n').slice(2).join('\n'));
34
+ console.log(context.stack.split(EOL).slice(2).join(EOL));
30
35
  });
31
36
 
32
37
  if (failed.length) process.exit(1);
@@ -143,7 +148,7 @@ async function whichBuildType () {
143
148
  if (await checkBuildType(envBuildType)) {
144
149
  buildType = envBuildType;
145
150
  } else {
146
- throw new Error(`The ${envBuildType} build doesn't exists.`);
151
+ throw new Error(`The ${envBuildType} build doesn't exist.`);
147
152
  }
148
153
  } else {
149
154
  throw new Error('Invalid value for NODE_API_BUILD_CONFIG environment variable. It should be set to Release or Debug.');
@@ -164,7 +169,7 @@ exports.runTest = async function (test, buildType, buildPathRoot = process.env.B
164
169
  ].map(it => require.resolve(it));
165
170
 
166
171
  for (const item of bindings) {
167
- await Promise.resolve(test(require(item)))
172
+ await Promise.resolve(test(require(item), { bindingPath: item }))
168
173
  .finally(exports.mustCall());
169
174
  }
170
175
  };
@@ -190,3 +195,52 @@ exports.runTestWithBuildType = async function (test, buildType) {
190
195
  await Promise.resolve(test(buildType))
191
196
  .finally(exports.mustCall());
192
197
  };
198
+
199
+ // Some tests have to run in their own process, otherwise they would interfere
200
+ // with each other. Such tests export a factory function rather than the test
201
+ // itself so as to avoid automatic instantiation, and therefore interference,
202
+ // in the main process. Two examples are addon and addon_data, both of which
203
+ // use Napi::Env::SetInstanceData(). This helper function provides a common
204
+ // approach for running such tests.
205
+ exports.runTestInChildProcess = function ({ suite, testName, expectedStderr, execArgv }) {
206
+ return exports.runTestWithBindingPath((bindingName) => {
207
+ return new Promise((resolve) => {
208
+ bindingName = escapeBackslashes(bindingName);
209
+ // Test suites are assumed to be located here.
210
+ const suitePath = escapeBackslashes(path.join(__dirname, '..', 'child_processes', suite));
211
+ const child = spawn(process.execPath, [
212
+ '--expose-gc',
213
+ ...(execArgv ?? []),
214
+ '-e',
215
+ `require('${suitePath}').${testName}(require('${bindingName}'))`
216
+ ]);
217
+ const resultOfProcess = { stderr: [] };
218
+
219
+ // Capture the exit code and signal.
220
+ child.on('close', (code, signal) => resolve(Object.assign(resultOfProcess, { code, signal })));
221
+
222
+ // Capture the stderr as an array of lines.
223
+ readline
224
+ .createInterface({ input: child.stderr })
225
+ .on('line', (line) => {
226
+ resultOfProcess.stderr.push(line);
227
+ });
228
+ }).then(actual => {
229
+ // Back up the stderr in case the assertion fails.
230
+ const fullStderr = actual.stderr.map(item => `from child process: ${item}`);
231
+ const expected = { stderr: expectedStderr, code: 0, signal: null };
232
+
233
+ if (!expectedStderr) {
234
+ // If we don't care about stderr, delete it.
235
+ delete actual.stderr;
236
+ delete expected.stderr;
237
+ } else {
238
+ // Otherwise we only care about expected lines in the actual stderr, so
239
+ // filter out everything else.
240
+ actual.stderr = actual.stderr.filter(line => expectedStderr.includes(line));
241
+ }
242
+
243
+ assert.deepStrictEqual(actual, expected, `Assertion for child process test ${suite}.${testName} failed:${EOL}` + fullStderr.join(EOL));
244
+ });
245
+ });
246
+ };
@@ -0,0 +1,25 @@
1
+ #include "napi.h"
2
+ #include "test_helper.h"
3
+
4
+ #if (NAPI_VERSION > 8)
5
+
6
+ using namespace Napi;
7
+
8
+ namespace {
9
+
10
+ Value GetModuleFileName(const CallbackInfo& info) {
11
+ Env env = info.Env();
12
+ return String::New(env, env.GetModuleFileName());
13
+ }
14
+
15
+ } // end anonymous namespace
16
+
17
+ Object InitEnvMiscellaneous(Env env) {
18
+ Object exports = Object::New(env);
19
+
20
+ exports["get_module_file_name"] = Function::New(env, GetModuleFileName);
21
+
22
+ return exports;
23
+ }
24
+
25
+ #endif
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ const assert = require('assert');
4
+ const { pathToFileURL } = require('url');
5
+
6
+ module.exports = require('./common').runTest(test);
7
+
8
+ function test (binding, { bindingPath } = {}) {
9
+ const path = binding.env_misc.get_module_file_name();
10
+ const bindingFileUrl = pathToFileURL(bindingPath).toString();
11
+ assert(bindingFileUrl === path);
12
+ }