Transaction

CD9967AF181847…B084C9F1BB26

Block 161,949 · index 0 · indexed

Summary

Hash
CD9967AF1818477B23808957E0F5FFBEA0069336B6833675CC04B084C9F1BB26
Block
161,949
Size
31999 bytes
Gas used
39,839,805 / 40,000,000
Fee
50000ugnot
Status
success

Messages

Arguments · 24

  1. #1expect
  2. #2README.md
  3. #3# Expect Package Package for testing Gno packages and realms using function chaining and expressive semantics. ## Asserting Values Use `Value()` to check that a value meets expectations. Chain `Not()` to negate an assertion, and use `AsInt()`, `AsString()`, `AsBoolean()` (and similar) to narrow to type-specific assertions. [embedmd]:# (readme_value_test.gno go) ```go package expect_test import ( "errors" "testing" "gno.land/p/g17khqpukees4237dtn3astzapmp462vjhsz6st4/expect" ) func TestReadmeValue(t *testing.T) { // Assert integer value score := 42 expect.Value(t, score).ToEqual(42) expect.Value(t, score).Not().ToEqual(0) expect.Value(t, score).AsInt().ToBeLowerThan(100) // Assert string value name := "Alice" expect.Value(t, name).AsString().ToEqual("Alice") expect.Value(t, name).AsString().ToHaveLength(5) // Assert boolean value expect.Value(t, true).AsBoolean().ToBeTruthy() // Assert pointer value var v any expect.Value(t, v).ToBeNil() // Assert error value err := errors.New("foo bar") expect.Value(t, err).ToEqual(err) expect.Value(t, err).ToContainErrorString("foo") } ``` ## Asserting Functions Use `Func()` to check that a function returns an error, panics, or returns an expected value. Chain `.ToFail()`, `.ToPanic()`, or `.ToReturn()` and then assert the message or value. Package supports four type of functions: - func() - func() any - func() error - func() (any, error) [embedmd]:# (readme_func_test.gno go) ```go package expect_test import ( "errors" "testing" "gno.land/p/g17khqpukees4237dtn3astzapmp462vjhsz6st4/expect" ) func TestReadmeFunc(t *testing.T) { foo := func() int { return 42 } fooPanic := func() { panic("boom!") } err := errors.New("boom!") fooError := func(err error) error { return err } // Assert that "fooError" function returns an error expect.Func(t, func() error { return fooError(err) }).ToFail().WithError(err) // Assert that "fooPanic" function panics with a message expect.Func(t, func() { fooPanic() }).ToPanic().WithMessage("boom!") // Assert that "foo" function returns 42 expect.Func(t, func() any { return foo() }).ToReturn(42) } ```
  4. #4boolean.gno
  5. #5package expect import ( "strconv" "gno.land/p/nt/ufmt/v0" ) // NewBooleanChecker creates a new checker of boolean values func NewBooleanChecker(ctx Context, value bool) BooleanChecker { return BooleanChecker{ctx, value} } // BooleanChecker asserts boolean values. type BooleanChecker struct { ctx Context value bool } // Not negates the next called expectation. func (c BooleanChecker) Not() BooleanChecker { c.ctx.negated = !c.ctx.negated return c } // ToEqual asserts that current value is equal to an expected value. func (c BooleanChecker) ToEqual(v bool) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value == v, func(ctx Context) string { got := formatBoolean(c.value) if !ctx.IsNegated() { want := formatBoolean(v) return ufmt.Sprintf("Expected values to match\nGot: %s\nWant: %s", got, want) } return ufmt.Sprintf("Expected values to be different\nGot: %s", got) }) } // ToBeFalsy asserts that current value is falsy. func (c BooleanChecker) ToBeFalsy() { c.ctx.T().Helper() c.ctx.CheckExpectation(!c.value, func(ctx Context) string { if !ctx.IsNegated() { return "Expected value to be falsy" } return "Expected value not to be falsy" }) } // ToBeTruthy asserts that current value is truthy. func (c BooleanChecker) ToBeTruthy() { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value, func(ctx Context) string { if !ctx.IsNegated() { return "Expected value to be truthy" } return "Expected value not to be truthy" }) } func asBoolean(value any) (bool, error) { if value == nil { return false, nil } var s string switch v := value.(type) { case bool: return v, nil case string: s = v case []byte: s = string(v) case Stringer: s = v.String() default: return false, ErrIncompatibleType } if s != "" { return strconv.ParseBool(s) } return false, nil } func formatBoolean(value bool) string { return strconv.FormatBool(value) }
  6. #6context.gno
  7. #7package expect import ( "strings" "gno.land/p/nt/ufmt/v0" ) const defaultAssertFailMsg = "assert expectation failed" // NewContext creates a new testing context. func NewContext(t TestingT) Context { return Context{t: t} } // Context preserves the current testing context. type Context struct { t TestingT negated bool prefix string } // T returns context's testing T instance. func (c Context) T() TestingT { if c.t == nil { panic("expect: context is not initialized") } return c.t } // Prefix returns context's error prefix. func (c Context) Prefix() string { return c.prefix } // IsNegated checks if current context negates current assert expectations. func (c Context) IsNegated() bool { return c.negated } // CheckExpectation checks an assert expectation and calls a callback on fail. // It returns true when the asserted expectation fails. // Callback is called when a negated assertion succeeds or when non negated assertion fails. func (c Context) CheckExpectation(success bool, cb func(Context) string) bool { failed := (c.negated && success) || (!c.negated && !success) if failed { msg := cb(c) if strings.TrimSpace(msg) == "" { msg = defaultAssertFailMsg } c.Fail(msg) } return failed } // Fail makes the current test fail with a custom message. func (c Context) Fail(msg string, args ...any) { if c.prefix != "" { msg = c.prefix + " - " + msg } c.t.Fatalf(msg, args...) } // TestingT defines a minimal interface for `testing.T` instances. type TestingT interface { Helper() Fatal(args ...any) Fatalf(format string, args ...any) } // MockTestingT creates a new testing mock that writes testing output to a string builder. func MockTestingT(output *strings.Builder) TestingT { return &testingT{output} } type testingT struct{ buf *strings.Builder } func (testingT) Helper() {} func (t testingT) Fatal(args ...any) { t.buf.WriteString(ufmt.Sprintln(args...)) } func (t testingT) Fatalf(fmt string, args ...any) { t.buf.WriteString(ufmt.Sprintf(fmt+"\n", args...)) }
  8. #8doc.gno
  9. #9// Package expect provides testing support for packages and realms. // // Values can be asserted using the `Value()` function, for example: // // func TestFoo(t *testing.T) { // got := 42 // expect.Value(t, got).ToEqual(42) // expect.Value(t, got).Not().ToEqual(0) // // expect.Value(t, "foo").ToEqual("foo") // expect.Value(t, 42).AsInt().Not().ToBeGreaterThan(50) // expect.Value(t, "TRUE").AsBoolean().ToBeTruthy() // } // // Functions can also be used to assert returned values, errors or panics. // // Package supports four type of functions: // // - func() // - func() any // - func() error // - func() (any, error) // // Functions can be asserted using the `Func()` function, for example: // // func TestFoo(t *testing.T) { // expect.Func(t, func() { // panic("Boom!") // }).ToPanic().WithMessage("Boom!") // // wantErr := errors.New("Boom!") // expect.Func(t, func() error { // return wantErr // }).ToFail().WithMessage("Boom!") // // expect.Func(t, func() error { // return wantErr // }).ToFail().WithError(wantErr) // } package expect
  10. #10error.gno
  11. #11package expect import "gno.land/p/nt/ufmt/v0" // NewErrorChecker creates a new checker of errors. func NewErrorChecker(ctx Context, err error) ErrorChecker { return ErrorChecker{ctx, err} } // ErrorChecker asserts error values. type ErrorChecker struct { ctx Context err error } // Not negates the next called expectation. func (c ErrorChecker) Not() ErrorChecker { c.ctx.negated = !c.ctx.negated return c } // WithMessage asserts that current error contains an expected message. func (c ErrorChecker) WithMessage(msg string) { c.ctx.T().Helper() if c.err == nil { c.ctx.Fail("Expected an error with message\nGot: nil\nWant: %s", msg) return } NewMessageChecker(c.ctx, c.err.Error(), MessageTypeError).WithMessage(msg) } // WithError asserts that current error message is the same as an expected error. func (c ErrorChecker) WithError(err error) { c.ctx.T().Helper() if c.err == nil { if err != nil { c.ctx.Fail("Expected an error\nGot: nil\nWant: %s", err.Error()) } return } got := c.err.Error() c.ctx.CheckExpectation(got == err.Error(), func(ctx Context) string { if !ctx.IsNegated() { return ufmt.Sprintf("Expected errors to match\nGot: %s\nWant: %s", got, err.Error()) } return ufmt.Sprintf("Expected errors to be different\nGot: %s", got) }) }
  12. #12float.gno
  13. #13package expect import ( "strconv" "gno.land/p/nt/ufmt/v0" ) // NewFloatChecker creates a new checker of float64 values. func NewFloatChecker(ctx Context, value float64) FloatChecker { return FloatChecker{ctx, value} } // FloatChecker asserts float64 values. type FloatChecker struct { ctx Context value float64 } // Not negates the next called expectation. func (c FloatChecker) Not() FloatChecker { c.ctx.negated = !c.ctx.negated return c } // ToEqual asserts that current value is equal to an expected value. func (c FloatChecker) ToEqual(value float64) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value == value, func(ctx Context) string { got := formatFloat(c.value) if !ctx.IsNegated() { want := formatFloat(value) return ufmt.Sprintf("Expected values to match\nGot: %s\nWant: %s", got, want) } return ufmt.Sprintf("Expected value to be different\nGot: %s", got) }) } // ToBeGreaterThan asserts that current value is greater than an expected value. func (c FloatChecker) ToBeGreaterThan(value float64) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value > value, func(ctx Context) string { got := formatFloat(c.value) want := formatFloat(value) if !ctx.IsNegated() { return ufmt.Sprintf("Expected values to be gerater than %s\nGot: %s", want, got) } return ufmt.Sprintf("Expected value to not to be greater than %s\nGot: %s", want, got) }) } // ToBeGreaterOrEqualThan asserts that current value is greater or equal than an expected value. func (c FloatChecker) ToBeGreaterOrEqualThan(value float64) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value >= value, func(ctx Context) string { got := formatFloat(c.value) want := formatFloat(value) if !ctx.IsNegated() { return ufmt.Sprintf("Expected values to be greater or equal than %s\nGot: %s", want, got) } return ufmt.Sprintf("Expected value to not to be greater or equal than %s\nGot: %s", want, got) }) } // ToBeLowerThan asserts that current value is lower than an expected value. func (c FloatChecker) ToBeLowerThan(value float64) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value < value, func(ctx Context) string { got := formatFloat(c.value) want := formatFloat(value) if !ctx.IsNegated() { return ufmt.Sprintf("Expected values to be lower than %s\nGot: %s", want, got) } return ufmt.Sprintf("Expected value to not to be lower than %s\nGot: %s", want, got) }) } // ToBeLowerOrEqualThan asserts that current value is lower or equal than an expected value. func (c FloatChecker) ToBeLowerOrEqualThan(value float64) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value <= value, func(ctx Context) string { got := formatFloat(c.value) want := formatFloat(value) if !ctx.IsNegated() { return ufmt.Sprintf("Expected values to be lower or equal than %s\nGot: %s", want, got) } return ufmt.Sprintf("Expected value to not to be lower or equal than %s\nGot: %s", want, got) }) } func formatFloat(value float64) string { return strconv.FormatFloat(value, 'g', -1, 64) } func asFloat(value any) (float64, error) { switch v := value.(type) { case float32: return float64(v), nil case float64: return v, nil default: return 0, ErrIncompatibleType } }
  14. #14func.gno
  15. #15package expect import "gno.land/p/nt/ufmt/v0" type ( // Fn defines a type for generic functions. Fn = func() // ErrorFn defines a type for generic functions that return an error. ErrorFn = func() error // AnyFn defines a type for generic functions that returns a value. AnyFn = func() any // AnyErrorFn defines a type for generic functions that return a value and an error. AnyErrorFn = func() (any, error) ) // Func creates a new checker for functions. func Func(t TestingT, fn any) FuncChecker { return FuncChecker{ ctx: NewContext(t), fn: fn, } } // FuncChecker asserts function panics, errors and returned value. type FuncChecker struct { ctx Context fn any } // WithFailPrefix assigns a prefix that will be prefixed to testing errors when an assertion fails. func (c FuncChecker) WithFailPrefix(prefix string) FuncChecker { c.ctx.prefix = prefix return c } // Not negates the next called expectation. func (c FuncChecker) Not() FuncChecker { c.ctx.negated = !c.ctx.negated return c } // ToFail return an error checker to assert if current function returns an error. func (c FuncChecker) ToFail() ErrorChecker { c.ctx.T().Helper() var err error switch fn := c.fn.(type) { case ErrorFn: err = fn() case AnyErrorFn: _, err = fn() default: c.ctx.Fail("Unsupported error func type\nGot: %T", c.fn) return ErrorChecker{} } c.ctx.CheckExpectation(err != nil, func(ctx Context) string { if !ctx.IsNegated() { return "Expected func to return an error" } return ufmt.Sprintf("Func failed with error\nGot: %s", err.Error()) }) return NewErrorChecker(c.ctx, err) } // ToPanic return an message checker to assert if current function panicked. // This assertion is handled within the same realm, to assert panics when crossing // to another realm use the `ToAbort()` assertion. // // Example usage: // // func TestFoo(t *testing.T) { // expect.Func(t, func() { // Foo(cross) // }).Not().ToCrossPanic() // } func (c FuncChecker) ToPanic() MessageChecker { c.ctx.T().Helper() var ( msg string panicked bool ) switch fn := c.fn.(type) { case Fn: msg, panicked = handlePanic(fn) case ErrorFn: msg, panicked = handlePanic(func() { _ = fn() }) case AnyFn: msg, panicked = handlePanic(func() { _ = fn() }) case AnyErrorFn: msg, panicked = handlePanic(func() { _, _ = fn() }) default: c.ctx.Fail("Unsupported func type\nGot: %T", c.fn) return MessageChecker{} } c.ctx.CheckExpectation(panicked, func(ctx Context) string { if !ctx.IsNegated() { return "Expected function to panic" } return ufmt.Sprintf("Expected func not to panic\nGot: %s", msg) }) return NewMessageChecker(c.ctx, msg, MessageTypePanic) } // ToCrossPanic return an message checker to assert if current function panicked when crossing. // This assertion is handled only when making a crossing call to another realm, when asserting // within the same realm use `ToPanic()`. func (c FuncChecker) ToCrossPanic() MessageChecker { c.ctx.T().Helper() var ( msg string panicked bool ) switch fn := c.fn.(type) { case Fn: msg, panicked = handleCrossPanic(fn) case ErrorFn: msg, panicked = handleCrossPanic(func() { _ = fn() }) case AnyFn: msg, panicked = handleCrossPanic(func() { _ = fn() }) case AnyErrorFn: msg, panicked = handleCrossPanic(func() { _, _ = fn() }) default: c.ctx.Fail("Unsupported func type\nGot: %T", c.fn) return MessageChecker{} } c.ctx.CheckExpectation(panicked, func(ctx Context) string { if !ctx.IsNegated() { return "Expected function to cross panic" } return ufmt.Sprintf("Expected func not to cross panic\nGot: %s", msg) }) return NewMessageChecker(c.ctx, msg, MessageTypeCrossPanic) } // ToReturn asserts that current function returned a value equal to an expected value. func (c FuncChecker) ToReturn(value any) { c.ctx.T().Helper() var ( err error v any ) if fn, ok := c.fn.(AnyFn); ok { v = fn() } else if fn, ok := c.fn.(AnyErrorFn); ok { v, err = fn() } else { c.ctx.Fail("Unsupported func type\nGot: %T", c.fn) return } if err != nil { c.ctx.Fail("Function returned unexpected error\nGot: %s", err.Error()) return } if c.ctx.negated { Value(c.ctx.T(), v).Not().ToEqual(value) } else { Value(c.ctx.T(), v).ToEqual(value) } } func handlePanic(fn func()) (msg string, panicked bool) { defer func() { r := recover() if r == nil { return } panicked = true if err, ok := r.(error); ok { msg = err.Error() return } if s, ok := r.(string); ok { msg = s return } msg = "unsupported panic type" }() fn() return } func handleCrossPanic(fn func()) (string, bool) { r := revive(fn) if r == nil { return "", false } if err, ok := r.(error); ok { return err.Error(), true } if s, ok := r.(string); ok { return s, true } return "unsupported panic type", true }
  16. #16gnomod.toml
  17. #17module = "gno.land/p/g17khqpukees4237dtn3astzapmp462vjhsz6st4/expect" gno = "0.9"
  18. #18int.gno
  19. #19package expect import ( "strconv" "gno.land/p/nt/ufmt/v0" ) // NewIntChecker creates a new checker of int64 values. func NewIntChecker(ctx Context, value int64) IntChecker { return IntChecker{ctx, value} } // IntChecker asserts int64 values. type IntChecker struct { ctx Context value int64 } // Not negates the next called expectation. func (c IntChecker) Not() IntChecker { c.ctx.negated = !c.ctx.negated return c } // ToEqual asserts that current value is equal to an expected value. func (c IntChecker) ToEqual(value int64) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value == value, func(ctx Context) string { got := formatInt(c.value) if !ctx.IsNegated() { want := formatInt(value) return ufmt.Sprintf("Expected values to match\nGot: %s\nWant: %s", got, want) } return ufmt.Sprintf("Expected value to be different\nGot: %s", got) }) } // ToBeGreaterThan asserts that current value is greater than an expected value. func (c IntChecker) ToBeGreaterThan(value int64) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value > value, func(ctx Context) string { got := formatInt(c.value) want := formatInt(value) if !ctx.IsNegated() { return ufmt.Sprintf("Expected values to be gerater than %s\nGot: %s", want, got) } return ufmt.Sprintf("Expected value to not to be greater than %s\nGot: %s", want, got) }) } // ToBeGreaterOrEqualThan asserts that current value is greater or equal than an expected value. func (c IntChecker) ToBeGreaterOrEqualThan(value int64) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value >= value, func(ctx Context) string { got := formatInt(c.value) want := formatInt(value) if !ctx.IsNegated() { return ufmt.Sprintf("Expected values to be greater or equal than %s\nGot: %s", want, got) } return ufmt.Sprintf("Expected value to not to be greater or equal than %s\nGot: %s", want, got) }) } // ToBeLowerThan asserts that current value is lower than an expected value. func (c IntChecker) ToBeLowerThan(value int64) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value < value, func(ctx Context) string { got := formatInt(c.value) want := formatInt(value) if !ctx.IsNegated() { return ufmt.Sprintf("Expected values to be lower than %s\nGot: %s", want, got) } return ufmt.Sprintf("Expected value to not to be lower than %s\nGot: %s", want, got) }) } // ToBeLowerOrEqualThan asserts that current value is lower or equal than an expected value. func (c IntChecker) ToBeLowerOrEqualThan(value int64) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value <= value, func(ctx Context) string { got := formatInt(c.value) want := formatInt(value) if !ctx.IsNegated() { return ufmt.Sprintf("Expected values to be lower or equal than %s\nGot: %s", want, got) } return ufmt.Sprintf("Expected value to not to be lower or equal than %s\nGot: %s", want, got) }) } func formatInt(value int64) string { return strconv.FormatInt(value, 10) } func asInt(value any) (int64, error) { switch v := value.(type) { case int: return int64(v), nil case int8: return int64(v), nil case int16: return int64(v), nil case int32: return int64(v), nil case int64: return v, nil default: return 0, ErrIncompatibleType } }
  20. #20message.gno
  21. #21package expect import "gno.land/p/nt/ufmt/v0" const ( MessageTypeCrossPanic MessageType = "cross panic" MessageTypeError = "error" MessageTypePanic = "panic" ) // MessageType defines a type for message checker errors. type MessageType string // NewMessageChecker creates a new checker for text messages. func NewMessageChecker(ctx Context, msg string, t MessageType) MessageChecker { return MessageChecker{ctx, msg, t} } // MessageChecker asserts text messages. type MessageChecker struct { ctx Context msg string msgType MessageType } // Not negates the next called expectation. func (c MessageChecker) Not() MessageChecker { c.ctx.negated = !c.ctx.negated return c } // WithMessage asserts that a message is equal to an expected message. func (c MessageChecker) WithMessage(msg string) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.msg == msg, func(ctx Context) string { if !ctx.IsNegated() { return ufmt.Sprintf("Expected %s message to match\nGot: %s\nWant: %s", string(c.msgType), c.msg, msg) } return ufmt.Sprintf("Expected %s message to be different\nGot: %s", string(c.msgType), c.msg) }) }
  22. #22string.gno
  23. #23package expect import ( "errors" "gno.land/p/nt/ufmt/v0" ) // ErrIncompatibleType indicates that a value can't be casted to a different type. var ErrIncompatibleType = errors.New("incompatible type") // NewStringChecker creates a new checker of string values. func NewStringChecker(ctx Context, value string) StringChecker { return StringChecker{ctx, value} } // StringChecker asserts string values. type StringChecker struct { ctx Context value string } // Not negates the next called expectation. func (c StringChecker) Not() StringChecker { c.ctx.negated = !c.ctx.negated return c } // ToEqual asserts that current value is equal to an expected value. func (c StringChecker) ToEqual(v string) { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value == v, func(ctx Context) string { if !ctx.IsNegated() { return ufmt.Sprintf("Expected values to match\nGot: %s\nWant: %s", c.value, v) } return ufmt.Sprintf("Expected values to be different\nGot: %s", c.value) }) } // ToBeEmpty asserts that current value is an empty string. func (c StringChecker) ToBeEmpty() { c.ctx.T().Helper() c.ctx.CheckExpectation(c.value == "", func(ctx Context) string { if !ctx.IsNegated() { return ufmt.Sprintf("Expected string to be empty\nGot: %s", c.value) } return ufmt.Sprintf("Unexpected empty string") }) } // ToHaveLength asserts that current value has an expected length. func (c StringChecker) ToHaveLength(length int) { c.ctx.T().Helper() c.ctx.CheckExpectation(len(c.value) == length, func(ctx Context) string { got := len(c.value) if !ctx.IsNegated() { return ufmt.Sprintf("Expected string length to match\nGot: %d\nWant: %d", got, length) } return ufmt.Sprintf("Expected string lengths to be different\nGot: %d", got) }) } // Stringer defines an interface for values that has a String method. type Stringer interface { String() string } func asString(value any) (string, error) { switch v := value.(type) { case string: return v, nil case []byte: return string(v), nil case Stringer: return v.String(), nil case address: return v.String(), nil default: return "", ErrIncompatibleType } }
  24. #24uint.gno

Result log

msg:0,success:true,log:,events:[]

← Back to block 161,949