github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/wasm/binary/section_test.go (about) 1 package binary 2 3 import ( 4 "bytes" 5 "testing" 6 7 "github.com/tetratelabs/wazero/api" 8 "github.com/tetratelabs/wazero/internal/testing/binaryencoding" 9 "github.com/tetratelabs/wazero/internal/testing/require" 10 "github.com/tetratelabs/wazero/internal/wasm" 11 ) 12 13 func TestTableSection(t *testing.T) { 14 three := uint32(3) 15 tests := []struct { 16 name string 17 input []byte 18 expected []wasm.Table 19 }{ 20 { 21 name: "min and min with max", 22 input: []byte{ 23 0x01, // 1 table 24 wasm.RefTypeFuncref, 0x01, 2, 3, // (table 2 3) 25 }, 26 expected: []wasm.Table{{Min: 2, Max: &three, Type: wasm.RefTypeFuncref}}, 27 }, 28 { 29 name: "min and min with max - three tables", 30 input: []byte{ 31 0x03, // 3 table 32 wasm.RefTypeFuncref, 0x01, 2, 3, // (table 2 3) 33 wasm.RefTypeExternref, 0x01, 2, 3, // (table 2 3) 34 wasm.RefTypeFuncref, 0x01, 2, 3, // (table 2 3) 35 }, 36 expected: []wasm.Table{ 37 {Min: 2, Max: &three, Type: wasm.RefTypeFuncref}, 38 {Min: 2, Max: &three, Type: wasm.RefTypeExternref}, 39 {Min: 2, Max: &three, Type: wasm.RefTypeFuncref}, 40 }, 41 }, 42 } 43 44 for _, tt := range tests { 45 tc := tt 46 47 t.Run(tc.name, func(t *testing.T) { 48 tables, err := decodeTableSection(bytes.NewReader(tc.input), api.CoreFeatureReferenceTypes) 49 require.NoError(t, err) 50 require.Equal(t, tc.expected, tables) 51 }) 52 } 53 } 54 55 func TestTableSection_Errors(t *testing.T) { 56 tests := []struct { 57 name string 58 input []byte 59 expectedErr string 60 features api.CoreFeatures 61 }{ 62 { 63 name: "min and min with max", 64 input: []byte{ 65 0x02, // 2 tables 66 wasm.RefTypeFuncref, 0x00, 0x01, // (table 1) 67 wasm.RefTypeFuncref, 0x01, 0x02, 0x03, // (table 2 3) 68 }, 69 expectedErr: "at most one table allowed in module as feature \"reference-types\" is disabled", 70 features: api.CoreFeaturesV1, 71 }, 72 } 73 74 for _, tt := range tests { 75 tc := tt 76 77 t.Run(tc.name, func(t *testing.T) { 78 _, err := decodeTableSection(bytes.NewReader(tc.input), tc.features) 79 require.EqualError(t, err, tc.expectedErr) 80 }) 81 } 82 } 83 84 func TestMemorySection(t *testing.T) { 85 max := wasm.MemoryLimitPages 86 87 three := uint32(3) 88 tests := []struct { 89 name string 90 input []byte 91 expected *wasm.Memory 92 }{ 93 { 94 name: "min and min with max", 95 input: []byte{ 96 0x01, // 1 memory 97 0x01, 0x02, 0x03, // (memory 2 3) 98 }, 99 expected: &wasm.Memory{Min: 2, Cap: 2, Max: three, IsMaxEncoded: true}, 100 }, 101 } 102 103 for _, tt := range tests { 104 tc := tt 105 106 t.Run(tc.name, func(t *testing.T) { 107 memories, err := decodeMemorySection(bytes.NewReader(tc.input), api.CoreFeaturesV2, newMemorySizer(max, false), max) 108 require.NoError(t, err) 109 require.Equal(t, tc.expected, memories) 110 }) 111 } 112 } 113 114 func TestMemorySection_Errors(t *testing.T) { 115 max := wasm.MemoryLimitPages 116 117 tests := []struct { 118 name string 119 input []byte 120 expectedErr string 121 }{ 122 { 123 name: "min and min with max", 124 input: []byte{ 125 0x02, // 2 memories 126 0x01, // (memory 1) 127 0x02, 0x03, // (memory 2 3) 128 }, 129 expectedErr: "at most one memory allowed in module, but read 2", 130 }, 131 } 132 133 for _, tt := range tests { 134 tc := tt 135 136 t.Run(tc.name, func(t *testing.T) { 137 _, err := decodeMemorySection(bytes.NewReader(tc.input), api.CoreFeaturesV2, newMemorySizer(max, false), max) 138 require.EqualError(t, err, tc.expectedErr) 139 }) 140 } 141 } 142 143 func TestDecodeExportSection(t *testing.T) { 144 tests := []struct { 145 name string 146 input []byte 147 expected []wasm.Export 148 }{ 149 { 150 name: "empty and non-empty name", 151 input: []byte{ 152 0x02, // 2 exports 153 0x00, // Size of empty name 154 wasm.ExternTypeFunc, 0x02, // func[2] 155 0x01, 'a', // Size of name, name 156 wasm.ExternTypeFunc, 0x01, // func[1] 157 }, 158 expected: []wasm.Export{ 159 {Name: "", Type: wasm.ExternTypeFunc, Index: wasm.Index(2)}, 160 {Name: "a", Type: wasm.ExternTypeFunc, Index: wasm.Index(1)}, 161 }, 162 }, 163 } 164 165 for _, tt := range tests { 166 tc := tt 167 168 t.Run(tc.name, func(t *testing.T) { 169 actual, actualExpMap, err := decodeExportSection(bytes.NewReader(tc.input)) 170 require.NoError(t, err) 171 require.Equal(t, tc.expected, actual) 172 173 expMap := make(map[string]*wasm.Export, len(tc.expected)) 174 for i := range tc.expected { 175 exp := &tc.expected[i] 176 expMap[exp.Name] = exp 177 } 178 require.Equal(t, expMap, actualExpMap) 179 }) 180 } 181 } 182 183 func TestDecodeExportSection_Errors(t *testing.T) { 184 tests := []struct { 185 name string 186 input []byte 187 expectedErr string 188 }{ 189 { 190 name: "duplicates empty name", 191 input: []byte{ 192 0x02, // 2 exports 193 0x00, // Size of empty name 194 wasm.ExternTypeFunc, 0x00, // func[0] 195 0x00, // Size of empty name 196 wasm.ExternTypeFunc, 0x00, // func[0] 197 }, 198 expectedErr: "export[1] duplicates name \"\"", 199 }, 200 { 201 name: "duplicates name", 202 input: []byte{ 203 0x02, // 2 exports 204 0x01, 'a', // Size of name, name 205 wasm.ExternTypeFunc, 0x00, // func[0] 206 0x01, 'a', // Size of name, name 207 wasm.ExternTypeFunc, 0x00, // func[0] 208 }, 209 expectedErr: "export[1] duplicates name \"a\"", 210 }, 211 } 212 213 for _, tt := range tests { 214 tc := tt 215 216 t.Run(tc.name, func(t *testing.T) { 217 _, _, err := decodeExportSection(bytes.NewReader(tc.input)) 218 require.EqualError(t, err, tc.expectedErr) 219 }) 220 } 221 } 222 223 func TestEncodeFunctionSection(t *testing.T) { 224 require.Equal(t, []byte{wasm.SectionIDFunction, 0x2, 0x01, 0x05}, binaryencoding.EncodeFunctionSection([]wasm.Index{5})) 225 } 226 227 // TestEncodeStartSection uses the same index as TestEncodeFunctionSection to highlight the encoding is different. 228 func TestEncodeStartSection(t *testing.T) { 229 require.Equal(t, []byte{wasm.SectionIDStart, 0x01, 0x05}, binaryencoding.EncodeStartSection(5)) 230 } 231 232 func TestDecodeDataCountSection(t *testing.T) { 233 t.Run("ok", func(t *testing.T) { 234 v, err := decodeDataCountSection(bytes.NewReader([]byte{0x1})) 235 require.NoError(t, err) 236 require.Equal(t, uint32(1), *v) 237 }) 238 t.Run("eof", func(t *testing.T) { 239 // EOF is fine as the datacount is optional. 240 _, err := decodeDataCountSection(bytes.NewReader([]byte{})) 241 require.NoError(t, err) 242 }) 243 }