Files
wazero/internal/wasm/binary/encoder_test.go
Crypt Keeper 0186e41b27 Consolidates API to config input types (#280)
This makes instantiating host or wasm-defined modules similar, by using
XXXConfig types. Doing so also allows configuration engines to seed
properties.

Since decoded modules are only usable during instantiation, this pushes
decoding inside those functions. By doing so, the API is easier to use
as it has less choices and less errors to catch. Detection is done
internally by peeking at the magic number.

See https://github.com/tetratelabs/wazero/issues/279

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-02-23 16:41:32 +08:00

172 lines
5.8 KiB
Go

package binary
import (
"testing"
"github.com/stretchr/testify/require"
wasm "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",
Kind: wasm.ImportKindFunc,
DescFunc: 1,
}, {
Module: "Math", Name: "Add",
Kind: wasm.ImportKindFunc,
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.ImportKindFunc,
0x01, // type index
0x04, 'M', 'a', 't', 'h', 0x03, 'A', 'd', 'd', wasm.ImportKindFunc,
0x00, // type index
),
},
{
name: "type function and start section",
input: &wasm.Module{
TypeSection: []*wasm.FunctionType{{}},
ImportSection: []*wasm.Import{{
Module: "", Name: "hello",
Kind: wasm.ImportKindFunc,
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.ImportKindFunc,
0x00, // type index
wasm.SectionIDStart, 0x01,
0x00, // start function index
),
},
{
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: map[string]*wasm.Export{
"AddInt": {Name: "AddInt", Kind: wasm.ExportKindFunc, 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.ExportKindFunc, 0x00, // func[0]
wasm.SectionIDCode, 0x09, // 9 bytes in this section
01, // one code section
07, // length of the body + locals
00, // 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"
),
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
bytes := EncodeModule(tc.input)
require.Equal(t, tc.expected, bytes)
})
}
}