aboutsummaryrefslogtreecommitdiff
path: root/test/bun.js/ffi.test.js
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-12-28 00:51:22 -0800
committerGravatar GitHub <noreply@github.com> 2022-12-28 00:51:22 -0800
commitc0dd2841362b67fdb5ede262b19688004a4eb9a4 (patch)
treea3cd6b353c25c30d66489de61b394af7d5568fed /test/bun.js/ffi.test.js
parent504972fa5deb92f2d0510d42f11b085351915a32 (diff)
downloadbun-c0dd2841362b67fdb5ede262b19688004a4eb9a4.tar.gz
bun-c0dd2841362b67fdb5ede262b19688004a4eb9a4.tar.zst
bun-c0dd2841362b67fdb5ede262b19688004a4eb9a4.zip
Upgrade to latest Zig (#1610)
* @min and @max * builtins and some trivial ones * Most of them * more * more! * More Progress * wip * Update tagged_pointer.zig * Update http_client_async.zig * Most of the iterable dir changes * alright * Remove usages of deprecated formatters * :camera: * fmt * Update shimmer.zig * wip * wip * wip * progress * more * Latest * stuck on error * latest * workaround stage2 * wip * Update string_immutable.zig * wip * Migrate `Dirent` and `require("fs')` to use JSC<>Zig bindings * Fix build errors * Fixup most of the test failures * Fix `make headers` * Fix "outside package path" error * Fixup aligned alloc * Add missing file * linux * More linux fixes * use latest peechy * Fix transpiler test failure * Forgot about these * Fixup test failure * Update node-timers.test.ts * [node:htt] Fix `undefined is not an object` error Fixes https://github.com/oven-sh/bun/issues/1618 * Update http.exports.js * Make this test less flaky * fix hashes * Fix hex formatting and zls issues * Download zig version * Update Dockerfile * Update Dockerfile * Update uws * Update Dockerfile * Set llvm version * Update README.md * Update uws * Update Dockerfile * Update io_linux.zig * Update bun.zig * Log output * workaround strange @cInclude error * Make ffi tests better * Don't use cImport * Update c.zig * Update c-bindings.cpp * call setOutputDir * Update Dockerfile * Use a longer name * latest * Update serve.test.ts Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> Co-authored-by: Veikka Tuominen <git@vexu.eu>
Diffstat (limited to 'test/bun.js/ffi.test.js')
-rw-r--r--test/bun.js/ffi.test.js507
1 files changed, 251 insertions, 256 deletions
diff --git a/test/bun.js/ffi.test.js b/test/bun.js/ffi.test.js
index e3e858b1f..4adf67990 100644
--- a/test/bun.js/ffi.test.js
+++ b/test/bun.js/ffi.test.js
@@ -1,4 +1,4 @@
-import { expect, it } from "bun:test";
+import { afterAll, describe, expect, it } from "bun:test";
//
import {
CFunction,
@@ -310,186 +310,191 @@ function getTypes(fast) {
}
function ffiRunner(fast) {
- const types = getTypes(fast);
- const {
- symbols: {
- returns_true,
- returns_false,
- return_a_function_ptr_to_function_that_returns_true,
- returns_42_char,
- returns_42_float,
- returns_42_double,
- returns_42_uint8_t,
- returns_neg_42_int8_t,
- returns_42_uint16_t,
- returns_42_uint32_t,
- returns_42_uint64_t,
- returns_neg_42_int16_t,
- returns_neg_42_int32_t,
- returns_neg_42_int64_t,
- identity_char,
- identity_float,
- identity_bool,
- identity_double,
- identity_int8_t,
- identity_int16_t,
- identity_int32_t,
- identity_int64_t,
- identity_uint8_t,
- identity_uint16_t,
- identity_uint32_t,
- identity_uint64_t,
- add_char,
- add_float,
- add_double,
- add_int8_t,
- add_int16_t,
- add_int32_t,
- add_int64_t,
- add_uint8_t,
- add_uint16_t,
- identity_ptr,
- add_uint32_t,
- add_uint64_t,
- is_null,
- does_pointer_equal_42_as_int32_t,
- ptr_should_point_to_42_as_int32_t,
- cb_identity_true,
- cb_identity_false,
- cb_identity_42_char,
- cb_identity_42_float,
- cb_identity_42_double,
- cb_identity_42_uint8_t,
- cb_identity_neg_42_int8_t,
- cb_identity_42_uint16_t,
- cb_identity_42_uint32_t,
- cb_identity_42_uint64_t,
- cb_identity_neg_42_int16_t,
- cb_identity_neg_42_int32_t,
- cb_identity_neg_42_int64_t,
- getDeallocatorCalledCount,
- getDeallocatorCallback,
- getDeallocatorBuffer,
- },
- close,
- } = dlopen("/tmp/bun-ffi-test.dylib", types);
-
- Bun.gc(true);
- expect(returns_true()).toBe(true);
- Bun.gc(true);
- expect(returns_false()).toBe(false);
-
- expect(returns_42_char()).toBe(42);
- if (fast) expect(returns_42_uint64_t().valueOf()).toBe(42);
- else expect(returns_42_uint64_t().valueOf()).toBe(42n);
- Bun.gc(true);
- expect(Math.fround(returns_42_float())).toBe(Math.fround(42.41999804973602));
- expect(returns_42_double()).toBe(42.42);
- expect(returns_42_uint8_t()).toBe(42);
- expect(returns_neg_42_int8_t()).toBe(-42);
- expect(returns_42_uint16_t()).toBe(42);
- expect(returns_42_uint32_t()).toBe(42);
- if (fast) expect(returns_42_uint64_t()).toBe(42);
- else expect(returns_42_uint64_t()).toBe(42n);
- expect(returns_neg_42_int16_t()).toBe(-42);
- expect(returns_neg_42_int32_t()).toBe(-42);
- expect(identity_int32_t(10)).toBe(10);
- Bun.gc(true);
- if (fast) expect(returns_neg_42_int64_t()).toBe(-42);
- else expect(returns_neg_42_int64_t()).toBe(-42n);
-
- expect(identity_char(10)).toBe(10);
-
- expect(identity_float(10.199999809265137)).toBe(10.199999809265137);
-
- expect(identity_bool(true)).toBe(true);
-
- expect(identity_bool(false)).toBe(false);
- expect(identity_double(10.100000000000364)).toBe(10.100000000000364);
-
- expect(identity_int8_t(10)).toBe(10);
- expect(identity_int16_t(10)).toBe(10);
-
- if (fast) expect(identity_int64_t(10)).toBe(10);
- else expect(identity_int64_t(10)).toBe(10n);
- expect(identity_uint8_t(10)).toBe(10);
- expect(identity_uint16_t(10)).toBe(10);
- expect(identity_uint32_t(10)).toBe(10);
- if (fast) expect(identity_uint64_t(10)).toBe(10);
- else expect(identity_uint64_t(10)).toBe(10n);
- Bun.gc(true);
- var bigArray = new BigUint64Array(8);
- new Uint8Array(bigArray.buffer).fill(255);
- var bigIntArray = new BigInt64Array(bigArray.buffer);
- expect(identity_uint64_t(bigArray[0])).toBe(bigArray[0]);
- expect(identity_uint64_t(bigArray[0] - BigInt(1))).toBe(
- bigArray[0] - BigInt(1),
- );
- if (fast) {
- expect(add_uint64_t(BigInt(-1) * bigArray[0], bigArray[0])).toBe(0);
- expect(
- add_uint64_t(BigInt(-1) * bigArray[0] + BigInt(10), bigArray[0]),
- ).toBe(10);
- } else {
- expect(add_uint64_t(BigInt(-1) * bigArray[0], bigArray[0])).toBe(0n);
- expect(
- add_uint64_t(BigInt(-1) * bigArray[0] + BigInt(10), bigArray[0]),
- ).toBe(10n);
- }
- if (fast) {
- expect(identity_uint64_t(0)).toBe(0);
- expect(identity_uint64_t(100)).toBe(100);
- expect(identity_uint64_t(BigInt(100))).toBe(100);
-
- expect(identity_int64_t(bigIntArray[0])).toBe(-1);
- expect(identity_int64_t(bigIntArray[0] - BigInt(1))).toBe(-2);
- } else {
- expect(identity_uint64_t(0)).toBe(0n);
- expect(identity_uint64_t(100)).toBe(100n);
- expect(identity_uint64_t(BigInt(100))).toBe(100n);
-
- expect(identity_int64_t(bigIntArray[0])).toBe(bigIntArray[0]);
- expect(identity_int64_t(bigIntArray[0] - BigInt(1))).toBe(
- bigIntArray[0] - BigInt(1),
- );
- }
- Bun.gc(true);
- expect(add_char.native(1, 1)).toBe(2);
-
- expect(add_float(2.4, 2.8)).toBe(Math.fround(5.2));
- expect(add_double(4.2, 0.1)).toBe(4.3);
- expect(add_int8_t(1, 1)).toBe(2);
- expect(add_int16_t(1, 1)).toBe(2);
- expect(add_int32_t(1, 1)).toBe(2);
- if (fast) expect(add_int64_t(1, 1)).toBe(2);
- else expect(add_int64_t(1n, 1n)).toBe(2n);
- expect(add_uint8_t(1, 1)).toBe(2);
- expect(add_uint16_t(1, 1)).toBe(2);
- expect(add_uint32_t(1, 1)).toBe(2);
- Bun.gc(true);
- expect(is_null(null)).toBe(true);
- const cptr = ptr_should_point_to_42_as_int32_t();
- expect(cptr != 0).toBe(true);
- expect(typeof cptr === "number").toBe(true);
- expect(does_pointer_equal_42_as_int32_t(cptr)).toBe(true);
- const buffer = toBuffer(cptr, 0, 4);
- expect(buffer.readInt32(0)).toBe(42);
- expect(new DataView(toArrayBuffer(cptr, 0, 4), 0, 4).getInt32(0, true)).toBe(
- 42,
- );
- expect(ptr(buffer)).toBe(cptr);
- expect(new CString(cptr, 0, 1).toString()).toBe("*");
- expect(identity_ptr(cptr)).toBe(cptr);
- const second_ptr = ptr(new Buffer(8));
- expect(identity_ptr(second_ptr)).toBe(second_ptr);
-
- var myCFunction = new CFunction({
- ptr: return_a_function_ptr_to_function_that_returns_true(),
- returns: "bool",
- });
- expect(myCFunction()).toBe(true);
+ describe("FFI runner" + (fast ? " (fast int)" : ""), () => {
+ const types = getTypes(fast);
+ const {
+ symbols: {
+ returns_true,
+ returns_false,
+ return_a_function_ptr_to_function_that_returns_true,
+ returns_42_char,
+ returns_42_float,
+ returns_42_double,
+ returns_42_uint8_t,
+ returns_neg_42_int8_t,
+ returns_42_uint16_t,
+ returns_42_uint32_t,
+ returns_42_uint64_t,
+ returns_neg_42_int16_t,
+ returns_neg_42_int32_t,
+ returns_neg_42_int64_t,
+ identity_char,
+ identity_float,
+ identity_bool,
+ identity_double,
+ identity_int8_t,
+ identity_int16_t,
+ identity_int32_t,
+ identity_int64_t,
+ identity_uint8_t,
+ identity_uint16_t,
+ identity_uint32_t,
+ identity_uint64_t,
+ add_char,
+ add_float,
+ add_double,
+ add_int8_t,
+ add_int16_t,
+ add_int32_t,
+ add_int64_t,
+ add_uint8_t,
+ add_uint16_t,
+ identity_ptr,
+ add_uint32_t,
+ add_uint64_t,
+ is_null,
+ does_pointer_equal_42_as_int32_t,
+ ptr_should_point_to_42_as_int32_t,
+ cb_identity_true,
+ cb_identity_false,
+ cb_identity_42_char,
+ cb_identity_42_float,
+ cb_identity_42_double,
+ cb_identity_42_uint8_t,
+ cb_identity_neg_42_int8_t,
+ cb_identity_42_uint16_t,
+ cb_identity_42_uint32_t,
+ cb_identity_42_uint64_t,
+ cb_identity_neg_42_int16_t,
+ cb_identity_neg_42_int32_t,
+ cb_identity_neg_42_int64_t,
+ getDeallocatorCalledCount,
+ getDeallocatorCallback,
+ getDeallocatorBuffer,
+ },
+ close,
+ } = dlopen("/tmp/bun-ffi-test.dylib", types);
+ it("primitives", () => {
+ Bun.gc(true);
+ expect(returns_true()).toBe(true);
+ Bun.gc(true);
+ expect(returns_false()).toBe(false);
+
+ expect(returns_42_char()).toBe(42);
+ if (fast) expect(returns_42_uint64_t().valueOf()).toBe(42);
+ else expect(returns_42_uint64_t().valueOf()).toBe(42n);
+ Bun.gc(true);
+ expect(Math.fround(returns_42_float())).toBe(
+ Math.fround(42.41999804973602),
+ );
+ expect(returns_42_double()).toBe(42.42);
+ expect(returns_42_uint8_t()).toBe(42);
+ expect(returns_neg_42_int8_t()).toBe(-42);
+ expect(returns_42_uint16_t()).toBe(42);
+ expect(returns_42_uint32_t()).toBe(42);
+ if (fast) expect(returns_42_uint64_t()).toBe(42);
+ else expect(returns_42_uint64_t()).toBe(42n);
+ expect(returns_neg_42_int16_t()).toBe(-42);
+ expect(returns_neg_42_int32_t()).toBe(-42);
+ expect(identity_int32_t(10)).toBe(10);
+ Bun.gc(true);
+ if (fast) expect(returns_neg_42_int64_t()).toBe(-42);
+ else expect(returns_neg_42_int64_t()).toBe(-42n);
+
+ expect(identity_char(10)).toBe(10);
+
+ expect(identity_float(10.199999809265137)).toBe(10.199999809265137);
+
+ expect(identity_bool(true)).toBe(true);
+
+ expect(identity_bool(false)).toBe(false);
+ expect(identity_double(10.100000000000364)).toBe(10.100000000000364);
+
+ expect(identity_int8_t(10)).toBe(10);
+ expect(identity_int16_t(10)).toBe(10);
+
+ if (fast) expect(identity_int64_t(10)).toBe(10);
+ else expect(identity_int64_t(10)).toBe(10n);
+ expect(identity_uint8_t(10)).toBe(10);
+ expect(identity_uint16_t(10)).toBe(10);
+ expect(identity_uint32_t(10)).toBe(10);
+ if (fast) expect(identity_uint64_t(10)).toBe(10);
+ else expect(identity_uint64_t(10)).toBe(10n);
+ Bun.gc(true);
+ var bigArray = new BigUint64Array(8);
+ new Uint8Array(bigArray.buffer).fill(255);
+ var bigIntArray = new BigInt64Array(bigArray.buffer);
+ expect(identity_uint64_t(bigArray[0])).toBe(bigArray[0]);
+ expect(identity_uint64_t(bigArray[0] - BigInt(1))).toBe(
+ bigArray[0] - BigInt(1),
+ );
+ if (fast) {
+ expect(add_uint64_t(BigInt(-1) * bigArray[0], bigArray[0])).toBe(0);
+ expect(
+ add_uint64_t(BigInt(-1) * bigArray[0] + BigInt(10), bigArray[0]),
+ ).toBe(10);
+ } else {
+ expect(add_uint64_t(BigInt(-1) * bigArray[0], bigArray[0])).toBe(0n);
+ expect(
+ add_uint64_t(BigInt(-1) * bigArray[0] + BigInt(10), bigArray[0]),
+ ).toBe(10n);
+ }
+ if (fast) {
+ expect(identity_uint64_t(0)).toBe(0);
+ expect(identity_uint64_t(100)).toBe(100);
+ expect(identity_uint64_t(BigInt(100))).toBe(100);
+
+ expect(identity_int64_t(bigIntArray[0])).toBe(-1);
+ expect(identity_int64_t(bigIntArray[0] - BigInt(1))).toBe(-2);
+ } else {
+ expect(identity_uint64_t(0)).toBe(0n);
+ expect(identity_uint64_t(100)).toBe(100n);
+ expect(identity_uint64_t(BigInt(100))).toBe(100n);
+
+ expect(identity_int64_t(bigIntArray[0])).toBe(bigIntArray[0]);
+ expect(identity_int64_t(bigIntArray[0] - BigInt(1))).toBe(
+ bigIntArray[0] - BigInt(1),
+ );
+ }
+ Bun.gc(true);
+ expect(add_char.native(1, 1)).toBe(2);
+
+ expect(add_float(2.4, 2.8)).toBe(Math.fround(5.2));
+ expect(add_double(4.2, 0.1)).toBe(4.3);
+ expect(add_int8_t(1, 1)).toBe(2);
+ expect(add_int16_t(1, 1)).toBe(2);
+ expect(add_int32_t(1, 1)).toBe(2);
+ if (fast) expect(add_int64_t(1, 1)).toBe(2);
+ else expect(add_int64_t(1n, 1n)).toBe(2n);
+ expect(add_uint8_t(1, 1)).toBe(2);
+ expect(add_uint16_t(1, 1)).toBe(2);
+ expect(add_uint32_t(1, 1)).toBe(2);
+ Bun.gc(true);
+ expect(is_null(null)).toBe(true);
+ const cptr = ptr_should_point_to_42_as_int32_t();
+ expect(cptr != 0).toBe(true);
+ expect(typeof cptr === "number").toBe(true);
+ expect(does_pointer_equal_42_as_int32_t(cptr)).toBe(true);
+ const buffer = toBuffer(cptr, 0, 4);
+ expect(buffer.readInt32(0)).toBe(42);
+ expect(
+ new DataView(toArrayBuffer(cptr, 0, 4), 0, 4).getInt32(0, true),
+ ).toBe(42);
+ expect(ptr(buffer)).toBe(cptr);
+ expect(new CString(cptr, 0, 1).toString()).toBe("*");
+ expect(identity_ptr(cptr)).toBe(cptr);
+ const second_ptr = ptr(new Buffer(8));
+ expect(identity_ptr(second_ptr)).toBe(second_ptr);
+ });
+
+ it("CFunction", () => {
+ var myCFunction = new CFunction({
+ ptr: return_a_function_ptr_to_function_that_returns_true(),
+ returns: "bool",
+ });
+ expect(myCFunction()).toBe(true);
+ });
- {
const typeMap = {
int8_t: -8,
int16_t: -16,
@@ -505,25 +510,7 @@ function ffiRunner(fast) {
"void*": null,
};
- // Return types, 1 argument
- for (let [returnName, returnValue] of Object.entries(typeMap)) {
- var roundtripFunction = new CFunction({
- ptr: new JSCallback(
- (input) => {
- return input;
- },
- {
- returns: returnName,
- args: [returnName],
- },
- ).ptr,
- returns: returnName,
- args: [returnName],
- });
- expect(roundtripFunction(returnValue)).toBe(returnValue);
- }
-
- {
+ it("JSCallback", () => {
var toClose = new JSCallback(
(input) => {
return input;
@@ -536,65 +523,72 @@ function ffiRunner(fast) {
expect(toClose.ptr > 0).toBe(true);
toClose.close();
expect(toClose.ptr === null).toBe(true);
- }
-
- // Return types, no args
- for (let [name, value] of Object.entries(typeMap)) {
- var roundtripFunction = new CFunction({
- ptr: new JSCallback(() => value, {
- returns: name,
- }).ptr,
- returns: name,
- });
- expect(roundtripFunction()).toBe(value);
- }
-
- // 1 arg, threadsafe
- for (let [name, value] of Object.entries(typeMap)) {
- var roundtripFunction = new CFunction({
- ptr: new JSCallback(
- (arg1) => {
- expect(arg1).toBe(value);
- },
- {
+ });
+
+ describe("callbacks", () => {
+ // Return types, 1 argument
+ for (let [returnName, returnValue] of Object.entries(typeMap)) {
+ it("fn(" + returnName + ") " + returnName, () => {
+ var roundtripFunction = new CFunction({
+ ptr: new JSCallback(
+ (input) => {
+ return input;
+ },
+ {
+ returns: returnName,
+ args: [returnName],
+ },
+ ).ptr,
+ returns: returnName,
+ args: [returnName],
+ });
+ expect(roundtripFunction(returnValue)).toBe(returnValue);
+ });
+ }
+ // Return types, no args
+ for (let [name, value] of Object.entries(typeMap)) {
+ it("fn() " + name, () => {
+ var roundtripFunction = new CFunction({
+ ptr: new JSCallback(() => value, {
+ returns: name,
+ }).ptr,
+ returns: name,
+ });
+ expect(roundtripFunction()).toBe(value);
+ });
+ }
+ });
+
+ describe("threadsafe callback", (done) => {
+ // 1 arg, threadsafe
+ for (let [name, value] of Object.entries(typeMap)) {
+ it("fn(" + name + ") " + name, async () => {
+ const cb = new JSCallback(
+ (arg1) => {
+ expect(arg1).toBe(value);
+ },
+ {
+ args: [name],
+ threadsafe: true,
+ },
+ );
+ var roundtripFunction = new CFunction({
+ ptr: cb.ptr,
+ returns: "void",
args: [name],
- threadsafe: true,
- },
- ).ptr,
- returns: "void",
- args: [name],
- });
- roundtripFunction(value);
- }
- }
-
- // check deallocator is called
-
- // for (let constructor of [toArrayBuffer, toBuffer]) {
- // Bun.gc(true);
-
- // var bufferPtr = getDeallocatorBuffer();
-
- // for (let i = 0; i < 100; i++) {
- // // callback, no userData
- // constructor(bufferPtr, 0, 128, getDeallocatorCallback());
-
- // // callback, userData;
- // constructor(bufferPtr, 0, 128, bufferPtr, getDeallocatorCallback());
- // }
-
- // Bun.gc(true);
- // expect(getDeallocatorCalledCount() >= 190).toBe(true);
- // Bun.gc(true);
- // }
- close();
+ });
+ roundtripFunction(value);
+ await 1;
+ });
+ }
+ });
+
+ afterAll(() => {
+ close();
+ });
+ });
}
-// TODO: There is a crash when dlopen() two times the same library in quick succession
-// it("run ffi fast", () => {
-// ffiRunner(true);
-// });
-
it("read", () => {
const buffer = new BigInt64Array(16);
const dataView = new DataView(buffer.buffer);
@@ -629,6 +623,7 @@ it("read", () => {
}
});
-it("run ffi", () => {
+describe("run ffi", () => {
ffiRunner(false);
+ ffiRunner(true);
});