diff --git a/PORTING.md b/PORTING.md index 4607b87..dd42faf 100644 --- a/PORTING.md +++ b/PORTING.md @@ -58,7 +58,7 @@ Tests covering the engine-specific part of Node-API, defined in `js_native_api.h | `test_exception` | Ported ✅ | Medium | | `test_finalizer` | Ported ✅ | Medium | | `test_function` | Ported ✅ | Medium | -| `test_general` | Not ported | Hard | +| `test_general` | Partial | Hard | | `test_handle_scope` | Ported ✅ | Easy | | `test_instance_data` | Not ported | Medium | | `test_new_target` | Ported ✅ | Easy | diff --git a/tests/js-native-api/test_general/CMakeLists.txt b/tests/js-native-api/test_general/CMakeLists.txt new file mode 100644 index 0000000..1d36e70 --- /dev/null +++ b/tests/js-native-api/test_general/CMakeLists.txt @@ -0,0 +1 @@ +add_node_api_cts_addon(test_general test_general.c) diff --git a/tests/js-native-api/test_general/test.js b/tests/js-native-api/test_general/test.js new file mode 100644 index 0000000..54450d1 --- /dev/null +++ b/tests/js-native-api/test_general/test.js @@ -0,0 +1,96 @@ +const test_general = loadAddon('test_general'); + +const val1 = '1'; +const val2 = 1; +const val3 = 1; + +class BaseClass { +} + +class ExtendedClass extends BaseClass { +} + +const baseObject = new BaseClass(); +const extendedObject = new ExtendedClass(); + +// napi_strict_equals +assert.ok(test_general.testStrictEquals(val1, val1)); +assert.strictEqual(test_general.testStrictEquals(val1, val2), false); +assert.ok(test_general.testStrictEquals(val2, val3)); + +// napi_get_prototype +assert.strictEqual( + test_general.testGetPrototype(baseObject), + Object.getPrototypeOf(baseObject), +); +assert.strictEqual( + test_general.testGetPrototype(extendedObject), + Object.getPrototypeOf(extendedObject), +); +// Prototypes for base and extended should be different. +assert.notStrictEqual( + test_general.testGetPrototype(baseObject), + test_general.testGetPrototype(extendedObject), +); + +// napi_get_version. Upstream pins this to Node.js's own Node-API version; +// portably, the addon must report whatever version the runtime declares. +assert.strictEqual(test_general.testGetVersion(), napiVersion); + +// napi_typeof +[ + 123, + 'test string', + function() {}, + new Object(), + true, + undefined, + Symbol(), +].forEach((val) => { + assert.strictEqual(test_general.testNapiTypeof(val), typeof val); +}); + +// typeof null is 'object' in JS, so napi_null gets its own case. +assert.strictEqual(test_general.testNapiTypeof(null), 'null'); + +// Wrapping the same object twice fails. +const x = {}; +test_general.wrap(x); +assert.throws( + () => test_general.wrap(x), + { name: 'Error', message: 'Invalid argument' }, +); +// Clean up here, otherwise derefItemWasCalled() will be polluted. +test_general.removeWrap(x); + +// Wrapping twice succeeds if a removeWrap() separates the instances. +const y = {}; +test_general.wrap(y); +test_general.removeWrap(y); +test_general.wrap(y); +// Clean up here, otherwise derefItemWasCalled() will be polluted. +test_general.removeWrap(y); + +// napi_adjust_external_memory +const adjustedValue = test_general.testAdjustExternalMemory(); +assert.strictEqual(typeof adjustedValue, 'number'); +assert.ok(adjustedValue > 0); + +// Garbage collecting a wrapped object calls the finalizer. +assert.strictEqual(test_general.derefItemWasCalled(), false); + +(() => test_general.wrap({}))(); +await gcUntil( + 'deref_item() was called upon garbage collecting a wrapped object.', + () => test_general.derefItemWasCalled(), +); + +// Removing a wrap and then garbage collecting does not call the finalizer. +let z = {}; +test_general.testFinalizeWrap(z); +test_general.removeWrap(z); +z = null; +await gcUntil( + 'finalize callback was not called upon garbage collection.', + () => !test_general.finalizeWasCalled(), +); diff --git a/tests/js-native-api/test_general/testGlobals.js b/tests/js-native-api/test_general/testGlobals.js new file mode 100644 index 0000000..ad33b54 --- /dev/null +++ b/tests/js-native-api/test_general/testGlobals.js @@ -0,0 +1,4 @@ +const test_general = loadAddon('test_general'); + +assert.strictEqual(test_general.getUndefined(), undefined); +assert.strictEqual(test_general.getNull(), null); diff --git a/tests/js-native-api/test_general/testInstanceOf.js b/tests/js-native-api/test_general/testInstanceOf.js new file mode 100644 index 0000000..52f79b9 --- /dev/null +++ b/tests/js-native-api/test_general/testInstanceOf.js @@ -0,0 +1,41 @@ +const test_general = loadAddon('test_general'); + +// napi_instanceof must agree with the `instanceof` operator, including when a +// constructor overrides Symbol.hasInstance. +function compareToNative(theObject, theConstructor) { + assert.strictEqual( + test_general.doInstanceOf(theObject, theConstructor), + theObject instanceof theConstructor, + ); +} + +function MyClass() {} +Object.defineProperty(MyClass, Symbol.hasInstance, { + value: function(candidate) { + return 'mark' in candidate; + }, +}); + +function MySubClass() {} +MySubClass.prototype = new MyClass(); + +// MySubClass inherits MyClass's Symbol.hasInstance, so both constructors +// answer "does the candidate carry a mark?" rather than walking the prototype +// chain -- which is exactly what makes y fail against its own constructor. +let x = new MySubClass(); +let y = new MySubClass(); +x.mark = true; + +compareToNative(x, MySubClass); +compareToNative(y, MySubClass); +compareToNative(x, MyClass); +compareToNative(y, MyClass); + +x = new MyClass(); +y = new MyClass(); +x.mark = true; + +compareToNative(x, MySubClass); +compareToNative(y, MySubClass); +compareToNative(x, MyClass); +compareToNative(y, MyClass); diff --git a/tests/js-native-api/test_general/testNapiRun.js b/tests/js-native-api/test_general/testNapiRun.js new file mode 100644 index 0000000..d11ed81 --- /dev/null +++ b/tests/js-native-api/test_general/testNapiRun.js @@ -0,0 +1,7 @@ +const test_general = loadAddon('test_general'); + +assert.strictEqual(test_general.testNapiRun('(41.92 + 0.08);'), 42); +assert.throws( + () => test_general.testNapiRun({ abc: 'def' }), + /string was expected/, +); diff --git a/tests/js-native-api/test_general/testNapiStatus.js b/tests/js-native-api/test_general/testNapiStatus.js new file mode 100644 index 0000000..1a1cdf3 --- /dev/null +++ b/tests/js-native-api/test_general/testNapiStatus.js @@ -0,0 +1,10 @@ +const test_general = loadAddon('test_general'); + +// createNapiError provokes a failing call, then checks that +// napi_get_last_error_info reports that failure. The next successful call must +// reset the recorded status back to napi_ok. +test_general.createNapiError(); +assert.ok( + test_general.testNapiErrorCleanup(), + 'napi_status cleaned up for second call', +); diff --git a/tests/js-native-api/test_general/testV8Instanceof.js b/tests/js-native-api/test_general/testV8Instanceof.js new file mode 100644 index 0000000..6d274b0 --- /dev/null +++ b/tests/js-native-api/test_general/testV8Instanceof.js @@ -0,0 +1,99 @@ +// This test is adopted from V8's test suite. +// See deps/v8/test/mjsunit/instanceof.js in Node.js source repository. +// +// Copyright 2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +const addon = loadAddon('test_general'); + +assert.ok(addon.doInstanceOf({}, Object)); +assert.ok(addon.doInstanceOf([], Object)); + +assert.ok(!addon.doInstanceOf({}, Array)); +assert.ok(addon.doInstanceOf([], Array)); + +function TestChains() { + const A = {}; + const B = {}; + const C = {}; + Object.setPrototypeOf(B, A); + Object.setPrototypeOf(C, B); + + function F() { } + F.prototype = A; + assert.ok(addon.doInstanceOf(C, F)); + assert.ok(addon.doInstanceOf(B, F)); + assert.ok(!addon.doInstanceOf(A, F)); + + F.prototype = B; + assert.ok(addon.doInstanceOf(C, F)); + assert.ok(!addon.doInstanceOf(B, F)); + assert.ok(!addon.doInstanceOf(A, F)); + + F.prototype = C; + assert.ok(!addon.doInstanceOf(C, F)); + assert.ok(!addon.doInstanceOf(B, F)); + assert.ok(!addon.doInstanceOf(A, F)); +} + +TestChains(); + +function TestExceptions() { + function F() { } + const items = [ 1, new Number(42), + true, + 'string', new String('hest'), + {}, [], + F, new F(), + Object, String ]; + + let exceptions = 0; + let instanceofs = 0; + + for (let i = 0; i < items.length; i++) { + for (let j = 0; j < items.length; j++) { + try { + if (addon.doInstanceOf(items[i], items[j])) instanceofs++; + } catch (e) { + assert.ok(addon.doInstanceOf(e, TypeError)); + exceptions++; + } + } + } + assert.strictEqual(instanceofs, 10); + assert.strictEqual(exceptions, 88); + + // Make sure to throw an exception if the function prototype + // isn't a proper JavaScript object. + function G() { } + G.prototype = undefined; + assert.throws(function() { + addon.doInstanceOf({}, G); + }, Error); +} + +TestExceptions(); diff --git a/tests/js-native-api/test_general/testV8Instanceof2.js b/tests/js-native-api/test_general/testV8Instanceof2.js new file mode 100644 index 0000000..9a49531 --- /dev/null +++ b/tests/js-native-api/test_general/testV8Instanceof2.js @@ -0,0 +1,335 @@ +// This test is adopted from V8's test suite. +// See deps/v8/test/mjsunit/instanceof-2.js in Node.js source repository. +// +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +const addon = loadAddon('test_general'); + +const except = 'exception'; + +let correct_answer_index = 0; +const correct_answers = [ + false, false, true, true, false, false, true, true, + true, false, false, true, true, false, false, true, + false, true, true, false, false, true, true, false, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, false, true, + except, except, true, false, except, except, true, false, + except, except, false, false, except, except, false, false, + false, false, except, except, false, false, except, except, + true, false, except, except, true, false, except, except, + false, true, except, except, false, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, false, false, true, true, + true, false, false, true, false, false, true, true, + false, true, true, false, false, true, true, false, + true, true, false, false, false, true, true, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, true, false, + except, except, false, false, except, except, true, false, + false, false, except, except, false, false, except, except, + true, false, except, except, true, false, except, except, + false, true, except, except, false, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, false, true, true, false, + true, false, false, true, true, true, false, false, + false, true, true, false, false, true, true, false, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, false, true, + except, except, true, false, except, except, true, false, + except, except, false, false, except, except, false, false, + false, false, except, except, false, true, except, except, + true, false, except, except, true, true, except, except, + false, true, except, except, false, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, false, true, true, false, + true, false, false, true, false, true, true, false, + false, true, true, false, false, true, true, false, + true, true, false, false, false, true, true, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, true, false, + except, except, false, false, except, except, true, false, + false, false, except, except, false, true, except, except, + true, false, except, except, true, true, except, except, + false, true, except, except, false, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, false, false, true, true, + true, false, false, true, false, false, true, true, + false, true, true, false, true, true, false, false, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, false, false, + except, except, false, false, except, except, false, false, + false, false, except, except, false, false, except, except, + true, false, except, except, false, false, except, except, + false, true, except, except, true, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, false, false, true, true, + true, false, false, true, false, false, true, true, + false, true, true, false, true, true, false, false, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, false, false, + except, except, false, false, except, except, false, false, + false, false, except, except, false, false, except, except, + true, false, except, except, false, false, except, except, + false, true, except, except, true, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, true, true, false, false, + true, false, false, true, true, true, false, false, + false, true, true, false, true, true, false, false, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, false, false, + except, except, false, false, except, except, false, false, + false, false, except, except, true, true, except, except, + true, false, except, except, true, true, except, except, + false, true, except, except, true, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, true, true, false, false, + true, false, false, true, true, true, false, false, + false, true, true, false, true, true, false, false, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, false, false, + except, except, false, false, except, except, false, false, + false, false, except, except, true, true, except, except, + true, false, except, except, true, true, except, except, + false, true, except, except, true, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, false, false, true, true, + true, false, false, true, true, true, false, false, + false, true, true, false, false, false, true, true, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, false, false, + except, except, true, false, except, except, true, true, + except, except, false, false, except, except, false, false, + false, false, except, except, false, false, except, except, + true, false, except, except, true, true, except, except, + false, true, except, except, false, false, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, false, false, true, true, + true, false, false, true, false, false, true, true, + false, true, true, false, false, false, true, true, + true, true, false, false, false, false, true, true, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, true, true, + except, except, false, false, except, except, true, true, + false, false, except, except, false, false, except, except, + true, false, except, except, true, true, except, except, + false, true, except, except, false, false, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, false, false, true, true, + true, false, false, true, true, true, false, false, + false, true, true, false, false, false, true, true, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, false, false, + except, except, true, false, except, except, true, true, + except, except, false, false, except, except, false, false, + false, false, except, except, false, false, except, except, + true, false, except, except, true, true, except, except, + false, true, except, except, false, false, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, false, false, true, true, + true, false, false, true, false, false, true, true, + false, true, true, false, false, false, true, true, + true, true, false, false, false, false, true, true, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, true, true, + except, except, false, false, except, except, true, true, + false, false, except, except, false, false, except, except, + true, false, except, except, true, true, except, except, + false, true, except, except, false, false, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, false, false, true, true, + true, false, false, true, false, false, true, true, + false, true, true, false, true, true, false, false, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, false, false, + except, except, false, false, except, except, false, false, + false, false, except, except, false, false, except, except, + true, false, except, except, false, false, except, except, + false, true, except, except, true, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, false, false, true, true, + true, false, false, true, false, false, true, true, + false, true, true, false, true, true, false, false, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, false, false, + except, except, false, false, except, except, false, false, + false, false, except, except, false, false, except, except, + true, false, except, except, false, false, except, except, + false, true, except, except, true, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, true, true, false, false, + true, false, false, true, true, true, false, false, + false, true, true, false, true, true, false, false, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, false, false, + except, except, false, false, except, except, false, false, + false, false, except, except, true, true, except, except, + true, false, except, except, true, true, except, except, + false, true, except, except, true, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + false, false, true, true, true, true, false, false, + true, false, false, true, true, true, false, false, + false, true, true, false, true, true, false, false, + true, true, false, false, true, true, false, false, + except, except, true, true, except, except, true, true, + except, except, false, true, except, except, true, true, + except, except, true, false, except, except, false, false, + except, except, false, false, except, except, false, false, + false, false, except, except, true, true, except, except, + true, false, except, except, true, true, except, except, + false, true, except, except, true, true, except, except, + true, true, except, except, true, true, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except, + except, except, except, except, except, except, except, except]; + +for (let i = 0; i < 256; i++) { + Test(i & 1, i & 2, i & 4, i & 8, i & 0x10, i & 0x20, i & 0x40, i & 0x80); +} + + +function InstanceTest(x, func) { + try { + const answer = addon.doInstanceOf(x, func); + assert.strictEqual(correct_answers[correct_answer_index], answer); + } catch (e) { + assert.match(`${e}`, /prototype/); + assert.strictEqual(correct_answers[correct_answer_index], except); + } + correct_answer_index++; +} + + +function Test(a, b, c, d, e, f, g, h) { + function Foo() { } + + function Bar() { } + + if (c) Foo.prototype = 12; + if (d) Bar.prototype = 13; + const x = a ? new Foo() : new Bar(); + const y = b ? new Foo() : new Bar(); + InstanceTest(x, Foo); + InstanceTest(y, Foo); + InstanceTest(x, Bar); + InstanceTest(y, Bar); + if (e) x.__proto__ = Bar.prototype; + if (f) y.__proto__ = Foo.prototype; + if (g) { + Object.setPrototypeOf(x, y); + } else if (h) { + Object.setPrototypeOf(y, x); + } + InstanceTest(x, Foo); + InstanceTest(y, Foo); + InstanceTest(x, Bar); + InstanceTest(y, Bar); +} diff --git a/tests/js-native-api/test_general/test_general.c b/tests/js-native-api/test_general/test_general.c new file mode 100644 index 0000000..a08512f --- /dev/null +++ b/tests/js-native-api/test_general/test_general.c @@ -0,0 +1,244 @@ +#include +#include +#include "../common.h" +#include "../entry_point.h" + +static napi_value testStrictEquals(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2]; + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + bool bool_result; + napi_value result; + NODE_API_CALL(env, napi_strict_equals(env, args[0], args[1], &bool_result)); + NODE_API_CALL(env, napi_get_boolean(env, bool_result, &result)); + + return result; +} + +static napi_value testGetPrototype(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 result; + NODE_API_CALL(env, napi_get_prototype(env, args[0], &result)); + + return result; +} + +static napi_value testGetVersion(napi_env env, napi_callback_info info) { + uint32_t version; + napi_value result; + NODE_API_CALL(env, napi_get_version(env, &version)); + NODE_API_CALL(env, napi_create_uint32(env, version, &result)); + return result; +} + +static napi_value doInstanceOf(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2]; + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + bool is_instance; + NODE_API_CALL(env, napi_instanceof(env, args[0], args[1], &is_instance)); + + napi_value result; + NODE_API_CALL(env, napi_get_boolean(env, is_instance, &result)); + + return result; +} + +static napi_value getNull(napi_env env, napi_callback_info info) { + napi_value result; + NODE_API_CALL(env, napi_get_null(env, &result)); + return result; +} + +static napi_value getUndefined(napi_env env, napi_callback_info info) { + napi_value result; + NODE_API_CALL(env, napi_get_undefined(env, &result)); + return result; +} + +static napi_value createNapiError(napi_env env, napi_callback_info info) { + napi_value value; + NODE_API_CALL(env, napi_create_string_utf8(env, "xyz", 3, &value)); + + double double_value; + napi_status status = napi_get_value_double(env, value, &double_value); + + NODE_API_ASSERT(env, status != napi_ok, "Failed to produce error condition"); + + const napi_extended_error_info* error_info = 0; + NODE_API_CALL(env, napi_get_last_error_info(env, &error_info)); + + NODE_API_ASSERT(env, + error_info->error_code == status, + "Last error info code should match last status"); + NODE_API_ASSERT(env, + error_info->error_message, + "Last error info message should not be null"); + + return NULL; +} + +static napi_value testNapiErrorCleanup(napi_env env, napi_callback_info info) { + const napi_extended_error_info* error_info = 0; + NODE_API_CALL(env, napi_get_last_error_info(env, &error_info)); + + napi_value result; + bool is_ok = error_info->error_code == napi_ok; + NODE_API_CALL(env, napi_get_boolean(env, is_ok, &result)); + + return result; +} + +static napi_value testNapiTypeof(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_valuetype argument_type; + NODE_API_CALL(env, napi_typeof(env, args[0], &argument_type)); + + const char* name = NULL; + switch (argument_type) { + case napi_number: name = "number"; break; + case napi_string: name = "string"; break; + case napi_function: name = "function"; break; + case napi_object: name = "object"; break; + case napi_boolean: name = "boolean"; break; + case napi_undefined: name = "undefined"; break; + case napi_symbol: name = "symbol"; break; + case napi_null: name = "null"; break; + default: return NULL; + } + + napi_value result; + NODE_API_CALL( + env, napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &result)); + return result; +} + +static bool deref_item_called = false; + +static void deref_item(node_api_basic_env env, void* data, void* hint) { + (void)hint; + + NODE_API_BASIC_ASSERT_RETURN_VOID( + data == &deref_item_called, + "Finalize callback was called with the correct pointer"); + + deref_item_called = true; +} + +static napi_value deref_item_was_called(napi_env env, napi_callback_info info) { + napi_value it_was_called; + + NODE_API_CALL(env, napi_get_boolean(env, deref_item_called, &it_was_called)); + + return it_was_called; +} + +static napi_value wrap_first_arg(napi_env env, + napi_callback_info info, + node_api_basic_finalize finalizer, + void* data) { + size_t argc = 1; + napi_value to_wrap; + + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &to_wrap, NULL, NULL)); + NODE_API_CALL(env, napi_wrap(env, to_wrap, data, finalizer, NULL, NULL)); + + return to_wrap; +} + +static napi_value wrap(napi_env env, napi_callback_info info) { + deref_item_called = false; + return wrap_first_arg(env, info, deref_item, &deref_item_called); +} + +static napi_value remove_wrap(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value wrapped; + void* data; + + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &wrapped, NULL, NULL)); + NODE_API_CALL(env, napi_remove_wrap(env, wrapped, &data)); + + return NULL; +} + +static bool finalize_called = false; + +static void test_finalize(node_api_basic_env env, void* data, void* hint) { + (void)env; + (void)data; + (void)hint; + + finalize_called = true; +} + +static napi_value test_finalize_wrap(napi_env env, napi_callback_info info) { + return wrap_first_arg(env, info, test_finalize, NULL); +} + +static napi_value finalize_was_called(napi_env env, napi_callback_info info) { + napi_value it_was_called; + + NODE_API_CALL(env, napi_get_boolean(env, finalize_called, &it_was_called)); + + return it_was_called; +} + +static napi_value testAdjustExternalMemory(napi_env env, + napi_callback_info info) { + napi_value result; + int64_t adjustedValue; + + NODE_API_CALL(env, napi_adjust_external_memory(env, 1, &adjustedValue)); + NODE_API_CALL(env, napi_create_double(env, (double)adjustedValue, &result)); + + return result; +} + +static napi_value testNapiRun(napi_env env, napi_callback_info info) { + napi_value script, result; + size_t argc = 1; + + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &script, NULL, NULL)); + NODE_API_CALL(env, napi_run_script(env, script, &result)); + + return result; +} + +EXTERN_C_START +napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + DECLARE_NODE_API_PROPERTY("testStrictEquals", testStrictEquals), + DECLARE_NODE_API_PROPERTY("testGetPrototype", testGetPrototype), + DECLARE_NODE_API_PROPERTY("testGetVersion", testGetVersion), + DECLARE_NODE_API_PROPERTY("testNapiRun", testNapiRun), + DECLARE_NODE_API_PROPERTY("doInstanceOf", doInstanceOf), + DECLARE_NODE_API_PROPERTY("getUndefined", getUndefined), + DECLARE_NODE_API_PROPERTY("getNull", getNull), + DECLARE_NODE_API_PROPERTY("createNapiError", createNapiError), + DECLARE_NODE_API_PROPERTY("testNapiErrorCleanup", testNapiErrorCleanup), + DECLARE_NODE_API_PROPERTY("testNapiTypeof", testNapiTypeof), + DECLARE_NODE_API_PROPERTY("wrap", wrap), + DECLARE_NODE_API_PROPERTY("removeWrap", remove_wrap), + DECLARE_NODE_API_PROPERTY("testFinalizeWrap", test_finalize_wrap), + DECLARE_NODE_API_PROPERTY("finalizeWasCalled", finalize_was_called), + DECLARE_NODE_API_PROPERTY("derefItemWasCalled", deref_item_was_called), + DECLARE_NODE_API_PROPERTY("testAdjustExternalMemory", + testAdjustExternalMemory)}; + + NODE_API_CALL( + env, + napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors)); + + return exports; +} +EXTERN_C_END