Files
wazero/internal/wasm/binary/encoder_test.go
Crypt Keeper 329ccca6b1 Switches from gofmt to gofumpt (#848)
This switches to gofumpt and applies changes, as I've noticed working
in dapr (who uses this) that it finds some things that are annoying,
such as inconsistent block formatting in test tables.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-11-09 05:48:24 +01:00

223 lines
7.6 KiB
Go

package binary
import (
"testing"
"github.com/tetratelabs/wazero/internal/leb128"
"github.com/tetratelabs/wazero/internal/testing/require"
"github.com/tetratelabs/wazero/internal/wasm"
)
func TestModule_Encode(t *testing.T) {
i32, f32 := wasm.ValueTypeI32, wasm.ValueTypeF32
zero := uint32(0)
tests := []struct {
name string
input *wasm.Module
expected []byte
}{
{
name: "empty",
input: &wasm.Module{},
expected: append(Magic, version...),
},
{
name: "only name section",
input: &wasm.Module{NameSection: &wasm.NameSection{ModuleName: "simple"}},
expected: append(append(Magic, version...),
wasm.SectionIDCustom, 0x0e, // 14 bytes in this section
0x04, 'n', 'a', 'm', 'e',
subsectionIDModuleName, 0x07, // 7 bytes in this subsection
0x06, // the Module name simple is 6 bytes long
's', 'i', 'm', 'p', 'l', 'e'),
},
{
name: "type section",
input: &wasm.Module{
TypeSection: []*wasm.FunctionType{
{},
{Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32}},
{Params: []wasm.ValueType{i32, i32, i32, i32}, Results: []wasm.ValueType{i32}},
},
},
expected: append(append(Magic, version...),
wasm.SectionIDType, 0x12, // 18 bytes in this section
0x03, // 3 types
0x60, 0x00, 0x00, // func=0x60 no param no result
0x60, 0x02, i32, i32, 0x01, i32, // func=0x60 2 params and 1 result
0x60, 0x04, i32, i32, i32, i32, 0x01, i32, // func=0x60 4 params and 1 result
),
},
{
name: "type and import section",
input: &wasm.Module{
TypeSection: []*wasm.FunctionType{
{Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32}},
{Params: []wasm.ValueType{f32, f32}, Results: []wasm.ValueType{f32}},
},
ImportSection: []*wasm.Import{
{
Module: "Math", Name: "Mul",
Type: wasm.ExternTypeFunc,
DescFunc: 1,
}, {
Module: "Math", Name: "Add",
Type: wasm.ExternTypeFunc,
DescFunc: 0,
},
},
},
expected: append(append(Magic, version...),
wasm.SectionIDType, 0x0d, // 13 bytes in this section
0x02, // 2 types
0x60, 0x02, i32, i32, 0x01, i32, // func=0x60 2 params and 1 result
0x60, 0x02, f32, f32, 0x01, f32, // func=0x60 2 params and 1 result
wasm.SectionIDImport, 0x17, // 23 bytes in this section
0x02, // 2 imports
0x04, 'M', 'a', 't', 'h', 0x03, 'M', 'u', 'l', wasm.ExternTypeFunc,
0x01, // type index
0x04, 'M', 'a', 't', 'h', 0x03, 'A', 'd', 'd', wasm.ExternTypeFunc,
0x00, // type index
),
},
{
name: "type function and start section",
input: &wasm.Module{
TypeSection: []*wasm.FunctionType{{}},
ImportSection: []*wasm.Import{{
Module: "", Name: "hello",
Type: wasm.ExternTypeFunc,
DescFunc: 0,
}},
StartSection: &zero,
},
expected: append(append(Magic, version...),
wasm.SectionIDType, 0x04, // 4 bytes in this section
0x01, // 1 type
0x60, 0x0, 0x0, // func=0x60 0 params and 0 result
wasm.SectionIDImport, 0x0a, // 10 bytes in this section
0x01, // 1 import
0x00, 0x05, 'h', 'e', 'l', 'l', 'o', wasm.ExternTypeFunc,
0x00, // type index
wasm.SectionIDStart, 0x01,
0x00, // start function index
),
},
{
name: "table and memory section",
input: &wasm.Module{
TableSection: []*wasm.Table{{Min: 3, Type: wasm.RefTypeFuncref}},
MemorySection: &wasm.Memory{Min: 1, Max: 1, IsMaxEncoded: true},
},
expected: append(append(Magic, version...),
wasm.SectionIDTable, 0x04, // 4 bytes in this section
0x01, // 1 table
wasm.RefTypeFuncref, 0x0, 0x03, // func, only min: 3
wasm.SectionIDMemory, 0x04, // 4 bytes in this section
0x01, // 1 memory
0x01, 0x01, 0x01, // min and max = 1
),
},
{
name: "exported func with instructions",
input: &wasm.Module{
TypeSection: []*wasm.FunctionType{
{Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32}},
},
FunctionSection: []wasm.Index{0},
CodeSection: []*wasm.Code{
{Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeLocalGet, 1, wasm.OpcodeI32Add, wasm.OpcodeEnd}},
},
ExportSection: []*wasm.Export{
{Name: "AddInt", Type: wasm.ExternTypeFunc, Index: wasm.Index(0)},
},
NameSection: &wasm.NameSection{
FunctionNames: wasm.NameMap{{Index: wasm.Index(0), Name: "addInt"}},
LocalNames: wasm.IndirectNameMap{
{Index: wasm.Index(0), NameMap: wasm.NameMap{
{Index: wasm.Index(0), Name: "value_1"},
{Index: wasm.Index(1), Name: "value_2"},
}},
},
},
},
expected: append(append(Magic, version...),
wasm.SectionIDType, 0x07, // 7 bytes in this section
0x01, // 1 type
0x60, 0x02, i32, i32, 0x01, i32, // func=0x60 2 params and 1 result
wasm.SectionIDFunction, 0x02, // 2 bytes in this section
0x01, // 1 function
0x00, // func[0] type index 0
wasm.SectionIDExport, 0x0a, // 10 bytes in this section
0x01, // 1 export
0x06, 'A', 'd', 'd', 'I', 'n', 't', // size of "AddInt", "AddInt"
wasm.ExternTypeFunc, 0x00, // func[0]
wasm.SectionIDCode, 0x09, // 9 bytes in this section
0o1, // one code section
0o7, // length of the body + locals
0o0, // count of local blocks
wasm.OpcodeLocalGet, 0, // local.get 0
wasm.OpcodeLocalGet, 1, // local.get 1
wasm.OpcodeI32Add, // i32.add
wasm.OpcodeEnd, // end of instructions/code
wasm.SectionIDCustom, 0x27, // 39 bytes in this section
0x04, 'n', 'a', 'm', 'e',
subsectionIDFunctionNames, 0x09, // 9 bytes
0x01, // two function names
0x00, 0x06, 'a', 'd', 'd', 'I', 'n', 't', // index 0, size of "addInt", "addInt"
subsectionIDLocalNames, 0x15, // 21 bytes
0x01, // one function
0x00, 0x02, // index 0 has 2 locals
0x00, 0x07, 'v', 'a', 'l', 'u', 'e', '_', '1', // index 0, size of "value_1", "value_1"
0x01, 0x07, 'v', 'a', 'l', 'u', 'e', '_', '2', // index 1, size of "value_2", "value_2"
),
},
{
name: "exported global var",
input: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: i32, Mutable: true},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeInt32(0)},
},
},
ExportSection: []*wasm.Export{
{Name: "sp", Type: wasm.ExternTypeGlobal, Index: wasm.Index(0)},
},
},
expected: append(append(Magic, version...),
wasm.SectionIDGlobal, 0x06, // 6 bytes in this section
0x01, wasm.ValueTypeI32, 0x01, // 1 global i32 mutable
wasm.OpcodeI32Const, 0x00, wasm.OpcodeEnd, // arbitrary init to zero
wasm.SectionIDExport, 0x06, // 6 bytes in this section
0x01, // 1 export
0x02, 's', 'p', // size of "sp", "sp"
wasm.ExternTypeGlobal, 0x00, // global[0]
),
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
bytes := EncodeModule(tc.input)
require.Equal(t, tc.expected, bytes)
})
}
}
func TestModule_Encode_HostFunctionSection_Unsupported(t *testing.T) {
// We don't currently have an approach to serialize reflect.Value pointers
fn := func() {}
captured := require.CapturePanic(func() {
EncodeModule(&wasm.Module{
TypeSection: []*wasm.FunctionType{{}},
CodeSection: []*wasm.Code{wasm.MustParseGoReflectFuncCode(fn)},
})
})
require.EqualError(t, captured, "BUG: GoFunction is not encodable")
}