XNSim/XNSimHtml/node_modules/ffi-napi/test/foreign_function.js

216 lines
7.7 KiB
JavaScript
Raw Normal View History

2025-04-28 12:25:20 +08:00
'use strict';
const assert = require('assert');
const ref = require('ref-napi');
const Array = require('ref-array-di')(ref);
const Struct = require('ref-struct-di')(ref);
const ffi = require('../');
const bindings = require('node-gyp-build')(__dirname);
describe('ForeignFunction', function () {
afterEach(global.gc);
// these structs are also defined in ffi_tests.cc
const box = Struct({
width: ref.types.int,
height: ref.types.int
});
const arst = Struct({
num: 'int',
array: Array('double', 20)
});
it('should call the static "abs" bindings', function () {
const _abs = bindings.abs;
const abs = ffi.ForeignFunction(_abs, 'int', [ 'int' ]);
assert.strictEqual('function', typeof abs);
assert.strictEqual(1234, abs(-1234));
})
it('should throw an Error with a meaningful message when type\'s `set()` throws', function () {
const _abs = bindings.abs;
const abs = ffi.ForeignFunction(_abs, 'int', [ 'int' ]);
assert.throws(function () {
// Changed, because returning string is not failing because of this; https://github.com/iojs/io.js/issues/1161
abs(11111111111111111111);
}, /error setting argument 1/);
});
it('should call the static "atoi" bindings', function () {
const _atoi = bindings.atoi;
const atoi = ffi.ForeignFunction(_atoi, 'int', [ 'string' ]);
assert.strictEqual('function', typeof atoi);
assert.strictEqual(1234, atoi('1234'));
});
it('should call the static "double_box" bindings', function () {
const double_box = ffi.ForeignFunction(bindings.double_box, box, [ box ]);
const b = new box;
assert(b instanceof box);
b.width = 4;
b.height = 5;
const out = double_box(b);
// double_box writes to its input "box" struct, so make sure that the one we
// passed in remains unaffected (since we passed it in by value, not pointer)
assert.strictEqual(4, b.width);
assert.strictEqual(5, b.height);
assert(out instanceof box);
assert.strictEqual(8, out.width);
assert.strictEqual(10, out.height);
assert.notStrictEqual(b.ref().address(), out.ref().address());
});
it('should call the static "double_box_ptr" bindings', function () {
const boxPtr = ref.refType(box);
const double_box_ptr = ffi.ForeignFunction(bindings.double_box_ptr, box, [ boxPtr ]);
const b = new box;
b.width = 4;
b.height = 5;
const out = double_box_ptr(b.ref());
// double_box_ptr writes to its input "box" struct, so make sure that the one
// we passed in has it's values changed (since we passed it in by pointer)
assert.strictEqual(8, b.width);
assert.strictEqual(10, b.height);
assert(out instanceof box);
assert.strictEqual(8, out.width);
assert.strictEqual(10, out.height);
assert.notStrictEqual(b.ref().address(), out.ref().address());
});
it('should call the static "area_box" bindings', function () {
const area_box = ffi.ForeignFunction(bindings.area_box, ref.types.int, [ box ]);
const b = new box({ width: 5, height: 20 });
const rtn = area_box(b);
assert.strictEqual('number', typeof rtn);
assert.strictEqual(100, rtn);
});
it('should call the static "area_box_ptr" bindings', function () {
const boxPtr = ref.refType(box);
const area_box = ffi.ForeignFunction(bindings.area_box_ptr, ref.types.int, [ boxPtr ]);
const b = new box({ width: 5, height: 20 });
const rtn = area_box(b.ref());
assert.strictEqual('number', typeof rtn);
assert.strictEqual(100, rtn);
});
it('should call the static "create_box" bindings', function () {
const create_box = ffi.ForeignFunction(bindings.create_box, box, [ 'int', 'int' ]);
const rtn = create_box(1, 2);
assert(rtn instanceof box);
assert.strictEqual(1, rtn.width);
assert.strictEqual(2, rtn.height);
});
it('should call the static "add_boxes" bindings', function () {
const count = 3;
const boxes = new Buffer(box.size * count);
box.set(boxes, box.size * 0, { width: 1, height: 10 });
box.set(boxes, box.size * 1, { width: 2, height: 20 });
box.set(boxes, box.size * 2, { width: 3, height: 30 });
const boxPtr = ref.refType(box);
const add_boxes = ffi.ForeignFunction(bindings.add_boxes, box, [ boxPtr, 'int' ]);
const rtn = add_boxes(boxes, count);
assert(rtn instanceof box);
assert.strictEqual(6, rtn.width);
assert.strictEqual(60, rtn.height);
});
it('should call the static "int_array" bindings', function () {
const IntArray = Array('int');
const int_array = ffi.ForeignFunction(bindings.int_array, IntArray, [ IntArray ]);
const array = new IntArray([ 1, 2, 3, 4, 5, -1 ]);
const out = int_array(array);
out.length = array.length;
assert.strictEqual(2, out[0]);
assert.strictEqual(4, out[1]);
assert.strictEqual(6, out[2]);
assert.strictEqual(8, out[3]);
assert.strictEqual(10, out[4]);
assert.strictEqual(-1, out[5]);
});
it('should call the static "array_in_struct" bindings', function () {
const array_in_struct = ffi.ForeignFunction(bindings.array_in_struct, arst, [ arst ]);
const a = new arst;
assert.strictEqual(20, a.array.length);
a.num = 69;
for (let i = 0; i < 20; i++) {
a.array[i] = i / 3.14;
}
const b = array_in_struct(a);
assert(b instanceof arst);
assert.strictEqual(138, b.num);
assert.strictEqual(20, b.array.length);
for (let i = 0; i < 20; i++) {
// Math.round() because of floating point rounding erros
assert.strictEqual(i, Math.round(b.array[i]));
}
});
// allow a Buffer backing store to be used as a "string" FFI argument
// https://github.com/node-ffi/node-ffi/issues/169
it('should call the static "test_169" bindings', function () {
const test = ffi.ForeignFunction(bindings.test_169, 'int', [ 'string', 'int' ]);
const b = new Buffer(20);
const len = test(b, b.length);
assert.strictEqual('sample str', b.toString('ascii', 0, len));
});
// testing `bool` ref type
// https://github.com/TooTallNate/ref/issues/56
it('should call the static "test_169" bindings', function () {
const Obj56 = Struct({
'traceMode': ref.types.bool
});
const t = new Obj56({ traceMode: true });
const f = new Obj56({ traceMode: false });
const test = ffi.ForeignFunction(bindings.test_ref_56, 'int', [ ref.refType(Obj56) ]);
assert.strictEqual(1, test(t.ref()));
assert.strictEqual(0, test(f.ref()));
});
it('should not call the "ref()" function of its arguments', function () {
const void_ptr_arg = ffi.ForeignFunction(bindings.abs, 'void *', [ 'void *' ]);
const b = new Buffer(0);
b.ref = assert.bind(null, 0, '"ref()" should not be called');
void_ptr_arg(b);
});
describe('async', function () {
it('should call the static "abs" bindings asynchronously', function (done) {
const _abs = bindings.abs;
const abs = ffi.ForeignFunction(_abs, 'int', [ 'int' ]);
assert.strictEqual('function', typeof abs.async);
// invoke asynchronously
abs.async(-1234, function (err, res) {
assert.strictEqual(null, err);
assert.strictEqual(1234, res);
done();
});
});
it('should invoke the callback with an Error with a meaningful message when type\'s `set()` throws', function (done) {
const _abs = bindings.abs;
const abs = ffi.ForeignFunction(_abs, 'int', [ 'int' ]);
// Changed, because returning string is not failing because of this; https://github.com/iojs/io.js/issues/1161
abs.async(1111111111111111111111, function (err, res) {
try {
assert(err);
assert(/error setting argument 0/.test(err.message));
assert.strictEqual('undefined', typeof res);
done();
}
catch (e) {
done(e);
}
});
});
});
});