Add WASI unit tests for the C# API.
This commit is contained in:
BIN
crates/misc/dotnet/tests/Modules/Wasi.wasm
Normal file
BIN
crates/misc/dotnet/tests/Modules/Wasi.wasm
Normal file
Binary file not shown.
66
crates/misc/dotnet/tests/Modules/Wasi.wat
Normal file
66
crates/misc/dotnet/tests/Modules/Wasi.wat
Normal file
@@ -0,0 +1,66 @@
|
||||
(module
|
||||
(type $t0 (func (param i32 i32) (result i32)))
|
||||
(type $t1 (func (param i32 i32 i32 i32) (result i32)))
|
||||
(type $t2 (func (param i32) (result i32)))
|
||||
(type $t3 (func (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
|
||||
(import "wasi_snapshot_preview1" "environ_sizes_get" (func $wasi_snapshot_preview1.environ_sizes_get (type $t0)))
|
||||
(import "wasi_snapshot_preview1" "environ_get" (func $wasi_snapshot_preview1.environ_get (type $t0)))
|
||||
(import "wasi_snapshot_preview1" "args_sizes_get" (func $wasi_snapshot_preview1.args_sizes_get (type $t0)))
|
||||
(import "wasi_snapshot_preview1" "args_get" (func $wasi_snapshot_preview1.args_get (type $t0)))
|
||||
(import "wasi_snapshot_preview1" "fd_write" (func $wasi_snapshot_preview1.fd_write (type $t1)))
|
||||
(import "wasi_snapshot_preview1" "fd_read" (func $wasi_snapshot_preview1.fd_read (type $t1)))
|
||||
(import "wasi_snapshot_preview1" "fd_close" (func $wasi_snapshot_preview1.fd_close (type $t2)))
|
||||
(import "wasi_snapshot_preview1" "path_open" (func $wasi_snapshot_preview1.path_open (type $t3)))
|
||||
(memory $memory 1)
|
||||
(export "memory" (memory 0))
|
||||
(func $call_environ_sizes_get (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
call $wasi_snapshot_preview1.environ_sizes_get)
|
||||
(func $call_environ_get (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
call $wasi_snapshot_preview1.environ_get)
|
||||
(func $call_args_sizes_get (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
call $wasi_snapshot_preview1.args_sizes_get)
|
||||
(func $call_args_get (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
call $wasi_snapshot_preview1.args_get)
|
||||
(func $call_fd_write (type $t1) (param $p0 i32) (param $p1 i32) (param $p2 i32) (param $p3 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
local.get $p2
|
||||
local.get $p3
|
||||
call $wasi_snapshot_preview1.fd_write)
|
||||
(func $call_fd_read (type $t1) (param $p0 i32) (param $p1 i32) (param $p2 i32) (param $p3 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
local.get $p2
|
||||
local.get $p3
|
||||
call $wasi_snapshot_preview1.fd_read)
|
||||
(func $call_fd_close (type $t2) (param $p0 i32) (result i32)
|
||||
local.get $p0
|
||||
call $wasi_snapshot_preview1.fd_close)
|
||||
(func $call_path_open (type $t3) (param $p0 i32) (param $p1 i32) (param $p2 i32) (param $p3 i32) (param $p4 i32) (param $p5 i64) (param $p6 i64) (param $p7 i32) (param $p8 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
local.get $p2
|
||||
local.get $p3
|
||||
local.get $p4
|
||||
local.get $p5
|
||||
local.get $p6
|
||||
local.get $p7
|
||||
local.get $p8
|
||||
call $wasi_snapshot_preview1.path_open)
|
||||
(export "call_environ_sizes_get" (func $call_environ_sizes_get))
|
||||
(export "call_environ_get" (func $call_environ_get))
|
||||
(export "call_args_sizes_get" (func $call_args_sizes_get))
|
||||
(export "call_args_get" (func $call_args_get))
|
||||
(export "call_fd_write" (func $call_fd_write))
|
||||
(export "call_fd_read" (func $call_fd_read))
|
||||
(export "call_fd_close" (func $call_fd_close))
|
||||
(export "call_path_open" (func $call_path_open))
|
||||
)
|
||||
24
crates/misc/dotnet/tests/TempFile.cs
Normal file
24
crates/misc/dotnet/tests/TempFile.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Wasmtime.Tests
|
||||
{
|
||||
internal class TempFile : IDisposable
|
||||
{
|
||||
public TempFile()
|
||||
{
|
||||
Path = System.IO.Path.GetTempFileName();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Path != null)
|
||||
{
|
||||
File.Delete(Path);
|
||||
Path = null;
|
||||
}
|
||||
}
|
||||
|
||||
public string Path { get; private set; }
|
||||
}
|
||||
}
|
||||
250
crates/misc/dotnet/tests/WasiTests.cs
Normal file
250
crates/misc/dotnet/tests/WasiTests.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace Wasmtime.Tests
|
||||
{
|
||||
public class WasiFixture : ModuleFixture
|
||||
{
|
||||
protected override string ModuleFileName => "Wasi.wasm";
|
||||
}
|
||||
|
||||
public class WasiTests : IClassFixture<WasiFixture>
|
||||
{
|
||||
public WasiTests(WasiFixture fixture)
|
||||
{
|
||||
Fixture = fixture;
|
||||
}
|
||||
|
||||
private WasiFixture Fixture { get; set; }
|
||||
|
||||
[Fact]
|
||||
public void ItHasNoEnvironmentByDefault()
|
||||
{
|
||||
using var instance = Fixture.Module.Instantiate(new Wasi(Fixture.Module.Store));
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_environ_sizes_get(0, 4));
|
||||
Assert.Equal(0, memory.ReadInt32(0));
|
||||
Assert.Equal(0, memory.ReadInt32(4));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItHasSpecifiedEnvironment()
|
||||
{
|
||||
var env = new Dictionary<string, string>() {
|
||||
{"FOO", "BAR"},
|
||||
{"WASM", "IS"},
|
||||
{"VERY", "COOL"},
|
||||
};
|
||||
|
||||
var wasi = new WasiBuilder()
|
||||
.WithEnvironmentVariables(env.Select(kvp => (kvp.Key, kvp.Value)))
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_environ_sizes_get(0, 4));
|
||||
Assert.Equal(env.Count, memory.ReadInt32(0));
|
||||
Assert.Equal(env.Sum(kvp => kvp.Key.Length + kvp.Value.Length + 2), memory.ReadInt32(4));
|
||||
Assert.Equal(0, inst.call_environ_get(0, 4 * env.Count));
|
||||
|
||||
for (int i = 0; i < env.Count; ++i)
|
||||
{
|
||||
var kvp = memory.ReadNullTerminatedString(memory.ReadInt32(i * 4)).Split("=");
|
||||
Assert.Equal(env[kvp[0]], kvp[1]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItInheritsEnvironment()
|
||||
{
|
||||
var wasi = new WasiBuilder()
|
||||
.WithInheritedEnvironment()
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_environ_sizes_get(0, 4));
|
||||
Assert.Equal(Environment.GetEnvironmentVariables().Keys.Count, memory.ReadInt32(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItHasNoArgumentsByDefault()
|
||||
{
|
||||
using var instance = Fixture.Module.Instantiate(new Wasi(Fixture.Module.Store));
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_args_sizes_get(0, 4));
|
||||
Assert.Equal(0, memory.ReadInt32(0));
|
||||
Assert.Equal(0, memory.ReadInt32(4));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItHasSpecifiedArguments()
|
||||
{
|
||||
var args = new List<string>() {
|
||||
"WASM",
|
||||
"IS",
|
||||
"VERY",
|
||||
"COOL"
|
||||
};
|
||||
|
||||
var wasi = new WasiBuilder()
|
||||
.WithArgs(args)
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_args_sizes_get(0, 4));
|
||||
Assert.Equal(args.Count, memory.ReadInt32(0));
|
||||
Assert.Equal(args.Sum(a => a.Length + 1), memory.ReadInt32(4));
|
||||
Assert.Equal(0, inst.call_args_get(0, 4 * args.Count));
|
||||
|
||||
for (int i = 0; i < args.Count; ++i)
|
||||
{
|
||||
var arg = memory.ReadNullTerminatedString(memory.ReadInt32(i * 4));
|
||||
Assert.Equal(args[i], arg);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItInheritsArguments()
|
||||
{
|
||||
var wasi = new WasiBuilder()
|
||||
.WithInheritedArgs()
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
|
||||
Assert.Equal(0, inst.call_args_sizes_get(0, 4));
|
||||
Assert.Equal(Environment.GetCommandLineArgs().Length, memory.ReadInt32(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItSetsStdIn()
|
||||
{
|
||||
const string MESSAGE = "WASM IS VERY COOL";
|
||||
|
||||
using (var file = new TempFile())
|
||||
{
|
||||
File.WriteAllText(file.Path, MESSAGE);
|
||||
|
||||
var wasi = new WasiBuilder()
|
||||
.WithStandardInput(file.Path)
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
memory.WriteInt32(0, 8);
|
||||
memory.WriteInt32(4, MESSAGE.Length);
|
||||
|
||||
Assert.Equal(0, inst.call_fd_read(0, 0, 1, 32));
|
||||
Assert.Equal(MESSAGE.Length, memory.ReadInt32(32));
|
||||
Assert.Equal(MESSAGE, memory.ReadString(8, MESSAGE.Length));
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
public void ItSetsStdOutAndStdErr(int fd)
|
||||
{
|
||||
const string MESSAGE = "WASM IS VERY COOL";
|
||||
|
||||
using (var file = new TempFile())
|
||||
{
|
||||
var builder = new WasiBuilder();
|
||||
if (fd == 1)
|
||||
{
|
||||
builder.WithStandardOutput(file.Path);
|
||||
}
|
||||
else if (fd == 2)
|
||||
{
|
||||
builder.WithStandardError(file.Path);
|
||||
}
|
||||
|
||||
var wasi = builder.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
memory.WriteInt32(0, 8);
|
||||
memory.WriteInt32(4, MESSAGE.Length);
|
||||
memory.WriteString(8, MESSAGE);
|
||||
|
||||
Assert.Equal(0, inst.call_fd_write(fd, 0, 1, 32));
|
||||
Assert.Equal(MESSAGE.Length, memory.ReadInt32(32));
|
||||
Assert.Equal(MESSAGE, File.ReadAllText(file.Path));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItSetsPreopenDirectories()
|
||||
{
|
||||
const string MESSAGE = "WASM IS VERY COOL";
|
||||
|
||||
using (var file = new TempFile())
|
||||
{
|
||||
var wasi = new WasiBuilder()
|
||||
.WithPreopenedDirectory(Path.GetDirectoryName(file.Path), "/foo")
|
||||
.Build(Fixture.Module.Store);
|
||||
|
||||
using var instance = Fixture.Module.Instantiate(wasi);
|
||||
dynamic inst = instance;
|
||||
|
||||
var memory = instance.Externs.Memories[0];
|
||||
var fileName = Path.GetFileName(file.Path);
|
||||
memory.WriteString(0, fileName);
|
||||
|
||||
Assert.Equal(0, inst.call_path_open(
|
||||
3,
|
||||
0,
|
||||
0,
|
||||
fileName.Length,
|
||||
0,
|
||||
0x40 /* RIGHTS_FD_WRITE */,
|
||||
0,
|
||||
0,
|
||||
64
|
||||
)
|
||||
);
|
||||
|
||||
var fileFd = (int) memory.ReadInt32(64);
|
||||
Assert.True(fileFd > 3);
|
||||
|
||||
memory.WriteInt32(0, 8);
|
||||
memory.WriteInt32(4, MESSAGE.Length);
|
||||
memory.WriteString(8, MESSAGE);
|
||||
|
||||
Assert.Equal(0, inst.call_fd_write(fileFd, 0, 1, 64));
|
||||
Assert.Equal(MESSAGE.Length, memory.ReadInt32(64));
|
||||
Assert.Equal(MESSAGE, File.ReadAllText(file.Path));
|
||||
|
||||
Assert.Equal(0, inst.call_fd_close(fileFd));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user