diff --git a/test/addons/make-callback/binding.cc b/test/addons/make-callback/binding.cc new file mode 100644 index 00000000000000..3012a39ff70a73 --- /dev/null +++ b/test/addons/make-callback/binding.cc @@ -0,0 +1,40 @@ +#include "node.h" +#include "v8.h" + +#include "../../../src/util.h" + +#include + +namespace { + +void MakeCallback(const v8::FunctionCallbackInfo& args) { + CHECK(args[0]->IsObject()); + CHECK(args[1]->IsFunction() || args[1]->IsString()); + auto isolate = args.GetIsolate(); + auto recv = args[0].As(); + std::vector> argv; + for (size_t n = 2; n < static_cast(args.Length()); n += 1) { + argv.push_back(args[n]); + } + v8::Local result; + if (args[1]->IsFunction()) { + auto method = args[1].As(); + result = + node::MakeCallback(isolate, recv, method, argv.size(), argv.data()); + } else if (args[1]->IsString()) { + auto method = args[1].As(); + result = + node::MakeCallback(isolate, recv, method, argv.size(), argv.data()); + } else { + UNREACHABLE(); + } + args.GetReturnValue().Set(result); +} + +void Initialize(v8::Local target) { + NODE_SET_METHOD(target, "makeCallback", MakeCallback); +} + +} // namespace anonymous + +NODE_MODULE(binding, Initialize) diff --git a/test/addons/make-callback/binding.gyp b/test/addons/make-callback/binding.gyp new file mode 100644 index 00000000000000..3bfb84493f3e87 --- /dev/null +++ b/test/addons/make-callback/binding.gyp @@ -0,0 +1,8 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'sources': [ 'binding.cc' ] + } + ] +} diff --git a/test/addons/make-callback/test.js b/test/addons/make-callback/test.js new file mode 100644 index 00000000000000..80ea0db796ab30 --- /dev/null +++ b/test/addons/make-callback/test.js @@ -0,0 +1,61 @@ +'use strict'; + +const common = require('../../common'); +const assert = require('assert'); +const vm = require('vm'); +const binding = require('./build/Release/binding'); +const makeCallback = binding.makeCallback; + +assert.strictEqual(42, makeCallback(process, common.mustCall(function() { + assert.strictEqual(0, arguments.length); + assert.strictEqual(this, process); + return 42; +}))); + +assert.strictEqual(42, makeCallback(process, common.mustCall(function(x) { + assert.strictEqual(1, arguments.length); + assert.strictEqual(this, process); + assert.strictEqual(x, 1337); + return 42; +}), 1337)); + +const recv = { + one: common.mustCall(function() { + assert.strictEqual(0, arguments.length); + assert.strictEqual(this, recv); + return 42; + }), + two: common.mustCall(function(x) { + assert.strictEqual(1, arguments.length); + assert.strictEqual(this, recv); + assert.strictEqual(x, 1337); + return 42; + }), +}; + +assert.strictEqual(42, makeCallback(recv, 'one')); +assert.strictEqual(42, makeCallback(recv, 'two', 1337)); + +// Check that the callback is made in the context of the receiver. +const target = vm.runInNewContext(` + (function($Object) { + if (Object === $Object) + throw Error('bad'); + return Object; + }) +`); +assert.notStrictEqual(Object, makeCallback(process, target, Object)); + +// Runs in inner context. +const forward = vm.runInNewContext(` + (function(forward) { + return forward(Object); + }) +`); +// Runs in outer context. +const endpoint = function($Object) { + if (Object === $Object) + throw Error('bad'); + return Object; +}; +assert.strictEqual(Object, makeCallback(process, forward, endpoint));