UNPKG

ffi

Version:

A foreign function interface (FFI) for Node.js

220 lines (190 loc) 7.42 kB
var assert = require('assert') , ref = require('ref') , Array = require('ref-array') , Struct = require('ref-struct') , ffi = require('../') , bindings = require('bindings')({ module_root: __dirname, bindings: 'ffi_tests' }) describe('ForeignFunction', function () { afterEach(gc) // these structs are also defined in ffi_tests.cc var box = Struct({ width: ref.types.int , height: ref.types.int }) var arst = Struct({ num: 'int' , array: Array('double', 20) }) it('should call the static "abs" bindings', function () { var _abs = bindings.abs var abs = ffi.ForeignFunction(_abs, 'int', [ 'int' ]) assert.equal('function', typeof abs) assert.equal(1234, abs(-1234)) }) it('should throw an Error with a meaningful message when type\'s `set()` throws', function () { var _abs = bindings.abs var 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 0/) }) it('should call the static "atoi" bindings', function () { var _atoi = bindings.atoi var atoi = ffi.ForeignFunction(_atoi, 'int', [ 'string' ]) assert.equal('function', typeof atoi) assert.equal(1234, atoi('1234')) }) it('should call the static "double_box" bindings', function () { var double_box = ffi.ForeignFunction(bindings.double_box, box, [ box ]) var b = new box assert(b instanceof box) b.width = 4 b.height = 5 var 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.equal(4, b.width) assert.equal(5, b.height) assert(out instanceof box) assert.equal(8, out.width) assert.equal(10, out.height) assert.notEqual(b.ref().address(), out.ref().address()) }) it('should call the static "double_box_ptr" bindings', function () { var boxPtr = ref.refType(box) var double_box_ptr = ffi.ForeignFunction(bindings.double_box_ptr, box, [ boxPtr ]) var b = new box b.width = 4 b.height = 5 var 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.equal(8, b.width) assert.equal(10, b.height) assert(out instanceof box) assert.equal(8, out.width) assert.equal(10, out.height) assert.notEqual(b.ref().address(), out.ref().address()) }) it('should call the static "area_box" bindings', function () { var area_box = ffi.ForeignFunction(bindings.area_box, ref.types.int, [ box ]) var b = new box({ width: 5, height: 20 }) var rtn = area_box(b) assert.equal('number', typeof rtn) assert.equal(100, rtn) }) it('should call the static "area_box_ptr" bindings', function () { var boxPtr = ref.refType(box) var area_box = ffi.ForeignFunction(bindings.area_box_ptr, ref.types.int, [ boxPtr ]) var b = new box({ width: 5, height: 20 }) var rtn = area_box(b.ref()) assert.equal('number', typeof rtn) assert.equal(100, rtn) }) it('should call the static "create_box" bindings', function () { var create_box = ffi.ForeignFunction(bindings.create_box, box, [ 'int', 'int' ]) var rtn = create_box(1, 2) assert(rtn instanceof box) assert.equal(1, rtn.width) assert.equal(2, rtn.height) }) it('should call the static "add_boxes" bindings', function () { var count = 3 var 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 }) var boxPtr = ref.refType(box) var add_boxes = ffi.ForeignFunction(bindings.add_boxes, box, [ boxPtr, 'int' ]) var rtn = add_boxes(boxes, count) assert(rtn instanceof box) assert.equal(6, rtn.width) assert.equal(60, rtn.height) }) it('should call the static "int_array" bindings', function () { var IntArray = Array('int') var int_array = ffi.ForeignFunction(bindings.int_array, IntArray, [ IntArray ]) var array = new IntArray([ 1, 2, 3, 4, 5, -1 ]) var out = int_array(array) out.length = array.length assert.equal(2, out[0]) assert.equal(4, out[1]) assert.equal(6, out[2]) assert.equal(8, out[3]) assert.equal(10, out[4]) assert.equal(-1, out[5]) }) it('should call the static "array_in_struct" bindings', function () { var array_in_struct = ffi.ForeignFunction(bindings.array_in_struct, arst, [ arst ]) var a = new arst assert.equal(20, a.array.length) a.num = 69 for (var i = 0; i < 20; i++) { a.array[i] = i / 3.14 } var b = array_in_struct(a) assert(b instanceof arst) assert.equal(138, b.num) assert.equal(20, b.array.length) for (var i = 0; i < 20; i++) { // Math.round() because of floating point rounding erros assert.equal(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 () { var test = ffi.ForeignFunction(bindings.test_169, 'int', [ 'string', 'int' ]) var b = new Buffer(20) var len = test(b, b.length) assert.equal('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 () { var Obj56 = Struct({ 'traceMode': ref.types.bool }) var t = new Obj56({ traceMode: true }) var f = new Obj56({ traceMode: false }) var test = ffi.ForeignFunction(bindings.test_ref_56, 'int', [ ref.refType(Obj56) ]) assert.equal(1, test(t.ref())) assert.equal(0, test(f.ref())) }) it('should not call the "ref()" function of its arguments', function () { var void_ptr_arg = ffi.ForeignFunction(bindings.abs, 'void *', [ 'void *' ]) var 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) { var _abs = bindings.abs var abs = ffi.ForeignFunction(_abs, 'int', [ 'int' ]) assert.equal('function', typeof abs.async) // invoke asynchronously abs.async(-1234, function (err, res) { assert.equal(null, err) assert.equal(1234, res) done() }) }) it('should invoke the callback with an Error with a meaningful message when type\'s `set()` throws', function (done) { var _abs = bindings.abs var 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.equal('undefined', typeof res) done() } catch (e) { done(e) } }) }) }) })