From 6a3c4c78cfd8f22359173b2bc2235f675bdccaf7 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Thu, 22 Jun 2023 16:14:26 +0200 Subject: [PATCH 01/14] feat: add p/demo/utestify Signed-off-by: Manfred Touron <94029+moul@users.noreply.github.com> --- examples/gno.land/p/demo/utestify/doc.gno | 1 + examples/gno.land/p/demo/utestify/gno.mod | 1 + .../gno.land/p/demo/utestify/utestify.gno | 23 +++++++++++++++++++ .../p/demo/utestify/utestify_test.gno | 5 ++++ .../gno.land/p/demo/utestify/z0_filetest.gno | 11 +++++++++ 5 files changed, 41 insertions(+) create mode 100644 examples/gno.land/p/demo/utestify/doc.gno create mode 100644 examples/gno.land/p/demo/utestify/gno.mod create mode 100644 examples/gno.land/p/demo/utestify/utestify.gno create mode 100644 examples/gno.land/p/demo/utestify/utestify_test.gno create mode 100644 examples/gno.land/p/demo/utestify/z0_filetest.gno diff --git a/examples/gno.land/p/demo/utestify/doc.gno b/examples/gno.land/p/demo/utestify/doc.gno new file mode 100644 index 00000000000..803df2da1c8 --- /dev/null +++ b/examples/gno.land/p/demo/utestify/doc.gno @@ -0,0 +1 @@ +package utestify // import "gno.land/p/demo/utestify" diff --git a/examples/gno.land/p/demo/utestify/gno.mod b/examples/gno.land/p/demo/utestify/gno.mod new file mode 100644 index 00000000000..fd41e8f6dad --- /dev/null +++ b/examples/gno.land/p/demo/utestify/gno.mod @@ -0,0 +1 @@ +module gno.land/p/demo/utestify diff --git a/examples/gno.land/p/demo/utestify/utestify.gno b/examples/gno.land/p/demo/utestify/utestify.gno new file mode 100644 index 00000000000..010296ce1eb --- /dev/null +++ b/examples/gno.land/p/demo/utestify/utestify.gno @@ -0,0 +1,23 @@ +package utestify + +import ( + "std" + "testing" +) + +func SameStrings(t *testing.T, a, b string) { + t.Helper() + if a != b { + t.Errorf("%q != %q") + } +} + +func SimilarStrings(t *testing.T, a, b string) { + t.Helper() + + a = strings.TrimSpace(a) + b = strings.TrimSpace(b) + if a != b { + t.Errorf("%q != %q") + } +} diff --git a/examples/gno.land/p/demo/utestify/utestify_test.gno b/examples/gno.land/p/demo/utestify/utestify_test.gno new file mode 100644 index 00000000000..efa02f4c726 --- /dev/null +++ b/examples/gno.land/p/demo/utestify/utestify_test.gno @@ -0,0 +1,5 @@ +package utestify + +func TestPackage(t *testing.T) { + SameStrings(t, "a", "a") +} diff --git a/examples/gno.land/p/demo/utestify/z0_filetest.gno b/examples/gno.land/p/demo/utestify/z0_filetest.gno new file mode 100644 index 00000000000..13dbc8fac21 --- /dev/null +++ b/examples/gno.land/p/demo/utestify/z0_filetest.gno @@ -0,0 +1,11 @@ +// PKGPATH: gno.land/p/demo/testify_test +package testify_test + +import "gno.land/p/demo/utestify" + +func main() { + println("TEST") +} + +// Output: +// TEST From ade2be5151fe4fccb6db88622688e576da7bc98a Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Thu, 22 Jun 2023 18:01:30 +0200 Subject: [PATCH 02/14] chore: fixup Signed-off-by: Manfred Touron <94029+moul@users.noreply.github.com> --- .../gno.land/p/demo/utestify/utestify.gno | 30 ++++++++++++++++--- .../p/demo/utestify/utestify_test.gno | 9 +++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/examples/gno.land/p/demo/utestify/utestify.gno b/examples/gno.land/p/demo/utestify/utestify.gno index 010296ce1eb..5ca2849ed0b 100644 --- a/examples/gno.land/p/demo/utestify/utestify.gno +++ b/examples/gno.land/p/demo/utestify/utestify.gno @@ -2,22 +2,44 @@ package utestify import ( "std" + "strings" "testing" ) -func SameStrings(t *testing.T, a, b string) { +func MustEqualStrings(t *testing.T, a, b string) { t.Helper() if a != b { - t.Errorf("%q != %q") + t.Errorf("%q != %q", a, b) } } -func SimilarStrings(t *testing.T, a, b string) { +func ShouldEqualStrings(t *testing.T, a, b string) bool { + t.Helper() + if a != b { + t.Logf("%q != %q", a, b) + return false + } + return true +} + +func MustResembleStrings(t *testing.T, a, b string) { + t.Helper() + + a = strings.TrimSpace(a) + b = strings.TrimSpace(b) + if a != b { + t.Errorf("%q != %q", a, b) + } +} + +func ShouldResembleStrings(t *testing.T, a, b string) bool { t.Helper() a = strings.TrimSpace(a) b = strings.TrimSpace(b) if a != b { - t.Errorf("%q != %q") + t.Logf("%q != %q", a, b) + return false } + return true } diff --git a/examples/gno.land/p/demo/utestify/utestify_test.gno b/examples/gno.land/p/demo/utestify/utestify_test.gno index efa02f4c726..1f5c0f4ed7e 100644 --- a/examples/gno.land/p/demo/utestify/utestify_test.gno +++ b/examples/gno.land/p/demo/utestify/utestify_test.gno @@ -1,5 +1,12 @@ package utestify +import "testing" + func TestPackage(t *testing.T) { - SameStrings(t, "a", "a") + if !ShouldEqualStrings(t, "a", "a") { + t.Errorf("ShouldSameStrings failed for same string") + } + if ShouldEqualStrings(t, "a", "b") { + t.Errorf("ShouldSameStrings failed for different string") + } } From 94e58856974e75148d7357819a0aeddf276636ac Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Fri, 23 Jun 2023 11:19:39 +0200 Subject: [PATCH 03/14] chore: fixup --- .../gno.land/p/demo/utestify/utestify.gno | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/examples/gno.land/p/demo/utestify/utestify.gno b/examples/gno.land/p/demo/utestify/utestify.gno index 5ca2849ed0b..2049b6f29c0 100644 --- a/examples/gno.land/p/demo/utestify/utestify.gno +++ b/examples/gno.land/p/demo/utestify/utestify.gno @@ -6,23 +6,29 @@ import ( "testing" ) -func MustEqualStrings(t *testing.T, a, b string) { +type TestingT interface { + Errorf(fmt string, args ...interface{}) +} + +func MustEqualStrings(t TestingT, a, b string) { t.Helper() - if a != b { - t.Errorf("%q != %q", a, b) - } + _ = checkEqualStrings(t, a, b, t.Errorf) } -func ShouldEqualStrings(t *testing.T, a, b string) bool { +func EqualStrings(t TestingT, a, b string) bool { t.Helper() + return checkEqualStrings(t, a, b, t.Logf) +} + +func checkEqualStrings(t TestingT, a, b string, cb printerFn) bool { if a != b { - t.Logf("%q != %q", a, b) + cb("%q != %q", a, b) return false } return true } -func MustResembleStrings(t *testing.T, a, b string) { +func MustResembleStrings(t TestingT, a, b string) { t.Helper() a = strings.TrimSpace(a) @@ -32,7 +38,7 @@ func MustResembleStrings(t *testing.T, a, b string) { } } -func ShouldResembleStrings(t *testing.T, a, b string) bool { +func ShouldResembleStrings(t TestingT, a, b string) bool { t.Helper() a = strings.TrimSpace(a) From f268d9cb148c03a72d6c8d8addd91a42a81cc589 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Fri, 23 Jun 2023 11:27:49 +0200 Subject: [PATCH 04/14] chore: fixup --- examples/gno.land/p/demo/uassert/doc.gno | 1 + examples/gno.land/p/demo/uassert/gno.mod | 1 + .../{utestify/utestify.gno => uassert/uassert.gno} | 2 +- .../utestify_test.gno => uassert/uassert_test.gno} | 2 +- examples/gno.land/p/demo/uassert/z0_filetest.gno | 11 +++++++++++ examples/gno.land/p/demo/utestify/doc.gno | 1 - examples/gno.land/p/demo/utestify/gno.mod | 1 - examples/gno.land/p/demo/utestify/z0_filetest.gno | 11 ----------- 8 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 examples/gno.land/p/demo/uassert/doc.gno create mode 100644 examples/gno.land/p/demo/uassert/gno.mod rename examples/gno.land/p/demo/{utestify/utestify.gno => uassert/uassert.gno} (97%) rename examples/gno.land/p/demo/{utestify/utestify_test.gno => uassert/uassert_test.gno} (93%) create mode 100644 examples/gno.land/p/demo/uassert/z0_filetest.gno delete mode 100644 examples/gno.land/p/demo/utestify/doc.gno delete mode 100644 examples/gno.land/p/demo/utestify/gno.mod delete mode 100644 examples/gno.land/p/demo/utestify/z0_filetest.gno diff --git a/examples/gno.land/p/demo/uassert/doc.gno b/examples/gno.land/p/demo/uassert/doc.gno new file mode 100644 index 00000000000..df95d78e394 --- /dev/null +++ b/examples/gno.land/p/demo/uassert/doc.gno @@ -0,0 +1 @@ +package uassert // import "gno.land/p/demo/uassert" diff --git a/examples/gno.land/p/demo/uassert/gno.mod b/examples/gno.land/p/demo/uassert/gno.mod new file mode 100644 index 00000000000..a70e7db825d --- /dev/null +++ b/examples/gno.land/p/demo/uassert/gno.mod @@ -0,0 +1 @@ +module gno.land/p/demo/uassert diff --git a/examples/gno.land/p/demo/utestify/utestify.gno b/examples/gno.land/p/demo/uassert/uassert.gno similarity index 97% rename from examples/gno.land/p/demo/utestify/utestify.gno rename to examples/gno.land/p/demo/uassert/uassert.gno index 2049b6f29c0..6488362d62c 100644 --- a/examples/gno.land/p/demo/utestify/utestify.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -1,4 +1,4 @@ -package utestify +package uassert import ( "std" diff --git a/examples/gno.land/p/demo/utestify/utestify_test.gno b/examples/gno.land/p/demo/uassert/uassert_test.gno similarity index 93% rename from examples/gno.land/p/demo/utestify/utestify_test.gno rename to examples/gno.land/p/demo/uassert/uassert_test.gno index 1f5c0f4ed7e..da39590b3eb 100644 --- a/examples/gno.land/p/demo/utestify/utestify_test.gno +++ b/examples/gno.land/p/demo/uassert/uassert_test.gno @@ -1,4 +1,4 @@ -package utestify +package uassert import "testing" diff --git a/examples/gno.land/p/demo/uassert/z0_filetest.gno b/examples/gno.land/p/demo/uassert/z0_filetest.gno new file mode 100644 index 00000000000..ab915f76430 --- /dev/null +++ b/examples/gno.land/p/demo/uassert/z0_filetest.gno @@ -0,0 +1,11 @@ +// PKGPATH: gno.land/p/demo/assert_test +package assert_test + +import "gno.land/p/demo/uassert" + +func main() { + println("TEST") +} + +// Output: +// TEST diff --git a/examples/gno.land/p/demo/utestify/doc.gno b/examples/gno.land/p/demo/utestify/doc.gno deleted file mode 100644 index 803df2da1c8..00000000000 --- a/examples/gno.land/p/demo/utestify/doc.gno +++ /dev/null @@ -1 +0,0 @@ -package utestify // import "gno.land/p/demo/utestify" diff --git a/examples/gno.land/p/demo/utestify/gno.mod b/examples/gno.land/p/demo/utestify/gno.mod deleted file mode 100644 index fd41e8f6dad..00000000000 --- a/examples/gno.land/p/demo/utestify/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/p/demo/utestify diff --git a/examples/gno.land/p/demo/utestify/z0_filetest.gno b/examples/gno.land/p/demo/utestify/z0_filetest.gno deleted file mode 100644 index 13dbc8fac21..00000000000 --- a/examples/gno.land/p/demo/utestify/z0_filetest.gno +++ /dev/null @@ -1,11 +0,0 @@ -// PKGPATH: gno.land/p/demo/testify_test -package testify_test - -import "gno.land/p/demo/utestify" - -func main() { - println("TEST") -} - -// Output: -// TEST From 2229692a69f5a851810d102e6d795e563ec3be8c Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Mon, 1 Jul 2024 22:35:48 +0200 Subject: [PATCH 05/14] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/demo/uassert/uassert.gno | 8 +++++++- examples/gno.land/p/demo/uassert/uassert_test.gno | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/gno.land/p/demo/uassert/uassert.gno b/examples/gno.land/p/demo/uassert/uassert.gno index 6488362d62c..4952df3f291 100644 --- a/examples/gno.land/p/demo/uassert/uassert.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -3,11 +3,17 @@ package uassert import ( "std" "strings" - "testing" ) type TestingT interface { + Skip(args ...interface{}) Errorf(fmt string, args ...interface{}) + Error(args ...interface{}) + Fatalf(fmt string, args ...interface{}) + Fatal(args ...interface{}) + Logf(fmt string, args ...interface{}) + // Run(name string, f testingFunc) + Helper() } func MustEqualStrings(t TestingT, a, b string) { diff --git a/examples/gno.land/p/demo/uassert/uassert_test.gno b/examples/gno.land/p/demo/uassert/uassert_test.gno index da39590b3eb..d116aebbeb5 100644 --- a/examples/gno.land/p/demo/uassert/uassert_test.gno +++ b/examples/gno.land/p/demo/uassert/uassert_test.gno @@ -2,6 +2,8 @@ package uassert import "testing" +var _ testing.T(nil) = TestingT + func TestPackage(t *testing.T) { if !ShouldEqualStrings(t, "a", "a") { t.Errorf("ShouldSameStrings failed for same string") From 381f35b4caa0db97c48e8642e811efc385a3f50e Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 02:00:12 +0200 Subject: [PATCH 06/14] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/demo/uassert/helpers.gno | 44 +++++ .../gno.land/p/demo/uassert/mock_test.gno | 57 +++++++ examples/gno.land/p/demo/uassert/types.gno | 9 + examples/gno.land/p/demo/uassert/uassert.gno | 154 ++++++++++++++---- .../gno.land/p/demo/uassert/uassert_test.gno | 145 ++++++++++++++++- .../gno.land/p/demo/uassert/z0_filetest.gno | 11 -- 6 files changed, 370 insertions(+), 50 deletions(-) create mode 100644 examples/gno.land/p/demo/uassert/helpers.gno create mode 100644 examples/gno.land/p/demo/uassert/mock_test.gno create mode 100644 examples/gno.land/p/demo/uassert/types.gno delete mode 100644 examples/gno.land/p/demo/uassert/z0_filetest.gno diff --git a/examples/gno.land/p/demo/uassert/helpers.gno b/examples/gno.land/p/demo/uassert/helpers.gno new file mode 100644 index 00000000000..8c0ee23e9e1 --- /dev/null +++ b/examples/gno.land/p/demo/uassert/helpers.gno @@ -0,0 +1,44 @@ +package uassert + +import "strings" + +func fail(t TestingT, customMsgs []string, failureMessage string, args ...interface{}) bool { + customMsg := "" + if len(customMsgs) > 0 { + customMsg = strings.Join(customMsgs, " ") + } + if customMsg != "" { + failureMessage += " - " + customMsg + } + t.Errorf(failureMessage, args...) + return false +} + +func checkDidPanic(f func()) (didPanic bool, message string) { + didPanic = true + defer func() { + r := recover() + + if r == nil { + message = "nil" + return + } + + err, ok := r.(error) + if ok { + message = err.Error() + return + } + + errStr, ok := r.(string) + if ok { + message = errStr + return + } + + message = "recover: unsupported type" + }() + f() + didPanic = false + return +} diff --git a/examples/gno.land/p/demo/uassert/mock_test.gno b/examples/gno.land/p/demo/uassert/mock_test.gno new file mode 100644 index 00000000000..d84f59f10f0 --- /dev/null +++ b/examples/gno.land/p/demo/uassert/mock_test.gno @@ -0,0 +1,57 @@ +package uassert + +import ( + "fmt" + "testing" +) + +type mockTestingT struct { + fmt string + args []interface{} +} + +// --- interface mock + +var _ TestingT = (*mockTestingT)(nil) + +func (mockT *mockTestingT) Helper() { /* noop */ } +func (mockT *mockTestingT) Skip(args ...interface{}) { /* not implmented */ } +func (mockT *mockTestingT) Logf(fmt string, args ...interface{}) { /* noop */ } + +func (mockT *mockTestingT) Fatalf(fmt string, args ...interface{}) { + mockT.fmt = "fatal: " + fmt + mockT.args = args +} + +func (mockT *mockTestingT) Errorf(fmt string, args ...interface{}) { + mockT.fmt = "error: " + fmt + mockT.args = args +} + +// --- helpers + +func (mockT *mockTestingT) actualString() string { + res := fmt.Sprintf(mockT.fmt, mockT.args...) + mockT.reset() + return res +} + +func (mockT *mockTestingT) reset() { + mockT.fmt = "" + mockT.args = nil +} + +func (mockT *mockTestingT) equals(t *testing.T, expected string) { + actual := mockT.actualString() + + if expected != actual { + t.Errorf("mockT differs:\n- expected: %s\n- actual: %s\n", expected, actual) + } +} + +func (mockT *mockTestingT) empty(t *testing.T) { + if mockT.fmt != "" || mockT.args != nil { + actual := mockT.actualString() + t.Errorf("mockT should be empty, got %s", actual) + } +} diff --git a/examples/gno.land/p/demo/uassert/types.gno b/examples/gno.land/p/demo/uassert/types.gno new file mode 100644 index 00000000000..8511022bf4f --- /dev/null +++ b/examples/gno.land/p/demo/uassert/types.gno @@ -0,0 +1,9 @@ +package uassert + +type TestingT interface { + Helper() + Skip(args ...interface{}) + Fatalf(fmt string, args ...interface{}) + Errorf(fmt string, args ...interface{}) + Logf(fmt string, args ...interface{}) +} diff --git a/examples/gno.land/p/demo/uassert/uassert.gno b/examples/gno.land/p/demo/uassert/uassert.gno index 4952df3f291..bd536a59731 100644 --- a/examples/gno.land/p/demo/uassert/uassert.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -1,57 +1,147 @@ +// uassert is an adapted lighter version of https://github.com/stretchr/testify/assert. package uassert -import ( - "std" - "strings" -) +import "std" -type TestingT interface { - Skip(args ...interface{}) - Errorf(fmt string, args ...interface{}) - Error(args ...interface{}) - Fatalf(fmt string, args ...interface{}) - Fatal(args ...interface{}) - Logf(fmt string, args ...interface{}) - // Run(name string, f testingFunc) - Helper() +// NoError asserts that a function returned no error (i.e. `nil`). +func NoError(t TestingT, err error, msgs ...string) bool { + t.Helper() + if err != nil { + return fail(t, msgs, "unexpected error: %s", err.Error()) + } + return true } -func MustEqualStrings(t TestingT, a, b string) { +// Error asserts that a function returned an error (i.e. not `nil`). +func Error(t TestingT, err error, msgs ...string) bool { t.Helper() - _ = checkEqualStrings(t, a, b, t.Errorf) + if err == nil { + return fail(t, msgs, "an error is expected but got nil") + } + return true } -func EqualStrings(t TestingT, a, b string) bool { +// True asserts that the specified value is true. +func True(t TestingT, value bool, msgs ...string) bool { t.Helper() - return checkEqualStrings(t, a, b, t.Logf) + if !value { + return fail(t, msgs, "should be true") + } + return true } -func checkEqualStrings(t TestingT, a, b string, cb printerFn) bool { - if a != b { - cb("%q != %q", a, b) - return false +// False asserts that the specified value is false. +func False(t TestingT, value bool, msgs ...string) bool { + t.Helper() + if value { + return fail(t, msgs, "should be false") } return true } -func MustResembleStrings(t TestingT, a, b string) { +// ErrorIs asserts the given error matches the target error +func ErrorIs(t TestingT, err, target error, msgs ...string) bool { t.Helper() - a = strings.TrimSpace(a) - b = strings.TrimSpace(b) - if a != b { - t.Errorf("%q != %q", a, b) + if err == nil || target == nil { + return err == target } + + // XXX: if errors.Is(err, target) return true + + if err.Error() != target.Error() { + return fail(t, msgs, "error mismatch, expected %s, got %s", target.Error(), err.Error()) + } + + return true } -func ShouldResembleStrings(t TestingT, a, b string) bool { +// PanicsWithError asserts that the code inside the specified func panics, +// and that the recovered panic value is an error that satisfies the given message +func PanicsWithError(t TestingT, errString string, f func(), msgs ...string) bool { t.Helper() - a = strings.TrimSpace(a) - b = strings.TrimSpace(b) - if a != b { - t.Logf("%q != %q", a, b) - return false + didPanic, panicValue := checkDidPanic(f) + if !didPanic { + return fail(t, msgs, "func should panic\n\tPanic value:\t%v", panicValue) + } + + if panicValue != errString { + return fail(t, msgs, "func should panic with error:\t%s\n\tPanic value:\t%s", panicValue, errString) } return true } + +// NotPanics asserts that the code inside the specified func does NOT panic. +func NotPanics(t TestingT, f func(), msgs ...string) bool { + t.Helper() + + didPanic, panicValue := checkDidPanic(f) + + if didPanic { + return fail(t, msgs, "func should not panic\n\tPanic value:\t%s", panicValue) + } + return true +} + +// Equal asserts that two objects are equal. +func Equal(t TestingT, expected, actual interface{}, msgs ...string) bool { + t.Helper() + + if expected == nil || actual == nil { + return expected == actual + } + + // XXX: errors + // XXX: slices + // XXX: pointers + + switch ev := expected.(type) { + case string: + av, ok := actual.(string) + return ok && ev == av + case int: + av, ok := actual.(int) + return ok && ev == av + case int8: + av, ok := actual.(int8) + return ok && ev == av + case int16: + av, ok := actual.(int16) + return ok && ev == av + case int32: + av, ok := actual.(int32) + return ok && ev == av + case int64: + av, ok := actual.(int64) + return ok && ev == av + case uint: + av, ok := actual.(uint) + return ok && ev == av + case uint8: + av, ok := actual.(uint8) + return ok && ev == av + case uint16: + av, ok := actual.(uint16) + return ok && ev == av + case uint32: + av, ok := actual.(uint32) + return ok && ev == av + case uint64: + av, ok := actual.(uint64) + return ok && ev == av + case bool: + av, ok := actual.(bool) + return ok && ev == av + case float32: + av, ok := actual.(float32) + return ok && ev == av + case float64: + av, ok := actual.(float64) + return ok && ev == av + default: + fail(t, msgs, "uassert.Equal: unsupported type") + } + + return false +} diff --git a/examples/gno.land/p/demo/uassert/uassert_test.gno b/examples/gno.land/p/demo/uassert/uassert_test.gno index d116aebbeb5..95a3aeafe6a 100644 --- a/examples/gno.land/p/demo/uassert/uassert_test.gno +++ b/examples/gno.land/p/demo/uassert/uassert_test.gno @@ -1,14 +1,145 @@ package uassert -import "testing" +import ( + "errors" + "fmt" + "testing" +) -var _ testing.T(nil) = TestingT +var _ TestingT = (*testing.T)(nil) -func TestPackage(t *testing.T) { - if !ShouldEqualStrings(t, "a", "a") { - t.Errorf("ShouldSameStrings failed for same string") +func TestMock(t *testing.T) { + mockT := new(mockTestingT) + mockT.empty(t) + NoError(mockT, errors.New("foo")) + mockT.equals(t, "error: unexpected error: foo") + NoError(mockT, errors.New("foo"), "custom message") + mockT.equals(t, "error: unexpected error: foo - custom message") + NoError(mockT, errors.New("foo"), "custom", "message") + mockT.equals(t, "error: unexpected error: foo - custom message") +} + +func TestNoError(t *testing.T) { + mockT := new(mockTestingT) + True(t, NoError(mockT, nil)) + mockT.empty(t) + False(t, NoError(mockT, errors.New("foo bar"))) + mockT.equals(t, "error: unexpected error: foo bar") +} + +func TestError(t *testing.T) { + mockT := new(mockTestingT) + True(t, Error(mockT, errors.New("foo bar"))) + mockT.empty(t) + False(t, Error(mockT, nil)) + mockT.equals(t, "error: an error is expected but got nil") +} + +func TestTrue(t *testing.T) { + mockT := new(mockTestingT) + if !True(mockT, true) { + t.Error("True should return true") + } + mockT.empty(t) + if True(mockT, false) { + t.Error("True should return false") } - if ShouldEqualStrings(t, "a", "b") { - t.Errorf("ShouldSameStrings failed for different string") + mockT.equals(t, "error: should be true") +} + +func TestFalse(t *testing.T) { + mockT := new(mockTestingT) + if !False(mockT, false) { + t.Error("False should return true") + } + mockT.empty(t) + if False(mockT, true) { + t.Error("False should return false") + } + mockT.equals(t, "error: should be false") +} + +func TestPanicsWithError(t *testing.T) { + mockT := new(mockTestingT) + if !PanicsWithError(mockT, "panic", func() { + panic(errors.New("panic")) + }) { + t.Error("PanicsWithError should return true") + } + mockT.empty(t) + + if PanicsWithError(mockT, "Panic!", func() { + // noop + }) { + t.Error("PanicsWithError should return false") + } + mockT.equals(t, "error: func should panic\n\tPanic value:\tnil") + + if PanicsWithError(mockT, "at the disco", func() { + panic(errors.New("panic")) + }) { + t.Error("PanicsWithError should return false") + } + mockT.equals(t, "error: func should panic with error:\tpanic\n\tPanic value:\tat the disco") + + if PanicsWithError(mockT, "Panic!", func() { + panic("panic") + }) { + t.Error("PanicsWithError should return false") + } + mockT.equals(t, "error: func should panic with error:\tpanic\n\tPanic value:\tPanic!") +} + +func TestNotPanics(t *testing.T) { + mockT := new(mockTestingT) + + if !NotPanics(mockT, func() { + // noop + }) { + t.Error("NotPanics should return true") + } + mockT.empty(t) + + if NotPanics(mockT, func() { + panic("Panic!") + }) { + t.Error("NotPanics should return false") + } +} + +func TestEqual(t *testing.T) { + mockT := new(mockTestingT) + + cases := []struct { + expected interface{} + actual interface{} + result bool + remark string + }{ + // expected to be equal + {"Hello World", "Hello World", true, ""}, + {123, 123, true, ""}, + {123.5, 123.5, true, ""}, + {nil, nil, true, ""}, + {int32(123), int32(123), true, ""}, + {uint64(123), uint64(123), true, ""}, + //{[]byte("Hello World"), []byte("Hello World"), true, ""}, + // {myType("1"), myType("1"), true, ""}, + //{&struct{}{}, &struct{}{}, true, "pointer equality is based on equality of underlying value"}, + + // not expected to be equal + {"Hello World", 42, false, ""}, + {10, uint(10), false, ""}, + } + + for _, c := range cases { + name := fmt.Sprintf("Equal(%v, %v)", c.expected, c.actual) + t.Run(name, func(t *testing.T) { + res := Equal(mockT, c.expected, c.actual) + + if res != c.result { + t.Errorf("%s should return %v: %s - %s", name, c.result, c.remark, mockT.actualString()) + } + }) } } diff --git a/examples/gno.land/p/demo/uassert/z0_filetest.gno b/examples/gno.land/p/demo/uassert/z0_filetest.gno deleted file mode 100644 index ab915f76430..00000000000 --- a/examples/gno.land/p/demo/uassert/z0_filetest.gno +++ /dev/null @@ -1,11 +0,0 @@ -// PKGPATH: gno.land/p/demo/assert_test -package assert_test - -import "gno.land/p/demo/uassert" - -func main() { - println("TEST") -} - -// Output: -// TEST From ed655171fecf7f0d908bb392894dbf2d6325391c Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 02:15:14 +0200 Subject: [PATCH 07/14] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/demo/uassert/uassert.gno | 3 +++ examples/gno.land/p/demo/uassert/uassert_test.gno | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/gno.land/p/demo/uassert/uassert.gno b/examples/gno.land/p/demo/uassert/uassert.gno index bd536a59731..d499b284e29 100644 --- a/examples/gno.land/p/demo/uassert/uassert.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -100,6 +100,9 @@ func Equal(t TestingT, expected, actual interface{}, msgs ...string) bool { case string: av, ok := actual.(string) return ok && ev == av + case std.Address: + av, ok := actual.(std.Address) + return ok && ev == av case int: av, ok := actual.(int) return ok && ev == av diff --git a/examples/gno.land/p/demo/uassert/uassert_test.gno b/examples/gno.land/p/demo/uassert/uassert_test.gno index 95a3aeafe6a..f729e8d1a96 100644 --- a/examples/gno.land/p/demo/uassert/uassert_test.gno +++ b/examples/gno.land/p/demo/uassert/uassert_test.gno @@ -3,6 +3,7 @@ package uassert import ( "errors" "fmt" + "std" "testing" ) @@ -123,12 +124,14 @@ func TestEqual(t *testing.T) { {nil, nil, true, ""}, {int32(123), int32(123), true, ""}, {uint64(123), uint64(123), true, ""}, + {std.Address("g12345"), std.Address("g12345"), true, ""}, //{[]byte("Hello World"), []byte("Hello World"), true, ""}, // {myType("1"), myType("1"), true, ""}, //{&struct{}{}, &struct{}{}, true, "pointer equality is based on equality of underlying value"}, // not expected to be equal {"Hello World", 42, false, ""}, + {41, 42, false, ""}, {10, uint(10), false, ""}, } From 243bdbbf4a7233bdc8743e5ff75fc84621066659 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 02:37:57 +0200 Subject: [PATCH 08/14] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .../gno.land/p/demo/uassert/mock_test.gno | 2 + examples/gno.land/p/demo/uassert/types.gno | 2 + examples/gno.land/p/demo/uassert/uassert.gno | 10 +-- .../gno.land/p/demo/uassert/uassert_test.gno | 22 +++--- examples/gno.land/p/demo/urequire/gno.mod | 3 + .../gno.land/p/demo/urequire/urequire.gno | 71 +++++++++++++++++++ .../p/demo/urequire/urequire_test.gno | 7 ++ examples/gno.land/r/demo/foo20/foo20_test.gno | 20 ++---- examples/gno.land/r/demo/foo20/gno.mod | 1 + 9 files changed, 107 insertions(+), 31 deletions(-) create mode 100644 examples/gno.land/p/demo/urequire/gno.mod create mode 100644 examples/gno.land/p/demo/urequire/urequire.gno create mode 100644 examples/gno.land/p/demo/urequire/urequire_test.gno diff --git a/examples/gno.land/p/demo/uassert/mock_test.gno b/examples/gno.land/p/demo/uassert/mock_test.gno index d84f59f10f0..b611faab668 100644 --- a/examples/gno.land/p/demo/uassert/mock_test.gno +++ b/examples/gno.land/p/demo/uassert/mock_test.gno @@ -16,6 +16,8 @@ var _ TestingT = (*mockTestingT)(nil) func (mockT *mockTestingT) Helper() { /* noop */ } func (mockT *mockTestingT) Skip(args ...interface{}) { /* not implmented */ } +func (mockT *mockTestingT) Fail() { /* not implmented */ } +func (mockT *mockTestingT) FailNow() { /* not implmented */ } func (mockT *mockTestingT) Logf(fmt string, args ...interface{}) { /* noop */ } func (mockT *mockTestingT) Fatalf(fmt string, args ...interface{}) { diff --git a/examples/gno.land/p/demo/uassert/types.gno b/examples/gno.land/p/demo/uassert/types.gno index 8511022bf4f..83950b5e8a4 100644 --- a/examples/gno.land/p/demo/uassert/types.gno +++ b/examples/gno.land/p/demo/uassert/types.gno @@ -6,4 +6,6 @@ type TestingT interface { Fatalf(fmt string, args ...interface{}) Errorf(fmt string, args ...interface{}) Logf(fmt string, args ...interface{}) + Fail() + FailNow() } diff --git a/examples/gno.land/p/demo/uassert/uassert.gno b/examples/gno.land/p/demo/uassert/uassert.gno index d499b284e29..3fe46811b5e 100644 --- a/examples/gno.land/p/demo/uassert/uassert.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -56,9 +56,9 @@ func ErrorIs(t TestingT, err, target error, msgs ...string) bool { return true } -// PanicsWithError asserts that the code inside the specified func panics, -// and that the recovered panic value is an error that satisfies the given message -func PanicsWithError(t TestingT, errString string, f func(), msgs ...string) bool { +// PanicsWithMessage asserts that the code inside the specified func panics, +// and that the recovered panic value satisfies the given message +func PanicsWithMessage(t TestingT, msg string, f func(), msgs ...string) bool { t.Helper() didPanic, panicValue := checkDidPanic(f) @@ -66,8 +66,8 @@ func PanicsWithError(t TestingT, errString string, f func(), msgs ...string) boo return fail(t, msgs, "func should panic\n\tPanic value:\t%v", panicValue) } - if panicValue != errString { - return fail(t, msgs, "func should panic with error:\t%s\n\tPanic value:\t%s", panicValue, errString) + if panicValue != msg { + return fail(t, msgs, "func should panic with message:\t%s\n\tPanic value:\t%s", panicValue, msg) } return true } diff --git a/examples/gno.land/p/demo/uassert/uassert_test.gno b/examples/gno.land/p/demo/uassert/uassert_test.gno index f729e8d1a96..04887c9c69f 100644 --- a/examples/gno.land/p/demo/uassert/uassert_test.gno +++ b/examples/gno.land/p/demo/uassert/uassert_test.gno @@ -60,35 +60,35 @@ func TestFalse(t *testing.T) { mockT.equals(t, "error: should be false") } -func TestPanicsWithError(t *testing.T) { +func TestPanicsWithMessage(t *testing.T) { mockT := new(mockTestingT) - if !PanicsWithError(mockT, "panic", func() { + if !PanicsWithMessage(mockT, "panic", func() { panic(errors.New("panic")) }) { - t.Error("PanicsWithError should return true") + t.Error("PanicsWithMessage should return true") } mockT.empty(t) - if PanicsWithError(mockT, "Panic!", func() { + if PanicsWithMessage(mockT, "Panic!", func() { // noop }) { - t.Error("PanicsWithError should return false") + t.Error("PanicsWithMessage should return false") } mockT.equals(t, "error: func should panic\n\tPanic value:\tnil") - if PanicsWithError(mockT, "at the disco", func() { + if PanicsWithMessage(mockT, "at the disco", func() { panic(errors.New("panic")) }) { - t.Error("PanicsWithError should return false") + t.Error("PanicsWithMessage should return false") } - mockT.equals(t, "error: func should panic with error:\tpanic\n\tPanic value:\tat the disco") + mockT.equals(t, "error: func should panic with message:\tpanic\n\tPanic value:\tat the disco") - if PanicsWithError(mockT, "Panic!", func() { + if PanicsWithMessage(mockT, "Panic!", func() { panic("panic") }) { - t.Error("PanicsWithError should return false") + t.Error("PanicsWithMessage should return false") } - mockT.equals(t, "error: func should panic with error:\tpanic\n\tPanic value:\tPanic!") + mockT.equals(t, "error: func should panic with message:\tpanic\n\tPanic value:\tPanic!") } func TestNotPanics(t *testing.T) { diff --git a/examples/gno.land/p/demo/urequire/gno.mod b/examples/gno.land/p/demo/urequire/gno.mod new file mode 100644 index 00000000000..f8d4697813f --- /dev/null +++ b/examples/gno.land/p/demo/urequire/gno.mod @@ -0,0 +1,3 @@ +module urequire + +require gno.land/p/demo/uassert v0.0.0-latest diff --git a/examples/gno.land/p/demo/urequire/urequire.gno b/examples/gno.land/p/demo/urequire/urequire.gno new file mode 100644 index 00000000000..bf0bfb05b44 --- /dev/null +++ b/examples/gno.land/p/demo/urequire/urequire.gno @@ -0,0 +1,71 @@ +// urequire is a sister package for uassert. +// XXX: codegen the package. +package urequire + +import "gno.land/p/demo/uassert" + +// type TestingT = uassert.TestingT // XXX: bug, should work + +func NoError(t uassert.TestingT, err error, msgs ...string) { + t.Helper() + if uassert.NoError(t, err, msgs...) { + return + } + t.FailNow() +} + +func Error(t uassert.TestingT, err error, msgs ...string) { + t.Helper() + if uassert.Error(t, err, msgs...) { + return + } + t.FailNow() +} + +func True(t uassert.TestingT, value bool, msgs ...string) { + t.Helper() + if uassert.True(t, value, msgs...) { + return + } + t.FailNow() +} + +func False(t uassert.TestingT, value bool, msgs ...string) { + t.Helper() + if uassert.False(t, value, msgs...) { + return + } + t.FailNow() +} + +func ErrorIs(t uassert.TestingT, err, target error, msgs ...string) { + t.Helper() + if uassert.ErrorIs(t, err, target, msgs...) { + return + } + t.FailNow() +} + +func PanicsWithError(t uassert.TestingT, errString string, f func(), msgs ...string) { + t.Helper() + if uassert.PanicsWithError(t, errString, f, msgs...) { + return + } + t.FailNow() +} + +func NotPanics(t uassert.TestingT, f func(), msgs ...string) { + t.Helper() + if uassert.NotPanics(t, f, msgs...) { + return + } + t.FailNow() +} + +func Equal(t uassert.TestingT, expected, actual interface{}, msgs ...string) { + t.Helper() + if uassert.Equal(t, expected, actual, msgs...) { + return + } + t.FailNow() +} diff --git a/examples/gno.land/p/demo/urequire/urequire_test.gno b/examples/gno.land/p/demo/urequire/urequire_test.gno new file mode 100644 index 00000000000..513c5cc2082 --- /dev/null +++ b/examples/gno.land/p/demo/urequire/urequire_test.gno @@ -0,0 +1,7 @@ +package urequire + +import "testing" + +func TestPackage(t *testing.T) { + Equal(t, 42, 42) +} diff --git a/examples/gno.land/r/demo/foo20/foo20_test.gno b/examples/gno.land/r/demo/foo20/foo20_test.gno index 38bdcb333c1..8cb8759fbe2 100644 --- a/examples/gno.land/r/demo/foo20/foo20_test.gno +++ b/examples/gno.land/r/demo/foo20/foo20_test.gno @@ -1,9 +1,11 @@ package foo20 import ( + "errors" "std" "testing" + "gno.land/p/demo/uassert" pusers "gno.land/p/demo/users" "gno.land/r/demo/users" ) @@ -73,21 +75,9 @@ func TestErrConditions(t *testing.T) { {"Approve(empty, 1))", "invalid address", func() { Approve(pusers.AddressOrName(empty), 1) }}, } for _, tc := range tests { - shouldPanicWithMsg(t, tc.fn, tc.msg) + t.Run(tc.name, func(t *testing.T) { + uassert.PanicsWithMessage(t, tc.msg, tc.fn) + }) } } } - -func shouldPanicWithMsg(t *testing.T, f func(), msg string) { - defer func() { - if r := recover(); r == nil { - t.Errorf("The code did not panic") - } else { - errMsg := error(r).Error() - if errMsg != msg { - t.Errorf("excepted panic(%v), got(%v)", msg, errMsg) - } - } - }() - f() -} diff --git a/examples/gno.land/r/demo/foo20/gno.mod b/examples/gno.land/r/demo/foo20/gno.mod index 96fefcf6163..bf50c3b5202 100644 --- a/examples/gno.land/r/demo/foo20/gno.mod +++ b/examples/gno.land/r/demo/foo20/gno.mod @@ -2,6 +2,7 @@ module gno.land/r/demo/foo20 require ( gno.land/p/demo/grc/grc20 v0.0.0-latest + gno.land/p/demo/uassert v0.0.0-latest gno.land/p/demo/ufmt v0.0.0-latest gno.land/p/demo/users v0.0.0-latest gno.land/r/demo/users v0.0.0-latest From d244a86dcdcd28ddbccce4df2afb5e5a7073670d Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 02:39:56 +0200 Subject: [PATCH 09/14] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/demo/urequire/urequire.gno | 4 ++-- examples/gno.land/p/demo/urequire/urequire_test.gno | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/gno.land/p/demo/urequire/urequire.gno b/examples/gno.land/p/demo/urequire/urequire.gno index bf0bfb05b44..849e988d2fb 100644 --- a/examples/gno.land/p/demo/urequire/urequire.gno +++ b/examples/gno.land/p/demo/urequire/urequire.gno @@ -46,9 +46,9 @@ func ErrorIs(t uassert.TestingT, err, target error, msgs ...string) { t.FailNow() } -func PanicsWithError(t uassert.TestingT, errString string, f func(), msgs ...string) { +func PanicsWithMessage(t uassert.TestingT, msg string, f func(), msgs ...string) { t.Helper() - if uassert.PanicsWithError(t, errString, f, msgs...) { + if uassert.PanicsWithMessage(t, msg, f, msgs...) { return } t.FailNow() diff --git a/examples/gno.land/p/demo/urequire/urequire_test.gno b/examples/gno.land/p/demo/urequire/urequire_test.gno index 513c5cc2082..463e3fffc07 100644 --- a/examples/gno.land/p/demo/urequire/urequire_test.gno +++ b/examples/gno.land/p/demo/urequire/urequire_test.gno @@ -4,4 +4,5 @@ import "testing" func TestPackage(t *testing.T) { Equal(t, 42, 42) + // XXX: find a way to unit test this package } From 807b53d6ed4dd7d7c658f33ad8cac0695bdbcb34 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 03:10:08 +0200 Subject: [PATCH 10/14] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/demo/ownable/gno.mod | 5 + .../gno.land/p/demo/ownable/ownable_test.gno | 41 ++---- examples/gno.land/p/demo/uassert/helpers.gno | 7 + examples/gno.land/p/demo/uassert/uassert.gno | 137 +++++++++++++----- 4 files changed, 131 insertions(+), 59 deletions(-) diff --git a/examples/gno.land/p/demo/ownable/gno.mod b/examples/gno.land/p/demo/ownable/gno.mod index 9a9abb1e661..c01460dc675 100644 --- a/examples/gno.land/p/demo/ownable/gno.mod +++ b/examples/gno.land/p/demo/ownable/gno.mod @@ -1 +1,6 @@ module gno.land/p/demo/ownable + +require ( + gno.land/p/demo/uassert v0.0.0-latest + gno.land/p/demo/urequire v0.0.0-latest +) diff --git a/examples/gno.land/p/demo/ownable/ownable_test.gno b/examples/gno.land/p/demo/ownable/ownable_test.gno index 2c28f867f4a..0c8041f7993 100644 --- a/examples/gno.land/p/demo/ownable/ownable_test.gno +++ b/examples/gno.land/p/demo/ownable/ownable_test.gno @@ -3,6 +3,9 @@ package ownable import ( "std" "testing" + + "gno.land/p/demo/uassert" + "gno.land/p/demo/urequire" ) var ( @@ -16,18 +19,14 @@ func TestNew(t *testing.T) { o := New() got := o.Owner() - if firstCaller != got { - t.Fatalf("Expected %s, got: %s", firstCaller, got) - } + uassert.Equal(t, firstCaller, got) } func TestNewWithAddress(t *testing.T) { o := NewWithAddress(firstCaller) got := o.Owner() - if firstCaller != got { - t.Fatalf("Expected %s, got: %s", firstCaller, got) - } + uassert.Equal(t, firstCaller, got) } func TestOwner(t *testing.T) { @@ -36,9 +35,7 @@ func TestOwner(t *testing.T) { o := New() expected := firstCaller got := o.Owner() - if expected != got { - t.Fatalf("Expected %s, got: %s", expected, got) - } + uassert.Equal(t, expected, got) } func TestTransferOwnership(t *testing.T) { @@ -47,14 +44,10 @@ func TestTransferOwnership(t *testing.T) { o := New() err := o.TransferOwnership(secondCaller) - if err != nil { - t.Fatalf("TransferOwnership failed, %v", err) - } + uassert.NoError(t, err, "TransferOwnership failed") got := o.Owner() - if secondCaller != got { - t.Fatalf("Expected: %s, got: %s", secondCaller, got) - } + uassert.Equal(t, secondCaller, got) } func TestCallerIsOwner(t *testing.T) { @@ -67,9 +60,7 @@ func TestCallerIsOwner(t *testing.T) { std.TestSetOrigCaller(unauthorizedCaller) // TODO(bug): should not be needed err := o.CallerIsOwner() - if err == nil { - t.Fatalf("Expected %s to not be owner", unauthorizedCaller) - } + uassert.Error(t, err) // XXX: IsError(..., unauthorizedCaller) } func TestDropOwnership(t *testing.T) { @@ -78,12 +69,10 @@ func TestDropOwnership(t *testing.T) { o := New() err := o.DropOwnership() - if err != nil { - t.Fatalf("DropOwnership failed, %v", err) - } + uassert.NoError(t, err, "DropOwnership failed") owner := o.Owner() - if owner != "" { + if owner != "" { // XXX: uassert.Empty... t.Fatalf("Expected owner to be empty, not %s", owner) } } @@ -100,12 +89,12 @@ func TestErrUnauthorized(t *testing.T) { std.TestSetOrigCaller(secondCaller) // TODO(bug): should not be needed err := o.TransferOwnership(firstCaller) - if err != ErrUnauthorized { + if err != ErrUnauthorized { // XXX: uassert.IsError t.Fatalf("Should've been ErrUnauthorized, was %v", err) } err = o.DropOwnership() - if err != ErrUnauthorized { + if err != ErrUnauthorized { // XXX: uassert.IsError t.Fatalf("Should've been ErrUnauthorized, was %v", err) } } @@ -116,12 +105,12 @@ func TestErrInvalidAddress(t *testing.T) { o := New() err := o.TransferOwnership("") - if err != ErrInvalidAddress { + if err != ErrInvalidAddress { // XXX: uassert.IsError t.Fatalf("Should've been ErrInvalidAddress, was %v", err) } err = o.TransferOwnership("10000000001000000000100000000010000000001000000000") - if err != ErrInvalidAddress { + if err != ErrInvalidAddress { // XXX: uassert.IsError t.Fatalf("Should've been ErrInvalidAddress, was %v", err) } } diff --git a/examples/gno.land/p/demo/uassert/helpers.gno b/examples/gno.land/p/demo/uassert/helpers.gno index 8c0ee23e9e1..76657e75ed4 100644 --- a/examples/gno.land/p/demo/uassert/helpers.gno +++ b/examples/gno.land/p/demo/uassert/helpers.gno @@ -14,6 +14,13 @@ func fail(t TestingT, customMsgs []string, failureMessage string, args ...interf return false } +func autofail(t TestingT, success bool, customMsgs []string, failureMessage string, args ...interface{}) bool { + if success { + return true + } + return fail(t, customMsgs, failureMessage, args...) +} + func checkDidPanic(f func()) (didPanic bool, message string) { didPanic = true defer func() { diff --git a/examples/gno.land/p/demo/uassert/uassert.gno b/examples/gno.land/p/demo/uassert/uassert.gno index 3fe46811b5e..4d470757fab 100644 --- a/examples/gno.land/p/demo/uassert/uassert.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -1,7 +1,10 @@ // uassert is an adapted lighter version of https://github.com/stretchr/testify/assert. package uassert -import "std" +import ( + "std" + "strconv" +) // NoError asserts that a function returned no error (i.e. `nil`). func NoError(t TestingT, err error, msgs ...string) bool { @@ -96,55 +99,123 @@ func Equal(t TestingT, expected, actual interface{}, msgs ...string) bool { // XXX: slices // XXX: pointers + equal := false + ok_ := false + es, as := "unsupported type", "unsupported type" + switch ev := expected.(type) { case string: - av, ok := actual.(string) - return ok && ev == av + if av, ok := actual.(string); ok { + equal = ev == av + ok_ = true + es, as = ev, as + } case std.Address: - av, ok := actual.(std.Address) - return ok && ev == av + if av, ok := actual.(std.Address); ok { + equal = ev == av + ok_ = true + es, as = string(ev), string(av) + } case int: - av, ok := actual.(int) - return ok && ev == av + if av, ok := actual.(int); ok { + equal = ev == av + ok_ = true + es, as = strconv.Itoa(ev), strconv.Itoa(av) + } case int8: - av, ok := actual.(int8) - return ok && ev == av + if av, ok := actual.(int8); ok { + equal = ev == av + ok_ = true + es, as = strconv.Itoa(int(ev)), strconv.Itoa(int(av)) + } case int16: - av, ok := actual.(int16) - return ok && ev == av + if av, ok := actual.(int16); ok { + equal = ev == av + ok_ = true + es, as = strconv.Itoa(int(ev)), strconv.Itoa(int(av)) + } case int32: - av, ok := actual.(int32) - return ok && ev == av + if av, ok := actual.(int32); ok { + equal = ev == av + ok_ = true + es, as = strconv.Itoa(int(ev)), strconv.Itoa(int(av)) + } case int64: - av, ok := actual.(int64) - return ok && ev == av + if av, ok := actual.(int64); ok { + equal = ev == av + ok_ = true + es, as = strconv.Itoa(int(ev)), strconv.Itoa(int(av)) + } case uint: - av, ok := actual.(uint) - return ok && ev == av + if av, ok := actual.(uint); ok { + equal = ev == av + ok_ = true + es, as = strconv.FormatUint(uint64(ev), 10), strconv.FormatUint(uint64(av), 10) + } case uint8: - av, ok := actual.(uint8) - return ok && ev == av + if av, ok := actual.(uint8); ok { + equal = ev == av + ok_ = true + es, as = strconv.FormatUint(uint64(ev), 10), strconv.FormatUint(uint64(av), 10) + } case uint16: - av, ok := actual.(uint16) - return ok && ev == av + if av, ok := actual.(uint16); ok { + equal = ev == av + ok_ = true + es, as = strconv.FormatUint(uint64(ev), 10), strconv.FormatUint(uint64(av), 10) + } case uint32: - av, ok := actual.(uint32) - return ok && ev == av + if av, ok := actual.(uint32); ok { + equal = ev == av + ok_ = true + es, as = strconv.FormatUint(uint64(ev), 10), strconv.FormatUint(uint64(av), 10) + } case uint64: - av, ok := actual.(uint64) - return ok && ev == av + if av, ok := actual.(uint64); ok { + equal = ev == av + ok_ = true + es, as = strconv.FormatUint(ev, 10), strconv.FormatUint(av, 10) + } case bool: - av, ok := actual.(bool) - return ok && ev == av + if av, ok := actual.(bool); ok { + equal = ev == av + ok_ = true + if ev { + es, as = "true", "false" + } else { + es, as = "false", "true" + } + } case float32: - av, ok := actual.(float32) - return ok && ev == av + if av, ok := actual.(float32); ok { + equal = ev == av + ok_ = true + } case float64: - av, ok := actual.(float64) - return ok && ev == av + if av, ok := actual.(float64); ok { + equal = ev == av + ok_ = true + } default: - fail(t, msgs, "uassert.Equal: unsupported type") + return fail(t, msgs, "uassert.Equal: unsupported type") } - return false + /* + type stringer interface{ String() string } + if ev, ok := expected.(stringer); ok { + if av, ok := actual.(stringer); ok { + equal = ev.String() == av.String() + ok_ = true + } + } + */ + + if !ok_ { + return fail(t, msgs, "uassert.Equal: different types") // XXX: display the types + } + if !equal { + return fail(t, msgs, "uassert.Equal: same type but different value\n\texpected: %s\n\tactual: %s", es, as) + } + + return true } From 803f2d48098dce83428125202a584c455152c96f Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 09:04:27 +0200 Subject: [PATCH 11/14] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/demo/ownable/gno.mod | 2 +- .../gno.land/p/demo/ownable/ownable_test.gno | 22 ++++++------------- examples/gno.land/p/demo/uassert/uassert.gno | 18 +++++++++++++++ .../gno.land/p/demo/uassert/uassert_test.gno | 8 +++++++ .../gno.land/p/demo/urequire/urequire.gno | 8 +++++++ 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/examples/gno.land/p/demo/ownable/gno.mod b/examples/gno.land/p/demo/ownable/gno.mod index c01460dc675..00f7812f6f5 100644 --- a/examples/gno.land/p/demo/ownable/gno.mod +++ b/examples/gno.land/p/demo/ownable/gno.mod @@ -1,6 +1,6 @@ module gno.land/p/demo/ownable require ( + gno.land/p/demo/testutils v0.0.0-latest gno.land/p/demo/uassert v0.0.0-latest - gno.land/p/demo/urequire v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/ownable/ownable_test.gno b/examples/gno.land/p/demo/ownable/ownable_test.gno index 0c8041f7993..19200c933b4 100644 --- a/examples/gno.land/p/demo/ownable/ownable_test.gno +++ b/examples/gno.land/p/demo/ownable/ownable_test.gno @@ -4,13 +4,13 @@ import ( "std" "testing" + "gno.land/p/demo/testutils" "gno.land/p/demo/uassert" - "gno.land/p/demo/urequire" ) var ( - firstCaller = std.Address("g1l9aypkr8xfvs82zeux486ddzec88ty69lue9de") - secondCaller = std.Address("g127jydsh6cms3lrtdenydxsckh23a8d6emqcvfa") + firstCaller = testutils.TestAddress("first") + secondCaller = testutils.TestAddress("second") ) func TestNew(t *testing.T) { @@ -89,14 +89,10 @@ func TestErrUnauthorized(t *testing.T) { std.TestSetOrigCaller(secondCaller) // TODO(bug): should not be needed err := o.TransferOwnership(firstCaller) - if err != ErrUnauthorized { // XXX: uassert.IsError - t.Fatalf("Should've been ErrUnauthorized, was %v", err) - } + uassert.ErrorContains(t, err, ErrUnauthorized.Error()) err = o.DropOwnership() - if err != ErrUnauthorized { // XXX: uassert.IsError - t.Fatalf("Should've been ErrUnauthorized, was %v", err) - } + uassert.ErrorContains(t, err, ErrUnauthorized.Error()) } func TestErrInvalidAddress(t *testing.T) { @@ -105,12 +101,8 @@ func TestErrInvalidAddress(t *testing.T) { o := New() err := o.TransferOwnership("") - if err != ErrInvalidAddress { // XXX: uassert.IsError - t.Fatalf("Should've been ErrInvalidAddress, was %v", err) - } + uassert.ErrorContains(t, err, ErrInvalidAddress.Error()) err = o.TransferOwnership("10000000001000000000100000000010000000001000000000") - if err != ErrInvalidAddress { // XXX: uassert.IsError - t.Fatalf("Should've been ErrInvalidAddress, was %v", err) - } + uassert.ErrorContains(t, err, ErrInvalidAddress.Error()) } diff --git a/examples/gno.land/p/demo/uassert/uassert.gno b/examples/gno.land/p/demo/uassert/uassert.gno index 4d470757fab..7b62c718281 100644 --- a/examples/gno.land/p/demo/uassert/uassert.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -4,6 +4,7 @@ package uassert import ( "std" "strconv" + "strings" ) // NoError asserts that a function returned no error (i.e. `nil`). @@ -24,6 +25,23 @@ func Error(t TestingT, err error, msgs ...string) bool { return true } +// ErrorContains asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +func ErrorContains(t TestingT, err error, contains string, msgs ...string) bool { + t.Helper() + + if !Error(t, err, msgs...) { + return false + } + + actual := err.Error() + if !strings.Contains(actual, contains) { + return fail(t, msgs, "error %q does not contain %q", actual, contains) + } + + return true +} + // True asserts that the specified value is true. func True(t TestingT, value bool, msgs ...string) bool { t.Helper() diff --git a/examples/gno.land/p/demo/uassert/uassert_test.gno b/examples/gno.land/p/demo/uassert/uassert_test.gno index 04887c9c69f..a89ea7639c9 100644 --- a/examples/gno.land/p/demo/uassert/uassert_test.gno +++ b/examples/gno.land/p/demo/uassert/uassert_test.gno @@ -36,6 +36,14 @@ func TestError(t *testing.T) { mockT.equals(t, "error: an error is expected but got nil") } +func TestErrorContains(t *testing.T) { + mockT := new(mockTestingT) + + // nil error + var err error + False(t, ErrorContains(mockT, err, ""), "ErrorContains should return false for nil arg") +} + func TestTrue(t *testing.T) { mockT := new(mockTestingT) if !True(mockT, true) { diff --git a/examples/gno.land/p/demo/urequire/urequire.gno b/examples/gno.land/p/demo/urequire/urequire.gno index 849e988d2fb..a8def54a573 100644 --- a/examples/gno.land/p/demo/urequire/urequire.gno +++ b/examples/gno.land/p/demo/urequire/urequire.gno @@ -22,6 +22,14 @@ func Error(t uassert.TestingT, err error, msgs ...string) { t.FailNow() } +func ErrorContains(t uassert.TestingT, err error, contains string, msgs ...string) { + t.Helper() + if uassert.ErrorContains(t, err, contains, msgs...) { + return + } + t.FailNow() +} + func True(t uassert.TestingT, value bool, msgs ...string) { t.Helper() if uassert.True(t, value, msgs...) { From c621d6ef544bdedb400cb0450327651dbf132706 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 09:28:38 +0200 Subject: [PATCH 12/14] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .../gno.land/p/demo/ownable/ownable_test.gno | 4 +- examples/gno.land/p/demo/uassert/uassert.gno | 22 +++++++++ .../gno.land/p/demo/uassert/uassert_test.gno | 45 +++++++++++++++++++ .../gno.land/p/demo/urequire/urequire.gno | 8 ++++ 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/examples/gno.land/p/demo/ownable/ownable_test.gno b/examples/gno.land/p/demo/ownable/ownable_test.gno index 19200c933b4..6217948d587 100644 --- a/examples/gno.land/p/demo/ownable/ownable_test.gno +++ b/examples/gno.land/p/demo/ownable/ownable_test.gno @@ -72,9 +72,7 @@ func TestDropOwnership(t *testing.T) { uassert.NoError(t, err, "DropOwnership failed") owner := o.Owner() - if owner != "" { // XXX: uassert.Empty... - t.Fatalf("Expected owner to be empty, not %s", owner) - } + uassert.Empty(t, owner, "owner should be empty") } // Errors diff --git a/examples/gno.land/p/demo/uassert/uassert.gno b/examples/gno.land/p/demo/uassert/uassert.gno index 7b62c718281..e3a58ce85b4 100644 --- a/examples/gno.land/p/demo/uassert/uassert.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -237,3 +237,25 @@ func Equal(t TestingT, expected, actual interface{}, msgs ...string) bool { return true } + +func Empty(t TestingT, obj interface{}, msgs ...string) bool { + t.Helper() + switch val := obj.(type) { + case string: + if val != "" { + return fail(t, msgs, "uassert.Empty: not empty string: %s", val) + } + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: + if val != 0 { + return fail(t, msgs, "uassert.Empty: not empty number: %d", val) + } + case std.Address: + var zeroAddr std.Address + if val != zeroAddr { + return fail(t, msgs, "uassert.Empty: not empty std.Address: %s", string(val)) + } + default: + return fail(t, msgs, "uassert.Empty: unsupported type") + } + return true +} diff --git a/examples/gno.land/p/demo/uassert/uassert_test.gno b/examples/gno.land/p/demo/uassert/uassert_test.gno index a89ea7639c9..813ead84325 100644 --- a/examples/gno.land/p/demo/uassert/uassert_test.gno +++ b/examples/gno.land/p/demo/uassert/uassert_test.gno @@ -154,3 +154,48 @@ func TestEqual(t *testing.T) { }) } } + +type myStruct struct { + S string + I int +} + +func TestEmpty(t *testing.T) { + mockT := new(mockTestingT) + + cases := []struct { + obj interface{} + expectedEmpty bool + }{ + // expected to be empty + {"", true}, + {0, true}, + {int(0), true}, + {int64(0), true}, + {uint(0), true}, + // XXX: continue + + // not expected to be empty + {"Hello World", false}, + {1, false}, + {int32(1), false}, + {uint64(1), false}, + {std.Address("g12345"), false}, + + // unsupported + {nil, false}, + {myStruct{}, false}, + {&myStruct{}, false}, + } + + for _, c := range cases { + name := fmt.Sprintf("Empty(%v)", c.obj) + t.Run(name, func(t *testing.T) { + res := Empty(mockT, c.obj) + + if res != c.expectedEmpty { + t.Errorf("%s should return %v: %s", name, c.expectedEmpty, mockT.actualString()) + } + }) + } +} diff --git a/examples/gno.land/p/demo/urequire/urequire.gno b/examples/gno.land/p/demo/urequire/urequire.gno index a8def54a573..810d32649f9 100644 --- a/examples/gno.land/p/demo/urequire/urequire.gno +++ b/examples/gno.land/p/demo/urequire/urequire.gno @@ -77,3 +77,11 @@ func Equal(t uassert.TestingT, expected, actual interface{}, msgs ...string) { } t.FailNow() } + +func Empty(t uassert.TestingT, obj interface{}, msgs ...string) { + t.Helper() + if uassert.Empty(t, obj, msgs...) { + return + } + t.FailNow() +} From c2622b99a2d4242cd697032708abe1d8d9fc22a7 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:27:13 +0200 Subject: [PATCH 13/14] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/demo/uassert/uassert_test.gno | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/gno.land/p/demo/uassert/uassert_test.gno b/examples/gno.land/p/demo/uassert/uassert_test.gno index 813ead84325..a881070a04b 100644 --- a/examples/gno.land/p/demo/uassert/uassert_test.gno +++ b/examples/gno.land/p/demo/uassert/uassert_test.gno @@ -133,14 +133,16 @@ func TestEqual(t *testing.T) { {int32(123), int32(123), true, ""}, {uint64(123), uint64(123), true, ""}, {std.Address("g12345"), std.Address("g12345"), true, ""}, - //{[]byte("Hello World"), []byte("Hello World"), true, ""}, - // {myType("1"), myType("1"), true, ""}, - //{&struct{}{}, &struct{}{}, true, "pointer equality is based on equality of underlying value"}, + // XXX: continue // not expected to be equal {"Hello World", 42, false, ""}, {41, 42, false, ""}, {10, uint(10), false, ""}, + // XXX: continue + + // expected to raise errors + // XXX: todo } for _, c := range cases { From a1cd550251e5256ab32d6a76ca4213004d133f18 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:28:06 +0200 Subject: [PATCH 14/14] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/demo/uassert/uassert.gno | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/gno.land/p/demo/uassert/uassert.gno b/examples/gno.land/p/demo/uassert/uassert.gno index e3a58ce85b4..61885574360 100644 --- a/examples/gno.land/p/demo/uassert/uassert.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -219,6 +219,7 @@ func Equal(t TestingT, expected, actual interface{}, msgs ...string) bool { } /* + // XXX: implement stringer and other well known similar interfaces type stringer interface{ String() string } if ev, ok := expected.(stringer); ok { if av, ok := actual.(stringer); ok {