// 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 import ( "fmt" "os" "reflect" "testing" "github.com/gogf/gf/debug/gdebug" "github.com/gogf/gf/util/gconv" ) const ( gPATH_FILTER_KEY = "/test/gtest/gtest" ) // C creates an unit testing case. // The parameter is the pointer to testing.T of stdlib (*testing.T). // The parameter is the closure function for unit testing case. func C(t *testing.T, f func(t *T)) { defer func() { if err := recover(); err != nil { fmt.Fprintf(os.Stderr, "%v\n%s", err, gdebug.StackWithFilter(gPATH_FILTER_KEY)) t.Fail() } }() f(&T{t}) } // Case creates an unit testing case. // The parameter is the pointer to testing.T of stdlib (*testing.T). // The parameter is the closure function for unit testing case. // Deprecated. func Case(t *testing.T, f func()) { defer func() { if err := recover(); err != nil { fmt.Fprintf(os.Stderr, "%v\n%s", err, gdebug.StackWithFilter(gPATH_FILTER_KEY)) t.Fail() } }() f() } // Assert checks and EQUAL. func Assert(value, expect interface{}) { rvExpect := reflect.ValueOf(expect) if isNil(value) { value = nil } if rvExpect.Kind() == reflect.Map { if err := compareMap(value, expect); err != nil { panic(err) } return } var ( strValue = gconv.String(value) strExpect = gconv.String(expect) ) if strValue != strExpect { panic(fmt.Sprintf(`[ASSERT] EXPECT %v == %v`, strValue, strExpect)) } } // AssertEQ checks and EQUAL, including their TYPES. func AssertEQ(value, expect interface{}) { // Value assert. rvExpect := reflect.ValueOf(expect) if isNil(value) { value = nil } if rvExpect.Kind() == reflect.Map { if err := compareMap(value, expect); err != nil { panic(err) } return } strValue := gconv.String(value) strExpect := gconv.String(expect) if strValue != strExpect { panic(fmt.Sprintf(`[ASSERT] EXPECT %v == %v`, strValue, strExpect)) } // Type assert. t1 := reflect.TypeOf(value) t2 := reflect.TypeOf(expect) if t1 != t2 { panic(fmt.Sprintf(`[ASSERT] EXPECT TYPE %v[%v] == %v[%v]`, strValue, t1, strExpect, t2)) } } // AssertNE checks and NOT EQUAL. func AssertNE(value, expect interface{}) { rvExpect := reflect.ValueOf(expect) if isNil(value) { value = nil } if rvExpect.Kind() == reflect.Map { if err := compareMap(value, expect); err == nil { panic(fmt.Sprintf(`[ASSERT] EXPECT %v != %v`, value, expect)) } return } var ( strValue = gconv.String(value) strExpect = gconv.String(expect) ) if strValue == strExpect { panic(fmt.Sprintf(`[ASSERT] EXPECT %v != %v`, strValue, strExpect)) } } // AssertNQ checks and NOT EQUAL, including their TYPES. func AssertNQ(value, expect interface{}) { // Type assert. t1 := reflect.TypeOf(value) t2 := reflect.TypeOf(expect) if t1 == t2 { panic( fmt.Sprintf( `[ASSERT] EXPECT TYPE %v[%v] != %v[%v]`, gconv.String(value), t1, gconv.String(expect), t2, ), ) } // Value assert. AssertNE(value, expect) } // AssertGT checks is GREATER THAN . // Notice that, only string, integer and float types can be compared by AssertGT, // others are invalid. 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)) } } // AssertGE checks is GREATER OR EQUAL THAN . // Notice that, only string, integer and float types can be compared by AssertGTE, // others are invalid. func AssertGE(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.Int64(value) >= gconv.Int64(expect) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: passed = gconv.Uint64(value) >= gconv.Uint64(expect) case reflect.Float32, reflect.Float64: passed = gconv.Float64(value) >= gconv.Float64(expect) } if !passed { panic(fmt.Sprintf( `[ASSERT] EXPECT %v(%v) >= %v(%v)`, value, reflect.ValueOf(value).Kind(), expect, reflect.ValueOf(expect).Kind(), )) } } // AssertLT checks is LESS EQUAL THAN . // Notice that, only string, integer and float types can be compared by AssertLT, // others are invalid. 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)) } } // AssertLE checks is LESS OR EQUAL THAN . // Notice that, only string, integer and float types can be compared by AssertLTE, // others are invalid. func AssertLE(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)) } } // AssertIN checks is IN . // The should be a slice, // but the can be a slice or a basic type variable. // TODO map support. func AssertIN(value, expect interface{}) { passed := true expectKind := reflect.ValueOf(expect).Kind() switch expectKind { case reflect.Slice, reflect.Array: expectSlice := gconv.Strings(expect) for _, v1 := range gconv.Strings(value) { result := false for _, v2 := range expectSlice { if v1 == v2 { result = true break } } if !result { passed = false break } } default: panic(fmt.Sprintf(`[ASSERT] INVALID EXPECT VALUE TYPE: %v`, expectKind)) } if !passed { panic(fmt.Sprintf(`[ASSERT] EXPECT %v IN %v`, value, expect)) } } // AssertNI checks is NOT IN . // The should be a slice, // but the can be a slice or a basic type variable. // TODO map support. func AssertNI(value, expect interface{}) { passed := true expectKind := reflect.ValueOf(expect).Kind() switch expectKind { case reflect.Slice, reflect.Array: for _, v1 := range gconv.Strings(value) { result := true for _, v2 := range gconv.Strings(expect) { if v1 == v2 { result = false break } } if !result { passed = false break } } default: panic(fmt.Sprintf(`[ASSERT] INVALID EXPECT VALUE TYPE: %v`, expectKind)) } if !passed { panic(fmt.Sprintf(`[ASSERT] EXPECT %v NOT IN %v`, value, expect)) } } // Error panics with given . func Error(message ...interface{}) { panic(fmt.Sprintf("[ERROR] %s", fmt.Sprint(message...))) } // Fatal prints to stderr and exit the process. func Fatal(message ...interface{}) { fmt.Fprintf(os.Stderr, "[FATAL] %s\n%s", fmt.Sprint(message...), gdebug.StackWithFilter(gPATH_FILTER_KEY)) os.Exit(1) } // compareMap compares two maps, returns nil if they are equal, or else returns error. func compareMap(value, expect interface{}) error { rvValue := reflect.ValueOf(value) rvExpect := reflect.ValueOf(expect) if isNil(value) { value = nil } if rvExpect.Kind() == reflect.Map { if rvValue.Kind() == reflect.Map { if rvExpect.Len() == rvValue.Len() { // Turn two interface maps to the same type for comparison. // Direct use of rvValue.MapIndex(key).Interface() will panic // when the key types are inconsistent. mValue := make(map[string]string) mExpect := make(map[string]string) ksValue := rvValue.MapKeys() ksExpect := rvExpect.MapKeys() for _, key := range ksValue { mValue[gconv.String(key.Interface())] = gconv.String(rvValue.MapIndex(key).Interface()) } for _, key := range ksExpect { mExpect[gconv.String(key.Interface())] = gconv.String(rvExpect.MapIndex(key).Interface()) } for k, v := range mExpect { if v != mValue[k] { return fmt.Errorf(`[ASSERT] EXPECT VALUE map["%v"]:%v == map["%v"]:%v`+ "\nGIVEN : %v\nEXPECT: %v", k, mValue[k], k, v, mValue, mExpect) } } } else { return fmt.Errorf(`[ASSERT] EXPECT MAP LENGTH %d == %d`, rvValue.Len(), rvExpect.Len()) } } else { return fmt.Errorf(`[ASSERT] EXPECT VALUE TO BE A MAP`) } } return nil } // isNil checks whether is nil. func isNil(value interface{}) bool { rv := reflect.ValueOf(value) switch rv.Kind() { case reflect.Slice, reflect.Array, reflect.Map, reflect.Ptr, reflect.Func: return rv.IsNil() default: return value == nil } }