wa-lang.org/wazero@v1.0.2/internal/wasmdebug/debug_test.go (about) 1 package wasmdebug 2 3 import ( 4 "errors" 5 "runtime" 6 "testing" 7 8 "wa-lang.org/wazero/api" 9 "wa-lang.org/wazero/internal/testing/require" 10 "wa-lang.org/wazero/internal/wasmruntime" 11 ) 12 13 func TestFuncName(t *testing.T) { 14 tests := []struct { 15 name, moduleName, funcName string 16 funcIdx uint32 17 expected string 18 }{ // Only tests a few edge cases to show what it might end up as. 19 {name: "empty", expected: ".$0"}, 20 {name: "empty module", funcName: "y", expected: ".y"}, 21 {name: "empty function", moduleName: "x", funcIdx: 255, expected: "x.$255"}, 22 {name: "looks like index in function", moduleName: "x", funcName: "[255]", expected: "x.[255]"}, 23 {name: "no special characters", moduleName: "x", funcName: "y", expected: "x.y"}, 24 {name: "dots in module", moduleName: "w.x", funcName: "y", expected: "w.x.y"}, 25 {name: "dots in function", moduleName: "x", funcName: "y.z", expected: "x.y.z"}, 26 {name: "spaces in module", moduleName: "w x", funcName: "y", expected: "w x.y"}, 27 {name: "spaces in function", moduleName: "x", funcName: "y z", expected: "x.y z"}, 28 } 29 30 for _, tt := range tests { 31 tc := tt 32 t.Run(tc.name, func(t *testing.T) { 33 funcName := FuncName(tc.moduleName, tc.funcName, tc.funcIdx) 34 require.Equal(t, tc.expected, funcName) 35 }) 36 } 37 } 38 39 func TestAddSignature(t *testing.T) { 40 i32, i64, f32, f64 := api.ValueTypeI32, api.ValueTypeI64, api.ValueTypeF32, api.ValueTypeF64 41 tests := []struct { 42 name string 43 paramTypes, resultTypes []api.ValueType 44 expected string 45 }{ 46 {name: "v_v", expected: "x.y()"}, 47 {name: "i32_v", paramTypes: []api.ValueType{i32}, expected: "x.y(i32)"}, 48 {name: "i32f64_v", paramTypes: []api.ValueType{i32, f64}, expected: "x.y(i32,f64)"}, 49 {name: "f32i32f64_v", paramTypes: []api.ValueType{f32, i32, f64}, expected: "x.y(f32,i32,f64)"}, 50 {name: "v_i64", resultTypes: []api.ValueType{i64}, expected: "x.y() i64"}, 51 {name: "v_i64f32", resultTypes: []api.ValueType{i64, f32}, expected: "x.y() (i64,f32)"}, 52 {name: "v_f32i32f64", resultTypes: []api.ValueType{f32, i32, f64}, expected: "x.y() (f32,i32,f64)"}, 53 {name: "i32_i64", paramTypes: []api.ValueType{i32}, resultTypes: []api.ValueType{i64}, expected: "x.y(i32) i64"}, 54 {name: "i64f32_i64f32", paramTypes: []api.ValueType{i64, f32}, resultTypes: []api.ValueType{i64, f32}, expected: "x.y(i64,f32) (i64,f32)"}, 55 {name: "i64f32f64_f32i32f64", paramTypes: []api.ValueType{i64, f32, f64}, resultTypes: []api.ValueType{f32, i32, f64}, expected: "x.y(i64,f32,f64) (f32,i32,f64)"}, 56 } 57 58 for _, tt := range tests { 59 tc := tt 60 t.Run(tc.name, func(t *testing.T) { 61 withSignature := signature("x.y", tc.paramTypes, tc.resultTypes) 62 require.Equal(t, tc.expected, withSignature) 63 }) 64 } 65 } 66 67 func TestErrorBuilder(t *testing.T) { 68 argErr := errors.New("invalid argument") 69 rteErr := testRuntimeErr("index out of bounds") 70 i32 := api.ValueTypeI32 71 i32i32i32i32 := []api.ValueType{i32, i32, i32, i32} 72 73 tests := []struct { 74 name string 75 build func(ErrorBuilder) error 76 expectedErr string 77 expectUnwrap error 78 }{ 79 { 80 name: "one", 81 build: func(builder ErrorBuilder) error { 82 builder.AddFrame("x.y", nil, nil) 83 return builder.FromRecovered(argErr) 84 }, 85 expectedErr: `invalid argument (recovered by wazero) 86 wasm stack trace: 87 x.y()`, 88 expectUnwrap: argErr, 89 }, 90 { 91 name: "two", 92 build: func(builder ErrorBuilder) error { 93 builder.AddFrame("wasi_snapshot_preview1.fd_write", i32i32i32i32, []api.ValueType{i32}) 94 builder.AddFrame("x.y", nil, nil) 95 return builder.FromRecovered(argErr) 96 }, 97 expectedErr: `invalid argument (recovered by wazero) 98 wasm stack trace: 99 wasi_snapshot_preview1.fd_write(i32,i32,i32,i32) i32 100 x.y()`, 101 expectUnwrap: argErr, 102 }, 103 { 104 name: "runtime.Error", 105 build: func(builder ErrorBuilder) error { 106 builder.AddFrame("wasi_snapshot_preview1.fd_write", i32i32i32i32, []api.ValueType{i32}) 107 builder.AddFrame("x.y", nil, nil) 108 return builder.FromRecovered(rteErr) 109 }, 110 expectedErr: `index out of bounds (recovered by wazero) 111 wasm stack trace: 112 wasi_snapshot_preview1.fd_write(i32,i32,i32,i32) i32 113 x.y()`, 114 expectUnwrap: rteErr, 115 }, 116 { 117 name: "wasmruntime.Error", 118 build: func(builder ErrorBuilder) error { 119 builder.AddFrame("wasi_snapshot_preview1.fd_write", i32i32i32i32, []api.ValueType{i32}) 120 builder.AddFrame("x.y", nil, nil) 121 return builder.FromRecovered(wasmruntime.ErrRuntimeStackOverflow) 122 }, 123 expectedErr: `wasm error: stack overflow 124 wasm stack trace: 125 wasi_snapshot_preview1.fd_write(i32,i32,i32,i32) i32 126 x.y()`, 127 expectUnwrap: wasmruntime.ErrRuntimeStackOverflow, 128 }, 129 } 130 131 for _, tt := range tests { 132 tc := tt 133 t.Run(tc.name, func(t *testing.T) { 134 withStackTrace := tc.build(NewErrorBuilder()) 135 require.Equal(t, tc.expectUnwrap, errors.Unwrap(withStackTrace)) 136 require.EqualError(t, withStackTrace, tc.expectedErr) 137 }) 138 } 139 } 140 141 // compile-time check to ensure testRuntimeErr implements runtime.Error. 142 var _ runtime.Error = testRuntimeErr("") 143 144 type testRuntimeErr string 145 146 func (e testRuntimeErr) RuntimeError() {} 147 148 func (e testRuntimeErr) Error() string { 149 return string(e) 150 }