github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/stdlibs/std/emit_event_test.go (about) 1 package std 2 3 import ( 4 "encoding/json" 5 "strconv" 6 "strings" 7 "testing" 8 9 gno "github.com/gnolang/gno/gnovm/pkg/gnolang" 10 "github.com/gnolang/gno/tm2/pkg/sdk" 11 "github.com/stretchr/testify/assert" 12 ) 13 14 func TestEmit(t *testing.T) { 15 m := gno.NewMachine("emit", nil) 16 pkgPath := CurrentRealmPath(m) 17 tests := []struct { 18 name string 19 eventType string 20 attrs []string 21 expectedEvents []gnoEvent 22 expectPanic bool 23 }{ 24 { 25 name: "SimpleValid", 26 eventType: "test", 27 attrs: []string{"key1", "value1", "key2", "value2"}, 28 expectedEvents: []gnoEvent{ 29 { 30 Type: "test", 31 PkgPath: pkgPath, 32 Func: "", 33 Attributes: []gnoEventAttribute{ 34 {Key: "key1", Value: "value1"}, 35 {Key: "key2", Value: "value2"}, 36 }, 37 }, 38 }, 39 expectPanic: false, 40 }, 41 { 42 name: "InvalidAttributes", 43 eventType: "test", 44 attrs: []string{"key1", "value1", "key2"}, 45 expectPanic: true, 46 }, 47 { 48 name: "EmptyAttribute", 49 eventType: "test", 50 attrs: []string{"key1", "", "key2", "value2"}, 51 expectedEvents: []gnoEvent{ 52 { 53 Type: "test", 54 PkgPath: pkgPath, 55 Func: "", 56 Attributes: []gnoEventAttribute{ 57 {Key: "key1", Value: ""}, 58 {Key: "key2", Value: "value2"}, 59 }, 60 }, 61 }, 62 expectPanic: false, 63 }, 64 { 65 name: "EmptyType", 66 eventType: "", 67 attrs: []string{"key1", "value1", "key2", "value2"}, 68 expectedEvents: []gnoEvent{ 69 { 70 Type: "", 71 PkgPath: pkgPath, 72 Func: "", 73 Attributes: []gnoEventAttribute{ 74 {Key: "key1", Value: "value1"}, 75 {Key: "key2", Value: "value2"}, 76 }, 77 }, 78 }, 79 expectPanic: false, 80 }, 81 { 82 name: "EmptyAttributeKey", 83 eventType: "test", 84 attrs: []string{"", "value1", "key2", "value2"}, 85 expectedEvents: []gnoEvent{ 86 { 87 Type: "test", 88 PkgPath: pkgPath, 89 Func: "", 90 Attributes: []gnoEventAttribute{ 91 {Key: "", Value: "value1"}, 92 {Key: "key2", Value: "value2"}, 93 }, 94 }, 95 }, 96 expectPanic: false, 97 }, 98 } 99 100 for _, tt := range tests { 101 t.Run(tt.name, func(t *testing.T) { 102 elgs := sdk.NewEventLogger() 103 m.Context = ExecContext{EventLogger: elgs} 104 105 if tt.expectPanic { 106 assert.Panics(t, func() { 107 X_emit(m, tt.eventType, tt.attrs) 108 }) 109 } else { 110 X_emit(m, tt.eventType, tt.attrs) 111 assert.Equal(t, len(tt.expectedEvents), len(elgs.Events())) 112 113 res, err := json.Marshal(elgs.Events()) 114 if err != nil { 115 t.Fatal(err) 116 } 117 118 expectRes, err := json.Marshal(tt.expectedEvents) 119 if err != nil { 120 t.Fatal(err) 121 } 122 123 assert.Equal(t, string(expectRes), string(res)) 124 } 125 }) 126 } 127 } 128 129 func TestEmit_MultipleEvents(t *testing.T) { 130 t.Parallel() 131 m := gno.NewMachine("emit", nil) 132 133 elgs := sdk.NewEventLogger() 134 m.Context = ExecContext{EventLogger: elgs} 135 136 attrs1 := []string{"key1", "value1", "key2", "value2"} 137 attrs2 := []string{"key3", "value3", "key4", "value4"} 138 X_emit(m, "test1", attrs1) 139 X_emit(m, "test2", attrs2) 140 141 assert.Equal(t, 2, len(elgs.Events())) 142 143 res, err := json.Marshal(elgs.Events()) 144 if err != nil { 145 t.Fatal(err) 146 } 147 148 expect := []gnoEvent{ 149 { 150 Type: "test1", 151 PkgPath: "", 152 Func: "", 153 Attributes: []gnoEventAttribute{ 154 {Key: "key1", Value: "value1"}, 155 {Key: "key2", Value: "value2"}, 156 }, 157 }, 158 { 159 Type: "test2", 160 PkgPath: "", 161 Func: "", 162 Attributes: []gnoEventAttribute{ 163 {Key: "key3", Value: "value3"}, 164 {Key: "key4", Value: "value4"}, 165 }, 166 }, 167 } 168 169 expectRes, err := json.Marshal(expect) 170 if err != nil { 171 t.Fatal(err) 172 } 173 174 assert.Equal(t, string(expectRes), string(res)) 175 } 176 177 func TestEmit_ContractInteraction(t *testing.T) { 178 const ( 179 testFoo = "foo" 180 testQux = "qux" 181 ) 182 183 type ( 184 contractA struct { 185 foo func(*gno.Machine, func()) 186 } 187 188 contractB struct { 189 qux func(m *gno.Machine) 190 } 191 ) 192 193 t.Parallel() 194 m := gno.NewMachine("emit", nil) 195 elgs := sdk.NewEventLogger() 196 m.Context = ExecContext{EventLogger: elgs} 197 198 baz := func(m *gno.Machine) { 199 X_emit(m, testFoo, []string{"k1", "v1", "k2", "v2"}) 200 } 201 202 a := &contractA{ 203 foo: func(m *gno.Machine, cb func()) { 204 baz(m) 205 cb() 206 }, 207 } 208 b := &contractB{ 209 qux: func(m *gno.Machine) { 210 X_emit(m, testQux, []string{"bar", "baz"}) 211 }, 212 } 213 214 a.foo(m, func() { 215 b.qux(m) 216 }) 217 218 assert.Equal(t, 2, len(elgs.Events())) 219 220 res, err := json.Marshal(elgs.Events()) 221 if err != nil { 222 t.Fatal(err) 223 } 224 225 expected := `[{"type":"foo","pkg_path":"","func":"","attrs":[{"key":"k1","value":"v1"},{"key":"k2","value":"v2"}]},{"type":"qux","pkg_path":"","func":"","attrs":[{"key":"bar","value":"baz"}]}]` 226 227 assert.Equal(t, expected, string(res)) 228 } 229 230 func TestEmit_Iteration(t *testing.T) { 231 const testBar = "bar" 232 m := gno.NewMachine("emit", nil) 233 234 elgs := sdk.NewEventLogger() 235 m.Context = ExecContext{EventLogger: elgs} 236 237 iterEvent := func(m *gno.Machine) { 238 for i := 0; i < 10; i++ { 239 X_emit(m, testBar, []string{"qux", "value1"}) 240 } 241 } 242 iterEvent(m) 243 assert.Equal(t, 10, len(elgs.Events())) 244 245 res, err := json.Marshal(elgs.Events()) 246 if err != nil { 247 t.Fatal(err) 248 } 249 250 var builder strings.Builder 251 builder.WriteString("[") 252 for i := 0; i < 10; i++ { 253 builder.WriteString(`{"type":"bar","pkg_path":"","func":"","attrs":[{"key":"qux","value":"value1"}]},`) 254 } 255 expected := builder.String()[:builder.Len()-1] + "]" 256 257 assert.Equal(t, expected, string(res)) 258 } 259 260 func complexInteraction(m *gno.Machine) { 261 deferEmitExample(m) 262 } 263 264 func deferEmitExample(m *gno.Machine) { 265 defer func() { 266 X_emit(m, "DeferEvent", []string{"key1", "value1", "key2", "value2"}) 267 }() 268 269 forLoopEmitExample(m, 3, func(i int) { 270 X_emit(m, "ForLoopEvent", []string{"iteration", strconv.Itoa(i), "key", "value"}) 271 }) 272 273 callbackEmitExample(m, func() { 274 X_emit(m, "CallbackEvent", []string{"key1", "value1", "key2", "value2"}) 275 }) 276 } 277 278 func forLoopEmitExample(m *gno.Machine, count int, callback func(int)) { 279 defer func() { 280 X_emit(m, "ForLoopCompletionEvent", []string{"count", strconv.Itoa(count)}) 281 }() 282 283 for i := 0; i < count; i++ { 284 callback(i) 285 } 286 } 287 288 func callbackEmitExample(m *gno.Machine, callback func()) { 289 defer func() { 290 X_emit(m, "CallbackCompletionEvent", []string{"key", "value"}) 291 }() 292 293 callback() 294 } 295 296 func TestEmit_ComplexInteraction(t *testing.T) { 297 m := gno.NewMachine("emit", nil) 298 299 elgs := sdk.NewEventLogger() 300 m.Context = ExecContext{EventLogger: elgs} 301 302 complexInteraction(m) 303 304 assert.Equal(t, 7, len(elgs.Events())) 305 306 res, err := json.Marshal(elgs.Events()) 307 if err != nil { 308 t.Fatal(err) 309 } 310 311 expected := `[{"type":"ForLoopEvent","pkg_path":"","func":"","attrs":[{"key":"iteration","value":"0"},{"key":"key","value":"value"}]},{"type":"ForLoopEvent","pkg_path":"","func":"","attrs":[{"key":"iteration","value":"1"},{"key":"key","value":"value"}]},{"type":"ForLoopEvent","pkg_path":"","func":"","attrs":[{"key":"iteration","value":"2"},{"key":"key","value":"value"}]},{"type":"ForLoopCompletionEvent","pkg_path":"","func":"","attrs":[{"key":"count","value":"3"}]},{"type":"CallbackEvent","pkg_path":"","func":"","attrs":[{"key":"key1","value":"value1"},{"key":"key2","value":"value2"}]},{"type":"CallbackCompletionEvent","pkg_path":"","func":"","attrs":[{"key":"key","value":"value"}]},{"type":"DeferEvent","pkg_path":"","func":"","attrs":[{"key":"key1","value":"value1"},{"key":"key2","value":"value2"}]}]` 312 313 assert.Equal(t, expected, string(res)) 314 }