wa-lang.org/wazero@v1.0.2/internal/wasm/global_test.go (about) 1 package wasm 2 3 import ( 4 "context" 5 "math" 6 "testing" 7 8 "wa-lang.org/wazero/api" 9 "wa-lang.org/wazero/internal/leb128" 10 "wa-lang.org/wazero/internal/testing/require" 11 "wa-lang.org/wazero/internal/u64" 12 ) 13 14 func TestGlobalTypes(t *testing.T) { 15 tests := []struct { 16 name string 17 global api.Global 18 expectedType api.ValueType 19 expectedVal uint64 20 expectedString string 21 expectedMutable bool 22 }{ 23 { 24 name: "i32 - immutable", 25 global: globalI32(1), 26 expectedType: ValueTypeI32, 27 expectedVal: 1, 28 expectedString: "global(1)", 29 }, 30 { 31 name: "i32 - immutable - max", 32 global: globalI32(math.MaxInt32), 33 expectedType: ValueTypeI32, 34 expectedVal: math.MaxInt32, 35 expectedString: "global(2147483647)", 36 }, 37 { 38 name: "i64 - immutable", 39 global: globalI64(1), 40 expectedType: ValueTypeI64, 41 expectedVal: 1, 42 expectedString: "global(1)", 43 }, 44 { 45 name: "i64 - immutable - max", 46 global: globalI64(math.MaxInt64), 47 expectedType: ValueTypeI64, 48 expectedVal: math.MaxInt64, 49 expectedString: "global(9223372036854775807)", 50 }, 51 { 52 name: "f32 - immutable", 53 global: globalF32(api.EncodeF32(1.0)), 54 expectedType: ValueTypeF32, 55 expectedVal: api.EncodeF32(1.0), 56 expectedString: "global(1.000000)", 57 }, 58 { 59 name: "f32 - immutable - max", 60 global: globalF32(api.EncodeF32(math.MaxFloat32)), 61 expectedType: ValueTypeF32, 62 expectedVal: api.EncodeF32(math.MaxFloat32), 63 expectedString: "global(340282346638528859811704183484516925440.000000)", 64 }, 65 { 66 name: "f64 - immutable", 67 global: globalF64(api.EncodeF64(1.0)), 68 expectedType: ValueTypeF64, 69 expectedVal: api.EncodeF64(1.0), 70 expectedString: "global(1.000000)", 71 }, 72 { 73 name: "f64 - immutable - max", 74 global: globalF64(api.EncodeF64(math.MaxFloat64)), 75 expectedType: ValueTypeF64, 76 expectedVal: api.EncodeF64(math.MaxFloat64), 77 expectedString: "global(179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000)", 78 }, 79 { 80 name: "i32 - mutable", 81 global: &mutableGlobal{g: &GlobalInstance{ 82 Type: &GlobalType{ValType: ValueTypeI32, Mutable: true}, 83 Val: 1, 84 }}, 85 expectedType: ValueTypeI32, 86 expectedVal: 1, 87 expectedString: "global(1)", 88 expectedMutable: true, 89 }, 90 { 91 name: "i64 - mutable", 92 global: &mutableGlobal{g: &GlobalInstance{ 93 Type: &GlobalType{ValType: ValueTypeI64, Mutable: true}, 94 Val: 1, 95 }}, 96 expectedType: ValueTypeI64, 97 expectedVal: 1, 98 expectedString: "global(1)", 99 expectedMutable: true, 100 }, 101 { 102 name: "f32 - mutable", 103 global: &mutableGlobal{g: &GlobalInstance{ 104 Type: &GlobalType{ValType: ValueTypeF32, Mutable: true}, 105 Val: api.EncodeF32(1.0), 106 }}, 107 expectedType: ValueTypeF32, 108 expectedVal: api.EncodeF32(1.0), 109 expectedString: "global(1.000000)", 110 expectedMutable: true, 111 }, 112 { 113 name: "f64 - mutable", 114 global: &mutableGlobal{g: &GlobalInstance{ 115 Type: &GlobalType{ValType: ValueTypeF64, Mutable: true}, 116 Val: api.EncodeF64(1.0), 117 }}, 118 expectedType: ValueTypeF64, 119 expectedVal: api.EncodeF64(1.0), 120 expectedString: "global(1.000000)", 121 expectedMutable: true, 122 }, 123 } 124 125 for _, tt := range tests { 126 tc := tt 127 128 t.Run(tc.name, func(t *testing.T) { 129 for _, ctx := range []context.Context{nil, testCtx} { // Ensure it doesn't crash on nil! 130 require.Equal(t, tc.expectedType, tc.global.Type()) 131 require.Equal(t, tc.expectedVal, tc.global.Get(ctx)) 132 require.Equal(t, tc.expectedString, tc.global.String()) 133 134 mutable, ok := tc.global.(api.MutableGlobal) 135 require.Equal(t, tc.expectedMutable, ok) 136 if ok { 137 mutable.Set(ctx, 2) 138 require.Equal(t, uint64(2), tc.global.Get(ctx)) 139 140 mutable.Set(ctx, tc.expectedVal) // Set it back! 141 require.Equal(t, tc.expectedVal, tc.global.Get(ctx)) 142 } 143 } 144 }) 145 } 146 } 147 148 func TestPublicModule_Global(t *testing.T) { 149 tests := []struct { 150 name string 151 module *Module // module as wat doesn't yet support globals 152 expected api.Global 153 }{ 154 { 155 name: "no global", 156 module: &Module{}, 157 }, 158 { 159 name: "global not exported", 160 module: &Module{ 161 GlobalSection: []*Global{ 162 { 163 Type: &GlobalType{ValType: ValueTypeI32}, 164 Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: const1}, 165 }, 166 }, 167 }, 168 }, 169 { 170 name: "global exported - immutable I32", 171 module: &Module{ 172 GlobalSection: []*Global{ 173 { 174 Type: &GlobalType{ValType: ValueTypeI32}, 175 Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: const1}, 176 }, 177 }, 178 ExportSection: []*Export{{Type: ExternTypeGlobal, Name: "global"}}, 179 }, 180 expected: globalI32(1), 181 }, 182 { 183 name: "global exported - immutable I64", 184 module: &Module{ 185 GlobalSection: []*Global{ 186 { 187 Type: &GlobalType{ValType: ValueTypeI64}, 188 Init: &ConstantExpression{Opcode: OpcodeI64Const, Data: leb128.EncodeInt64(1)}, 189 }, 190 }, 191 ExportSection: []*Export{{Type: ExternTypeGlobal, Name: "global"}}, 192 }, 193 expected: globalI64(1), 194 }, 195 { 196 name: "global exported - immutable F32", 197 module: &Module{ 198 GlobalSection: []*Global{ 199 { 200 Type: &GlobalType{ValType: ValueTypeF32}, 201 Init: &ConstantExpression{ 202 Opcode: OpcodeF32Const, 203 Data: u64.LeBytes(api.EncodeF32(1.0)), 204 }, 205 }, 206 }, 207 ExportSection: []*Export{{Type: ExternTypeGlobal, Name: "global"}}, 208 }, 209 expected: globalF32(api.EncodeF32(1.0)), 210 }, 211 { 212 name: "global exported - immutable F64", 213 module: &Module{ 214 GlobalSection: []*Global{ 215 { 216 Type: &GlobalType{ValType: ValueTypeF64}, 217 Init: &ConstantExpression{ 218 Opcode: OpcodeF64Const, 219 Data: u64.LeBytes(api.EncodeF64(1.0)), 220 }, 221 }, 222 }, 223 ExportSection: []*Export{{Type: ExternTypeGlobal, Name: "global"}}, 224 }, 225 expected: globalF64(api.EncodeF64(1.0)), 226 }, 227 { 228 name: "global exported - mutable I32", 229 module: &Module{ 230 GlobalSection: []*Global{ 231 { 232 Type: &GlobalType{ValType: ValueTypeI32, Mutable: true}, 233 Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: leb128.EncodeInt32(1)}, 234 }, 235 }, 236 ExportSection: []*Export{{Type: ExternTypeGlobal, Name: "global"}}, 237 }, 238 expected: &mutableGlobal{ 239 g: &GlobalInstance{Type: &GlobalType{ValType: ValueTypeI32, Mutable: true}, Val: 1}, 240 }, 241 }, 242 { 243 name: "global exported - mutable I64", 244 module: &Module{ 245 GlobalSection: []*Global{ 246 { 247 Type: &GlobalType{ValType: ValueTypeI64, Mutable: true}, 248 Init: &ConstantExpression{Opcode: OpcodeI64Const, Data: leb128.EncodeInt64(1)}, 249 }, 250 }, 251 ExportSection: []*Export{{Type: ExternTypeGlobal, Name: "global"}}, 252 }, 253 expected: &mutableGlobal{ 254 g: &GlobalInstance{Type: &GlobalType{ValType: ValueTypeI64, Mutable: true}, Val: 1}, 255 }, 256 }, 257 { 258 name: "global exported - mutable F32", 259 module: &Module{ 260 GlobalSection: []*Global{ 261 { 262 Type: &GlobalType{ValType: ValueTypeF32, Mutable: true}, 263 Init: &ConstantExpression{ 264 Opcode: OpcodeF32Const, 265 Data: u64.LeBytes(api.EncodeF32(1.0)), 266 }, 267 }, 268 }, 269 ExportSection: []*Export{{Type: ExternTypeGlobal, Name: "global"}}, 270 }, 271 expected: &mutableGlobal{ 272 g: &GlobalInstance{Type: &GlobalType{ValType: ValueTypeF32, Mutable: true}, Val: api.EncodeF32(1.0)}, 273 }, 274 }, 275 { 276 name: "global exported - mutable F64", 277 module: &Module{ 278 GlobalSection: []*Global{ 279 { 280 Type: &GlobalType{ValType: ValueTypeF64, Mutable: true}, 281 Init: &ConstantExpression{ 282 Opcode: OpcodeF64Const, 283 Data: u64.LeBytes(api.EncodeF64(1.0)), 284 }, 285 }, 286 }, 287 ExportSection: []*Export{{Type: ExternTypeGlobal, Name: "global"}}, 288 }, 289 expected: &mutableGlobal{ 290 g: &GlobalInstance{Type: &GlobalType{ValType: ValueTypeF64, Mutable: true}, Val: api.EncodeF64(1.0)}, 291 }, 292 }, 293 } 294 295 for _, tt := range tests { 296 tc := tt 297 298 s, ns := newStore() 299 t.Run(tc.name, func(t *testing.T) { 300 // Instantiate the module and get the export of the above global 301 module, err := s.Instantiate(context.Background(), ns, tc.module, t.Name(), nil) 302 require.NoError(t, err) 303 304 if global := module.ExportedGlobal("global"); tc.expected != nil { 305 require.Equal(t, tc.expected, global) 306 } else { 307 require.Nil(t, global) 308 } 309 }) 310 } 311 }