While compilers should be conservative when targeting WebAssembly Core features, runtimes should be lenient as otherwise people need to constantly turn on all features. Currently, most examples have to turn on 2.0 features because compilers such as AssemblyScript and TinyGo use them by default. This matches the policy with the reality, and should make first time use easier. This top-levels an internal type as `api.CoreFeatures` and defaults to 2.0 as opposed to 1.0, our previous default. This is less cluttered than the excess of `WithXXX` methods we had prior to implementing all planned WebAssembly Core Specification 1.0 features. Finally, this backfills rationale as flat config types were a distinct decision even if feature set selection muddied the topic. Signed-off-by: Adrian Cole <adrian@tetrate.io>
142 lines
4.3 KiB
Go
142 lines
4.3 KiB
Go
package binary
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/tetratelabs/wazero/api"
|
|
"github.com/tetratelabs/wazero/internal/testing/require"
|
|
"github.com/tetratelabs/wazero/internal/wasm"
|
|
)
|
|
|
|
func TestFunctionType(t *testing.T) {
|
|
i32, i64, funcRef, externRef := wasm.ValueTypeI32, wasm.ValueTypeI64, wasm.ValueTypeFuncref, wasm.ValueTypeExternref
|
|
tests := []struct {
|
|
name string
|
|
input *wasm.FunctionType
|
|
expected []byte
|
|
}{
|
|
{
|
|
name: "empty",
|
|
input: &wasm.FunctionType{},
|
|
expected: []byte{0x60, 0, 0},
|
|
},
|
|
{
|
|
name: "one param no result",
|
|
input: &wasm.FunctionType{Params: []wasm.ValueType{i32}},
|
|
expected: []byte{0x60, 1, i32, 0},
|
|
},
|
|
{
|
|
name: "no param one result",
|
|
input: &wasm.FunctionType{Results: []wasm.ValueType{i32}},
|
|
expected: []byte{0x60, 0, 1, i32},
|
|
},
|
|
{
|
|
name: "one param one result",
|
|
input: &wasm.FunctionType{Params: []wasm.ValueType{i64}, Results: []wasm.ValueType{i32}},
|
|
expected: []byte{0x60, 1, i64, 1, i32},
|
|
},
|
|
{
|
|
name: "two params no result",
|
|
input: &wasm.FunctionType{Params: []wasm.ValueType{i32, i64}},
|
|
expected: []byte{0x60, 2, i32, i64, 0},
|
|
},
|
|
{
|
|
name: "two param one result",
|
|
input: &wasm.FunctionType{Params: []wasm.ValueType{i32, i64}, Results: []wasm.ValueType{i32}},
|
|
expected: []byte{0x60, 2, i32, i64, 1, i32},
|
|
},
|
|
{
|
|
name: "no param two results",
|
|
input: &wasm.FunctionType{Results: []wasm.ValueType{i32, i64}},
|
|
expected: []byte{0x60, 0, 2, i32, i64},
|
|
},
|
|
{
|
|
name: "one param two results",
|
|
input: &wasm.FunctionType{Params: []wasm.ValueType{i64}, Results: []wasm.ValueType{i32, i64}},
|
|
expected: []byte{0x60, 1, i64, 2, i32, i64},
|
|
},
|
|
{
|
|
name: "two param two results",
|
|
input: &wasm.FunctionType{Params: []wasm.ValueType{i32, i64}, Results: []wasm.ValueType{i32, i64}},
|
|
expected: []byte{0x60, 2, i32, i64, 2, i32, i64},
|
|
},
|
|
{
|
|
name: "two param two results with funcrefs",
|
|
input: &wasm.FunctionType{Params: []wasm.ValueType{i32, funcRef}, Results: []wasm.ValueType{funcRef, i64}},
|
|
expected: []byte{0x60, 2, i32, funcRef, 2, funcRef, i64},
|
|
},
|
|
{
|
|
name: "two param two results with externrefs",
|
|
input: &wasm.FunctionType{Params: []wasm.ValueType{i32, externRef}, Results: []wasm.ValueType{externRef, i64}},
|
|
expected: []byte{0x60, 2, i32, externRef, 2, externRef, i64},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
|
|
b := encodeFunctionType(tc.input)
|
|
t.Run(fmt.Sprintf("encode - %s", tc.name), func(t *testing.T) {
|
|
require.Equal(t, tc.expected, b)
|
|
})
|
|
|
|
t.Run(fmt.Sprintf("decode - %s", tc.name), func(t *testing.T) {
|
|
binary, err := decodeFunctionType(api.CoreFeaturesV2, bytes.NewReader(b))
|
|
require.NoError(t, err)
|
|
require.Equal(t, binary, tc.input)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecodeFunctionType_Errors(t *testing.T) {
|
|
i32, i64 := wasm.ValueTypeI32, wasm.ValueTypeI64
|
|
tests := []struct {
|
|
name string
|
|
input []byte
|
|
enabledFeatures api.CoreFeatures
|
|
expectedErr string
|
|
}{
|
|
{
|
|
name: "undefined param no result",
|
|
input: []byte{0x60, 1, 0x6e, 0},
|
|
expectedErr: "could not read parameter types: invalid value type: 110",
|
|
},
|
|
{
|
|
name: "no param undefined result",
|
|
input: []byte{0x60, 0, 1, 0x6e},
|
|
expectedErr: "could not read result types: invalid value type: 110",
|
|
},
|
|
{
|
|
name: "undefined param undefined result",
|
|
input: []byte{0x60, 1, 0x6e, 1, 0x6e},
|
|
expectedErr: "could not read parameter types: invalid value type: 110",
|
|
},
|
|
{
|
|
name: "no param two results - multi-value not enabled",
|
|
input: []byte{0x60, 0, 2, i32, i64},
|
|
expectedErr: "multiple result types invalid as feature \"multi-value\" is disabled",
|
|
},
|
|
{
|
|
name: "one param two results - multi-value not enabled",
|
|
input: []byte{0x60, 1, i64, 2, i32, i64},
|
|
expectedErr: "multiple result types invalid as feature \"multi-value\" is disabled",
|
|
},
|
|
{
|
|
name: "two param two results - multi-value not enabled",
|
|
input: []byte{0x60, 2, i32, i64, 2, i32, i64},
|
|
expectedErr: "multiple result types invalid as feature \"multi-value\" is disabled",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := decodeFunctionType(api.CoreFeaturesV1, bytes.NewReader(tc.input))
|
|
require.EqualError(t, err, tc.expectedErr)
|
|
})
|
|
}
|
|
}
|