Files
wazero/internal/wasm/counts_test.go
Crypt Keeper 0da1af2d51 Supports mix of wasm and go funcs in the same module (#707)
This removes the constraint of a module being exclusively wasm or host
functions. Later pull requests can optimize special imports to be
implemented in wasm, particularly useful for disabled logging callbacks.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-07-19 11:55:37 +08:00

306 lines
7.1 KiB
Go

package wasm
import (
"testing"
"github.com/tetratelabs/wazero/internal/testing/require"
)
func TestModule_ImportFuncCount(t *testing.T) {
tests := []struct {
name string
input *Module
expected uint32
}{
{
name: "none",
input: &Module{},
},
{
name: "none with function section",
input: &Module{FunctionSection: []Index{0}},
},
{
name: "one",
input: &Module{ImportSection: []*Import{{Type: ExternTypeFunc}}},
expected: 1,
},
{
name: "one with function section",
input: &Module{ImportSection: []*Import{{Type: ExternTypeFunc}}, FunctionSection: []Index{0}},
expected: 1,
},
{
name: "one with other imports",
input: &Module{ImportSection: []*Import{{Type: ExternTypeFunc}, {Type: ExternTypeMemory}}},
expected: 1,
},
{
name: "two",
input: &Module{ImportSection: []*Import{{Type: ExternTypeFunc}, {Type: ExternTypeFunc}}},
expected: 2,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
require.Equal(t, tc.expected, tc.input.ImportFuncCount())
})
}
}
func TestModule_ImportTableCount(t *testing.T) {
tests := []struct {
name string
input *Module
expected uint32
}{
{
name: "none",
input: &Module{},
},
{
name: "none with table section",
input: &Module{TableSection: []*Table{{Min: 1, Max: nil}}},
},
{
name: "one",
input: &Module{ImportSection: []*Import{{Type: ExternTypeTable}}},
expected: 1,
},
{
name: "one with table section",
input: &Module{
ImportSection: []*Import{{Type: ExternTypeTable}},
TableSection: []*Table{{Min: 1, Max: nil}},
},
expected: 1,
},
{
name: "one with other imports",
input: &Module{ImportSection: []*Import{{Type: ExternTypeTable}, {Type: ExternTypeMemory}}},
expected: 1,
},
{
name: "two",
input: &Module{ImportSection: []*Import{{Type: ExternTypeTable}, {Type: ExternTypeTable}}},
expected: 2,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
require.Equal(t, tc.expected, tc.input.ImportTableCount())
})
}
}
// TODO: once we fix up-front validation, this only needs to check zero or one
func TestModule_ImportMemoryCount(t *testing.T) {
tests := []struct {
name string
input *Module
expected uint32
}{
{
name: "none",
input: &Module{},
},
{
name: "none with memory section",
input: &Module{MemorySection: &Memory{Min: 1}},
},
{
name: "one",
input: &Module{ImportSection: []*Import{{Type: ExternTypeMemory}}},
expected: 1,
},
{
name: "one with memory section",
input: &Module{
ImportSection: []*Import{{Type: ExternTypeMemory}},
MemorySection: &Memory{Min: 1},
},
expected: 1,
},
{
name: "one with other imports",
input: &Module{ImportSection: []*Import{{Type: ExternTypeMemory}, {Type: ExternTypeTable}}},
expected: 1,
},
{
name: "two",
input: &Module{ImportSection: []*Import{{Type: ExternTypeMemory}, {Type: ExternTypeMemory}}},
expected: 2,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
require.Equal(t, tc.expected, tc.input.ImportMemoryCount())
})
}
}
func TestModule_ImportGlobalCount(t *testing.T) {
tests := []struct {
name string
input *Module
expected uint32
}{
{
name: "none",
input: &Module{},
},
{
name: "none with global section",
input: &Module{GlobalSection: []*Global{{Type: &GlobalType{ValType: ValueTypeI64}}}},
},
{
name: "one",
input: &Module{ImportSection: []*Import{{Type: ExternTypeGlobal}}},
expected: 1,
},
{
name: "one with global section",
input: &Module{
ImportSection: []*Import{{Type: ExternTypeGlobal}},
GlobalSection: []*Global{{Type: &GlobalType{ValType: ValueTypeI64}}},
},
expected: 1,
},
{
name: "one with other imports",
input: &Module{ImportSection: []*Import{{Type: ExternTypeGlobal}, {Type: ExternTypeMemory}}},
expected: 1,
},
{
name: "two",
input: &Module{ImportSection: []*Import{{Type: ExternTypeGlobal}, {Type: ExternTypeGlobal}}},
expected: 2,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
require.Equal(t, tc.expected, tc.input.ImportGlobalCount())
})
}
}
func TestModule_SectionElementCount(t *testing.T) {
i32, f32 := ValueTypeI32, ValueTypeF32
zero := uint32(0)
empty := &ConstantExpression{Opcode: OpcodeI32Const, Data: const0}
tests := []struct {
name string
input *Module
expected map[string]uint32
}{
{
name: "empty",
input: &Module{},
expected: map[string]uint32{},
},
{
name: "NameSection",
input: &Module{NameSection: &NameSection{ModuleName: "simple"}},
expected: map[string]uint32{"custom": 1},
},
{
name: "TypeSection",
input: &Module{
TypeSection: []*FunctionType{
{},
{Params: []ValueType{i32, i32}, Results: []ValueType{i32}},
{Params: []ValueType{i32, i32, i32, i32}, Results: []ValueType{i32}},
},
},
expected: map[string]uint32{"type": 3},
},
{
name: "TypeSection and ImportSection",
input: &Module{
TypeSection: []*FunctionType{
{Params: []ValueType{i32, i32}, Results: []ValueType{i32}},
{Params: []ValueType{f32, f32}, Results: []ValueType{f32}},
},
ImportSection: []*Import{
{
Module: "Math", Name: "Mul",
Type: ExternTypeFunc,
DescFunc: 1,
}, {
Module: "Math", Name: "Add",
Type: ExternTypeFunc,
DescFunc: 0,
},
},
},
expected: map[string]uint32{"import": 2, "type": 2},
},
{
name: "TypeSection, FunctionSection, CodeSection, ExportSection and StartSection",
input: &Module{
TypeSection: []*FunctionType{{}},
FunctionSection: []Index{0},
CodeSection: []*Code{
{Body: []byte{OpcodeLocalGet, 0, OpcodeLocalGet, 1, OpcodeI32Add, OpcodeEnd}},
},
ExportSection: []*Export{
{Name: "AddInt", Type: ExternTypeFunc, Index: Index(0)},
},
StartSection: &zero,
},
expected: map[string]uint32{"code": 1, "export": 1, "function": 1, "start": 1, "type": 1},
},
{
name: "MemorySection and DataSection",
input: &Module{
MemorySection: &Memory{Min: 1},
DataSection: []*DataSegment{{OffsetExpression: empty}},
},
expected: map[string]uint32{"data": 1, "memory": 1},
},
{
name: "TableSection and ElementSection",
input: &Module{
TableSection: []*Table{{Min: 1}},
ElementSection: []*ElementSegment{{OffsetExpr: empty}},
},
expected: map[string]uint32{"element": 1, "table": 1},
},
{
name: "TableSection (multiple tables) and ElementSection",
input: &Module{
TableSection: []*Table{{Min: 1}, {Min: 2}},
ElementSection: []*ElementSegment{{OffsetExpr: empty}},
},
expected: map[string]uint32{"element": 1, "table": 2},
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
actual := map[string]uint32{}
for i := SectionID(0); i <= SectionIDData; i++ {
if size := tc.input.SectionElementCount(i); size > 0 {
actual[SectionIDName(i)] = size
}
}
require.Equal(t, tc.expected, actual)
})
}
}