wa-lang.org/wazero@v1.0.2/experimental/logging/log_listener_test.go (about) 1 package logging_test 2 3 import ( 4 "bytes" 5 "context" 6 "io" 7 "math" 8 "testing" 9 10 "wa-lang.org/wazero/api" 11 "wa-lang.org/wazero/experimental/logging" 12 "wa-lang.org/wazero/imports/wasi_snapshot_preview1" 13 "wa-lang.org/wazero/internal/testing/require" 14 "wa-lang.org/wazero/internal/wasm" 15 ) 16 17 // testCtx is an arbitrary, non-default context. Non-nil also prevents linter errors. 18 var testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary") 19 20 func Test_loggingListener(t *testing.T) { 21 wasiFuncName := "random_get" 22 wasiFuncType := &wasm.FunctionType{ 23 Params: []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, 24 Results: []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, 25 } 26 wasiParamNames := []string{"buf", "buf_len"} 27 wasiParams := []uint64{0, 8} 28 29 tests := []struct { 30 name string 31 moduleName, funcName string 32 functype *wasm.FunctionType 33 isHostFunc bool 34 paramNames []string 35 params, results []uint64 36 err error 37 expected string 38 }{ 39 { 40 name: "v_v", 41 functype: &wasm.FunctionType{}, 42 expected: `--> test.fn() 43 <-- () 44 `, 45 }, 46 { 47 name: "error", 48 functype: &wasm.FunctionType{}, 49 err: io.EOF, 50 expected: `--> test.fn() 51 <-- error: EOF 52 `, 53 }, 54 { 55 name: "host", 56 functype: &wasm.FunctionType{}, 57 isHostFunc: true, 58 expected: `==> test.fn() 59 <== () 60 `, 61 }, 62 { 63 name: "wasi", 64 functype: wasiFuncType, 65 moduleName: wasi_snapshot_preview1.ModuleName, 66 funcName: wasiFuncName, 67 paramNames: wasiParamNames, 68 isHostFunc: true, 69 params: wasiParams, 70 results: []uint64{uint64(wasi_snapshot_preview1.ErrnoSuccess)}, 71 expected: `==> wasi_snapshot_preview1.random_get(buf=0,buf_len=8) 72 <== ESUCCESS 73 `, 74 }, 75 { 76 name: "wasi errno", 77 functype: wasiFuncType, 78 moduleName: wasi_snapshot_preview1.ModuleName, 79 funcName: wasiFuncName, 80 paramNames: wasiParamNames, 81 isHostFunc: true, 82 params: wasiParams, 83 results: []uint64{uint64(wasi_snapshot_preview1.ErrnoFault)}, 84 expected: `==> wasi_snapshot_preview1.random_get(buf=0,buf_len=8) 85 <== EFAULT 86 `, 87 }, 88 { 89 name: "wasi error", 90 functype: wasiFuncType, 91 moduleName: wasi_snapshot_preview1.ModuleName, 92 funcName: wasiFuncName, 93 paramNames: wasiParamNames, 94 isHostFunc: true, 95 params: wasiParams, 96 err: io.EOF, // not possible as we coerce errors to numbers, but test anyway! 97 expected: `==> wasi_snapshot_preview1.random_get(buf=0,buf_len=8) 98 <== error: EOF 99 `, 100 }, 101 { 102 name: "i32", 103 functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeI32}}, 104 params: []uint64{math.MaxUint32}, 105 expected: `--> test.fn(4294967295) 106 <-- () 107 `, 108 }, 109 { 110 name: "i32 named", 111 functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeI32}}, 112 params: []uint64{math.MaxUint32}, 113 paramNames: []string{"x"}, 114 expected: `--> test.fn(x=4294967295) 115 <-- () 116 `, 117 }, 118 { 119 name: "i64", 120 functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeI64}}, 121 params: []uint64{math.MaxUint64}, 122 expected: `--> test.fn(18446744073709551615) 123 <-- () 124 `, 125 }, 126 { 127 name: "i64 named", 128 functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeI64}}, 129 params: []uint64{math.MaxUint64}, 130 paramNames: []string{"x"}, 131 expected: `--> test.fn(x=18446744073709551615) 132 <-- () 133 `, 134 }, 135 { 136 name: "f32", 137 functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeF32}}, 138 params: []uint64{api.EncodeF32(math.MaxFloat32)}, 139 expected: `--> test.fn(3.4028235e+38) 140 <-- () 141 `, 142 }, 143 { 144 name: "f32 named", 145 functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeF32}}, 146 params: []uint64{api.EncodeF32(math.MaxFloat32)}, 147 paramNames: []string{"x"}, 148 expected: `--> test.fn(x=3.4028235e+38) 149 <-- () 150 `, 151 }, 152 { 153 name: "f64", 154 functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeF64}}, 155 params: []uint64{api.EncodeF64(math.MaxFloat64)}, 156 expected: `--> test.fn(1.7976931348623157e+308) 157 <-- () 158 `, 159 }, 160 { 161 name: "f64 named", 162 functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeF64}}, 163 params: []uint64{api.EncodeF64(math.MaxFloat64)}, 164 paramNames: []string{"x"}, 165 expected: `--> test.fn(x=1.7976931348623157e+308) 166 <-- () 167 `, 168 }, 169 { 170 name: "externref", 171 functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeExternref}}, 172 params: []uint64{0}, 173 expected: `--> test.fn(0000000000000000) 174 <-- () 175 `, 176 }, 177 { 178 name: "externref named", 179 functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeExternref}}, 180 params: []uint64{0}, 181 paramNames: []string{"x"}, 182 expected: `--> test.fn(x=0000000000000000) 183 <-- () 184 `, 185 }, 186 { 187 name: "v128", 188 functype: &wasm.FunctionType{Params: []api.ValueType{0x7b}}, 189 params: []uint64{0, 1}, 190 expected: `--> test.fn(00000000000000000000000000000001) 191 <-- () 192 `, 193 }, 194 { 195 name: "v128 named", 196 functype: &wasm.FunctionType{Params: []api.ValueType{0x7b}}, 197 params: []uint64{0, 1}, 198 paramNames: []string{"x"}, 199 expected: `--> test.fn(x=00000000000000000000000000000001) 200 <-- () 201 `, 202 }, 203 { 204 name: "funcref", 205 functype: &wasm.FunctionType{Params: []api.ValueType{0x70}}, 206 params: []uint64{0}, 207 expected: `--> test.fn(0000000000000000) 208 <-- () 209 `, 210 }, 211 { 212 name: "funcref named", 213 functype: &wasm.FunctionType{Params: []api.ValueType{0x70}}, 214 params: []uint64{0}, 215 paramNames: []string{"x"}, 216 expected: `--> test.fn(x=0000000000000000) 217 <-- () 218 `, 219 }, 220 { 221 name: "no params, one result", 222 functype: &wasm.FunctionType{Results: []api.ValueType{api.ValueTypeI32}}, 223 results: []uint64{math.MaxUint32}, 224 expected: `--> test.fn() 225 <-- (4294967295) 226 `, 227 }, 228 { 229 name: "one param, one result", 230 functype: &wasm.FunctionType{ 231 Params: []api.ValueType{api.ValueTypeI32}, 232 Results: []api.ValueType{api.ValueTypeF32}, 233 }, 234 params: []uint64{math.MaxUint32}, 235 results: []uint64{api.EncodeF32(math.MaxFloat32)}, 236 expected: `--> test.fn(4294967295) 237 <-- (3.4028235e+38) 238 `, 239 }, 240 { 241 name: "two params, two results", 242 functype: &wasm.FunctionType{ 243 Params: []api.ValueType{api.ValueTypeI32, api.ValueTypeI64}, 244 Results: []api.ValueType{api.ValueTypeF32, api.ValueTypeF64}, 245 }, 246 params: []uint64{math.MaxUint32, math.MaxUint64}, 247 results: []uint64{api.EncodeF32(math.MaxFloat32), api.EncodeF64(math.MaxFloat64)}, 248 expected: `--> test.fn(4294967295,18446744073709551615) 249 <-- (3.4028235e+38,1.7976931348623157e+308) 250 `, 251 }, 252 { 253 name: "two params, two results named", 254 functype: &wasm.FunctionType{ 255 Params: []api.ValueType{api.ValueTypeI32, api.ValueTypeI64}, 256 Results: []api.ValueType{api.ValueTypeF32, api.ValueTypeF64}, 257 }, 258 params: []uint64{math.MaxUint32, math.MaxUint64}, 259 paramNames: []string{"x", "y"}, 260 results: []uint64{api.EncodeF32(math.MaxFloat32), api.EncodeF64(math.MaxFloat64)}, 261 expected: `--> test.fn(x=4294967295,y=18446744073709551615) 262 <-- (3.4028235e+38,1.7976931348623157e+308) 263 `, 264 }, 265 } 266 267 var out bytes.Buffer 268 lf := logging.NewLoggingListenerFactory(&out) 269 fn := func() {} 270 for _, tt := range tests { 271 tc := tt 272 t.Run(tc.name, func(t *testing.T) { 273 if tc.moduleName == "" { 274 tc.moduleName = "test" 275 } 276 if tc.funcName == "" { 277 tc.funcName = "fn" 278 } 279 m := &wasm.Module{ 280 TypeSection: []*wasm.FunctionType{tc.functype}, 281 FunctionSection: []wasm.Index{0}, 282 NameSection: &wasm.NameSection{ 283 ModuleName: tc.moduleName, 284 FunctionNames: wasm.NameMap{{Name: tc.funcName}}, 285 LocalNames: wasm.IndirectNameMap{{NameMap: toNameMap(tc.paramNames)}}, 286 }, 287 } 288 289 if tc.isHostFunc { 290 m.CodeSection = []*wasm.Code{wasm.MustParseGoReflectFuncCode(fn)} 291 } else { 292 m.CodeSection = []*wasm.Code{{Body: []byte{wasm.OpcodeEnd}}} 293 } 294 m.BuildFunctionDefinitions() 295 def := m.FunctionDefinitionSection[0] 296 l := lf.NewListener(m.FunctionDefinitionSection[0]) 297 298 out.Reset() 299 ctx := l.Before(testCtx, def, tc.params) 300 l.After(ctx, def, tc.err, tc.results) 301 require.Equal(t, tc.expected, out.String()) 302 }) 303 } 304 } 305 306 func toNameMap(names []string) wasm.NameMap { 307 if len(names) == 0 { 308 return nil 309 } 310 var ret wasm.NameMap 311 for i, n := range names { 312 ret = append(ret, &wasm.NameAssoc{Index: wasm.Index(i), Name: n}) 313 } 314 return ret 315 } 316 317 func Test_loggingListener_indentation(t *testing.T) { 318 out := bytes.NewBuffer(nil) 319 lf := logging.NewLoggingListenerFactory(out) 320 m := &wasm.Module{ 321 TypeSection: []*wasm.FunctionType{{}}, 322 FunctionSection: []wasm.Index{0, 0}, 323 CodeSection: []*wasm.Code{{Body: []byte{wasm.OpcodeEnd}}, {Body: []byte{wasm.OpcodeEnd}}}, 324 NameSection: &wasm.NameSection{ 325 ModuleName: "test", 326 FunctionNames: wasm.NameMap{{Index: 0, Name: "fn1"}, {Index: 1, Name: "fn2"}}, 327 }, 328 } 329 m.BuildFunctionDefinitions() 330 def1 := m.FunctionDefinitionSection[0] 331 l1 := lf.NewListener(def1) 332 def2 := m.FunctionDefinitionSection[1] 333 l2 := lf.NewListener(def2) 334 335 ctx := l1.Before(testCtx, def1, []uint64{}) 336 ctx1 := l2.Before(ctx, def2, []uint64{}) 337 l2.After(ctx1, def2, nil, []uint64{}) 338 l1.After(ctx, def1, nil, []uint64{}) 339 require.Equal(t, `--> test.fn1() 340 --> test.fn2() 341 <-- () 342 <-- () 343 `, out.String()) 344 }