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  }