From 7b2c9769df02be60423aed22d1cb77a18a7913d0 Mon Sep 17 00:00:00 2001 From: Ajani Bilby <11359344+AjaniBilby@users.noreply.github.com> Date: Mon, 11 Sep 2023 20:40:51 +1000 Subject: [PATCH] ~Migrated tests to deno --- deno.json | 3 +- package.json | 4 +- tests/wasm/hello-world.test.js | 86 ---------------------------------- tests/wasm/hello-world.test.ts | 84 +++++++++++++++++++++++++++++++++ tests/wasm/type.test.js | 54 --------------------- tests/wasm/type.test.ts | 49 +++++++++++++++++++ 6 files changed, 135 insertions(+), 145 deletions(-) delete mode 100644 tests/wasm/hello-world.test.js create mode 100644 tests/wasm/hello-world.test.ts delete mode 100644 tests/wasm/type.test.js create mode 100644 tests/wasm/type.test.ts diff --git a/deno.json b/deno.json index f8a2581..6eda044 100644 --- a/deno.json +++ b/deno.json @@ -24,8 +24,7 @@ "lock": false, "nodeModulesDir": true, "test": { - "include": ["source/"], - "exclude": ["source/bnf/"] + "include": ["tests/*"] }, "tasks": { "start": "deno run --allow-read --allow-write cli.ts" diff --git a/package.json b/package.json index 3f0f17f..12eb37d 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,7 @@ "scripts": { "build": "run-s build:*", "build:syntax": "npx bnf-compile ./source/bnf/", - "test": "run-s test:*", - "test:types": "tsc --noEmit", - "test:mocha": "npx mocha" + "test": "deno test" }, "bin": { "salient": "bin/cli.js" diff --git a/tests/wasm/hello-world.test.js b/tests/wasm/hello-world.test.js deleted file mode 100644 index 4b886eb..0000000 --- a/tests/wasm/hello-world.test.js +++ /dev/null @@ -1,86 +0,0 @@ -import { expect } from 'chai'; - -import { Module, Instruction, Type } from "../../bin/wasm/index.js"; - -const decoder = new TextDecoder(); - - -describe('Wasm module test', () => { - const goalText = "Hello, World!" + Math.floor(Math.random()*9); - it(`should print "${goalText}"`, async () => { - let mod = new Module(); - const mem = mod.addMemory(1); - mod.exportMemory("memory", mem); - - const type0 = mod.makeType([Type.Intrinsic.i32], [Type.Intrinsic.i32]); - const type1 = mod.makeType([Type.Intrinsic.i32, Type.Intrinsic.i32, Type.Intrinsic.i32, Type.Intrinsic.i32], [Type.Intrinsic.i32]); - - const fd_write = mod.importFunction("wasi_snapshot_preview1", "fd_write", type1); - - mod.setData(0, goalText); - // The WASI iovec struct, which consists of a pointer to - // the data and the length of the data. - // This starts at address 100, to leave some room after the string data. - mod.setData(16, "\x00\x00\x00\x00\x0e\x00\x00\x00"); // Set pointer to 0 and length to 14 - - const main = mod.makeFunction([], []); - main.code.push(Instruction.const.i32(1)); // File descriptor for stdout - main.code.push(Instruction.const.i32(16)); // iovec array - main.code.push(Instruction.const.i32(1)); // number of iovec structs - main.code.push(Instruction.const.i32(0)); // address to store number of bytes written (ignoring it here) - main.code.push(Instruction.call(fd_write)); - main.code.push(Instruction.drop()); - - const extra = mod.makeFunction([Type.Intrinsic.i32], [Type.Intrinsic.i32]); - extra.code.push(Instruction.local.get(0)); - extra.code.push(Instruction.return()); - - mod.exportFunction("_start", main.ref); - - let stdout = ""; - - let memory; - - const imports = { - wasi_snapshot_preview1: { - fd_write: (fd, iovs, iovs_len, n_written) => { - const memoryArray = new Int32Array(memory.buffer); - const byteArray = new Uint8Array(memory.buffer); - for (let iovIdx = 0; iovIdx < iovs_len; iovIdx++) { - const bufPtr = memoryArray.at(iovs/4 + iovIdx*2) || 0; - const bufLen = memoryArray.at(iovs/4 + iovIdx*2 + 1) || 0; - const data = decoder.decode(byteArray.slice(bufPtr, bufPtr + bufLen)); - stdout += data; - } - return 0; // Return 0 to indicate success - } - } - }; - - // Load the wasm module - const wasmModule = new WebAssembly.Module(mod.toBinary()); - - try { - // Instantiate the wasm module - const instance = await WebAssembly.instantiate(wasmModule, imports); - - const { exports } = instance; - memory = exports.memory; - - // Check if the _start function exists - expect(exports).to.have.property('_start').that.is.a('function'); - - // Call the _start function - if (typeof(exports._start) !== "function") throw new Error("Missing start function"); - exports._start(); - - // Check stdout - expect(stdout).to.equal(goalText); - - } catch (err) { - // If there's an error, the test will fail - expect.fail(`Failed to run wasm module: ${err}`); - } - - }); -}); \ No newline at end of file diff --git a/tests/wasm/hello-world.test.ts b/tests/wasm/hello-world.test.ts new file mode 100644 index 0000000..6faf644 --- /dev/null +++ b/tests/wasm/hello-world.test.ts @@ -0,0 +1,84 @@ +/// +import { assert, fail, assertEquals } from "https://deno.land/std@0.201.0/assert/mod.ts"; +import { Module, Instruction, Type } from "../../source/wasm/index.ts"; + +const decoder = new TextDecoder(); + +const goalText = "Hello, World!" + Math.floor(Math.random() * 9); + +Deno.test(`Wasm module test: should print "${goalText}"`, async () => { + let mod = new Module(); + const mem = mod.addMemory(1); + mod.exportMemory("memory", mem); + + const type0 = mod.makeType([Type.Intrinsic.i32], [Type.Intrinsic.i32]); + const type1 = mod.makeType([Type.Intrinsic.i32, Type.Intrinsic.i32, Type.Intrinsic.i32, Type.Intrinsic.i32], [Type.Intrinsic.i32]); + + const fd_write = mod.importFunction("wasi_snapshot_preview1", "fd_write", type1); + + mod.setData(0, goalText); + // The WASI iovec struct, which consists of a pointer to + // the data and the length of the data. + // This starts at address 100, to leave some room after the string data. + mod.setData(16, "\x00\x00\x00\x00\x0e\x00\x00\x00"); // Set pointer to 0 and length to 14 + + const main = mod.makeFunction([], []); + main.code.push(Instruction.const.i32(1)); // File descriptor for stdout + main.code.push(Instruction.const.i32(16)); // iovec array + main.code.push(Instruction.const.i32(1)); // number of iovec structs + main.code.push(Instruction.const.i32(0)); // address to store number of bytes written (ignoring it here) + main.code.push(Instruction.call(fd_write)); + main.code.push(Instruction.drop()); + + const extra = mod.makeFunction([Type.Intrinsic.i32], [Type.Intrinsic.i32]); + extra.code.push(Instruction.local.get(0)); + extra.code.push(Instruction.return()); + + mod.exportFunction("_start", main.ref); + + let stdout = ""; + + let memory: WebAssembly.Memory; + + const imports = { + wasi_snapshot_preview1: { + fd_write: (fd: number, iovs: number, iovs_len: number, n_written: number) => { + const memoryArray = new Int32Array(memory.buffer); + const byteArray = new Uint8Array(memory.buffer); + for (let iovIdx = 0; iovIdx < iovs_len; iovIdx++) { + const bufPtr = memoryArray.at(iovs/4 + iovIdx*2) || 0; + const bufLen = memoryArray.at(iovs/4 + iovIdx*2 + 1) || 0; + const data = decoder.decode(byteArray.slice(bufPtr, bufPtr + bufLen)); + stdout += data; + } + return 0; // Return 0 to indicate success + } + } + }; + + // Load the wasm module + const wasmModule = new WebAssembly.Module(mod.toBinary()); + + try { + // Instantiate the wasm module + const instance = await WebAssembly.instantiate(wasmModule, imports); + + const exports = instance.exports; + memory = exports.memory as WebAssembly.Memory; + + // Call the _start function + if (typeof exports._start === "function") { + (exports._start as Function)(); + } else { + fail(`Expected _start to be a function`); + } + + // Check stdout + assertEquals(stdout, goalText); + + } catch (err) { + // If there's an error, the test will fail + fail(`Failed to run wasm module: ${err}`); + } + +}); \ No newline at end of file diff --git a/tests/wasm/type.test.js b/tests/wasm/type.test.js deleted file mode 100644 index 1bfda79..0000000 --- a/tests/wasm/type.test.js +++ /dev/null @@ -1,54 +0,0 @@ -import { describe, it } from 'mocha'; -import { expect } from 'chai'; - -import { EncodeSignedLEB, EncodeUnsignedLEB } from "../../bin/wasm/type.js"; - - -function toHex(arr) { - return arr.map(x => x.toString(16).padStart(2, "0")).join(""); -} - -describe('EncodeSignedLEB', () => { - it('zero encoding', () => { - expect(toHex(EncodeSignedLEB(0))).to.deep.equal("00"); - }); - - it('small positive integer', () => { - expect(toHex(EncodeSignedLEB(8))).to.deep.equal("08"); - expect(toHex(EncodeSignedLEB(10))).to.deep.equal("0a"); - expect(toHex(EncodeSignedLEB(100))).to.deep.equal("e400"); - expect(toHex(EncodeSignedLEB(123456))).to.deep.equal("c0c407"); - expect(toHex(EncodeSignedLEB(2141192192))).to.deep.equal("808080fd07"); - }); - - it('small negative integer', () => { - expect(toHex(EncodeSignedLEB(-100))).to.deep.equal("9c7f"); - }); - - it('should throw an error for non-integers', () => { - expect(() => EncodeSignedLEB(12.34)).to.throw(); - }); -}); - -describe('EncodeUnsignedLEB', () => { - it('zero encoding', () => { - expect(toHex(EncodeUnsignedLEB(0))).to.deep.equal("00"); - }); - - it('small integer', () => { - expect(toHex(EncodeUnsignedLEB(1))).to.deep.equal("01"); - expect(toHex(EncodeUnsignedLEB(8))).to.deep.equal("08"); - expect(toHex(EncodeUnsignedLEB(127))).to.deep.equal("7f"); - expect(toHex(EncodeUnsignedLEB(128))).to.deep.equal("8001"); - expect(toHex(EncodeUnsignedLEB(255))).to.deep.equal("ff01"); - expect(toHex(EncodeUnsignedLEB(256))).to.deep.equal("8002"); - expect(toHex(EncodeUnsignedLEB(624485))).to.deep.equal("e58e26"); - }); - - it('should throw an error for non-integers', () => { - expect(() => EncodeUnsignedLEB(12.34)).to.throw(); - }); - it('should throw an error for negative integers', () => { - expect(() => EncodeUnsignedLEB(-12)).to.throw(); - }); -}); \ No newline at end of file diff --git a/tests/wasm/type.test.ts b/tests/wasm/type.test.ts new file mode 100644 index 0000000..4b5ec78 --- /dev/null +++ b/tests/wasm/type.test.ts @@ -0,0 +1,49 @@ +/// +import { assertEquals, assertThrows } from "https://deno.land/std@0.201.0/assert/mod.ts"; +import { EncodeSignedLEB, EncodeUnsignedLEB } from "../../source/wasm/type.ts"; + +function toHex(arr: number[]): string { + return arr.map(x => x.toString(16).padStart(2, "0")).join(""); +} + +Deno.test("EncodeSignedLEB: zero encoding", () => { + assertEquals(toHex(EncodeSignedLEB(0)), "00"); +}); + +Deno.test("EncodeSignedLEB: small positive integer", () => { + assertEquals(toHex(EncodeSignedLEB(8)), "08"); + assertEquals(toHex(EncodeSignedLEB(10)), "0a"); + assertEquals(toHex(EncodeSignedLEB(100)), "e400"); + assertEquals(toHex(EncodeSignedLEB(123456)), "c0c407"); + assertEquals(toHex(EncodeSignedLEB(2141192192)), "808080fd07"); +}); + +Deno.test("EncodeSignedLEB: small negative integer", () => { + assertEquals(toHex(EncodeSignedLEB(-100)), "9c7f"); +}); + +Deno.test("EncodeSignedLEB: should throw an error for non-integers", () => { + assertThrows(() => EncodeSignedLEB(12.34)); +}); + +Deno.test("EncodeUnsignedLEB: zero encoding", () => { + assertEquals(toHex(EncodeUnsignedLEB(0)), "00"); +}); + +Deno.test("EncodeUnsignedLEB: small integer", () => { + assertEquals(toHex(EncodeUnsignedLEB(1)), "01"); + assertEquals(toHex(EncodeUnsignedLEB(8)), "08"); + assertEquals(toHex(EncodeUnsignedLEB(127)), "7f"); + assertEquals(toHex(EncodeUnsignedLEB(128)), "8001"); + assertEquals(toHex(EncodeUnsignedLEB(255)), "ff01"); + assertEquals(toHex(EncodeUnsignedLEB(256)), "8002"); + assertEquals(toHex(EncodeUnsignedLEB(624485)), "e58e26"); +}); + +Deno.test("EncodeUnsignedLEB: should throw an error for non-integers", () => { + assertThrows(() => EncodeUnsignedLEB(12.34)); +}); + +Deno.test("EncodeUnsignedLEB: should throw an error for negative integers", () => { + assertThrows(() => EncodeUnsignedLEB(-12)); +});