Add test for consuming interface types inputs (#1900)

This commit adds a test suite for consuming interface types modules as
input and producing a JS polyfill output. The tests are relatively
simple today and don't exercise a ton of functionality, but they should
hopefully cover the breadth of at least some basics of what wasm
interface types supports today.

A few small fixes were applied along the way, such as:

* Don't require modules to have a stack pointer

* Allow passing `*.wat`, `*.wit`, or `*.wasm` files as input to
  `wasm-bindgen` instead of always requiring `*.wasm`.
This commit is contained in:
Alex Crichton
2019-12-04 22:39:57 -06:00
committed by GitHub
parent a1d90398d0
commit 057c9157b3
22 changed files with 319 additions and 15 deletions

View File

@ -36,6 +36,7 @@ rayon = "1.0"
tempfile = "3.0"
walrus = "0.14"
wit-printer = "0.1"
wit-text = "0.1"
wit-validator = "0.1"
wit-walrus = "0.1"
@ -43,5 +44,9 @@ wit-walrus = "0.1"
name = "reference"
harness = false
[[test]]
name = "interface-types"
harness = false
[features]
vendored-openssl = ['openssl/vendored']

View File

@ -0,0 +1,85 @@
use anyhow::{bail, Result};
use assert_cmd::prelude::*;
use rayon::prelude::*;
use std::env;
use std::path::Path;
use std::process::Command;
fn main() -> Result<()> {
let filter = env::args().nth(1);
let mut tests = Vec::new();
let dir = env::current_dir()?.join("tests/interface-types");
for entry in dir.read_dir()? {
let path = entry?.path();
if path.extension().and_then(|s| s.to_str()) != Some("wit") {
continue;
}
if let Some(filter) = &filter {
if !path.display().to_string().contains(filter) {
continue;
}
}
tests.push(path);
}
tests.sort();
let errs = tests
.par_iter()
.filter_map(|t| runtest(t).err().map(|e| (t, e)))
.collect::<Vec<_>>();
if errs.len() == 0 {
println!("{} tests passed", tests.len());
return Ok(());
}
eprintln!("failed tests:\n");
for (test, err) in errs {
eprintln!("{} failure\n{}", test.display(), tab(&format!("{:?}", err)));
}
bail!("tests failed");
}
fn runtest(test: &Path) -> Result<()> {
let js = test.with_extension("js");
let td = tempfile::TempDir::new()?;
let mut bindgen = Command::cargo_bin("wasm-bindgen")?;
bindgen
.arg("--out-dir")
.arg(td.path())
.arg(test)
.arg("--out-name=wasm")
.arg("--nodejs")
.arg("--no-typescript");
exec(&mut bindgen)?;
exec(Command::new("node")
.arg("--experimental-wasm-anyref")
.arg("--experimental-wasm-mv")
.arg(&js).env("NODE_PATH", td.path()))?;
Ok(())
}
fn exec(cmd: &mut Command) -> Result<()> {
let output = cmd.output()?;
if output.status.success() {
return Ok(());
}
let mut err = format!("command failed {:?}", cmd);
err.push_str(&format!("\nstatus: {}", output.status));
err.push_str(&format!(
"\nstderr:\n{}",
tab(&String::from_utf8_lossy(&output.stderr))
));
err.push_str(&format!(
"\nstdout:\n{}",
tab(&String::from_utf8_lossy(&output.stdout))
));
bail!("{}", err);
}
fn tab(s: &str) -> String {
format!(" {}", s.replace("\n", "\n "))
}

View File

@ -0,0 +1,16 @@
const assert = require('assert');
const wasm = require('wasm');
const obj = {};
assert.strictEqual(wasm.foo(obj), obj);
wasm.store('x');
assert.strictEqual(wasm.load(), 'x');
const obj2 = {};
wasm.store(obj2);
assert.strictEqual(wasm.load(), obj2);
assert.strictEqual(wasm.load(), obj2);
wasm.store(undefined);
assert.strictEqual(wasm.load(), undefined);

View File

@ -0,0 +1,26 @@
(module
(func $foo (param anyref) (result anyref)
local.get 0)
(func $store (param anyref)
i32.const 0
local.get 0
table.set 0)
(func $load (result anyref)
i32.const 0
table.get 0)
(table 1 anyref)
(@interface func (export "foo") (param anyref) (result anyref)
arg.get 0
call-core $foo)
(@interface func (export "store") (param anyref)
arg.get 0
call-core $store)
(@interface func (export "load") (result anyref)
call-core $load)
)

View File

@ -0,0 +1,5 @@
const wasm = require('wasm');
const assert = require('assert');
assert.strictEqual(wasm.foo(), 0);
assert.strictEqual(wasm.get(), 1);

View File

@ -0,0 +1,21 @@
(module
(global $ctr (mut i32) (i32.const 0))
(func $increment
global.get $ctr
i32.const 1
i32.add
global.set $ctr)
(func $get (result i32)
global.get $ctr)
(@interface func (export "foo") (result s32)
defer-call-core $increment
call-core $get
i32-to-s32)
(@interface func (export "get") (result s32)
call-core $get
i32-to-s32)
)

View File

@ -0,0 +1,2 @@
const m = require('wasm');

View File

@ -0,0 +1 @@
(module)

View File

@ -0,0 +1,9 @@
const assert = require('assert');
const wasm = require('wasm');
assert.strictEqual(wasm.add_i8(0, 1), 1);
assert.strictEqual(wasm.add_u8(0, 1), 1);
assert.strictEqual(wasm.add_i16(0, 1), 1);
assert.strictEqual(wasm.add_u16(0, 1), 1);
assert.strictEqual(wasm.add_i32(0, 1), 1);
assert.strictEqual(wasm.add_u32(0, 1), 1);

View File

@ -0,0 +1,54 @@
(module
(func $add_i32 (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add)
(@interface func (export "add_i8") (param s8) (param s8) (result s8)
arg.get 0
s8-to-i32
arg.get 1
s8-to-i32
call-core $add_i32
i32-to-s8)
(@interface func (export "add_i16") (param s16) (param s16) (result s16)
arg.get 0
s16-to-i32
arg.get 1
s16-to-i32
call-core $add_i32
i32-to-s16)
(@interface func (export "add_i32") (param s32) (param s32) (result s32)
arg.get 0
s32-to-i32
arg.get 1
s32-to-i32
call-core $add_i32
i32-to-s32)
(@interface func (export "add_u8") (param s8) (param s8) (result s8)
arg.get 0
s8-to-i32
arg.get 1
s8-to-i32
call-core $add_i32
i32-to-s8)
(@interface func (export "add_u16") (param u16) (param u16) (result u16)
arg.get 0
u16-to-i32
arg.get 1
u16-to-i32
call-core $add_i32
i32-to-u16)
(@interface func (export "add_u32") (param u32) (param u32) (result u32)
arg.get 0
u32-to-i32
arg.get 1
u32-to-i32
call-core $add_i32
i32-to-u32)
)

View File

@ -0,0 +1,5 @@
const wasm = require('wasm');
const assert = require('assert');
assert.strictEqual(wasm.foo(), 'foo');
assert.strictEqual(wasm.hexa(), 'hexa');

View File

@ -0,0 +1,21 @@
(module
(memory 1)
(func $foo (result i32 i32)
i32.const 0
i32.const 3)
(func $hexa (result i32 i32)
i32.const 10
i32.const 4)
(data (i32.const 0) "foo")
(data (i32.const 10) "hexa")
(@interface func (export "foo") (result string)
call-core $foo
memory-to-string)
(@interface func (export "hexa") (result string)
call-core $hexa
memory-to-string)
)

View File

@ -0,0 +1,5 @@
const assert = require('assert');
const wasm = require('wasm');
wasm.nop();
assert.strictEqual(wasm.roundtrip(1), 1);

View File

@ -0,0 +1,5 @@
(module
(@interface func (export "nop"))
(@interface func (export "roundtrip") (param s32) (result s32)
arg.get 0)
)

View File

@ -0,0 +1,11 @@
const wasm = require('wasm');
const assert = require('assert');
const test = s => {
wasm.set(s);
assert.strictEqual(s, wasm.get());
};
test('');
test('x');
test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');

View File

@ -0,0 +1,27 @@
(module
(memory 1)
(global $glen (mut i32) (i32.const 0))
(global $gptr (mut i32) (i32.const 0))
(func $malloc (param i32) (result i32) i32.const 23)
(func $set (param $ptr i32) (param $len i32)
local.get $ptr
global.set $gptr
local.get $len
global.set $glen)
(func $get (result i32 i32)
global.get $gptr
global.get $glen)
(@interface func (export "set") (param string)
arg.get 0
string-to-memory $malloc
call-core $set)
(@interface func (export "get") (result string)
call-core $get
memory-to-string)
)