| 'use strict'; |
| |
| const assert = require('assert'); |
| const asyncHook = require('async_hooks'); |
| |
| module.exports = require('./common').runTest(async (binding) => { |
| await test(binding.functionreference); |
| }); |
| |
| function installAsyncHook () { |
| let id; |
| let destroyed; |
| let hook; |
| const events = []; |
| return new Promise((resolve, reject) => { |
| const interval = setInterval(() => { |
| if (destroyed) { |
| hook.disable(); |
| clearInterval(interval); |
| resolve(events); |
| } |
| }, 10); |
| |
| hook = asyncHook |
| .createHook({ |
| init (asyncId, type, triggerAsyncId, resource) { |
| if (id === undefined && type === 'func_ref_resources') { |
| id = asyncId; |
| events.push({ eventName: 'init', type, triggerAsyncId, resource }); |
| } |
| }, |
| before (asyncId) { |
| if (asyncId === id) { |
| events.push({ eventName: 'before' }); |
| } |
| }, |
| after (asyncId) { |
| if (asyncId === id) { |
| events.push({ eventName: 'after' }); |
| } |
| }, |
| destroy (asyncId) { |
| if (asyncId === id) { |
| events.push({ eventName: 'destroy' }); |
| destroyed = true; |
| } |
| } |
| }) |
| .enable(); |
| }); |
| } |
| |
| function canConstructRefFromExistingRef (binding) { |
| const testFunc = () => 240; |
| assert(binding.ConstructWithMove(testFunc) === 240); |
| } |
| |
| function canCallFunctionWithDifferentOverloads (binding) { |
| let outsideRef = {}; |
| const testFunc = (a, b) => a * a - b * b; |
| const testFuncB = (a, b, c) => a + b - c * c; |
| const testFuncC = (a, b, c) => { |
| outsideRef.a = a; |
| outsideRef.b = b; |
| outsideRef.c = c; |
| }; |
| const testFuncD = (a, b, c, d) => { |
| outsideRef.result = a + b * c - d; |
| return outsideRef.result; |
| }; |
| |
| assert(binding.CallWithVec(testFunc, 5, 4) === testFunc(5, 4)); |
| assert(binding.CallWithInitList(testFuncB, 2, 4, 5) === testFuncB(2, 4, 5)); |
| |
| binding.CallWithRecvVector(testFuncC, outsideRef, 1, 2, 4); |
| assert(outsideRef.a === 1 && outsideRef.b === 2 && outsideRef.c === 4); |
| |
| outsideRef = {}; |
| binding.CallWithRecvInitList(testFuncC, outsideRef, 1, 2, 4); |
| assert(outsideRef.a === 1 && outsideRef.b === 2 && outsideRef.c === 4); |
| |
| outsideRef = {}; |
| binding.CallWithRecvArgc(testFuncD, outsideRef, 2, 4, 5, 6); |
| assert(outsideRef.result === testFuncD(2, 4, 5, 6)); |
| } |
| |
| async function canCallAsyncFunctionWithDifferentOverloads (binding) { |
| const testFunc = () => 2100; |
| const testFuncB = (a, b, c, d) => a + b + c + d; |
| let hook = installAsyncHook(); |
| binding.AsyncCallWithInitList(testFunc); |
| let triggerAsyncId = asyncHook.executionAsyncId(); |
| let res = await hook; |
| assert.deepStrictEqual(res, [ |
| { |
| eventName: 'init', |
| type: 'func_ref_resources', |
| triggerAsyncId, |
| resource: {} |
| }, |
| { eventName: 'before' }, |
| { eventName: 'after' }, |
| { eventName: 'destroy' } |
| ]); |
| |
| hook = installAsyncHook(); |
| triggerAsyncId = asyncHook.executionAsyncId(); |
| assert( |
| binding.AsyncCallWithVector(testFuncB, 2, 4, 5, 6) === testFuncB(2, 4, 5, 6) |
| ); |
| res = await hook; |
| assert.deepStrictEqual(res, [ |
| { |
| eventName: 'init', |
| type: 'func_ref_resources', |
| triggerAsyncId, |
| resource: {} |
| }, |
| { eventName: 'before' }, |
| { eventName: 'after' }, |
| { eventName: 'destroy' } |
| ]); |
| |
| hook = installAsyncHook(); |
| triggerAsyncId = asyncHook.executionAsyncId(); |
| assert( |
| binding.AsyncCallWithArgv(testFuncB, 2, 4, 5, 6) === testFuncB(2, 4, 5, 6) |
| ); |
| } |
| async function test (binding) { |
| const e = new Error('foobar'); |
| const functionMayThrow = () => { |
| throw e; |
| }; |
| const classMayThrow = class { |
| constructor () { |
| throw e; |
| } |
| }; |
| |
| const newRef = binding.CreateFuncRefWithNew(120); |
| assert(newRef.getValue() === 120); |
| |
| const newRefWithVecArg = binding.CreateFuncRefWithNewVec(80); |
| assert(newRefWithVecArg.getValue() === 80); |
| |
| assert.throws(() => { |
| binding.call(functionMayThrow); |
| }, /foobar/); |
| assert.throws(() => { |
| binding.construct(classMayThrow); |
| }, /foobar/); |
| |
| canConstructRefFromExistingRef(binding); |
| canCallFunctionWithDifferentOverloads(binding); |
| await canCallAsyncFunctionWithDifferentOverloads(binding); |
| } |