Skip to content

Commit

Permalink
feat: 添加一系列用于比较数值的方法
Browse files Browse the repository at this point in the history
  • Loading branch information
caixw committed Apr 17, 2024
1 parent 7407f6c commit aacbd71
Show file tree
Hide file tree
Showing 8 changed files with 439 additions and 259 deletions.
121 changes: 0 additions & 121 deletions assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@
package assert

import (
"errors"
"fmt"
"io/fs"
"os"
"reflect"
"regexp"
"strings"
"testing"
"time"
)
Expand Down Expand Up @@ -108,89 +104,6 @@ func (a *Assertion) NotEmpty(expr interface{}, msg ...interface{}) *Assertion {
return a.Assert(!isEmpty(expr), NewFailure("NotEmpty", msg, map[string]interface{}{"v": expr}))
}

// Error 断言有错误发生
//
// 传递未初始化的 error 值(var err error = nil),将断言失败
//
// [Assertion.NotNil] 的特化版本,限定了类型为 error。
func (a *Assertion) Error(expr error, msg ...interface{}) *Assertion {
a.TB().Helper()
return a.Assert(!isNil(expr), NewFailure("Error", msg, map[string]interface{}{"v": expr}))
}

// ErrorString 断言有错误发生且错误信息中包含指定的字符串 str
//
// 传递未初始化的 error 值(var err error = nil),将断言失败
func (a *Assertion) ErrorString(expr error, str string, msg ...interface{}) *Assertion {
a.TB().Helper()

if isNil(expr) { // 空值,必定没有错误
return a.Assert(false, NewFailure("ErrorString", msg, map[string]interface{}{"v": expr}))
}
return a.Assert(strings.Contains(expr.Error(), str), NewFailure("ErrorString", msg, map[string]interface{}{"v": expr}))
}

// ErrorIs 断言 expr 为 target 类型
//
// 相当于 a.True(errors.Is(expr, target))
func (a *Assertion) ErrorIs(expr, target error, msg ...interface{}) *Assertion {
a.TB().Helper()
return a.Assert(errors.Is(expr, target), NewFailure("ErrorIs", msg, map[string]interface{}{"err": expr}))
}

// NotError 断言没有错误
//
// [Assertion.Nil] 的特化版本,限定了类型为 error。
func (a *Assertion) NotError(expr error, msg ...interface{}) *Assertion {
a.TB().Helper()
return a.Assert(isNil(expr), NewFailure("NotError", msg, map[string]interface{}{"v": expr}))
}

// Panic 断言函数会发生 panic
func (a *Assertion) Panic(fn func(), msg ...interface{}) *Assertion {
a.TB().Helper()
has, _ := hasPanic(fn)
return a.Assert(has, NewFailure("Panic", msg, nil))
}

// PanicString 断言函数会发生 panic 且 panic 信息中包含指定的字符串内容
func (a *Assertion) PanicString(fn func(), str string, msg ...interface{}) *Assertion {
a.TB().Helper()

if has, m := hasPanic(fn); has {
return a.Assert(strings.Contains(fmt.Sprint(m), str), NewFailure("PanicString", msg, map[string]interface{}{"msg": m}))
}
return a.Assert(false, NewFailure("PanicString", msg, nil))
}

// PanicType 断言函数会发生 panic 且抛出指定的类型
func (a *Assertion) PanicType(fn func(), typ interface{}, msg ...interface{}) *Assertion {
a.TB().Helper()

if has, m := hasPanic(fn); has {
t1, t2 := getType(true, m, typ)
return a.Assert(t1 == t2, NewFailure("PanicType", msg, map[string]interface{}{"v1": t1, "v2": t2}))
}
return a.Assert(false, NewFailure("PanicType", msg, nil))
}

// PanicValue 断言函数会抛出与 v 相同的信息
func (a *Assertion) PanicValue(fn func(), v interface{}, msg ...interface{}) *Assertion {
a.TB().Helper()

if has, m := hasPanic(fn); has {
return a.Assert(isEqual(m, v), NewFailure("PanicValue", msg, map[string]interface{}{"v": m}))
}
return a.Assert(false, NewFailure("PanicType", msg, nil))
}

// NotPanic 断言 fn 不会 panic
func (a *Assertion) NotPanic(fn func(), msg ...interface{}) *Assertion {
a.TB().Helper()
has, m := hasPanic(fn)
return a.Assert(!has, NewFailure("NotPanic", msg, map[string]interface{}{"err": m}))
}

// Contains 断言 container 包含 item 或是包含 item 中的所有项
//
// 若 container string、[]byte 和 []rune 类型,
Expand Down Expand Up @@ -224,40 +137,6 @@ func (a *Assertion) NotZero(v interface{}, msg ...interface{}) *Assertion {
return a.Assert(!isZero(v), NewFailure("NotZero", msg, map[string]interface{}{"v": v}))
}

// Length 断言长度是否为指定的值
//
// v 可以是以下类型:
// - map
// - string
// - slice
// - array
func (a *Assertion) Length(v interface{}, l int, msg ...interface{}) *Assertion {
a.TB().Helper()

rl, err := getLen(v)
if err != "" {
a.Assert(false, NewFailure("Length", msg, map[string]interface{}{"err": err}))
}
return a.Assert(rl == l, NewFailure("Length", msg, map[string]interface{}{"l1": rl, "l2": l}))
}

// NotLength 断言长度不是指定的值
//
// v 可以是以下类型:
// - map
// - string
// - slice
// - array
func (a *Assertion) NotLength(v interface{}, l int, msg ...interface{}) *Assertion {
a.TB().Helper()

rl, err := getLen(v)
if err != "" {
a.Assert(false, NewFailure("NotLength", msg, map[string]interface{}{"err": err}))
}
return a.Assert(rl != l, NewFailure("NotLength", msg, map[string]interface{}{"l": rl}))
}

// TypeEqual 断言两个值的类型是否相同
//
// ptr 如果为 true,则会在对象为指针时,查找其指向的对象。
Expand Down
65 changes: 0 additions & 65 deletions assertion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ package assert

import (
"database/sql"
"errors"
"fmt"
"regexp"
"testing"
"time"
Expand Down Expand Up @@ -66,51 +64,6 @@ func TestAssertion_Equal_NotEqual_Nil_NotNil(t *testing.T) {
NotNil(v6, "a.NotNil(v6) failed")
}

func TestAssertion_Error(t *testing.T) {
a := New(t, false)

err := errors.New("test")
a.Error(err, "a.Error(err) failed")
a.ErrorString(err, "test", "ErrorString(err) failed")

err2 := &errorImpl{msg: "msg"}
a.Error(err2, "ErrorString(errorImpl) failed")
a.ErrorString(err2, "msg", "ErrorString(errorImpl) failed")

var err3 error
a.NotError(err3, "var err1 error failed")

err4 := errors.New("err4")
err5 := fmt.Errorf("err5 with %w", err4)
a.ErrorIs(err5, err4)
}

func TestAssertion_Panic(t *testing.T) {
a := New(t, false)

f1 := func() {
panic("panic message")
}

a.Panic(f1)
a.PanicString(f1, "message")
a.PanicType(f1, "abc")
a.PanicValue(f1, "panic message")

f1 = func() {
panic(errors.New("panic"))
}
a.PanicType(f1, errors.New("abc"))

f1 = func() {
panic(&errorImpl{msg: "panic"})
}
a.PanicType(f1, &errorImpl{msg: "abc"})

f1 = func() {}
a.NotPanic(f1)
}

func TestAssertion_Zero_NotZero(t *testing.T) {
a := New(t, false)

Expand All @@ -128,24 +81,6 @@ func TestAssertion_Zero_NotZero(t *testing.T) {
a.NotZero([]int{})
}

func TestAssertion_Length_NotLength(t *testing.T) {
a := New(t, false)

a.Length(nil, 0)
a.Length([]int{1, 2}, 2)
a.Length([3]int{1, 2, 3}, 3)
a.NotLength([3]int{1, 2, 3}, 2)
a.Length(map[string]string{"1": "1", "2": "2"}, 2)
a.NotLength(map[string]string{"1": "1", "2": "2"}, 3)
slices := []rune{'a', 'b', 'c'}
ps := &slices
pps := &ps
a.Length(pps, 3)
a.NotLength(pps, 2)
a.Length("string", 6)
a.NotLength("string", 4)
}

func TestAssertion_Contains(t *testing.T) {
a := New(t, false)

Expand Down
107 changes: 107 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// SPDX-FileCopyrightText: 2014-2024 caixw
//
// SPDX-License-Identifier: MIT

package assert

import (
"errors"
"fmt"
"strings"
)

// Error 断言有错误发生
//
// 传递未初始化的 error 值(var err error = nil),将断言失败
//
// [Assertion.NotNil] 的特化版本,限定了类型为 error。
func (a *Assertion) Error(expr error, msg ...interface{}) *Assertion {
a.TB().Helper()
return a.Assert(!isNil(expr), NewFailure("Error", msg, map[string]interface{}{"v": expr}))
}

// ErrorString 断言有错误发生且错误信息中包含指定的字符串 str
//
// 传递未初始化的 error 值(var err error = nil),将断言失败
func (a *Assertion) ErrorString(expr error, str string, msg ...interface{}) *Assertion {
a.TB().Helper()

if isNil(expr) { // 空值,必定没有错误
return a.Assert(false, NewFailure("ErrorString", msg, map[string]interface{}{"v": expr}))
}
return a.Assert(strings.Contains(expr.Error(), str), NewFailure("ErrorString", msg, map[string]interface{}{"v": expr}))
}

// ErrorIs 断言 expr 为 target 类型
//
// 相当于 a.True(errors.Is(expr, target))
func (a *Assertion) ErrorIs(expr, target error, msg ...interface{}) *Assertion {
a.TB().Helper()
return a.Assert(errors.Is(expr, target), NewFailure("ErrorIs", msg, map[string]interface{}{"err": expr}))
}

// NotError 断言没有错误
//
// [Assertion.Nil] 的特化版本,限定了类型为 error。
func (a *Assertion) NotError(expr error, msg ...interface{}) *Assertion {
a.TB().Helper()
return a.Assert(isNil(expr), NewFailure("NotError", msg, map[string]interface{}{"v": expr}))
}

// Panic 断言函数会发生 panic
func (a *Assertion) Panic(fn func(), msg ...interface{}) *Assertion {
a.TB().Helper()
has, _ := hasPanic(fn)
return a.Assert(has, NewFailure("Panic", msg, nil))
}

// PanicString 断言函数会发生 panic 且 panic 信息中包含指定的字符串内容
func (a *Assertion) PanicString(fn func(), str string, msg ...interface{}) *Assertion {
a.TB().Helper()

if has, m := hasPanic(fn); has {
return a.Assert(strings.Contains(fmt.Sprint(m), str), NewFailure("PanicString", msg, map[string]interface{}{"msg": m}))
}
return a.Assert(false, NewFailure("PanicString", msg, nil))
}

// PanicType 断言函数会发生 panic 且抛出指定的类型
func (a *Assertion) PanicType(fn func(), typ interface{}, msg ...interface{}) *Assertion {
a.TB().Helper()

if has, m := hasPanic(fn); has {
t1, t2 := getType(true, m, typ)
return a.Assert(t1 == t2, NewFailure("PanicType", msg, map[string]interface{}{"v1": t1, "v2": t2}))
}
return a.Assert(false, NewFailure("PanicType", msg, nil))
}

// PanicValue 断言函数会抛出与 v 相同的信息
func (a *Assertion) PanicValue(fn func(), v interface{}, msg ...interface{}) *Assertion {
a.TB().Helper()

if has, m := hasPanic(fn); has {
return a.Assert(isEqual(m, v), NewFailure("PanicValue", msg, map[string]interface{}{"v": m}))
}
return a.Assert(false, NewFailure("PanicType", msg, nil))
}

// NotPanic 断言 fn 不会 panic
func (a *Assertion) NotPanic(fn func(), msg ...interface{}) *Assertion {
a.TB().Helper()
has, m := hasPanic(fn)
return a.Assert(!has, NewFailure("NotPanic", msg, map[string]interface{}{"err": m}))
}

// hasPanic 判断 fn 函数是否会发生 panic
// 若发生了 panic,将把 msg 一起返回。
func hasPanic(fn func()) (has bool, msg interface{}) {
defer func() {
if msg = recover(); msg != nil {
has = true
}
}()
fn()

return
}
Loading

0 comments on commit aacbd71

Please sign in to comment.