Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
type binOp[T cmp.Ordered] struct {
name string
cmp int
op func(T, T)
op func(T, T, ...string)
}

func binOps[T cmp.Ordered]() []binOp[T] {
Expand Down
72 changes: 40 additions & 32 deletions check.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,104 +4,112 @@ import (
"cmp"
"errors"
"fmt"
"strings"
)

func formatCmp[T any](cmp string, a, b T) string {
return fmt.Sprintf("%v %s %v", a, cmp, b)
func panicMsg(base string, msg []string) string {
if len(msg) > 0 {
return strings.Join(msg, " ") + ": " + base
}
return base
}

func formatCmp[T any](cmp string, a, b T, msg []string) string {
return panicMsg(fmt.Sprintf("%v %s %v", a, cmp, b), msg)
}

// Eq compares the two input values and panics if they are not equal
func Eq[T comparable](a, b T) {
func Eq[T comparable](a, b T, msg ...string) {
if a != b {
panic(formatCmp("==", a, b))
panic(formatCmp("==", a, b, msg))
}
}

// NotEq compares the two input values and panics if they are equal
func NotEq[T comparable](a, b T) {
func NotEq[T comparable](a, b T, msg ...string) {
if a == b {
panic(formatCmp("!=", a, b))
panic(formatCmp("!=", a, b, msg))
}
}

// GT panics if a is not greater than b
func GT[T cmp.Ordered](a, b T) {
func GT[T cmp.Ordered](a, b T, msg ...string) {
if a <= b {
panic(formatCmp(">", a, b))
panic(formatCmp(">", a, b, msg))
}
}

// LT panics if a is not less than b
func LT[T cmp.Ordered](a, b T) {
func LT[T cmp.Ordered](a, b T, msg ...string) {
if a >= b {
panic(formatCmp("<", a, b))
panic(formatCmp("<", a, b, msg))
}
}

// GTE panics if a is not greater than or equal to b
func GTE[T cmp.Ordered](a, b T) {
func GTE[T cmp.Ordered](a, b T, msg ...string) {
if a < b {
panic(formatCmp(">=", a, b))
panic(formatCmp(">=", a, b, msg))
}
}

// LTE panics if a is not less than or equal to b
func LTE[T cmp.Ordered](a, b T) {
func LTE[T cmp.Ordered](a, b T, msg ...string) {
if a > b {
panic(formatCmp(">=", a, b))
panic(formatCmp(">=", a, b, msg))
}
}

func Between[T cmp.Ordered](a, low, high T) {
GT(a, low)
LT(a, high)
func Between[T cmp.Ordered](a, low, high T, msg ...string) {
GT(a, low, msg...)
LT(a, high, msg...)
}

func BetweenInclusive[T cmp.Ordered](a, low, high T) {
GTE(a, low)
LTE(a, high)
func BetweenInclusive[T cmp.Ordered](a, low, high T, msg ...string) {
GTE(a, low, msg...)
LTE(a, high, msg...)
}

// Nil panics if x is not nil
func Nil(x any) {
func Nil(x any, msg ...string) {
if x != nil {
panic(formatCmp("!=", x, nil))
panic(formatCmp("!=", x, nil, msg))
}
}

// NotNil panics if x is nil
func NotNil(x any) {
func NotNil(x any, msg ...string) {
if x == nil {
panic(formatCmp("==", x, nil))
panic(formatCmp("==", x, nil, msg))
}
}

// Is panics if a is not of type T
func Is[T any](a any) {
func Is[T any](a any, msg ...string) {
if _, ok := a.(T); !ok {
var want T
panic(fmt.Sprintf("%v != %T", a, want))
panic(panicMsg(fmt.Sprintf("%v != %T", a, want), msg))
}
}

// ErrIs panics if e does not match target using errors.Is
func ErrIs(e error, target error) {
func ErrIs(e error, target error, msg ...string) {
if !errors.Is(e, target) {
panic(fmt.Sprintf("%v is not %v", e, target))
panic(panicMsg(fmt.Sprintf("%v is not %v", e, target), msg))
}
}

func Must[T any](t T, err error) T {
Nil(err)
func Must[T any](t T, err error, msg ...string) T {
Nil(err, msg...)
return t
}

// Panics executes f and panics if f does not panic
func Panics(f func()) {
func Panics(f func(), msg ...string) {
defer func() {
r := recover()
if r == nil {
panic(fmt.Sprintf("Expected %T to panic but it did not", f))
panic(panicMsg(fmt.Sprintf("Expected %T to panic but it did not", f), msg))
}
}()
f()
Expand Down
2 changes: 1 addition & 1 deletion check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestPanics(t *testing.T) {
func TestCmp(t *testing.T) {
table := []struct {
a, b int
cmp func(int, int)
cmp func(int, int, ...string)
passes bool
}{
{1, 0, GT[int], true},
Expand Down
14 changes: 7 additions & 7 deletions slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,32 @@ import (
)

// SliceEq panics if slices a and b are not element-wise equal
func SliceEq[T comparable](a, b []T) {
func SliceEq[T comparable](a, b []T, msg ...string) {
if len(a) != len(b) {
panic(fmt.Sprintf("slice lengths differ: %d != %d\n a: %v\n b: %v", len(a), len(b), a, b))
panic(panicMsg(fmt.Sprintf("slice lengths differ: %d != %d\n a: %v\n b: %v", len(a), len(b), a, b), msg))
}
for i := range a {
if a[i] != b[i] {
panic(fmt.Sprintf("slices differ at index %d: %v != %v", i, a[i], b[i]))
panic(panicMsg(fmt.Sprintf("slices differ at index %d: %v != %v", i, a[i], b[i]), msg))
}
}
}

// SliceContains panics if v is not found in s
func SliceContains[T comparable](s []T, v T) {
func SliceContains[T comparable](s []T, v T, msg ...string) {
for _, x := range s {
if x == v {
return
}
}
panic(fmt.Sprintf("%v not found in %v", v, s))
panic(panicMsg(fmt.Sprintf("%v not found in %v", v, s), msg))
}

// SliceSorted panics if s is not sorted in ascending order
func SliceSorted[T cmp.Ordered](s []T) {
func SliceSorted[T cmp.Ordered](s []T, msg ...string) {
for i := 1; i < len(s); i++ {
if s[i] < s[i-1] {
panic(fmt.Sprintf("slice not sorted at index %d, %d: %v > %v", i-1, i, s[i-1], s[i]))
panic(panicMsg(fmt.Sprintf("slice not sorted at index %d, %d: %v > %v", i-1, i, s[i-1], s[i]), msg))
}
}
}
Loading