uassert_test.gno

13.92 Kb ยท 561 lines
  1package uassert_test
  2
  3import (
  4	"errors"
  5	"fmt"
  6	"testing"
  7
  8	"gno.land/p/nt/uassert"
  9	tests "gno.land/r/tests/vm"
 10)
 11
 12var _ uassert.TestingT = (*testing.T)(nil)
 13
 14func TestMock(t *testing.T) {
 15	mockT := new(mockTestingT)
 16	mockT.empty(t)
 17	uassert.NoError(mockT, errors.New("foo"))
 18	mockT.equals(t, "error: unexpected error: foo")
 19	uassert.NoError(mockT, errors.New("foo"), "custom message")
 20	mockT.equals(t, "error: unexpected error: foo - custom message")
 21	uassert.NoError(mockT, errors.New("foo"), "custom", "message")
 22	mockT.equals(t, "error: unexpected error: foo - custom message")
 23}
 24
 25func TestNoError(t *testing.T) {
 26	mockT := new(mockTestingT)
 27	uassert.True(t, uassert.NoError(mockT, nil))
 28	mockT.empty(t)
 29	uassert.False(t, uassert.NoError(mockT, errors.New("foo bar")))
 30	mockT.equals(t, "error: unexpected error: foo bar")
 31}
 32
 33func TestError(t *testing.T) {
 34	mockT := new(mockTestingT)
 35	uassert.True(t, uassert.Error(mockT, errors.New("foo bar")))
 36	mockT.empty(t)
 37	uassert.False(t, uassert.Error(mockT, nil))
 38	mockT.equals(t, "error: an error is expected but got nil")
 39}
 40
 41func TestErrorContains(t *testing.T) {
 42	mockT := new(mockTestingT)
 43
 44	// nil error
 45	var err error
 46	uassert.False(t, uassert.ErrorContains(mockT, err, ""), "ErrorContains should return false for nil arg")
 47}
 48
 49func TestTrue(t *testing.T) {
 50	mockT := new(mockTestingT)
 51	if !uassert.True(mockT, true) {
 52		t.Error("True should return true")
 53	}
 54	mockT.empty(t)
 55	if uassert.True(mockT, false) {
 56		t.Error("True should return false")
 57	}
 58	mockT.equals(t, "error: should be true")
 59}
 60
 61func TestFalse(t *testing.T) {
 62	mockT := new(mockTestingT)
 63	if !uassert.False(mockT, false) {
 64		t.Error("False should return true")
 65	}
 66	mockT.empty(t)
 67	if uassert.False(mockT, true) {
 68		t.Error("False should return false")
 69	}
 70	mockT.equals(t, "error: should be false")
 71}
 72
 73func TestPanicsWithMessage(t *testing.T) {
 74	mockT := new(mockTestingT)
 75	if !uassert.PanicsWithMessage(mockT, "panic", func() {
 76		panic(errors.New("panic"))
 77	}) {
 78		t.Error("PanicsWithMessage should return true")
 79	}
 80	mockT.empty(t)
 81
 82	if uassert.PanicsWithMessage(mockT, "Panic!", func() {
 83		// noop
 84	}) {
 85		t.Error("PanicsWithMessage should return false")
 86	}
 87	mockT.equals(t, "error: func should panic\n\tPanic value:\tnil")
 88
 89	if uassert.PanicsWithMessage(mockT, "at the disco", func() {
 90		panic(errors.New("panic"))
 91	}) {
 92		t.Error("PanicsWithMessage should return false")
 93	}
 94	mockT.equals(t, "error: func should panic with message:\t\"at the disco\"\n\tActual panic value:\t\"panic\"")
 95
 96	if uassert.PanicsWithMessage(mockT, "Panic!", func() {
 97		panic("panic")
 98	}) {
 99		t.Error("PanicsWithMessage should return false")
100	}
101	mockT.equals(t, "error: func should panic with message:\t\"Panic!\"\n\tActual panic value:\t\"panic\"")
102}
103
104func TestPanicsContains(t *testing.T) {
105	mockT := new(mockTestingT)
106	if !uassert.PanicsContains(mockT, "panic", func() {
107		panic(errors.New("panic: something happened"))
108	}) {
109		t.Error("PanicsContains should return true for substring match")
110	}
111	mockT.empty(t)
112
113	if uassert.PanicsContains(mockT, "notfound", func() {
114		panic(errors.New("panic: something happened"))
115	}) {
116		t.Error("PanicsContains should return false for missing substring")
117	}
118	mockT.equals(t, "error: func should panic with message containing:\t\"notfound\"\n\tActual panic value:\t\"panic: something happened\"")
119
120	if uassert.PanicsContains(mockT, "panic", func() {
121		// noop
122	}) {
123		t.Error("PanicsContains should return false when no panic occurs")
124	}
125	mockT.equals(t, "error: func should panic\n\tPanic value:\tnil")
126}
127
128func TestAbortsWithMessage(t *testing.T) {
129	mockT := new(mockTestingT)
130	if !uassert.AbortsWithMessage(mockT, "abort message", func() {
131		tests.ExecSwitch(cross, func() {
132			panic("abort message")
133		})
134		panic("dontcare")
135	}) {
136		t.Error("AbortsWithMessage should return true")
137	}
138	mockT.empty(t)
139
140	if uassert.AbortsWithMessage(mockT, "Abort!", func() {
141		// noop
142	}) {
143		t.Error("AbortsWithMessage should return false")
144	}
145	mockT.equals(t, "error: func should abort")
146
147	if uassert.AbortsWithMessage(mockT, "at the disco", func() {
148		tests.ExecSwitch(cross, func() {
149			panic("abort message")
150		})
151		panic("dontcare")
152	}) {
153		t.Error("AbortsWithMessage should return false (wrong message)")
154	}
155	mockT.equals(t, "error: func should abort with message:\t\"at the disco\"\n\tActual abort value:\t\"abort message\"")
156
157	// Test that non-crossing panics don't count as abort.
158	uassert.PanicsWithMessage(mockT, "non-abort panic", func() {
159		uassert.AbortsWithMessage(mockT, "dontcare2", func() {
160			panic("non-abort panic")
161		})
162		t.Error("AbortsWithMessage should not have caught non-abort panic")
163	}, "non-abort panic")
164	mockT.empty(t)
165
166	// Test case where abort value is not a string
167	if uassert.AbortsWithMessage(mockT, "doesn't matter", func() {
168		tests.ExecSwitch(cross, func() {
169			panic(123) // abort with an integer
170		})
171		panic("dontcare")
172	}) {
173		t.Error("AbortsWithMessage should return false when abort value is not a string")
174	}
175	mockT.equals(t, "error: func should abort with message:\t\"doesn't matter\"\n\tActual abort value:\t\"123\"")
176
177	// XXX: test with Error
178}
179
180func TestAbortsContains(t *testing.T) {
181	mockT := new(mockTestingT)
182	if !uassert.AbortsContains(mockT, "abort", func() {
183		tests.ExecSwitch(cross, func() {
184			panic("abort message: something happened")
185		})
186		panic("dontcare")
187	}) {
188		t.Error("AbortsContains should return true for substring match")
189	}
190	mockT.empty(t)
191
192	if uassert.AbortsContains(mockT, "notfound", func() {
193		tests.ExecSwitch(cross, func() {
194			panic("abort message: something happened")
195		})
196		panic("dontcare")
197	}) {
198		t.Error("AbortsContains should return false for missing substring")
199	}
200	mockT.equals(t, "error: func should abort with message containing:\t\"notfound\"\n\tActual abort value:\t\"abort message: something happened\"")
201
202	if uassert.AbortsContains(mockT, "abort", func() {
203		// noop
204	}) {
205		t.Error("AbortsContains should return false when no abort occurs")
206	}
207	mockT.equals(t, "error: func should abort")
208}
209
210func TestNotAborts(t *testing.T) {
211	mockT := new(mockTestingT)
212
213	if !uassert.NotPanics(mockT, func() {
214		// noop
215	}) {
216		t.Error("NotAborts should return true")
217	}
218	mockT.empty(t)
219
220	if uassert.NotPanics(mockT, func() {
221		tests.ExecSwitch(cross, func() {
222			panic("Abort!")
223		})
224		panic("dontcare")
225	}) {
226		t.Error("NotAborts should return false")
227	}
228	mockT.equals(t, "error: func should not abort\n\tAbort value:\tAbort!")
229}
230
231func TestNotPanics(t *testing.T) {
232	mockT := new(mockTestingT)
233
234	if !uassert.NotPanics(mockT, func() {
235		// noop
236	}) {
237		t.Error("NotPanics should return true")
238	}
239	mockT.empty(t)
240
241	if uassert.NotPanics(mockT, func() {
242		panic("Panic!")
243	}) {
244		t.Error("NotPanics should return false")
245	}
246	mockT.equals(t, "error: func should not panic\n\tPanic value:\tPanic!")
247}
248
249func TestEqual(t *testing.T) {
250	mockT := new(mockTestingT)
251
252	cases := []struct {
253		expected any
254		actual   any
255		result   bool
256		remark   string
257	}{
258		// expected to be equal
259		{"Hello World", "Hello World", true, ""},
260		{123, 123, true, ""},
261		{123.5, 123.5, true, ""},
262		{nil, nil, true, ""},
263		{int32(123), int32(123), true, ""},
264		{uint64(123), uint64(123), true, ""},
265		{address("g12345"), address("g12345"), true, ""},
266		// XXX: continue
267
268		// not expected to be equal
269		{"Hello World", 42, false, ""},
270		{41, 42, false, ""},
271		{10, uint(10), false, ""},
272		// XXX: continue
273
274		// expected to raise errors
275		// XXX: todo
276	}
277
278	for _, c := range cases {
279		name := fmt.Sprintf("Equal(%v, %v)", c.expected, c.actual)
280		t.Run(name, func(t *testing.T) {
281			res := uassert.Equal(mockT, c.expected, c.actual)
282
283			if res != c.result {
284				t.Errorf("%s should return %v: %s - %s", name, c.result, c.remark, mockT.actualString())
285			}
286		})
287	}
288}
289
290func TestNotEqual(t *testing.T) {
291	mockT := new(mockTestingT)
292
293	cases := []struct {
294		expected any
295		actual   any
296		result   bool
297		remark   string
298	}{
299		// expected to be not equal
300		{"Hello World", "Hello", true, ""},
301		{123, 124, true, ""},
302		{123.5, 123.6, true, ""},
303		{nil, 123, true, ""},
304		{int32(123), int32(124), true, ""},
305		{uint64(123), uint64(124), true, ""},
306		{address("g12345"), address("g67890"), true, ""},
307		// XXX: continue
308
309		// not expected to be not equal
310		{"Hello World", "Hello World", false, ""},
311		{123, 123, false, ""},
312		{123.5, 123.5, false, ""},
313		{nil, nil, false, ""},
314		{int32(123), int32(123), false, ""},
315		{uint64(123), uint64(123), false, ""},
316		{address("g12345"), address("g12345"), false, ""},
317		// XXX: continue
318
319		// expected to raise errors
320		// XXX: todo
321	}
322
323	for _, c := range cases {
324		name := fmt.Sprintf("NotEqual(%v, %v)", c.expected, c.actual)
325		t.Run(name, func(t *testing.T) {
326			res := uassert.NotEqual(mockT, c.expected, c.actual)
327
328			if res != c.result {
329				t.Errorf("%s should return %v: %s - %s", name, c.result, c.remark, mockT.actualString())
330			}
331		})
332	}
333}
334
335type myStruct struct {
336	S string
337	I int
338}
339
340func TestEmpty(t *testing.T) {
341	mockT := new(mockTestingT)
342
343	cases := []struct {
344		obj           any
345		expectedEmpty bool
346	}{
347		// expected to be empty
348		{"", true},
349		{0, true},
350		{int(0), true},
351		{int32(0), true},
352		{int64(0), true},
353		{uint(0), true},
354		// XXX: continue
355
356		// not expected to be empty
357		{"Hello World", false},
358		{1, false},
359		{int32(1), false},
360		{uint64(1), false},
361		{address("g12345"), false},
362
363		// unsupported
364		{nil, false},
365		{myStruct{}, false},
366		{&myStruct{}, false},
367	}
368
369	for _, c := range cases {
370		name := fmt.Sprintf("Empty(%v)", c.obj)
371		t.Run(name, func(t *testing.T) {
372			res := uassert.Empty(mockT, c.obj)
373
374			if res != c.expectedEmpty {
375				t.Errorf("%s should return %v: %s", name, c.expectedEmpty, mockT.actualString())
376			}
377		})
378	}
379}
380
381func TestEqualWithStringDiff(t *testing.T) {
382	cases := []struct {
383		name        string
384		expected    string
385		actual      string
386		shouldPass  bool
387		expectedMsg string
388	}{
389		{
390			name:        "Identical strings",
391			expected:    "Hello, world!",
392			actual:      "Hello, world!",
393			shouldPass:  true,
394			expectedMsg: "",
395		},
396		{
397			name:        "Different strings - simple",
398			expected:    "Hello, world!",
399			actual:      "Hello, World!",
400			shouldPass:  false,
401			expectedMsg: "error: uassert.Equal: strings are different\n\tDiff: Hello, [-w][+W]orld!",
402		},
403		{
404			name:        "Different strings - complex",
405			expected:    "The quick brown fox jumps over the lazy dog",
406			actual:      "The quick brown cat jumps over the lazy dog",
407			shouldPass:  false,
408			expectedMsg: "error: uassert.Equal: strings are different\n\tDiff: The quick brown [-fox][+cat] jumps over the lazy dog",
409		},
410		{
411			name:        "Different strings - prefix",
412			expected:    "prefix_string",
413			actual:      "string",
414			shouldPass:  false,
415			expectedMsg: "error: uassert.Equal: strings are different\n\tDiff: [-prefix_]string",
416		},
417		{
418			name:        "Different strings - suffix",
419			expected:    "string",
420			actual:      "string_suffix",
421			shouldPass:  false,
422			expectedMsg: "error: uassert.Equal: strings are different\n\tDiff: string[+_suffix]",
423		},
424		{
425			name:        "Empty string vs non-empty string",
426			expected:    "",
427			actual:      "non-empty",
428			shouldPass:  false,
429			expectedMsg: "error: uassert.Equal: strings are different\n\tDiff: [+non-empty]",
430		},
431		{
432			name:        "Non-empty string vs empty string",
433			expected:    "non-empty",
434			actual:      "",
435			shouldPass:  false,
436			expectedMsg: "error: uassert.Equal: strings are different\n\tDiff: [-non-empty]",
437		},
438	}
439
440	for _, tc := range cases {
441		t.Run(tc.name, func(t *testing.T) {
442			mockT := &mockTestingT{}
443			result := uassert.Equal(mockT, tc.expected, tc.actual)
444
445			if result != tc.shouldPass {
446				t.Errorf("Expected Equal to return %v, but got %v", tc.shouldPass, result)
447			}
448
449			if tc.shouldPass {
450				mockT.empty(t)
451			} else {
452				mockT.equals(t, tc.expectedMsg)
453			}
454		})
455	}
456}
457
458func TestNotEmpty(t *testing.T) {
459	mockT := new(mockTestingT)
460
461	cases := []struct {
462		obj              any
463		expectedNotEmpty bool
464	}{
465		// expected to be empty
466		{"", false},
467		{0, false},
468		{int(0), false},
469		{int32(0), false},
470		{int64(0), false},
471		{uint(0), false},
472		{address(""), false},
473
474		// not expected to be empty
475		{"Hello World", true},
476		{1, true},
477		{int32(1), true},
478		{uint64(1), true},
479		{address("g12345"), true},
480
481		// unsupported
482		{nil, false},
483		{myStruct{}, false},
484		{&myStruct{}, false},
485	}
486
487	for _, c := range cases {
488		name := fmt.Sprintf("NotEmpty(%v)", c.obj)
489		t.Run(name, func(t *testing.T) {
490			res := uassert.NotEmpty(mockT, c.obj)
491
492			if res != c.expectedNotEmpty {
493				t.Errorf("%s should return %v: %s", name, c.expectedNotEmpty, mockT.actualString())
494			}
495		})
496	}
497}
498
499func TestNil(t *testing.T) {
500	mockT := new(mockTestingT)
501	if !uassert.Nil(mockT, nil) {
502		t.Error("Nil should return true")
503	}
504	mockT.empty(t)
505	if uassert.Nil(mockT, 0) {
506		t.Error("Nil should return false")
507	}
508	mockT.equals(t, "error: should be nil")
509	if uassert.Nil(mockT, (*int)(nil)) {
510		t.Error("Nil should return false")
511	}
512	mockT.equals(t, "error: should be nil")
513}
514
515func TestNotNil(t *testing.T) {
516	mockT := new(mockTestingT)
517	if uassert.NotNil(mockT, nil) {
518		t.Error("NotNil should return false")
519	}
520	mockT.equals(t, "error: should not be nil")
521	if !uassert.NotNil(mockT, 0) {
522		t.Error("NotNil should return true")
523	}
524	mockT.empty(t)
525	if !uassert.NotNil(mockT, (*int)(nil)) {
526		t.Error("NotNil should return true")
527	}
528	mockT.empty(t)
529}
530
531func TestTypedNil(t *testing.T) {
532	mockT := new(mockTestingT)
533	if uassert.TypedNil(mockT, nil) {
534		t.Error("TypedNil should return false")
535	}
536	mockT.equals(t, "error: should be typed-nil but got nil instead")
537	if uassert.TypedNil(mockT, 0) {
538		t.Error("TypedNil should return false")
539	}
540	mockT.equals(t, "error: should be typed-nil")
541	if !uassert.TypedNil(mockT, (*int)(nil)) {
542		t.Error("TypedNil should return true")
543	}
544	mockT.empty(t)
545}
546
547func TestNotTypedNil(t *testing.T) {
548	mockT := new(mockTestingT)
549	if !uassert.NotTypedNil(mockT, nil) {
550		t.Error("NotTypedNil should return true")
551	}
552	mockT.empty(t)
553	if !uassert.NotTypedNil(mockT, 0) {
554		t.Error("NotTypedNil should return true")
555	}
556	mockT.empty(t)
557	if uassert.NotTypedNil(mockT, (*int)(nil)) {
558		t.Error("NotTypedNil should return false")
559	}
560	mockT.equals(t, "error: should not be typed-nil")
561}