Files
gf/g/test/gtest/gtest.go
2019-02-15 08:55:29 +08:00

301 lines
9.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package gtest provides simple and useful test utils.
//
// 测试模块.
package gtest
import (
"fmt"
"github.com/gogf/gf/g/util/gconv"
"os"
"reflect"
"regexp"
"runtime"
"testing"
)
// 封装一个测试用例
func Case(t *testing.T, f func()) {
defer func() {
if err := recover(); err != nil {
fmt.Fprintf(os.Stderr, "%v\n%s", err, getBacktrace())
t.Fail()
}
}()
f()
}
// 断言判断, 相等
func Assert(value, expect interface{}) {
rvValue := reflect.ValueOf(value)
rvExpect := reflect.ValueOf(expect)
if rvValue.Kind() == reflect.Ptr {
if rvValue.IsNil() {
value = nil
}
}
if rvExpect.Kind() == reflect.Map {
if err := compareMap(value, expect); err != nil {
panic(err)
}
return
}
if fmt.Sprintf("%v", value) != fmt.Sprintf("%v", expect) {
panic(fmt.Sprintf(`[ASSERT] EXPECT %v == %v`, value, expect))
}
}
// 断言判断, 相等, 包括数据类型
func AssertEQ(value, expect interface{}) {
// 类型判断
t1 := reflect.TypeOf(value)
t2 := reflect.TypeOf(expect)
if t1 != t2 {
panic(fmt.Sprintf(`[ASSERT] EXPECT TYPE %v == %v`, t1, t2))
}
rvValue := reflect.ValueOf(value)
rvExpect := reflect.ValueOf(expect)
if rvValue.Kind() == reflect.Ptr {
if rvValue.IsNil() {
value = nil
}
}
if rvExpect.Kind() == reflect.Map {
if err := compareMap(value, expect); err != nil {
panic(err)
}
return
}
if fmt.Sprintf("%v", value) != fmt.Sprintf("%v", expect) {
panic(fmt.Sprintf(`[ASSERT] EXPECT %v == %v`, value, expect))
}
}
// 断言判断, 不相等
func AssertNE(value, expect interface{}) {
rvValue := reflect.ValueOf(value)
rvExpect := reflect.ValueOf(expect)
if rvValue.Kind() == reflect.Ptr {
if rvValue.IsNil() {
value = nil
}
}
if rvExpect.Kind() == reflect.Map {
if err := compareMap(value, expect); err == nil {
panic(fmt.Sprintf(`[ASSERT] EXPECT %v != %v`, value, expect))
}
return
}
if fmt.Sprintf("%v", value) == fmt.Sprintf("%v", expect) {
panic(fmt.Sprintf(`[ASSERT] EXPECT %v != %v`, value, expect))
}
}
// 断言判断, value > expect; 注意: 仅有字符串、整形、浮点型才可以比较
func AssertGT(value, expect interface{}) {
passed := false
switch reflect.ValueOf(expect).Kind() {
case reflect.String:
passed = gconv.String(value) > gconv.String(expect)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
passed = gconv.Int(value) > gconv.Int(expect)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
passed = gconv.Uint(value) > gconv.Uint(expect)
case reflect.Float32, reflect.Float64:
passed = gconv.Float64(value) > gconv.Float64(expect)
}
if !passed {
panic(fmt.Sprintf(`[ASSERT] EXPECT %v > %v`, value, expect))
}
}
// 断言判断, value >= expect; 注意: 仅有字符串、整形、浮点型才可以比较
func AssertGTE(value, expect interface{}) {
passed := false
switch reflect.ValueOf(expect).Kind() {
case reflect.String:
passed = gconv.String(value) >= gconv.String(expect)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
passed = gconv.Int(value) >= gconv.Int(expect)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
passed = gconv.Uint(value) >= gconv.Uint(expect)
case reflect.Float32, reflect.Float64:
passed = gconv.Float64(value) >= gconv.Float64(expect)
}
if !passed {
panic(fmt.Sprintf(`[ASSERT] EXPECT %v >= %v`, value, expect))
}
}
// 断言判断, value < expect; 注意: 仅有字符串、整形、浮点型才可以比较
func AssertLT(value, expect interface{}) {
passed := false
switch reflect.ValueOf(expect).Kind() {
case reflect.String:
passed = gconv.String(value) < gconv.String(expect)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
passed = gconv.Int(value) < gconv.Int(expect)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
passed = gconv.Uint(value) < gconv.Uint(expect)
case reflect.Float32, reflect.Float64:
passed = gconv.Float64(value) < gconv.Float64(expect)
}
if !passed {
panic(fmt.Sprintf(`[ASSERT] EXPECT %v < %v`, value, expect))
}
}
// 断言判断, value <= expect; 注意: 仅有字符串、整形、浮点型才可以比较
func AssertLTE(value, expect interface{}) {
passed := false
switch reflect.ValueOf(expect).Kind() {
case reflect.String:
passed = gconv.String(value) <= gconv.String(expect)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
passed = gconv.Int(value) <= gconv.Int(expect)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
passed = gconv.Uint(value) <= gconv.Uint(expect)
case reflect.Float32, reflect.Float64:
passed = gconv.Float64(value) <= gconv.Float64(expect)
}
if !passed {
panic(fmt.Sprintf(`[ASSERT] EXPECT %v <= %v`, value, expect))
}
}
// 断言判断, value IN expect; 注意: expect必须为slice类型
func AssertIN(value, expect interface{}) {
passed := false
switch reflect.ValueOf(expect).Kind() {
case reflect.Slice, reflect.Array:
for _, v := range gconv.Interfaces(expect) {
if v == value {
passed = true
break
}
}
}
if !passed {
panic(fmt.Sprintf(`[ASSERT] EXPECT %v IN %v`, value, expect))
}
}
// 断言判断, value NOT IN expect; 注意: expect必须为slice类型
func AssertNI(value, expect interface{}) {
passed := false
switch reflect.ValueOf(expect).Kind() {
case reflect.Slice, reflect.Array:
for _, v := range gconv.Interfaces(expect) {
if v == value {
passed = true
break
}
}
}
if passed {
panic(fmt.Sprintf(`[ASSERT] EXPECT %v NOT IN %v`, value, expect))
}
}
// 提示错误不退出进程执行
func Error(message...interface{}) {
fmt.Fprintf(os.Stderr, "[ERROR] %s\n%s", fmt.Sprint(message...), getBacktrace())
}
// 提示错误并退出进程执行
func Fatal(message...interface{}) {
fmt.Fprintf(os.Stderr, "[FATAL] %s\n%s", fmt.Sprint(message...), getBacktrace())
os.Exit(1)
}
// Map比较如果相等返回nil否则返回错误信息.
func compareMap(value, expect interface{}) error {
rvValue := reflect.ValueOf(value)
rvExpect := reflect.ValueOf(expect)
if rvValue.Kind() == reflect.Ptr {
if rvValue.IsNil() {
value = nil
}
}
if rvExpect.Kind() == reflect.Map {
if rvValue.Kind() == reflect.Map {
if rvExpect.Len() == rvValue.Len() {
ksExpect := rvExpect.MapKeys()
for _, key := range ksExpect {
if fmt.Sprintf("%v", rvValue.MapIndex(key).Interface()) != fmt.Sprintf("%v", rvExpect.MapIndex(key).Interface()) {
return fmt.Errorf(`[ASSERT] EXPECT VALUE map["%v"]:%v == %v`,
key,
rvValue.MapIndex(key).Interface(),
rvExpect.MapIndex(key).Interface(),
)
}
}
} else {
return fmt.Errorf(`[ASSERT] EXPECT MAP LENGTH %d == %d`, rvExpect.Len(), rvValue.Len())
}
} else {
return fmt.Errorf(`[ASSERT] EXPECT VALUE TO BE A MAP`)
}
}
return nil
}
// 获取文件调用回溯字符串参数skip表示调用端往上多少级开始回溯
func getBacktrace(skip...int) string {
customSkip := 0
if len(skip) > 0 {
customSkip = skip[0]
}
backtrace := ""
index := 1
from := 0
// 首先定位业务文件开始位置
for i := 0; i < 10; i++ {
if _, file, _, ok := runtime.Caller(i); ok {
if reg, _ := regexp.Compile(`gtest\.go$`); !reg.MatchString(file) {
from = i
break
}
}
}
// 从业务文件开始位置根据自定义的skip开始backtrace
goRoot := runtime.GOROOT()
for i := from + customSkip; i < 10000; i++ {
if _, file, cline, ok := runtime.Caller(i); ok && file != "" {
if reg, _ := regexp.Compile(`<autogenerated>`); reg.MatchString(file) {
continue
}
if reg, _ := regexp.Compile(`gtest\.go$`); reg.MatchString(file) {
continue
}
if goRoot != "" {
if reg, _ := regexp.Compile("^" + goRoot); reg.MatchString(file) {
continue
}
}
backtrace += fmt.Sprintf(`%d. %s:%d%s`, index, file, cline, "\n")
index++
} else {
break
}
}
return backtrace
}