wa-lang.org/wazero@v1.0.2/internal/wasm/binary/decoder_test.go (about) 1 package binary 2 3 import ( 4 "testing" 5 6 "wa-lang.org/wazero/api" 7 "wa-lang.org/wazero/internal/testing/require" 8 "wa-lang.org/wazero/internal/wasm" 9 ) 10 11 // TestDecodeModule relies on unit tests for Module.Encode, specifically that the encoding is both known and correct. 12 // This avoids having to copy/paste or share variables to assert against byte arrays. 13 func TestDecodeModule(t *testing.T) { 14 i32, f32 := wasm.ValueTypeI32, wasm.ValueTypeF32 15 zero := uint32(0) 16 17 tests := []struct { 18 name string 19 input *wasm.Module // round trip test! 20 }{ 21 { 22 name: "empty", 23 input: &wasm.Module{}, 24 }, 25 { 26 name: "only name section", 27 input: &wasm.Module{NameSection: &wasm.NameSection{ModuleName: "simple"}}, 28 }, 29 { 30 name: "type section", 31 input: &wasm.Module{ 32 TypeSection: []*wasm.FunctionType{ 33 {}, 34 {Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32}}, 35 {Params: []wasm.ValueType{i32, i32, i32, i32}, Results: []wasm.ValueType{i32}}, 36 }, 37 }, 38 }, 39 { 40 name: "type and import section", 41 input: &wasm.Module{ 42 TypeSection: []*wasm.FunctionType{ 43 {Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32}}, 44 {Params: []wasm.ValueType{f32, f32}, Results: []wasm.ValueType{f32}}, 45 }, 46 ImportSection: []*wasm.Import{ 47 { 48 Module: "Math", Name: "Mul", 49 Type: wasm.ExternTypeFunc, 50 DescFunc: 1, 51 }, { 52 Module: "Math", Name: "Add", 53 Type: wasm.ExternTypeFunc, 54 DescFunc: 0, 55 }, 56 }, 57 }, 58 }, 59 { 60 name: "table and memory section", 61 input: &wasm.Module{ 62 TableSection: []*wasm.Table{{Min: 3, Type: wasm.RefTypeFuncref}}, 63 MemorySection: &wasm.Memory{Min: 1, Cap: 1, Max: 1, IsMaxEncoded: true}, 64 }, 65 }, 66 { 67 name: "type function and start section", 68 input: &wasm.Module{ 69 TypeSection: []*wasm.FunctionType{{}}, 70 ImportSection: []*wasm.Import{{ 71 Module: "", Name: "hello", 72 Type: wasm.ExternTypeFunc, 73 DescFunc: 0, 74 }}, 75 StartSection: &zero, 76 }, 77 }, 78 } 79 80 for _, tt := range tests { 81 tc := tt 82 83 t.Run(tc.name, func(t *testing.T) { 84 m, e := DecodeModule(EncodeModule(tc.input), api.CoreFeaturesV1, wasm.MemoryLimitPages, false) 85 require.NoError(t, e) 86 require.Equal(t, tc.input, m) 87 }) 88 } 89 90 t.Run("skips custom section", func(t *testing.T) { 91 input := append(append(Magic, version...), 92 wasm.SectionIDCustom, 0xf, // 15 bytes in this section 93 0x04, 'm', 'e', 'm', 'e', 94 1, 2, 3, 4, 5, 6, 7, 8, 9, 0) 95 m, e := DecodeModule(input, api.CoreFeaturesV1, wasm.MemoryLimitPages, false) 96 require.NoError(t, e) 97 require.Equal(t, &wasm.Module{}, m) 98 }) 99 100 t.Run("skips custom section, but not name", func(t *testing.T) { 101 input := append(append(Magic, version...), 102 wasm.SectionIDCustom, 0xf, // 15 bytes in this section 103 0x04, 'm', 'e', 'm', 'e', 104 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 105 wasm.SectionIDCustom, 0x0e, // 14 bytes in this section 106 0x04, 'n', 'a', 'm', 'e', 107 subsectionIDModuleName, 0x07, // 7 bytes in this subsection 108 0x06, // the Module name simple is 6 bytes long 109 's', 'i', 'm', 'p', 'l', 'e') 110 m, e := DecodeModule(input, api.CoreFeaturesV1, wasm.MemoryLimitPages, false) 111 require.NoError(t, e) 112 require.Equal(t, &wasm.Module{NameSection: &wasm.NameSection{ModuleName: "simple"}}, m) 113 }) 114 t.Run("data count section disabled", func(t *testing.T) { 115 input := append(append(Magic, version...), 116 wasm.SectionIDDataCount, 1, 0) 117 _, e := DecodeModule(input, api.CoreFeaturesV1, wasm.MemoryLimitPages, false) 118 require.EqualError(t, e, `data count section not supported as feature "bulk-memory-operations" is disabled`) 119 }) 120 } 121 122 func TestDecodeModule_Errors(t *testing.T) { 123 tests := []struct { 124 name string 125 input []byte 126 expectedErr string 127 }{ 128 { 129 name: "wrong magic", 130 input: []byte("wasm\x01\x00\x00\x00"), 131 expectedErr: "invalid magic number", 132 }, 133 { 134 name: "wrong version", 135 input: []byte("\x00asm\x01\x00\x00\x01"), 136 expectedErr: "invalid version header", 137 }, 138 { 139 name: "multiple start sections", 140 input: append(append(Magic, version...), 141 wasm.SectionIDType, 4, 1, 0x60, 0, 0, 142 wasm.SectionIDFunction, 2, 1, 0, 143 wasm.SectionIDCode, 4, 1, 144 2, 0, wasm.OpcodeEnd, 145 wasm.SectionIDStart, 1, 0, 146 wasm.SectionIDStart, 1, 0, 147 ), 148 expectedErr: `multiple start sections are invalid`, 149 }, 150 { 151 name: "redundant name section", 152 input: append(append(Magic, version...), 153 wasm.SectionIDCustom, 0x09, // 9 bytes in this section 154 0x04, 'n', 'a', 'm', 'e', 155 subsectionIDModuleName, 0x02, 0x01, 'x', 156 wasm.SectionIDCustom, 0x09, // 9 bytes in this section 157 0x04, 'n', 'a', 'm', 'e', 158 subsectionIDModuleName, 0x02, 0x01, 'x'), 159 expectedErr: "section custom: redundant custom section name", 160 }, 161 } 162 163 for _, tt := range tests { 164 tc := tt 165 166 t.Run(tc.name, func(t *testing.T) { 167 _, e := DecodeModule(tc.input, api.CoreFeaturesV1, wasm.MemoryLimitPages, false) 168 require.EqualError(t, e, tc.expectedErr) 169 }) 170 } 171 }