From 30d798366b11466387d918db0145e7359f5710e4 Mon Sep 17 00:00:00 2001 From: donutloop Date: Fri, 7 Jan 2022 13:19:27 +0100 Subject: [PATCH 01/23] Slice: find v2 (#17) * If slice len is zero then return false * Convert find to generic form. * If return T is nil then no items matched the predicate func --- README.md | 2 +- README_zh-CN.md | 2 +- slice/slice.go | 27 +++++++++++---------------- slice/slice_test.go | 2 +- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 9df4975..5fbfcb2 100644 --- a/README.md +++ b/README.md @@ -401,7 +401,7 @@ func Drop(slice interface{}, n int) interface{} //creates a slice with `n` eleme func Every(slice, function interface{}) bool //return true if all of the values in the slice pass the predicate function, function signature should be func(index int, value interface{}) bool func None(slice, function interface{}) bool // return true if all the values in the slice mismatch the criteria func Filter [T any] (slice []T, fn func(index int, t T) bool) []T //filter slice, fn signature should be func(int, T) bool. -func Find(slice, function interface{}) (interface{}, bool) //iterates over elements of slice, returning the first one that passes a truth test on function.function signature should be func(index int, value interface{}) bool . +func Find[T any](slice []T, fn func(index int, t T) bool) (*T, bool) //iterates over elements of slice, returning the first one that passes a truth test on function.function signature should be func(index int, value interface{}) bool . func FlattenDeep(slice interface{}) interface{} //flattens slice recursive func ForEach [T any] (slice []T, fn func(index int, t T)) //iterates over elements of slice and invokes function for each element, fn signature should be func(int, T ). func IntSlice(slice interface{}) ([]int, error) //convert value to int slice diff --git a/README_zh-CN.md b/README_zh-CN.md index 25990f5..37307da 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -401,7 +401,7 @@ func DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error func Drop(slice interface{}, n int) interface{} //创建一个新切片,当n大于0时删除原切片前n个元素,当n小于0时删除原切片后n个元素 func Every(slice, function interface{}) bool //slice中所有元素都符合函数条件时返回true, 否则返回false. 函数签名:func(index int, value interface{}) bool func None(slice, function interface{}) bool //slice中所有元素都不符合函数条件时返回true, 否则返回false. 函数签名:func(index int, value interface{}) bool -func Find(slice, function interface{}) (interface{}, bool)//查找slice中第一个符合条件的元素,函数签名:func(index int, value interface{}) bool +func Find[T any](slice []T, fn func(index int, t T) bool) (*T, bool)//查找slice中第一个符合条件的元素,函数签名:func(index int, value interface{}) bool func Filter(slice, function interface{}) interface{} //过滤slice, 函数签名:func(index int, value interface{}) bool func FlattenDeep(slice interface{}) interface{} //将slice递归为一维切片。 func ForEach(slice, function interface{}) //遍历切片,在每个元素上执行函数,函数签名:func(index int, value interface{}) diff --git a/slice/slice.go b/slice/slice.go index 7a1f38d..6f43f6a 100644 --- a/slice/slice.go +++ b/slice/slice.go @@ -167,7 +167,7 @@ func Some(slice, function interface{}) bool { // Filter iterates over elements of slice, returning an slice of all elements `signature` returns truthy for. // The fn signature should be func(int, T) bool. -func Filter [T any] (slice []T, fn func(index int, t T) bool) []T { +func Filter[T any](slice []T, fn func(index int, t T) bool) []T { res := make([]T, 0, 0) for i, v := range slice { if fn(i, v) { @@ -227,30 +227,25 @@ func GroupBy(slice, function interface{}) (interface{}, interface{}) { // Find iterates over elements of slice, returning the first one that passes a truth test on function. // The function signature should be func(index int, value interface{}) bool . -func Find(slice, function interface{}) (interface{}, bool) { - sv := sliceValue(slice) - fn := functionValue(function) - - elemType := sv.Type().Elem() - if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) { - panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String()) +// If return T is nil then no items matched the predicate func +func Find[T any](slice []T, fn func(index int, t T) bool) (*T, bool) { + if len(slice) == 0 { + return nil, false } index := -1 - for i := 0; i < sv.Len(); i++ { - flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0] - if flag.Bool() { + for i, v := range slice { + if fn(i, v) { index = i break } } if index == -1 { - var none interface{} - return none, false + return nil, false } - return sv.Index(index).Interface(), true + return &slice[index], true } // FlattenDeep flattens slice recursive @@ -279,7 +274,7 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value { // ForEach iterates over elements of slice and invokes function for each element // The fn signature should be func(int, T ). -func ForEach [T any] (slice []T, fn func(index int, t T)) { +func ForEach[T any](slice []T, fn func(index int, t T)) { for i, v := range slice { fn(i, v) } @@ -287,7 +282,7 @@ func ForEach [T any] (slice []T, fn func(index int, t T)) { // Map creates an slice of values by running each element of `slice` thru `function`. // The fn signature should be func(int, T). -func Map [T any, U any] (slice []T, fn func(index int, t T) U) []U { +func Map[T any, U any](slice []T, fn func(index int, t T) U) []U { res := make([]U, len(slice), cap(slice)) for i, v := range slice { res[i] = fn(i, v) diff --git a/slice/slice_test.go b/slice/slice_test.go index c528535..3b948b1 100644 --- a/slice/slice_test.go +++ b/slice/slice_test.go @@ -220,7 +220,7 @@ func TestFind(t *testing.T) { t.Fatal("found nothing") } - if res != 2 { + if *res != 2 { internal.LogFailedTestInfo(t, "Find", nums, 2, res) t.FailNow() } From 73f4ae7b3523dfdaa1658797bd01bbc3ac0830b9 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sat, 8 Jan 2022 21:58:35 +0800 Subject: [PATCH 02/23] refactor: add internal/assert.go and rewrite all unit funcs string_test.go with assert --- internal/assert.go | 148 ++++++++++++++++++++++ internal/assert_test.go | 28 +++++ strutil/string_test.go | 272 +++++++++++++++------------------------- 3 files changed, 278 insertions(+), 170 deletions(-) create mode 100644 internal/assert.go create mode 100644 internal/assert_test.go diff --git a/internal/assert.go b/internal/assert.go new file mode 100644 index 0000000..df2df52 --- /dev/null +++ b/internal/assert.go @@ -0,0 +1,148 @@ +package internal + +import ( + "fmt" + "reflect" + "testing" +) + +const ( + compareNotEqual int = iota - 2 + compareLess + compareEqual + compareGreater +) + +// Assert is a simple implementation of assertion, only for internal useage +type Assert struct { + T *testing.T + CaseName string +} + +// NewAssert return instance of Assert +func NewAssert(t *testing.T, caseName string) *Assert { + return &Assert{T: t, CaseName: caseName} +} + +// Equal check if expected is equal with actual +func (a *Assert) Equal(expected, actual interface{}) { + if compare(expected, actual) != compareEqual { + logFailedInfo(a.T, a.CaseName, expected, actual) + } +} + +// NotEqual check if expected is not equal with actual +func (a *Assert) NotEqual(expected, actual interface{}) { + if compare(expected, actual) == compareEqual { + expectedInfo := fmt.Sprintf("not %v", expected) + logFailedInfo(a.T, a.CaseName, expectedInfo, actual) + } +} + +// Greater check if expected is greate than actual +func (a *Assert) Greater(expected, actual interface{}) { + if compare(expected, actual) != compareGreater { + expectedInfo := fmt.Sprintf("> %v", expected) + logFailedInfo(a.T, a.CaseName, expectedInfo, actual) + } +} + +// Less check if expected is less than actual +func (a *Assert) Less(expected, actual interface{}) { + if compare(expected, actual) != compareLess { + expectedInfo := fmt.Sprintf("< %v", expected) + logFailedInfo(a.T, a.CaseName, expectedInfo, actual) + } +} + +// IsNil check if actual is nil +func (a *Assert) IsNil(actual interface{}) { + if actual != nil { + logFailedInfo(a.T, a.CaseName, nil, actual) + } +} + +// IsNil check if actual is not nil +func (a *Assert) IsNotNil(actual interface{}) { + if actual == nil { + logFailedInfo(a.T, a.CaseName, "not nil", actual) + } +} + +// compare x and y retun : +// x > y -> 1, x < y -> -1, x == y -> 0, x != y -> -2 +func compare(x, y interface{}) int { + vx := reflect.ValueOf(x) + vy := reflect.ValueOf(y) + + if vx.Type() != vy.Type() { + return compareNotEqual + } + + switch vx.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + xInt := vx.Int() + yInt := vy.Int() + if xInt > yInt { + return compareGreater + } + if xInt == yInt { + return compareEqual + } + if xInt < yInt { + return compareLess + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + xUint := vx.Uint() + yUint := vy.Uint() + if xUint > yUint { + return compareGreater + } + if xUint == yUint { + return compareEqual + } + if xUint < yUint { + return compareLess + } + case reflect.Float32, reflect.Float64: + xFloat := vx.Float() + yFloat := vy.Float() + if xFloat > yFloat { + return compareGreater + } + if xFloat == yFloat { + return compareEqual + } + if xFloat < yFloat { + return compareLess + } + case reflect.String: + xString := vx.String() + yString := vy.String() + if xString > yString { + return compareGreater + } + if xString == yString { + return compareEqual + } + if xString < yString { + return compareLess + } + default: + if reflect.DeepEqual(x, y) { + return compareEqual + } else { + return compareNotEqual + } + } + + return compareNotEqual + +} + +// logFailedInfo make test failed and log error info +func logFailedInfo(t *testing.T, caseName string, expected, actual interface{}) { + errInfo := fmt.Sprintf("Test case %v: expected: %v, actual: %v", caseName, expected, actual) + t.Error(errInfo) + t.FailNow() +} diff --git a/internal/assert_test.go b/internal/assert_test.go new file mode 100644 index 0000000..fd80530 --- /dev/null +++ b/internal/assert_test.go @@ -0,0 +1,28 @@ +package internal + +import ( + "testing" +) + +func TestAssert(t *testing.T) { + assert := NewAssert(t, "TestAssert") + assert.Equal(0, 0) + assert.NotEqual(1, 0) + assert.Greater(1, 0) + assert.Less(0, 1) + + assert.Greater(1.1, 0.1) + assert.Less(0.1, 1.1) + + assert.Equal("abc", "abc") + assert.NotEqual("abc", "abd") + assert.Less("abc", "abd") + assert.Greater("abd", "abc") + + assert.Equal([]int{1, 2, 3}, []int{1, 2, 3}) + assert.NotEqual([]int{1, 2, 3}, []int{1, 2}) + + assert.IsNil(nil) + assert.IsNotNil("abc") + +} diff --git a/strutil/string_test.go b/strutil/string_test.go index 009974d..4f8f80c 100644 --- a/strutil/string_test.go +++ b/strutil/string_test.go @@ -7,231 +7,163 @@ import ( ) func TestCamelCase(t *testing.T) { - camelCase(t, "foo_bar", "fooBar") - camelCase(t, "Foo-Bar", "fooBar") - camelCase(t, "Foo&bar", "fooBar") - camelCase(t, "foo bar", "fooBar") -} + assert := internal.NewAssert(t, "TestCamelCase") -func camelCase(t *testing.T, test string, expected string) { - res := CamelCase(test) - if res != expected { - internal.LogFailedTestInfo(t, "CamelCase", test, expected, res) - t.FailNow() - } + assert.Equal("fooBar", CamelCase("foo_bar")) + assert.Equal("fooBar", CamelCase("Foo-Bar")) + assert.Equal("fooBar", CamelCase("Foo&bar")) + assert.Equal("fooBar", CamelCase("foo bar")) + + assert.NotEqual("FooBar", CamelCase("foo_bar")) } func TestCapitalize(t *testing.T) { - capitalize(t, "foo", "Foo") - capitalize(t, "fOO", "Foo") - capitalize(t, "FOo", "Foo") -} + assert := internal.NewAssert(t, "TestCapitalize") -func capitalize(t *testing.T, test string, expected string) { - res := Capitalize(test) - if res != expected { - internal.LogFailedTestInfo(t, "Capitalize", test, expected, res) - t.FailNow() - } + assert.Equal("Foo", Capitalize("foo")) + assert.Equal("Foo", Capitalize("Foo")) + assert.Equal("Foo", Capitalize("Foo")) + + assert.NotEqual("foo", Capitalize("Foo")) } func TestKebabCase(t *testing.T) { - kebabCase(t, "Foo Bar-", "foo-bar") - kebabCase(t, "foo_Bar", "foo-bar") - kebabCase(t, "fooBar", "foo-bar") - kebabCase(t, "__FOO_BAR__", "f-o-o-b-a-r") -} + assert := internal.NewAssert(t, "TestKebabCase") -func kebabCase(t *testing.T, test string, expected string) { - res := KebabCase(test) - if res != expected { - internal.LogFailedTestInfo(t, "KebabCase", test, expected, res) - t.FailNow() - } + assert.Equal("foo-bar", KebabCase("Foo Bar-")) + assert.Equal("foo-bar", KebabCase("foo_Bar")) + assert.Equal("foo-bar", KebabCase("fooBar")) + assert.Equal("f-o-o-b-a-r", KebabCase("__FOO_BAR__")) + + assert.NotEqual("foo_bar", KebabCase("fooBar")) } func TestSnakeCase(t *testing.T) { - snakeCase(t, "Foo Bar-", "foo_bar") - snakeCase(t, "foo_Bar", "foo_bar") - snakeCase(t, "fooBar", "foo_bar") - snakeCase(t, "__FOO_BAR__", "f_o_o_b_a_r") - snakeCase(t, "aBbc-s$@a&%_B.B^C", "a_bbc_s_a_b_b_c") -} + assert := internal.NewAssert(t, "TestSnakeCase") -func snakeCase(t *testing.T, test string, expected string) { - res := SnakeCase(test) - if res != expected { - internal.LogFailedTestInfo(t, "SnakeCase", test, expected, res) - t.FailNow() - } + assert.Equal("foo_bar", SnakeCase("Foo Bar-")) + assert.Equal("foo_bar", SnakeCase("foo_Bar")) + assert.Equal("foo_bar", SnakeCase("fooBar")) + assert.Equal("f_o_o_b_a_r", SnakeCase("__FOO_BAR__")) + assert.Equal("a_bbc_s_a_b_b_c", SnakeCase("aBbc-s$@a&%_B.B^C")) + + assert.NotEqual("foo-bar", SnakeCase("foo_Bar")) } func TestLowerFirst(t *testing.T) { - lowerFirst(t, "foo", "foo") - lowerFirst(t, "BAR", "bAR") - lowerFirst(t, "FOo", "fOo") - lowerFirst(t, "FOo大", "fOo大") -} + assert := internal.NewAssert(t, "TestLowerFirst") -func lowerFirst(t *testing.T, test string, expected string) { - res := LowerFirst(test) - if res != expected { - internal.LogFailedTestInfo(t, "LowerFirst", test, expected, res) - t.FailNow() - } + assert.Equal("foo", LowerFirst("foo")) + assert.Equal("bAR", LowerFirst("BAR")) + assert.Equal("fOo", LowerFirst("FOo")) + assert.Equal("fOo大", LowerFirst("FOo大")) + + assert.NotEqual("Bar", LowerFirst("BAR")) } func TestPadEnd(t *testing.T) { - padEnd(t, "a", 1, "b", "a") - padEnd(t, "a", 2, "b", "ab") - padEnd(t, "abcd", 6, "mno", "abcdmn") - padEnd(t, "abcd", 6, "m", "abcdmm") - padEnd(t, "abc", 6, "ab", "abcaba") -} + assert := internal.NewAssert(t, "TestPadEnd") -func padEnd(t *testing.T, source string, size int, fillString string, expected string) { - res := PadEnd(source, size, fillString) - if res != expected { - internal.LogFailedTestInfo(t, "PadEnd", source, expected, res) - t.FailNow() - } + assert.Equal("a", PadEnd("a", 1, "b")) + assert.Equal("ab", PadEnd("a", 2, "b")) + assert.Equal("abcdmn", PadEnd("abcd", 6, "mno")) + assert.Equal("abcdmm", PadEnd("abcd", 6, "m")) + assert.Equal("abcaba", PadEnd("abc", 6, "ab")) + + assert.NotEqual("ba", PadEnd("a", 2, "b")) } func TestPadStart(t *testing.T) { - padStart(t, "a", 1, "b", "a") - padStart(t, "a", 2, "b", "ba") - padStart(t, "abcd", 6, "mno", "mnabcd") - padStart(t, "abcd", 6, "m", "mmabcd") - padStart(t, "abc", 6, "ab", "abaabc") -} + assert := internal.NewAssert(t, "TestPadStart") -func padStart(t *testing.T, source string, size int, fillString string, expected string) { - res := PadStart(source, size, fillString) - if res != expected { - internal.LogFailedTestInfo(t, "PadEnd", source, expected, res) - t.FailNow() - } + assert.Equal("a", PadStart("a", 1, "b")) + assert.Equal("ba", PadStart("a", 2, "b")) + assert.Equal("mnabcd", PadStart("abcd", 6, "mno")) + assert.Equal("mmabcd", PadStart("abcd", 6, "m")) + assert.Equal("abaabc", PadStart("abc", 6, "ab")) + + assert.NotEqual("ab", PadStart("a", 2, "b")) } func TestBefore(t *testing.T) { - before(t, "lancet", "", "lancet") - before(t, "github.com/test/lancet", "/", "github.com") - before(t, "github.com/test/lancet", "test", "github.com/") -} + assert := internal.NewAssert(t, "TestBefore") -func before(t *testing.T, source, char, expected string) { - res := Before(source, char) - if res != expected { - internal.LogFailedTestInfo(t, "Before", source, expected, res) - t.FailNow() - } + assert.Equal("lancet", Before("lancet", "")) + assert.Equal("github.com", Before("github.com/test/lancet", "/")) + assert.Equal("github.com/", Before("github.com/test/lancet", "test")) } func TestBeforeLast(t *testing.T) { - beforeLast(t, "lancet", "", "lancet") - beforeLast(t, "github.com/test/lancet", "/", "github.com/test") - beforeLast(t, "github.com/test/test/lancet", "test", "github.com/test/") -} + assert := internal.NewAssert(t, "TestBeforeLast") -func beforeLast(t *testing.T, source, char, expected string) { - res := BeforeLast(source, char) - if res != expected { - internal.LogFailedTestInfo(t, "BeforeLast", source, expected, res) - t.FailNow() - } + assert.Equal("lancet", BeforeLast("lancet", "")) + assert.Equal("github.com/test", BeforeLast("github.com/test/lancet", "/")) + assert.Equal("github.com/test/", BeforeLast("github.com/test/test/lancet", "test")) + + assert.NotEqual("github.com/", BeforeLast("github.com/test/test/lancet", "test")) } func TestAfter(t *testing.T) { - after(t, "lancet", "", "lancet") - after(t, "github.com/test/lancet", "/", "test/lancet") - after(t, "github.com/test/lancet", "test", "/lancet") -} + assert := internal.NewAssert(t, "TestAfter") -func after(t *testing.T, source, char, expected string) { - res := After(source, char) - if res != expected { - internal.LogFailedTestInfo(t, "After", source, expected, res) - t.FailNow() - } + assert.Equal("lancet", After("lancet", "")) + assert.Equal("test/lancet", After("github.com/test/lancet", "/")) + assert.Equal("/lancet", After("github.com/test/lancet", "test")) } func TestAfterLast(t *testing.T) { - afterLast(t, "lancet", "", "lancet") - afterLast(t, "github.com/test/lancet", "/", "lancet") - afterLast(t, "github.com/test/test/lancet", "test", "/lancet") -} + assert := internal.NewAssert(t, "TestAfterLast") -func afterLast(t *testing.T, source, char, expected string) { - res := AfterLast(source, char) - if res != expected { - internal.LogFailedTestInfo(t, "AfterLast", source, expected, res) - t.FailNow() - } + assert.Equal("lancet", AfterLast("lancet", "")) + assert.Equal("lancet", AfterLast("github.com/test/lancet", "/")) + assert.Equal("/lancet", AfterLast("github.com/test/lancet", "test")) + assert.Equal("/lancet", AfterLast("github.com/test/test/lancet", "test")) + + assert.NotEqual("/test/lancet", AfterLast("github.com/test/test/lancet", "test")) } func TestIsString(t *testing.T) { - isString(t, "lancet", true) - isString(t, 1, false) - isString(t, true, false) - isString(t, []string{}, false) -} + assert := internal.NewAssert(t, "TestIsString") -func isString(t *testing.T, test interface{}, expected bool) { - res := IsString(test) - if res != expected { - internal.LogFailedTestInfo(t, "IsString", test, expected, res) - t.FailNow() - } + assert.Equal(true, IsString("lancet")) + assert.Equal(true, IsString("")) + assert.Equal(false, IsString(1)) + assert.Equal(false, IsString(true)) + assert.Equal(false, IsString([]string{})) } func TestReverseStr(t *testing.T) { - reverseStr(t, "abc", "cba") - reverseStr(t, "12345", "54321") -} + assert := internal.NewAssert(t, "TestReverseStr") -func reverseStr(t *testing.T, test string, expected string) { - res := ReverseStr(test) - if res != expected { - internal.LogFailedTestInfo(t, "ReverseStr", test, expected, res) - t.FailNow() - } + assert.Equal("cba", ReverseStr("abc")) + assert.Equal("54321", ReverseStr("12345")) } func TestWrap(t *testing.T) { - wrap(t, "ab", "", "ab") - wrap(t, "", "*", "") - wrap(t, "ab", "*", "*ab*") - wrap(t, "ab", "\"", "\"ab\"") - wrap(t, "ab", "'", "'ab'") -} + assert := internal.NewAssert(t, "TestWrap") -func wrap(t *testing.T, test string, wrapWith string, expected string) { - res := Wrap(test, wrapWith) - if res != expected { - internal.LogFailedTestInfo(t, "Wrap", test, expected, res) - t.FailNow() - } + assert.Equal("ab", Wrap("ab", "")) + assert.Equal("", Wrap("", "*")) + assert.Equal("*ab*", Wrap("ab", "*")) + assert.Equal("\"ab\"", Wrap("ab", "\"")) + assert.Equal("'ab'", Wrap("ab", "'")) } func TestUnwrap(t *testing.T) { - unwrap(t, "", "*", "") - unwrap(t, "ab", "", "ab") - unwrap(t, "ab", "*", "ab") - unwrap(t, "**ab**", "*", "*ab*") - unwrap(t, "**ab**", "**", "ab") - unwrap(t, "\"ab\"", "\"", "ab") - unwrap(t, "*ab", "*", "*ab") - unwrap(t, "ab*", "*", "ab*") - unwrap(t, "***", "*", "*") - unwrap(t, "**", "*", "") - unwrap(t, "***", "**", "***") - unwrap(t, "**", "**", "**") -} + assert := internal.NewAssert(t, "TestUnwrap") + + assert.Equal("", Unwrap("", "*")) + assert.Equal("ab", Unwrap("ab", "")) + assert.Equal("ab", Unwrap("ab", "*")) + assert.Equal("*ab*", Unwrap("**ab**", "*")) + assert.Equal("ab", Unwrap("**ab**", "**")) + assert.Equal("ab", Unwrap("\"ab\"", "\"")) + assert.Equal("*ab", Unwrap("*ab", "*")) + assert.Equal("ab*", Unwrap("ab*", "*")) + assert.Equal("*", Unwrap("***", "*")) + + assert.Equal("", Unwrap("**", "*")) + assert.Equal("***", Unwrap("***", "**")) + assert.Equal("**", Unwrap("**", "**")) -func unwrap(t *testing.T, test string, wrapToken string, expected string) { - res := Unwrap(test, wrapToken) - if res != expected { - internal.LogFailedTestInfo(t, "Unwrap", test+"->"+wrapToken, expected, res) - t.FailNow() - } } From 3438f3b18a0e03048d0001b1b03bd8821d67677d Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 13:07:49 +0800 Subject: [PATCH 03/23] refactor: rewrite all unit test functions with assert --- internal/assert.go | 4 +- slice/slice_test.go | 506 ++++++++++++++--------------------------- strutil/string_test.go | 1 - 3 files changed, 179 insertions(+), 332 deletions(-) diff --git a/internal/assert.go b/internal/assert.go index df2df52..3043f7b 100644 --- a/internal/assert.go +++ b/internal/assert.go @@ -3,6 +3,7 @@ package internal import ( "fmt" "reflect" + "runtime" "testing" ) @@ -142,7 +143,8 @@ func compare(x, y interface{}) int { // logFailedInfo make test failed and log error info func logFailedInfo(t *testing.T, caseName string, expected, actual interface{}) { - errInfo := fmt.Sprintf("Test case %v: expected: %v, actual: %v", caseName, expected, actual) + _, file, line, _ := runtime.Caller(2) + errInfo := fmt.Sprintf("Case %v failed. file: %v, line: %v, expected: %v, actual: %v.", caseName, file, line, expected, actual) t.Error(errInfo) t.FailNow() } diff --git a/slice/slice_test.go b/slice/slice_test.go index db28b10..d3f402e 100644 --- a/slice/slice_test.go +++ b/slice/slice_test.go @@ -8,34 +8,25 @@ import ( ) func TestContain(t *testing.T) { - t1 := []string{"a", "b", "c", "d"} - contain(t, t1, "a", true) - contain(t, t1, "e", false) + assert := internal.NewAssert(t, "TestContain") - var t2 []string - contain(t, t2, "1", false) + assert.Equal(true, Contain([]string{"a", "b", "c"}, "a")) + assert.Equal(false, Contain([]string{"a", "b", "c"}, "d")) + assert.Equal(true, Contain([]string{""}, "")) + assert.Equal(false, Contain([]string{}, "")) - m := make(map[string]int) - m["a"] = 1 - contain(t, m, "a", true) - contain(t, m, "b", false) + var m = map[string]int{"a": 1} + assert.Equal(true, Contain(m, "a")) + assert.Equal(false, Contain(m, "b")) - s := "hello" - contain(t, s, "h", true) - contain(t, s, "s", false) -} - -func contain(t *testing.T, test interface{}, value interface{}, expected bool) { - res := Contain(test, value) - if res != expected { - internal.LogFailedTestInfo(t, "Contain", test, expected, res) - t.FailNow() - } + assert.Equal(true, Contain("abc", "a")) + assert.Equal(false, Contain("abc", "d")) } func TestChunk(t *testing.T) { - t1 := []string{"a", "b", "c", "d", "e"} + assert := internal.NewAssert(t, "TestChunk") + arr := []string{"a", "b", "c", "d", "e"} r1 := [][]interface{}{ {"a"}, {"b"}, @@ -43,26 +34,26 @@ func TestChunk(t *testing.T) { {"d"}, {"e"}, } - chunk(t, InterfaceSlice(t1), 1, r1) + assert.Equal(r1, Chunk(InterfaceSlice(arr), 1)) r2 := [][]interface{}{ {"a", "b"}, {"c", "d"}, {"e"}, } - chunk(t, InterfaceSlice(t1), 2, r2) + assert.Equal(r2, Chunk(InterfaceSlice(arr), 2)) r3 := [][]interface{}{ {"a", "b", "c"}, {"d", "e"}, } - chunk(t, InterfaceSlice(t1), 3, r3) + assert.Equal(r3, Chunk(InterfaceSlice(arr), 3)) r4 := [][]interface{}{ {"a", "b", "c", "d"}, {"e"}, } - chunk(t, InterfaceSlice(t1), 4, r4) + assert.Equal(r4, Chunk(InterfaceSlice(arr), 4)) r5 := [][]interface{}{ {"a"}, @@ -71,16 +62,7 @@ func TestChunk(t *testing.T) { {"d"}, {"e"}, } - chunk(t, InterfaceSlice(t1), 5, r5) - -} - -func chunk(t *testing.T, test []interface{}, num int, expected [][]interface{}) { - res := Chunk(test, num) - if !reflect.DeepEqual(res, expected) { - internal.LogFailedTestInfo(t, "Chunk", test, expected, res) - t.FailNow() - } + assert.Equal(r5, Chunk(InterfaceSlice(arr), 5)) } func TestConvertSlice(t *testing.T) { @@ -101,11 +83,9 @@ func TestEvery(t *testing.T) { isEven := func(i, num int) bool { return num%2 == 0 } - res := Every(nums, isEven) - if res != false { - internal.LogFailedTestInfo(t, "Every", nums, false, res) - t.FailNow() - } + + assert := internal.NewAssert(t, "TestEvery") + assert.Equal(false, Every(nums, isEven)) } func TestNone(t *testing.T) { @@ -113,42 +93,34 @@ func TestNone(t *testing.T) { check := func(i, num int) bool { return num%2 == 1 } - res := None(nums, check) - if res != false { - internal.LogFailedTestInfo(t, "None", nums, false, res) - t.FailNow() - } + + assert := internal.NewAssert(t, "TestNone") + assert.Equal(false, None(nums, check)) } func TestSome(t *testing.T) { nums := []int{1, 2, 3, 5} - isEven := func(i, num int) bool { + hasEven := func(i, num int) bool { return num%2 == 0 } - res := Some(nums, isEven) - if res != true { - internal.LogFailedTestInfo(t, "Some", nums, true, res) - t.FailNow() - } + + assert := internal.NewAssert(t, "TestSome") + assert.Equal(true, Some(nums, hasEven)) } func TestFilter(t *testing.T) { nums := []int{1, 2, 3, 4, 5} - even := func(i, num int) bool { + isEven := func(i, num int) bool { return num%2 == 0 } - e1 := []int{2, 4} - r1 := Filter(nums, even) - if !reflect.DeepEqual(r1, e1) { - internal.LogFailedTestInfo(t, "Filter", nums, e1, r1) - t.FailNow() - } + + assert := internal.NewAssert(t, "TestFilter") + assert.Equal([]int{2, 4}, Filter(nums, isEven)) type student struct { name string age int } - students := []student{ {"a", 10}, {"b", 11}, @@ -156,8 +128,7 @@ func TestFilter(t *testing.T) { {"d", 13}, {"e", 14}, } - - e2 := []student{ + studentsOfAageGreat12 := []student{ {"d", 13}, {"e", 14}, } @@ -165,12 +136,7 @@ func TestFilter(t *testing.T) { return s.age > 12 } - r2 := Filter(students, filterFunc) - if !reflect.DeepEqual(r2, e2) { - internal.LogFailedTestInfo(t, "Filter", students, e2, r2) - t.FailNow() - } - + assert.Equal(studentsOfAageGreat12, Filter(students, filterFunc)) } func TestGroupBy(t *testing.T) { @@ -179,22 +145,12 @@ func TestGroupBy(t *testing.T) { return (num % 2) == 0 } expectedEven := []int{2, 4, 6} + expectedOdd := []int{1, 3, 5} even, odd := GroupBy(nums, evenFunc) - t.Log("odd", odd) - - t.Log("even", even) - - if !reflect.DeepEqual(IntSlice(even), expectedEven) { - internal.LogFailedTestInfo(t, "GroupBy even", nums, expectedEven, even) - t.FailNow() - } - - expectedOdd := []int{1, 3, 5} - if !reflect.DeepEqual(IntSlice(odd), expectedOdd) { - internal.LogFailedTestInfo(t, "GroupBy odd", nums, expectedOdd, odd) - t.FailNow() - } + assert := internal.NewAssert(t, "TestGroupBy") + assert.Equal(expectedEven, even) + assert.Equal(expectedOdd, odd) } func TestCount(t *testing.T) { @@ -202,12 +158,9 @@ func TestCount(t *testing.T) { evenFunc := func(i, num int) bool { return (num % 2) == 0 } - c := Count(nums, evenFunc) - if c != 3 { - internal.LogFailedTestInfo(t, "Count", nums, 3, c) - t.FailNow() - } + assert := internal.NewAssert(t, "TestCount") + assert.Equal(3, Count(nums, evenFunc)) } func TestFind(t *testing.T) { @@ -220,10 +173,8 @@ func TestFind(t *testing.T) { t.Fatal("found nothing") } - if res != 2 { - internal.LogFailedTestInfo(t, "Find", nums, 2, res) - t.FailNow() - } + assert := internal.NewAssert(t, "TestFind") + assert.Equal(2, res) } func TestFindFoundNothing(t *testing.T) { @@ -232,20 +183,19 @@ func TestFindFoundNothing(t *testing.T) { return num > 1 } _, ok := Find(nums, findFunc) - if ok { - t.Fatal("found something") - } + // if ok { + // t.Fatal("found something") + // } + assert := internal.NewAssert(t, "TestFindFoundNothing") + assert.Equal(false, ok) } func TestFlattenDeep(t *testing.T) { input := [][][]string{{{"a", "b"}}, {{"c", "d"}}} expected := []string{"a", "b", "c", "d"} - res := FlattenDeep(input) - if !reflect.DeepEqual(res, expected) { - internal.LogFailedTestInfo(t, "FlattenDeep", input, expected, res) - t.FailNow() - } + assert := internal.NewAssert(t, "TestFlattenDeep") + assert.Equal(expected, FlattenDeep(input)) } func TestForEach(t *testing.T) { @@ -257,24 +207,18 @@ func TestForEach(t *testing.T) { numbersAddTwo = append(numbersAddTwo, value+2) }) - if !reflect.DeepEqual(numbersAddTwo, expected) { - internal.LogFailedTestInfo(t, "ForEach", numbers, expected, numbersAddTwo) - t.FailNow() - } - + assert := internal.NewAssert(t, "TestForEach") + assert.Equal(expected, numbersAddTwo) } func TestMap(t *testing.T) { - s1 := []int{1, 2, 3, 4} + nums := []int{1, 2, 3, 4} multiplyTwo := func(i, num int) int { return num * 2 } - e1 := []int{2, 4, 6, 8} - r1 := Map(s1, multiplyTwo) - if !reflect.DeepEqual(r1, e1) { - internal.LogFailedTestInfo(t, "Map", s1, e1, r1) - t.FailNow() - } + + assert := internal.NewAssert(t, "TestMap") + assert.Equal([]int{2, 4, 6, 8}, Map(nums, multiplyTwo)) type student struct { name string @@ -285,8 +229,7 @@ func TestMap(t *testing.T) { {"b", 2}, {"c", 3}, } - - e2 := []student{ + studentsOfAdd10Aage := []student{ {"a", 11}, {"b", 12}, {"c", 13}, @@ -295,11 +238,8 @@ func TestMap(t *testing.T) { s.age += 10 return s } - r2 := Map(students, mapFunc) - if !reflect.DeepEqual(r2, e2) { - internal.LogFailedTestInfo(t, "Filter", students, e2, r2) - t.FailNow() - } + + assert.Equal(studentsOfAdd10Aage, Map(students, mapFunc)) } func TestReduce(t *testing.T) { @@ -307,239 +247,154 @@ func TestReduce(t *testing.T) { {}, {1}, {1, 2, 3, 4}} + expected := []int{0, 1, 10} + f := func(i, v1, v2 int) int { return v1 + v2 } + + assert := internal.NewAssert(t, "TestReduce") + for i := 0; i < len(cases); i++ { - res := Reduce(cases[i], f, 0) - if res != expected[i] { - internal.LogFailedTestInfo(t, "Reduce", cases[i], expected[i], res) - t.FailNow() - } + actual := Reduce(cases[i], f, 0) + assert.Equal(expected[i], actual) } } func TestIntSlice(t *testing.T) { - var t1 []interface{} - t1 = append(t1, 1, 2, 3, 4, 5) - expect := []int{1, 2, 3, 4, 5} - intSlice(t, t1, expect) -} + var nums []interface{} + nums = append(nums, 1, 2, 3) -func intSlice(t *testing.T, test interface{}, expected []int) { - res := IntSlice(test) - - if !reflect.DeepEqual(res, expected) { - internal.LogFailedTestInfo(t, "IntSlice", test, expected, res) - t.FailNow() - } + assert := internal.NewAssert(t, "TestIntSlice") + assert.Equal([]int{1, 2, 3}, IntSlice(nums)) } func TestStringSlice(t *testing.T) { - var t1 []interface{} - t1 = append(t1, "a", "b", "c", "d", "e") - expect := []string{"a", "b", "c", "d", "e"} - stringSlice(t, t1, expect) -} + var strs []interface{} + strs = append(strs, "a", "b", "c") -func stringSlice(t *testing.T, test interface{}, expected []string) { - res := StringSlice(test) - if !reflect.DeepEqual(res, expected) { - internal.LogFailedTestInfo(t, "StringSlice", test, expected, res) - t.FailNow() - } + assert := internal.NewAssert(t, "TestStringSlice") + assert.Equal([]string{"a", "b", "c"}, StringSlice(strs)) } func TestInterfaceSlice(t *testing.T) { - t1 := []string{"a", "b", "c", "d", "e"} - expect := []interface{}{"a", "b", "c", "d", "e"} - interfaceSlice(t, t1, expect) -} + strs := []string{"a", "b", "c"} + expect := []interface{}{"a", "b", "c"} -func interfaceSlice(t *testing.T, test interface{}, expected []interface{}) { - res := InterfaceSlice(test) - if !reflect.DeepEqual(res, expected) { - internal.LogFailedTestInfo(t, "InterfaceSlice", test, expected, res) - t.FailNow() - } + assert := internal.NewAssert(t, "TestInterfaceSlice") + assert.Equal(expect, InterfaceSlice(strs)) } func TestDeleteByIndex(t *testing.T) { - origin := []string{"a", "b", "c", "d", "e"} + assert := internal.NewAssert(t, "TestDeleteByIndex") t1 := []string{"a", "b", "c", "d", "e"} r1 := []string{"b", "c", "d", "e"} - deleteByIndex(t, origin, t1, 0, 0, r1) + a1, _ := DeleteByIndex(t1, 0) + assert.Equal(r1, a1) - t1 = []string{"a", "b", "c", "d", "e"} + t2 := []string{"a", "b", "c", "d", "e"} r2 := []string{"a", "b", "c", "e"} - deleteByIndex(t, origin, t1, 3, 0, r2) + a2, _ := DeleteByIndex(t2, 3) + assert.Equal(r2, a2) - t1 = []string{"a", "b", "c", "d", "e"} - r3 := []string{"a", "b", "c", "d"} - deleteByIndex(t, origin, t1, 4, 0, r3) + t3 := []string{"a", "b", "c", "d", "e"} + r3 := []string{"c", "d", "e"} + a3, _ := DeleteByIndex(t3, 0, 2) + assert.Equal(r3, a3) - t1 = []string{"a", "b", "c", "d", "e"} - r4 := []string{"c", "d", "e"} - deleteByIndex(t, origin, t1, 0, 2, r4) + t4 := []string{"a", "b", "c", "d", "e"} + r4 := []string{} + a4, _ := DeleteByIndex(t4, 0, 5) + assert.Equal(r4, a4) - t1 = []string{"a", "b", "c", "d", "e"} - r5 := []string{} // var r5 []string{} failed - deleteByIndex(t, origin, t1, 0, 5, r5) + t5 := []string{"a", "b", "c", "d", "e"} + _, err := DeleteByIndex(t5, 1, 1) + assert.IsNotNil(err) - // failed - //t1 = []string{"a", "b", "c", "d","e"} - //r6 := []string{"a", "c", "d","e"} - //deleteByIndex(t, origin, t1, 1, 1, r6) - - // failed - //t1 = []string{"a", "b", "c", "d","e"} - //r7 := []string{} - //deleteByIndex(t, origin, t1, 0, 6, r7) -} - -func deleteByIndex(t *testing.T, origin, test interface{}, start, end int, expected interface{}) { - var res interface{} - var err error - if end != 0 { - res, err = DeleteByIndex(test, start, end) - } else { - res, err = DeleteByIndex(test, start) - } - if err != nil { - t.Error("DeleteByIndex Error: " + err.Error()) - } - - if !reflect.DeepEqual(res, expected) { - internal.LogFailedTestInfo(t, "DeleteByIndex", origin, expected, res) - t.FailNow() - } + _, err = DeleteByIndex(t5, 0, 6) + assert.IsNotNil(err) } func TestDrop(t *testing.T) { - drop(t, []int{}, 0, []int{}) - drop(t, []int{}, 1, []int{}) - drop(t, []int{}, -1, []int{}) + assert := internal.NewAssert(t, "TestInterfaceSlice") - drop(t, []int{1, 2, 3, 4, 5}, 0, []int{1, 2, 3, 4, 5}) - drop(t, []int{1, 2, 3, 4, 5}, 1, []int{2, 3, 4, 5}) - drop(t, []int{1, 2, 3, 4, 5}, 5, []int{}) - drop(t, []int{1, 2, 3, 4, 5}, 6, []int{}) + assert.Equal([]int{}, Drop([]int{}, 0)) + assert.Equal([]int{}, Drop([]int{}, 1)) + assert.Equal([]int{}, Drop([]int{}, -1)) - drop(t, []int{1, 2, 3, 4, 5}, -1, []int{1, 2, 3, 4}) - drop(t, []int{1, 2, 3, 4, 5}, -5, []int{}) - drop(t, []int{1, 2, 3, 4, 5}, -6, []int{}) -} + assert.Equal([]int{1, 2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, 0)) + assert.Equal([]int{2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, 1)) + assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 5)) + assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 6)) -func drop(t *testing.T, test interface{}, n int, expected interface{}) { - res := Drop(test, n) - if !reflect.DeepEqual(res, expected) { - internal.LogFailedTestInfo(t, "Drop", test, expected, res) - t.FailNow() - } + assert.Equal([]int{1, 2, 3, 4}, Drop([]int{1, 2, 3, 4, 5}, -1)) + assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, -6)) + assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, -6)) } func TestInsertByIndex(t *testing.T) { + assert := internal.NewAssert(t, "TestInsertByIndex") + t1 := []string{"a", "b", "c"} + r1, _ := InsertByIndex(t1, 0, "1") + assert.Equal([]string{"1", "a", "b", "c"}, r1) - r1 := []string{"1", "a", "b", "c"} - insertByIndex(t, t1, 0, "1", r1) + r2, _ := InsertByIndex(t1, 1, "1") + assert.Equal([]string{"a", "1", "b", "c"}, r2) - r2 := []string{"a", "1", "b", "c"} - insertByIndex(t, t1, 1, "1", r2) + r3, _ := InsertByIndex(t1, 3, "1") + assert.Equal([]string{"a", "b", "c", "1"}, r3) - r3 := []string{"a", "b", "c", "1"} - insertByIndex(t, t1, 3, "1", r3) + r4, _ := InsertByIndex(t1, 0, []string{"1", "2", "3"}) + assert.Equal([]string{"1", "2", "3", "a", "b", "c"}, r4) - r4 := []string{"1", "2", "3", "a", "b", "c"} - insertByIndex(t, t1, 0, []string{"1", "2", "3"}, r4) + r5, _ := InsertByIndex(t1, 3, []string{"1", "2", "3"}) + assert.Equal([]string{"a", "b", "c", "1", "2", "3"}, r5) - r5 := []string{"a", "1", "2", "3", "b", "c"} - insertByIndex(t, t1, 1, []string{"1", "2", "3"}, r5) + _, err := InsertByIndex(t1, 4, "1") + assert.IsNotNil(err) - r6 := []string{"a", "b", "1", "2", "3", "c"} - insertByIndex(t, t1, 2, []string{"1", "2", "3"}, r6) - - r7 := []string{"a", "b", "c", "1", "2", "3"} - insertByIndex(t, t1, 3, []string{"1", "2", "3"}, r7) -} - -func insertByIndex(t *testing.T, test interface{}, index int, value, expected interface{}) { - res, err := InsertByIndex(test, index, value) - if err != nil { - t.Error("InsertByIndex Error: " + err.Error()) - } - - if !reflect.DeepEqual(res, expected) { - internal.LogFailedTestInfo(t, "InsertByIndex", test, expected, res) - t.FailNow() - } + _, err = InsertByIndex(t1, 0, 1) + assert.IsNotNil(err) } func TestUpdateByIndex(t *testing.T) { + assert := internal.NewAssert(t, "TestUpdateByIndex") + t1 := []string{"a", "b", "c"} - r1 := []string{"1", "b", "c"} - updateByIndex(t, t1, 0, "1", r1) + r1, _ := UpdateByIndex(t1, 0, "1") + assert.Equal([]string{"1", "b", "c"}, r1) - t1 = []string{"a", "b", "c"} - r2 := []string{"a", "1", "c"} - updateByIndex(t, t1, 1, "1", r2) + t2 := []string{"a", "b", "c"} + r2, _ := UpdateByIndex(t2, 1, "1") + assert.Equal([]string{"a", "1", "c"}, r2) - t1 = []string{"a", "b", "c"} - r3 := []string{"a", "b", "1"} - updateByIndex(t, t1, 2, "1", r3) + _, err := UpdateByIndex([]string{"a", "b", "c"}, 4, "1") + assert.IsNotNil(err) -} - -func updateByIndex(t *testing.T, test interface{}, index int, value, expected interface{}) { - res, err := UpdateByIndex(test, index, value) - if err != nil { - t.Error("UpdateByIndex Error: " + err.Error()) - } - - if !reflect.DeepEqual(res, expected) { - internal.LogFailedTestInfo(t, "UpdateByIndex", test, expected, res) - t.FailNow() - } + _, err = UpdateByIndex([]string{"a", "b", "c"}, 0, 1) + assert.IsNotNil(err) } func TestUnique(t *testing.T) { - t1 := []int{1, 2, 2, 3} - e1 := []int{1, 2, 3} - r1 := Unique(t1) - if !reflect.DeepEqual(r1, e1) { - internal.LogFailedTestInfo(t, "Unique", t1, e1, r1) - t.FailNow() - } + assert := internal.NewAssert(t, "TestUnique") - t2 := []string{"a", "a", "b", "c"} - e2 := []string{"a", "b", "c"} - r2 := Unique(t2) - if !reflect.DeepEqual(r2, e2) { - internal.LogFailedTestInfo(t, "Unique", t2, e2, r2) - t.FailNow() - } + assert.Equal([]int{1, 2, 3}, Unique([]int{1, 2, 2, 3})) + assert.Equal([]string{"a", "b", "c"}, Unique([]string{"a", "a", "b", "c"})) } func TestUnion(t *testing.T) { + assert := internal.NewAssert(t, "TestUnion") + s1 := []int{1, 3, 4, 6} s2 := []int{1, 2, 5, 6} s3 := []int{0, 4, 5, 7} - expected1 := []int{1, 3, 4, 6, 2, 5, 0, 7} - res1 := Union(s1, s2, s3) - if !reflect.DeepEqual(res1, expected1) { - internal.LogFailedTestInfo(t, "Union", s1, expected1, res1) - t.FailNow() - } - - expected2 := []int{1, 3, 4, 6} - res2 := Union(s1) - if !reflect.DeepEqual(res2, expected2) { - internal.LogFailedTestInfo(t, "Union", s1, expected2, res2) - t.FailNow() - } + assert.Equal([]int{1, 3, 4, 6, 2, 5, 0, 7}, Union(s1, s2, s3)) + assert.Equal([]int{1, 3, 4, 6, 2, 5}, Union(s1, s2)) + assert.Equal([]int{1, 3, 4, 6}, Union(s1)) } func TestIntersection(t *testing.T) { @@ -560,45 +415,37 @@ func TestIntersection(t *testing.T) { Intersection(s1), Intersection(s1, s4), } - for i := 0; i < len(res); i++ { - if !reflect.DeepEqual(res[i], expected[i]) { - internal.LogFailedTestInfo(t, "Intersection", "Intersection", expected[i], res[i]) - t.FailNow() - } - } + assert := internal.NewAssert(t, "TestIntersection") + + for i := 0; i < len(res); i++ { + assert.Equal(res[i], expected[i]) + } } func TestReverseSlice(t *testing.T) { + assert := internal.NewAssert(t, "TestIntersection") + s1 := []int{1, 2, 3, 4, 5} - e1 := []int{5, 4, 3, 2, 1} ReverseSlice(s1) - if !reflect.DeepEqual(s1, e1) { - internal.LogFailedTestInfo(t, "ReverseSlice", s1, e1, s1) - t.FailNow() - } + assert.Equal([]int{5, 4, 3, 2, 1}, s1) s2 := []string{"a", "b", "c", "d", "e"} - e2 := []string{"e", "d", "c", "b", "a"} ReverseSlice(s2) - if !reflect.DeepEqual(s2, e2) { - internal.LogFailedTestInfo(t, "ReverseSlice", s2, e2, s2) - t.FailNow() - } + assert.Equal([]string{"e", "d", "c", "b", "a"}, s2) } func TestDifference(t *testing.T) { + assert := internal.NewAssert(t, "TestIntersection") + s1 := []int{1, 2, 3, 4, 5} s2 := []int{4, 5, 6} - e1 := []int{1, 2, 3} - r1 := Difference(s1, s2) - if !reflect.DeepEqual(r1, e1) { - internal.LogFailedTestInfo(t, "Difference", s1, e1, r1) - t.FailNow() - } + assert.Equal([]int{1, 2, 3}, Difference(s1, s2)) } func TestSortByField(t *testing.T) { + assert := internal.NewAssert(t, "TestWithout") + type student struct { name string age int @@ -609,8 +456,7 @@ func TestSortByField(t *testing.T) { {"c", 5}, {"d", 6}, } - - sortByAge := []student{ + studentsOfSortByAge := []student{ {"b", 15}, {"a", 10}, {"d", 6}, @@ -618,35 +464,35 @@ func TestSortByField(t *testing.T) { } err := SortByField(students, "age", "desc") - if err != nil { - t.Error("IntSlice Error: " + err.Error()) - } - - if !reflect.DeepEqual(students, sortByAge) { - internal.LogFailedTestInfo(t, "SortByField", students, sortByAge, students) - t.FailNow() - } + assert.IsNil(err) + assert.Equal(students, studentsOfSortByAge) } func TestWithout(t *testing.T) { - s := []int{1, 2, 3, 4, 5} - expected := []int{3, 4, 5} - res := Without(s, 1, 2) - - if !reflect.DeepEqual(res, expected) { - internal.LogFailedTestInfo(t, "Without", s, expected, res) - t.FailNow() - } + assert := internal.NewAssert(t, "TestWithout") + assert.Equal([]int{3, 4, 5}, Without([]int{1, 2, 3, 4, 5}, 1, 2)) + assert.Equal([]int{1, 2, 3, 4, 5}, Without([]int{1, 2, 3, 4, 5})) } func TestShuffle(t *testing.T) { + assert := internal.NewAssert(t, "TestShuffle") + s := []int{1, 2, 3, 4, 5} res := Shuffle(s) t.Log("Shuffle result: ", res) - if reflect.TypeOf(s) != reflect.TypeOf(res) { - internal.LogFailedTestInfo(t, "Shuffle", s, res, res) - t.FailNow() - } + assert.Equal(reflect.TypeOf(s), reflect.TypeOf(res)) + + rv := reflect.ValueOf(res) + assert.Equal(5, rv.Len()) + + assert.Equal(true, rv.Kind() == reflect.Slice) + assert.Equal(true, rv.Type().Elem().Kind() == reflect.Int) + + assert.Equal(true, Contain(res, 1)) + assert.Equal(true, Contain(res, 2)) + assert.Equal(true, Contain(res, 3)) + assert.Equal(true, Contain(res, 4)) + assert.Equal(true, Contain(res, 5)) } diff --git a/strutil/string_test.go b/strutil/string_test.go index 4f8f80c..ac7e35c 100644 --- a/strutil/string_test.go +++ b/strutil/string_test.go @@ -165,5 +165,4 @@ func TestUnwrap(t *testing.T) { assert.Equal("", Unwrap("**", "*")) assert.Equal("***", Unwrap("***", "**")) assert.Equal("**", Unwrap("**", "**")) - } From f490ef240413dd5812add05dcbfa3580b0c1c322 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 13:30:08 +0800 Subject: [PATCH 04/23] refactor: rewrite all unit test functions with assert --- convertor/convertor_test.go | 127 +++++++++++------------------------- 1 file changed, 39 insertions(+), 88 deletions(-) diff --git a/convertor/convertor_test.go b/convertor/convertor_test.go index 9bb2b73..b7fedca 100644 --- a/convertor/convertor_test.go +++ b/convertor/convertor_test.go @@ -2,13 +2,14 @@ package convertor import ( "fmt" - "reflect" "testing" "github.com/duke-git/lancet/internal" ) func TestToChar(t *testing.T) { + assert := internal.NewAssert(t, "TestToChar") + cases := []string{"", "abc", "1 2#3"} expected := [][]string{ {""}, @@ -16,28 +17,25 @@ func TestToChar(t *testing.T) { {"1", " ", "2", "#", "3"}, } for i := 0; i < len(cases); i++ { - res := ToChar(cases[i]) - if !reflect.DeepEqual(res, expected[i]) { - internal.LogFailedTestInfo(t, "ToChar", cases[i], expected[i], res) - t.FailNow() - } + assert.Equal(expected[i], ToChar(cases[i])) } } func TestToBool(t *testing.T) { + assert := internal.NewAssert(t, "TestToBool") + cases := []string{"true", "True", "false", "False", "0", "1", "123"} expected := []bool{true, true, false, false, false, true, false} for i := 0; i < len(cases); i++ { - res, _ := ToBool(cases[i]) - if res != expected[i] { - internal.LogFailedTestInfo(t, "ToBool", cases[i], expected[i], res) - t.FailNow() - } + actual, _ := ToBool(cases[i]) + assert.Equal(expected[i], actual) } } func TestToBytes(t *testing.T) { + assert := internal.NewAssert(t, "TestToBytes") + cases := []interface{}{ 0, false, @@ -49,16 +47,14 @@ func TestToBytes(t *testing.T) { {4, 12, 0, 1, 49}, } for i := 0; i < len(cases); i++ { - res, _ := ToBytes(cases[i]) - fmt.Println(res) - if !reflect.DeepEqual(res, expected[i]) { - internal.LogFailedTestInfo(t, "ToBytes", cases[i], expected[i], res) - t.FailNow() - } + actual, _ := ToBytes(cases[i]) + assert.Equal(expected[i], actual) } } func TestToInt(t *testing.T) { + assert := internal.NewAssert(t, "TestToInt") + cases := []interface{}{"123", "-123", 123, uint(123), uint8(123), uint16(123), uint32(123), uint64(123), float32(12.3), float64(12.3), @@ -67,15 +63,14 @@ func TestToInt(t *testing.T) { expected := []int64{123, -123, 123, 123, 123, 123, 123, 123, 12, 12, 0, 0, 0} for i := 0; i < len(cases); i++ { - res, _ := ToInt(cases[i]) - if res != expected[i] { - internal.LogFailedTestInfo(t, "ToInt", cases[i], expected[i], res) - t.FailNow() - } + actual, _ := ToInt(cases[i]) + assert.Equal(expected[i], actual) } } func TestToFloat(t *testing.T) { + assert := internal.NewAssert(t, "TestToFloat") + cases := []interface{}{ "", "-1", "-.11", "1.23e3", ".123e10", "abc", int(0), int8(1), int16(-1), int32(123), int64(123), @@ -86,22 +81,19 @@ func TestToFloat(t *testing.T) { 0, 1, -1, 123, 123, 123, 123, 123, 123, 123, 12.3, 12.300000190734863} for i := 0; i < len(cases); i++ { - res, _ := ToFloat(cases[i]) - if res != expected[i] { - internal.LogFailedTestInfo(t, "ToFloat", cases[i], expected[i], res) - t.FailNow() - } + actual, _ := ToFloat(cases[i]) + assert.Equal(expected[i], actual) } } func TestToString(t *testing.T) { - // map + assert := internal.NewAssert(t, "TestToString") + aMap := make(map[string]int) aMap["a"] = 1 aMap["b"] = 2 aMap["c"] = 3 - // struct type TestStruct struct { Name string } @@ -124,75 +116,39 @@ func TestToString(t *testing.T) { "[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"} for i := 0; i < len(cases); i++ { - res := ToString(cases[i]) - if res != expected[i] { - internal.LogFailedTestInfo(t, "ToString", cases[i], expected[i], res) - t.FailNow() - } + actual := ToString(cases[i]) + assert.Equal(expected[i], actual) } } func TestToJson(t *testing.T) { - // map - aMap := make(map[string]int) - aMap["a"] = 1 - aMap["b"] = 2 - aMap["c"] = 3 + assert := internal.NewAssert(t, "TestToJson") - mapJson := "{\"a\":1,\"b\":2,\"c\":3}" - r1, _ := ToJson(aMap) - if r1 != mapJson { - internal.LogFailedTestInfo(t, "ToJson", aMap, mapJson, r1) - t.FailNow() - } + var aMap = map[string]int{"a": 1, "b": 2, "c": 3} + mapJsonStr, _ := ToJson(aMap) + assert.Equal("{\"a\":1,\"b\":2,\"c\":3}", mapJsonStr) - // struct type TestStruct struct { Name string } aStruct := TestStruct{Name: "TestStruct"} - structJson := "{\"Name\":\"TestStruct\"}" - r2, _ := ToJson(aStruct) - if r2 != structJson { - internal.LogFailedTestInfo(t, "ToJson", aMap, mapJson, r1) - t.FailNow() - } + structJsonStr, _ := ToJson(aStruct) + assert.Equal("{\"Name\":\"TestStruct\"}", structJsonStr) } func TestStructToMap(t *testing.T) { + assert := internal.NewAssert(t, "TestStructToMap") + type People struct { Name string `json:"name"` age int } - - p1 := People{ + p := People{ "test", 100, } - - pm1, _ := StructToMap(p1) - m1 := make(map[string]interface{}) - m1["name"] = "test" - //exp1["100"] = 100 - - if !reflect.DeepEqual(pm1, m1) { - internal.LogFailedTestInfo(t, "StructToMap", p1, m1, pm1) - t.FailNow() - } - - p2 := People{ - "test", - 100, - } - - pm2, _ := StructToMap(p1) - m2 := make(map[string]interface{}) - m2["name"] = "test" - m2["100"] = 100 - - if reflect.DeepEqual(pm2, m2) { - internal.LogFailedTestInfo(t, "StructToMap", p2, m2, pm2) - t.FailNow() - } + pm, _ := StructToMap(p) + var expected = map[string]interface{}{"name": "test"} + assert.Equal(expected, pm) } func TestColorHexToRGB(t *testing.T) { @@ -201,22 +157,17 @@ func TestColorHexToRGB(t *testing.T) { colorRGB := fmt.Sprintf("%d,%d,%d", r, g, b) expected := "0,51,102" - if colorRGB != expected { - internal.LogFailedTestInfo(t, "ColorHexToRGB", colorHex, expected, colorRGB) - t.FailNow() - } + assert := internal.NewAssert(t, "TestColorHexToRGB") + assert.Equal(expected, colorRGB) } func TestColorRGBToHex(t *testing.T) { r := 0 g := 51 b := 102 - colorRGB := fmt.Sprintf("%d,%d,%d", r, g, b) colorHex := ColorRGBToHex(r, g, b) expected := "#003366" - if colorHex != expected { - internal.LogFailedTestInfo(t, "ColorHexToRGB", colorRGB, expected, colorHex) - t.FailNow() - } + assert := internal.NewAssert(t, "TestColorRGBToHex") + assert.Equal(expected, colorHex) } From 3ffd81a98a7b2479260e6aeaea23a2437c879d2f Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 13:51:07 +0800 Subject: [PATCH 05/23] refactor: rewrite all unit test functions with assert --- random/random_test.go | 61 ++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 38 deletions(-) diff --git a/random/random_test.go b/random/random_test.go index 6e7d845..bd09ed3 100644 --- a/random/random_test.go +++ b/random/random_test.go @@ -9,7 +9,6 @@ package random import ( - "fmt" "reflect" "regexp" "testing" @@ -18,54 +17,40 @@ import ( ) func TestRandString(t *testing.T) { - randStr := RandString(6) - fmt.Println(randStr) pattern := `^[a-zA-Z]+$` reg := regexp.MustCompile(pattern) - if len(randStr) != 6 || !reg.MatchString(randStr) { - internal.LogFailedTestInfo(t, "RandString", "RandString(6)", "RandString(6) should be 6 letters ", randStr) - t.FailNow() - } + randStr := RandString(6) + + assert := internal.NewAssert(t, "TestRandString") + assert.Equal(6, len(randStr)) + assert.Equal(true, reg.MatchString(randStr)) } func TestRandInt(t *testing.T) { - res1 := RandInt(1, 10) - if res1 < 1 || res1 >= 10 { - internal.LogFailedTestInfo(t, "RandInt", "RandInt(1, 10)", "RandInt(1, 10) should between [1, 10) ", res1) - t.FailNow() - } + assert := internal.NewAssert(t, "TestRandInt") - res2 := RandInt(1, 1) - if res2 != 1 { - internal.LogFailedTestInfo(t, "RandInt", "RandInt(1, 1)", "RandInt(1, 1) should be 1 ", res2) - t.FailNow() - } + r1 := RandInt(1, 10) + assert.Greater(r1, 1) + assert.Less(r1, 10) - res3 := RandInt(10, 1) - if res3 < 1 || res3 >= 10 { - internal.LogFailedTestInfo(t, "RandInt", "RandInt(10, 1)", "RandInt(10, 1) should between [1, 10) ", res3) - t.FailNow() - } + r2 := RandInt(1, 1) + assert.Equal(1, r2) + + r3 := RandInt(10, 1) + assert.Greater(r1, 1) + assert.Less(r3, 10) } func TestRandBytes(t *testing.T) { - randBytes := RandBytes(4) - if len(randBytes) != 4 { - internal.LogFailedTestInfo(t, "RandBytes", "RandBytes(4)", "RandBytes(4) should return 4 element of []bytes", randBytes) - t.FailNow() - } - v := reflect.ValueOf(randBytes) - et := v.Type().Elem() - if v.Kind() != reflect.Slice || et.Kind() != reflect.Uint8 { - internal.LogFailedTestInfo(t, "RandBytes", "RandBytes(4)", "RandBytes(4) should return 4 element of []bytes", randBytes) - t.FailNow() - } + assert := internal.NewAssert(t, "TestRandBytes") - randErr := RandBytes(0) - if randErr != nil { - internal.LogFailedTestInfo(t, "RandBytes", "RandBytes(0)", "RandBytes(0) should return nil", randErr) - t.FailNow() - } + randBytes := RandBytes(4) + assert.Equal(4, len(randBytes)) + + v := reflect.ValueOf(randBytes) + elemType := v.Type().Elem() + assert.Equal(reflect.Slice, v.Kind()) + assert.Equal(reflect.Uint8, elemType.Kind()) } From 65719515bdf7ed22ff787f69e25c382c01fc0cfd Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 13:58:27 +0800 Subject: [PATCH 06/23] feat: add LessOrEqual and GreaterOrEqual --- internal/assert.go | 18 ++++++++++++++++++ internal/assert_test.go | 2 ++ 2 files changed, 20 insertions(+) diff --git a/internal/assert.go b/internal/assert.go index 3043f7b..4aa2f22 100644 --- a/internal/assert.go +++ b/internal/assert.go @@ -48,6 +48,15 @@ func (a *Assert) Greater(expected, actual interface{}) { } } +// GreaterOrEqual check if expected is greate than or equal with actual +func (a *Assert) GreaterOrEqual(expected, actual interface{}) { + isGreatOrEqual := compare(expected, actual) == compareGreater || compare(expected, actual) == compareEqual + if !isGreatOrEqual { + expectedInfo := fmt.Sprintf(">= %v", expected) + logFailedInfo(a.T, a.CaseName, expectedInfo, actual) + } +} + // Less check if expected is less than actual func (a *Assert) Less(expected, actual interface{}) { if compare(expected, actual) != compareLess { @@ -56,6 +65,15 @@ func (a *Assert) Less(expected, actual interface{}) { } } +// Less check if expected is less than or equal with actual +func (a *Assert) LessOrEqual(expected, actual interface{}) { + isLessOrEqual := compare(expected, actual) == compareLess || compare(expected, actual) == compareEqual + if !isLessOrEqual { + expectedInfo := fmt.Sprintf("<= %v", expected) + logFailedInfo(a.T, a.CaseName, expectedInfo, actual) + } +} + // IsNil check if actual is nil func (a *Assert) IsNil(actual interface{}) { if actual != nil { diff --git a/internal/assert_test.go b/internal/assert_test.go index fd80530..185dd79 100644 --- a/internal/assert_test.go +++ b/internal/assert_test.go @@ -9,7 +9,9 @@ func TestAssert(t *testing.T) { assert.Equal(0, 0) assert.NotEqual(1, 0) assert.Greater(1, 0) + assert.GreaterOrEqual(1, 1) assert.Less(0, 1) + assert.LessOrEqual(0, 0) assert.Greater(1.1, 0.1) assert.Less(0.1, 1.1) From 25b2ae6b98129794469e26b25fac93fa76643085 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 14:00:23 +0800 Subject: [PATCH 07/23] fix: return empty byte slice when rand bytes lenght less 1 --- random/random.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/random/random.go b/random/random.go index c015e57..ebd708d 100644 --- a/random/random.go +++ b/random/random.go @@ -39,7 +39,7 @@ func RandInt(min, max int) int { // RandBytes generate random byte slice func RandBytes(length int) []byte { if length < 1 { - return nil + return []byte{} } b := make([]byte, length) From 642d0b8077606faf176839b04a32ad9416505c3f Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 14:01:51 +0800 Subject: [PATCH 08/23] refactor: rewrite all unit test functions with assert --- random/random_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/random/random_test.go b/random/random_test.go index bd09ed3..39bbde7 100644 --- a/random/random_test.go +++ b/random/random_test.go @@ -31,14 +31,14 @@ func TestRandInt(t *testing.T) { assert := internal.NewAssert(t, "TestRandInt") r1 := RandInt(1, 10) - assert.Greater(r1, 1) + assert.GreaterOrEqual(r1, 1) assert.Less(r1, 10) r2 := RandInt(1, 1) assert.Equal(1, r2) r3 := RandInt(10, 1) - assert.Greater(r1, 1) + assert.GreaterOrEqual(r1, 1) assert.Less(r3, 10) } @@ -53,4 +53,5 @@ func TestRandBytes(t *testing.T) { assert.Equal(reflect.Slice, v.Kind()) assert.Equal(reflect.Uint8, elemType.Kind()) + assert.Equal([]byte{}, RandBytes(0)) } From 31e08197d4233795dd2c7d4f4d14bf1ebf16f191 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 14:03:46 +0800 Subject: [PATCH 09/23] remove file comment --- random/random_test.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/random/random_test.go b/random/random_test.go index 39bbde7..190113c 100644 --- a/random/random_test.go +++ b/random/random_test.go @@ -1,11 +1,3 @@ -/* - * @Descripttion: - * @version: v1.0.0 - * @Author: dudaodong@kingsoft.com - * @Date: 2021-11-29 11:43:28 - * @LastEditors: dudaodong@kingsoft.com - * @LastEditTime: 2021-12-01 18:05:29 - */ package random import ( From e4cd7dad35eca6f3dd068ce58624f060d37a21b4 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 14:31:31 +0800 Subject: [PATCH 10/23] refactor: rewrite all unit test functions with assert --- cryptor/aes_test.go | 30 +++++---------- cryptor/basic_test.go | 90 ++++++++++++------------------------------- cryptor/des_test.go | 30 +++++---------- cryptor/rsa_test.go | 6 +-- 4 files changed, 46 insertions(+), 110 deletions(-) diff --git a/cryptor/aes_test.go b/cryptor/aes_test.go index 15c7484..928d63e 100644 --- a/cryptor/aes_test.go +++ b/cryptor/aes_test.go @@ -13,10 +13,8 @@ func TestAesEcbEncrypt(t *testing.T) { aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key)) aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key)) - if string(aesEcbDecrypt) != data { - internal.LogFailedTestInfo(t, "AesEcbEncrypt/AesEcbDecrypt", data, data, string(aesEcbDecrypt)) - t.FailNow() - } + assert := internal.NewAssert(t, "TestAesEcbEncrypt") + assert.Equal(data, string(aesEcbDecrypt)) } func TestAesCbcEncrypt(t *testing.T) { @@ -26,10 +24,8 @@ func TestAesCbcEncrypt(t *testing.T) { aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key)) aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key)) - if string(aesCbcDecrypt) != data { - internal.LogFailedTestInfo(t, "AesCbcEncrypt/AesCbcDecrypt", data, data, string(aesCbcDecrypt)) - t.FailNow() - } + assert := internal.NewAssert(t, "TestAesCbcEncrypt") + assert.Equal(data, string(aesCbcDecrypt)) } func TestAesCtrCrypt(t *testing.T) { @@ -39,10 +35,8 @@ func TestAesCtrCrypt(t *testing.T) { aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key)) aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key)) - if string(aesCtrDeCrypt) != data { - internal.LogFailedTestInfo(t, "AesCtrCrypt", data, data, string(aesCtrDeCrypt)) - t.FailNow() - } + assert := internal.NewAssert(t, "TestAesCtrCrypt") + assert.Equal(data, string(aesCtrDeCrypt)) } func TestAesCfbEncrypt(t *testing.T) { @@ -52,10 +46,8 @@ func TestAesCfbEncrypt(t *testing.T) { aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key)) aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key)) - if string(aesCfbDecrypt) != data { - internal.LogFailedTestInfo(t, "AesCfbEncrypt/AesCfbDecrypt", data, data, string(aesCfbDecrypt)) - t.FailNow() - } + assert := internal.NewAssert(t, "TestAesCfbEncrypt") + assert.Equal(data, string(aesCfbDecrypt)) } func TestAesOfbEncrypt(t *testing.T) { @@ -65,8 +57,6 @@ func TestAesOfbEncrypt(t *testing.T) { aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key)) aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key)) - if string(aesOfbDecrypt) != data { - internal.LogFailedTestInfo(t, "AesOfbEncrypt/AesOfbDecrypt", data, data, string(aesOfbDecrypt)) - t.FailNow() - } + assert := internal.NewAssert(t, "TestAesOfbEncrypt") + assert.Equal(data, string(aesOfbDecrypt)) } diff --git a/cryptor/basic_test.go b/cryptor/basic_test.go index 95af5cc..f0cccbe 100644 --- a/cryptor/basic_test.go +++ b/cryptor/basic_test.go @@ -1,66 +1,36 @@ package cryptor import ( - "fmt" - "os" "testing" "github.com/duke-git/lancet/internal" ) func TestBase64StdEncode(t *testing.T) { - s := "hello world" - bs := Base64StdEncode(s) - - if bs != "aGVsbG8gd29ybGQ=" { - internal.LogFailedTestInfo(t, "Base64StdEncode", s, "aGVsbG8gd29ybGQ=", bs) - t.FailNow() - } + assert := internal.NewAssert(t, "TestBase64StdEncode") + assert.Equal("aGVsbG8gd29ybGQ=", Base64StdEncode("hello world")) } func TestBase64StdDecode(t *testing.T) { - bs := "aGVsbG8gd29ybGQ=" - s := Base64StdDecode(bs) - - if s != "hello world" { - internal.LogFailedTestInfo(t, "Base64StdDecode", bs, "hello world=", s) - t.FailNow() - } + assert := internal.NewAssert(t, "TestBase64StdDecode") + assert.Equal("hello world", Base64StdEncode("aGVsbG8gd29ybGQ=")) } func TestMd5String(t *testing.T) { - s := "hello" - smd5 := Md5String(s) - expected := "5d41402abc4b2a76b9719d911017c592" - - if smd5 != expected { - internal.LogFailedTestInfo(t, "Md5String", s, expected, smd5) - t.FailNow() - } + assert := internal.NewAssert(t, "TestMd5String") + assert.Equal("5d41402abc4b2a76b9719d911017c592", Md5String("hello")) } func TestMd5File(t *testing.T) { - file, _ := os.Create("./hello.txt") - defer file.Close() - file.WriteString("hello\n") - - fileMd5, err := Md5File("./hello.txt") - if err != nil { - t.FailNow() - } - fmt.Println(fileMd5) + fileMd5, err := Md5File("./basic.go") + assert := internal.NewAssert(t, "TestMd5File") + assert.IsNotNil(fileMd5) + assert.IsNil(err) } func TestHmacMd5(t *testing.T) { - s := "hello world" - key := "12345" - hmacMd5 := HmacMd5(s, key) - expected := "5f4c9faaff0a1ad3007d9ddc06abe36d" - - if hmacMd5 != expected { - internal.LogFailedTestInfo(t, "HmacMd5", s, expected, hmacMd5) - t.FailNow() - } + assert := internal.NewAssert(t, "TestHmacMd5") + assert.Equal("5f4c9faaff0a1ad3007d9ddc06abe36d", HmacMd5("hello world", "12345")) } func TestHmacSha1(t *testing.T) { @@ -69,10 +39,8 @@ func TestHmacSha1(t *testing.T) { hmacSha1 := HmacSha1(s, key) expected := "3826f812255d8683f051ee97346d1359234d5dbd" - if hmacSha1 != expected { - internal.LogFailedTestInfo(t, "HmacSha1", s, expected, hmacSha1) - t.FailNow() - } + assert := internal.NewAssert(t, "TestHmacSha1") + assert.Equal(expected, hmacSha1) } func TestHmacSha256(t *testing.T) { @@ -81,10 +49,8 @@ func TestHmacSha256(t *testing.T) { hmacSha256 := HmacSha256(s, key) expected := "9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8" - if hmacSha256 != expected { - internal.LogFailedTestInfo(t, "HmacSha256", s, expected, hmacSha256) - t.FailNow() - } + assert := internal.NewAssert(t, "TestHmacSha256") + assert.Equal(expected, hmacSha256) } func TestHmacSha512(t *testing.T) { @@ -93,10 +59,8 @@ func TestHmacSha512(t *testing.T) { hmacSha512 := HmacSha512(s, key) expected := "5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175" - if hmacSha512 != expected { - internal.LogFailedTestInfo(t, "HmacSha512", s, expected, hmacSha512) - t.FailNow() - } + assert := internal.NewAssert(t, "TestHmacSha512") + assert.Equal(expected, hmacSha512) } func TestSha1(t *testing.T) { @@ -104,10 +68,8 @@ func TestSha1(t *testing.T) { sha1 := Sha1(s) expected := "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed" - if sha1 != expected { - internal.LogFailedTestInfo(t, "Sha1", s, expected, sha1) - t.FailNow() - } + assert := internal.NewAssert(t, "TestSha1") + assert.Equal(expected, sha1) } func TestSha256(t *testing.T) { @@ -115,10 +77,8 @@ func TestSha256(t *testing.T) { sha256 := Sha256(s) expected := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" - if sha256 != expected { - internal.LogFailedTestInfo(t, "Sha256", s, expected, sha256) - t.FailNow() - } + assert := internal.NewAssert(t, "TestSha256") + assert.Equal(expected, sha256) } func TestSha512(t *testing.T) { @@ -126,8 +86,6 @@ func TestSha512(t *testing.T) { sha512 := Sha512(s) expected := "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f" - if sha512 != expected { - internal.LogFailedTestInfo(t, "Sha512", s, expected, sha512) - t.FailNow() - } + assert := internal.NewAssert(t, "TestSha512") + assert.Equal(expected, sha512) } diff --git a/cryptor/des_test.go b/cryptor/des_test.go index f73336e..229fd41 100644 --- a/cryptor/des_test.go +++ b/cryptor/des_test.go @@ -13,10 +13,8 @@ func TestDesEcbEncrypt(t *testing.T) { desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key)) desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key)) - if string(desEcbDecrypt) != data { - internal.LogFailedTestInfo(t, "DesEcbEncrypt/DesEcbDecrypt", data, data, string(desEcbDecrypt)) - t.FailNow() - } + assert := internal.NewAssert(t, "TestDesEcbEncrypt") + assert.Equal(data, string(desEcbDecrypt)) } func TestDesCbcEncrypt(t *testing.T) { @@ -26,10 +24,8 @@ func TestDesCbcEncrypt(t *testing.T) { desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key)) desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key)) - if string(desCbcDecrypt) != data { - internal.LogFailedTestInfo(t, "DesCbcEncrypt/DesCbcDecrypt", data, data, string(desCbcDecrypt)) - t.FailNow() - } + assert := internal.NewAssert(t, "TestDesCbcEncrypt") + assert.Equal(data, string(desCbcDecrypt)) } func TestDesCtrCrypt(t *testing.T) { @@ -39,10 +35,8 @@ func TestDesCtrCrypt(t *testing.T) { desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key)) desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key)) - if string(desCtrDeCrypt) != data { - internal.LogFailedTestInfo(t, "DesCtrCrypt", data, data, string(desCtrDeCrypt)) - t.FailNow() - } + assert := internal.NewAssert(t, "TestDesCtrCrypt") + assert.Equal(data, string(desCtrDeCrypt)) } func TestDesCfbEncrypt(t *testing.T) { @@ -52,10 +46,8 @@ func TestDesCfbEncrypt(t *testing.T) { desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key)) desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key)) - if string(desCfbDecrypt) != data { - internal.LogFailedTestInfo(t, "DesCfbEncrypt/DesCfbDecrypt", data, data, string(desCfbDecrypt)) - t.FailNow() - } + assert := internal.NewAssert(t, "TestDesCfbEncrypt") + assert.Equal(data, string(desCfbDecrypt)) } func TestDesOfbEncrypt(t *testing.T) { @@ -65,8 +57,6 @@ func TestDesOfbEncrypt(t *testing.T) { desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key)) desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key)) - if string(desOfbDecrypt) != data { - internal.LogFailedTestInfo(t, "DesOfbEncrypt/DesOfbDecrypt", data, data, string(desOfbDecrypt)) - t.FailNow() - } + assert := internal.NewAssert(t, "TestDesOfbEncrypt") + assert.Equal(data, string(desOfbDecrypt)) } diff --git a/cryptor/rsa_test.go b/cryptor/rsa_test.go index 58be7c2..8ed2a34 100644 --- a/cryptor/rsa_test.go +++ b/cryptor/rsa_test.go @@ -12,8 +12,6 @@ func TestRsaEncrypt(t *testing.T) { encrypted := RsaEncrypt(data, "rsa_public.pem") decrypted := RsaDecrypt(encrypted, "rsa_private.pem") - if string(data) != string(decrypted) { - internal.LogFailedTestInfo(t, "RsaEncrypt/RsaDecrypt", string(data), string(data), string(decrypted)) - t.FailNow() - } + assert := internal.NewAssert(t, "TestRsaEncrypt") + assert.Equal(string(data), string(decrypted)) } From 9cb9aa2f2fa048a4938a083b032ff94214559393 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 14:46:17 +0800 Subject: [PATCH 11/23] refactor: rewrite all unit test functions with assert --- datetime/datetime_test.go | 87 ++++++++++++++------------------------- 1 file changed, 31 insertions(+), 56 deletions(-) diff --git a/datetime/datetime_test.go b/datetime/datetime_test.go index f4bd091..ae92442 100644 --- a/datetime/datetime_test.go +++ b/datetime/datetime_test.go @@ -1,90 +1,67 @@ package datetime import ( - "github.com/duke-git/lancet/internal" "testing" "time" + + "github.com/duke-git/lancet/internal" ) func TestAddDay(t *testing.T) { - now := time.Now() + assert := internal.NewAssert(t, "TestAddDay") + now := time.Now() after2Days := AddDay(now, 2) diff1 := after2Days.Sub(now) - if diff1.Hours() != 48 { - internal.LogFailedTestInfo(t, "AddDay", now, 48, diff1.Hours()) - t.FailNow() - } + assert.Equal(float64(48), diff1.Hours()) before2Days := AddDay(now, -2) diff2 := before2Days.Sub(now) - if diff2.Hours() != -48 { - internal.LogFailedTestInfo(t, "AddDay", now, -48, diff2.Hours()) - t.FailNow() - } - + assert.Equal(float64(-48), diff2.Hours()) } -func TestAddHour(t *testing.T) { - now := time.Now() +func TestAddHour(t *testing.T) { + assert := internal.NewAssert(t, "TestAddHour") + + now := time.Now() after2Hours := AddHour(now, 2) diff1 := after2Hours.Sub(now) - if diff1.Hours() != 2 { - internal.LogFailedTestInfo(t, "AddHour", now, 2, diff1.Hours()) - t.FailNow() - } + assert.Equal(float64(2), diff1.Hours()) before2Hours := AddHour(now, -2) diff2 := before2Hours.Sub(now) - if diff2.Hours() != -2 { - internal.LogFailedTestInfo(t, "AddHour", now, -2, diff2.Hours()) - t.FailNow() - } + assert.Equal(float64(-2), diff2.Hours()) } func TestAddMinute(t *testing.T) { - now := time.Now() + assert := internal.NewAssert(t, "TestAddMinute") + now := time.Now() after2Minutes := AddMinute(now, 2) diff1 := after2Minutes.Sub(now) - if diff1.Minutes() != 2 { - internal.LogFailedTestInfo(t, "AddMinute", now, 2, diff1.Minutes()) - t.FailNow() - } + assert.Equal(float64(2), diff1.Minutes()) before2Minutes := AddMinute(now, -2) diff2 := before2Minutes.Sub(now) - if diff2.Minutes() != -2 { - internal.LogFailedTestInfo(t, "AddMinute", now, -2, diff2.Minutes()) - t.FailNow() - } + assert.Equal(float64(-2), diff2.Minutes()) } func TestGetNowDate(t *testing.T) { - date := GetNowDate() + assert := internal.NewAssert(t, "TestGetNowDate") expected := time.Now().Format("2006-01-02") - if date != expected { - internal.LogFailedTestInfo(t, "GetNowDate", "", expected, date) - t.FailNow() - } + assert.Equal(expected, GetNowDate()) } func TestGetNotTime(t *testing.T) { - ts := GetNowTime() + assert := internal.NewAssert(t, "TestGetNotTime") expected := time.Now().Format("15:04:05") - if ts != expected { - internal.LogFailedTestInfo(t, "GetNowTime", "", expected, ts) - t.FailNow() - } + assert.Equal(expected, GetNowTime()) } func TestGetNowDateTime(t *testing.T) { - ts := GetNowDateTime() + assert := internal.NewAssert(t, "TestGetNowDateTime") expected := time.Now().Format("2006-01-02 15:04:05") - if ts != expected { - internal.LogFailedTestInfo(t, "GetNowDateTime", "", expected, ts) - t.FailNow() - } + assert.Equal(expected, GetNowDateTime()) } //todo @@ -98,6 +75,8 @@ func TestGetNowDateTime(t *testing.T) { //} func TestFormatTimeToStr(t *testing.T) { + assert := internal.NewAssert(t, "TestFormatTimeToStr") + datetime, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08") cases := []string{ "yyyy-mm-dd hh:mm:ss", "yyyy-mm-dd", @@ -110,16 +89,15 @@ func TestFormatTimeToStr(t *testing.T) { "16:04:08", "2021/01"} for i := 0; i < len(cases); i++ { - res := FormatTimeToStr(datetime, cases[i]) - if res != expected[i] { - internal.LogFailedTestInfo(t, "FormatTimeToStr", cases[i], expected[i], res) - t.FailNow() - } - } + actual := FormatTimeToStr(datetime, cases[i]) + assert.Equal(expected[i], actual) + } } func TestFormatStrToTime(t *testing.T) { + assert := internal.NewAssert(t, "TestFormatStrToTime") + formats := []string{ "2006-01-02 15:04:05", "2006-01-02", "02-01-06 15:04:05", "2006/01/02 15:04:05", @@ -135,14 +113,11 @@ func TestFormatStrToTime(t *testing.T) { "2021/01"} for i := 0; i < len(cases); i++ { - res, err := FormatStrToTime(datetimeStr[i], cases[i]) + actual, err := FormatStrToTime(datetimeStr[i], cases[i]) if err != nil { t.Fatal(err) } expected, _ := time.Parse(formats[i], datetimeStr[i]) - if res != expected { - internal.LogFailedTestInfo(t, "FormatTimeToStr", cases[i], expected, res) - t.FailNow() - } + assert.Equal(expected, actual) } } From 9da711516995011b51680ec60ad2bc13645f080c Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 15:10:56 +0800 Subject: [PATCH 12/23] refactor: rewrite all unit test functions with assert --- fileutil/file_test.go | 159 +++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 95 deletions(-) diff --git a/fileutil/file_test.go b/fileutil/file_test.go index a524438..446a9e2 100644 --- a/fileutil/file_test.go +++ b/fileutil/file_test.go @@ -2,72 +2,62 @@ package fileutil import ( "os" - "reflect" "testing" "github.com/duke-git/lancet/internal" ) func TestIsExist(t *testing.T) { + assert := internal.NewAssert(t, "TestIsExist") + cases := []string{"./", "./file.go", "./a.txt"} expected := []bool{true, true, false} for i := 0; i < len(cases); i++ { - res := IsExist(cases[i]) - if res != expected[i] { - internal.LogFailedTestInfo(t, "IsExist", cases[i], expected[i], res) - t.FailNow() - } + actual := IsExist(cases[i]) + assert.Equal(expected[i], actual) } } func TestCreateFile(t *testing.T) { + assert := internal.NewAssert(t, "TestCreateFile") + f := "./text.txt" if CreateFile(f) { file, err := os.Open(f) - if err != nil { - internal.LogFailedTestInfo(t, "CreateFile", f, f, "create file error: "+err.Error()) - t.FailNow() - } - if file.Name() != f { - internal.LogFailedTestInfo(t, "CreateFile", f, f, file.Name()) - t.FailNow() - } + assert.IsNil(err) + assert.Equal(f, file.Name()) } else { - internal.LogFailedTestInfo(t, "CreateFile", f, f, "create file error") t.FailNow() } os.Remove(f) } func TestIsDir(t *testing.T) { + assert := internal.NewAssert(t, "TestIsDir") + cases := []string{"./", "./a.txt"} expected := []bool{true, false} for i := 0; i < len(cases); i++ { - res := IsDir(cases[i]) - if res != expected[i] { - internal.LogFailedTestInfo(t, "IsDir", cases[i], expected[i], res) - t.FailNow() - } + actual := IsDir(cases[i]) + assert.Equal(expected[i], actual) } } func TestRemoveFile(t *testing.T) { + assert := internal.NewAssert(t, "TestRemoveFile") + f := "./text.txt" if CreateFile(f) { err := RemoveFile(f) - if err != nil { - internal.LogFailedTestInfo(t, "RemoveFile", f, f, err.Error()) - t.FailNow() - } - } else { - internal.LogFailedTestInfo(t, "RemoveFile", f, f, "create file error") - t.FailNow() + assert.IsNil(err) } } func TestCopyFile(t *testing.T) { + assert := internal.NewAssert(t, "TestCopyFile") + srcFile := "./text.txt" CreateFile(srcFile) @@ -76,126 +66,118 @@ func TestCopyFile(t *testing.T) { err := CopyFile(srcFile, destFile) if err != nil { file, err := os.Open(destFile) - if err != nil { - internal.LogFailedTestInfo(t, "CopyFile", srcFile, destFile, "create file error: "+err.Error()) - t.FailNow() - } - if file.Name() != destFile { - internal.LogFailedTestInfo(t, "CopyFile", srcFile, destFile, file.Name()) - t.FailNow() - } + assert.IsNil(err) + assert.Equal(destFile, file.Name()) } os.Remove(srcFile) os.Remove(destFile) } func TestListFileNames(t *testing.T) { - filesInCurrentPath, err := ListFileNames("../datetime/") - if err != nil { - t.FailNow() - } + assert := internal.NewAssert(t, "TestListFileNames") + + filesInPath, err := ListFileNames("../datetime/") + assert.IsNil(err) + expected := []string{"datetime.go", "datetime_test.go"} - if !reflect.DeepEqual(filesInCurrentPath, expected) { - internal.LogFailedTestInfo(t, "ToChar", "./", expected, filesInCurrentPath) - t.FailNow() - } + assert.Equal(expected, filesInPath) } func TestReadFileToString(t *testing.T) { + assert := internal.NewAssert(t, "TestReadFileToString") + path := "./text.txt" CreateFile(path) f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777) f.WriteString("hello world") - res, _ := ReadFileToString(path) - if res != "hello world" { - internal.LogFailedTestInfo(t, "ReadFileToString", path, "hello world", res) - t.FailNow() - } + content, _ := ReadFileToString(path) + assert.Equal("hello world", content) + os.Remove(path) } func TestClearFile(t *testing.T) { + assert := internal.NewAssert(t, "TestClearFile") + path := "./text.txt" CreateFile(path) f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777) + defer f.Close() + f.WriteString("hello world") err := ClearFile(path) - if err != nil { - t.Error("Clear file error: ", err) - } - fileContent, _ := ReadFileToString(path) - if fileContent != "" { - internal.LogFailedTestInfo(t, "ClearFile", path, "", fileContent) - t.FailNow() - } + assert.IsNil(err) + + content, _ := ReadFileToString(path) + assert.Equal("", content) + os.Remove(path) } func TestReadFileByLine(t *testing.T) { + assert := internal.NewAssert(t, "TestReadFileByLine") + path := "./text.txt" CreateFile(path) f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777) + defer f.Close() f.WriteString("hello\nworld") expected := []string{"hello", "world"} - res, _ := ReadFileByLine(path) - if !reflect.DeepEqual(res, expected) { - internal.LogFailedTestInfo(t, "ReadFileByLine", path, expected, res) - t.FailNow() - } + actual, _ := ReadFileByLine(path) + assert.Equal(expected, actual) + os.Remove(path) } func TestZipAndUnZip(t *testing.T) { + assert := internal.NewAssert(t, "TestZipAndUnZip") + srcFile := "./text.txt" CreateFile(srcFile) file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, 0777) + defer file.Close() file.WriteString("hello\nworld") zipFile := "./text.zip" err := Zip(srcFile, zipFile) - if err != nil { - internal.LogFailedTestInfo(t, "Zip", srcFile, zipFile, err) - t.FailNow() - } + assert.IsNil(err) unZipPath := "./unzip" err = UnZip(zipFile, unZipPath) - if err != nil { - internal.LogFailedTestInfo(t, "UnZip", srcFile, unZipPath, err) - t.FailNow() - } + assert.IsNil(err) unZipFile := "./unzip/text.txt" - if !IsExist(unZipFile) { - internal.LogFailedTestInfo(t, "UnZip", zipFile, zipFile, err) - t.FailNow() - } + assert.Equal(true, IsExist(unZipFile)) + os.Remove(srcFile) os.Remove(zipFile) os.RemoveAll(unZipPath) } func TestFileMode(t *testing.T) { + assert := internal.NewAssert(t, "TestFileMode") + srcFile := "./text.txt" CreateFile(srcFile) mode, err := FileMode(srcFile) - if err != nil { - t.Fail() - } + assert.IsNil(err) + t.Log(mode) os.Remove(srcFile) } func TestIsLink(t *testing.T) { + assert := internal.NewAssert(t, "TestIsLink") + srcFile := "./text.txt" CreateFile(srcFile) @@ -203,31 +185,18 @@ func TestIsLink(t *testing.T) { if !IsExist(linkFile) { _ = os.Symlink(srcFile, linkFile) } - if !IsLink(linkFile) { - internal.LogFailedTestInfo(t, "IsLink", linkFile, "true", "false") - t.FailNow() - } + assert.Equal(true, IsLink(linkFile)) + + assert.Equal(false, IsLink("./file.go")) - if IsLink("./file.go") { - internal.LogFailedTestInfo(t, "IsLink", "./file.go", "false", "true") - t.FailNow() - } os.Remove(srcFile) os.Remove(linkFile) } func TestMiMeType(t *testing.T) { - mt1 := MiMeType("./file.go") - expected := "text/plain; charset=utf-8" + assert := internal.NewAssert(t, "TestMiMeType") - if mt1 != expected { - internal.LogFailedTestInfo(t, "MiMeType", "./file.go", expected, mt1) - t.FailNow() - } f, _ := os.Open("./file.go") - mt2 := MiMeType(f) - if mt2 != expected { - internal.LogFailedTestInfo(t, "MiMeType", "./file.go", expected, mt2) - t.FailNow() - } + assert.Equal("text/plain; charset=utf-8", MiMeType(f)) + assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go")) } From d3525dfe8f7832bad6c85a7bd9052fc77cd793a8 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 15:34:17 +0800 Subject: [PATCH 13/23] refactor: rewrite all unit test functions with assert --- validator/validator_test.go | 286 +++++++++++------------------------- 1 file changed, 86 insertions(+), 200 deletions(-) diff --git a/validator/validator_test.go b/validator/validator_test.go index 5c5fb72..c500199 100644 --- a/validator/validator_test.go +++ b/validator/validator_test.go @@ -7,277 +7,163 @@ import ( ) func TestIsNumberStr(t *testing.T) { - isNumberStr(t, "3.", true) - isNumberStr(t, "+3.", true) - isNumberStr(t, "-3.", true) - isNumberStr(t, "+3e2", true) - isNumberStr(t, "abc", false) -} + assert := internal.NewAssert(t, "TestIsNumberStr") -func isNumberStr(t *testing.T, source string, expected bool) { - res := IsNumberStr(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsNumberStr", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsNumberStr("3.")) + assert.Equal(true, IsNumberStr("+3.")) + assert.Equal(true, IsNumberStr("-3.")) + assert.Equal(true, IsNumberStr("+3e2")) + assert.Equal(false, IsNumberStr("abc")) } func TestIsFloatStr(t *testing.T) { - isFloatStr(t, "3.", true) - isFloatStr(t, "+3.", true) - isFloatStr(t, "-3.", true) - isFloatStr(t, "12", true) - isFloatStr(t, "abc", false) -} + assert := internal.NewAssert(t, "TestIsFloatStr") -func isFloatStr(t *testing.T, source string, expected bool) { - res := IsFloatStr(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsFloatStr", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsFloatStr("3.")) + assert.Equal(true, IsFloatStr("+3.")) + assert.Equal(true, IsFloatStr("-3.")) + assert.Equal(true, IsFloatStr("12")) + assert.Equal(false, IsFloatStr("abc")) } func TestIsIntStr(t *testing.T) { - isIntStr(t, "+3", true) - isIntStr(t, "-3", true) - isIntStr(t, "3.", false) - isIntStr(t, "abc", false) -} + assert := internal.NewAssert(t, "TestIsIntStr") -func isIntStr(t *testing.T, source string, expected bool) { - res := IsIntStr(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsIntStr", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsIntStr("+3")) + assert.Equal(true, IsIntStr("-3")) + assert.Equal(false, IsIntStr("3.")) + assert.Equal(false, IsIntStr("abc")) } func TestIsIp(t *testing.T) { - isIp(t, "127.0.0.1", true) - isIp(t, "::0:0:0:0:0:0:1", true) - isIp(t, "120.0.0", false) - isIp(t, "abc", false) -} + assert := internal.NewAssert(t, "TestIsIntStr") -func isIp(t *testing.T, source string, expected bool) { - res := IsIp(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsIp", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsIp("127.0.0.1")) + assert.Equal(true, IsIp("::0:0:0:0:0:0:1")) + assert.Equal(false, IsIp("127.0.0")) + assert.Equal(false, IsIp("127")) } func TestIsIpV4(t *testing.T) { - isIpV4(t, "127.0.0.1", true) - isIpV4(t, "::0:0:0:0:0:0:1", false) -} + assert := internal.NewAssert(t, "TestIsIpV4") -func isIpV4(t *testing.T, source string, expected bool) { - res := IsIpV4(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsIpV4", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsIpV4("127.0.0.1")) + assert.Equal(false, IsIpV4("::0:0:0:0:0:0:1")) } func TestIsIpV6(t *testing.T) { - isIpV6(t, "127.0.0.1", false) - isIpV6(t, "::0:0:0:0:0:0:1", true) -} + assert := internal.NewAssert(t, "TestIsIpV6") -func isIpV6(t *testing.T, source string, expected bool) { - res := IsIpV6(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsIpV6", source, expected, res) - t.FailNow() - } + assert.Equal(false, IsIpV6("127.0.0.1")) + assert.Equal(true, IsIpV6("::0:0:0:0:0:0:1")) } func TestIsDns(t *testing.T) { - isDns(t, "abc.com", true) - isDns(t, "a.b.com", false) -} + assert := internal.NewAssert(t, "TestIsDns") -func isDns(t *testing.T, source string, expected bool) { - res := IsDns(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsDns", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsDns("abc.com")) + assert.Equal(false, IsDns("a.b.com")) } func TestIsEmail(t *testing.T) { - isEmail(t, "abc@xyz.com", true) - isEmail(t, "a.b@@com", false) -} + assert := internal.NewAssert(t, "TestIsEmail") -func isEmail(t *testing.T, source string, expected bool) { - res := IsEmail(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsEmail", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsEmail("abc@xyz.com")) + assert.Equal(false, IsEmail("a.b@@com")) } func TestContainChinese(t *testing.T) { - containChinese(t, "你好", true) - containChinese(t, "hello", false) - containChinese(t, "hello你好", true) -} + assert := internal.NewAssert(t, "TestContainChinese") -func containChinese(t *testing.T, source string, expected bool) { - res := ContainChinese(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsContainChineseChar", source, expected, res) - t.FailNow() - } + assert.Equal(true, ContainChinese("你好")) + assert.Equal(true, ContainChinese("你好hello")) + assert.Equal(false, ContainChinese("hello")) } func TestIsChineseMobile(t *testing.T) { - isChineseMobile(t, "13263527980", true) - isChineseMobile(t, "434324324", false) -} + assert := internal.NewAssert(t, "TestIsChineseMobile") -func isChineseMobile(t *testing.T, source string, expected bool) { - res := IsChineseMobile(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsChineseMobile", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsChineseMobile("13263527980")) + assert.Equal(false, IsChineseMobile("434324324")) } func TestIsChinesePhone(t *testing.T) { - isChinesePhone(t, "010-32116675", true) - isChinesePhone(t, "0464-8756213", true) - isChinesePhone(t, "123-87562", false) -} + assert := internal.NewAssert(t, "TestIsChinesePhone") + + assert.Equal(true, IsChinesePhone("010-32116675")) + assert.Equal(true, IsChinesePhone("0464-8756213")) + assert.Equal(false, IsChinesePhone("123-87562")) -func isChinesePhone(t *testing.T, source string, expected bool) { - res := IsChinesePhone(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsChinesePhone", source, expected, res) - t.FailNow() - } } func TestIsChineseIdNum(t *testing.T) { - isChineseIdNum(t, "210911192105130715", true) - isChineseIdNum(t, "21091119210513071X", true) - isChineseIdNum(t, "21091119210513071x", true) - isChineseIdNum(t, "123456", false) -} + assert := internal.NewAssert(t, "TestIsChineseIdNum") -func isChineseIdNum(t *testing.T, source string, expected bool) { - res := IsChineseIdNum(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsChineseIdNum", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsChineseIdNum("210911192105130715")) + assert.Equal(true, IsChineseIdNum("21091119210513071X")) + assert.Equal(true, IsChineseIdNum("21091119210513071x")) + assert.Equal(false, IsChineseIdNum("123456")) } func TestIsCreditCard(t *testing.T) { - isCreditCard(t, "4111111111111111", true) - isCreditCard(t, "123456", false) -} + assert := internal.NewAssert(t, "TestIsCreditCard") -func isCreditCard(t *testing.T, source string, expected bool) { - res := IsCreditCard(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsCreditCard", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsCreditCard("4111111111111111")) + assert.Equal(false, IsCreditCard("123456")) } func TestIsBase64(t *testing.T) { - isBase64(t, "aGVsbG8=", true) - isBase64(t, "123456", false) -} + assert := internal.NewAssert(t, "TestIsBase64") -func isBase64(t *testing.T, source string, expected bool) { - res := IsBase64(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsBase64", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsBase64("aGVsbG8=")) + assert.Equal(false, IsBase64("123456")) } func TestIsEmptyString(t *testing.T) { - isEmptyString(t, "111", false) - isEmptyString(t, " ", false) - isEmptyString(t, "\t", false) - isEmptyString(t, "", true) -} + assert := internal.NewAssert(t, "TestIsEmptyString") -func isEmptyString(t *testing.T, source string, expected bool) { - res := IsEmptyString(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsEmptyString", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsEmptyString("")) + assert.Equal(false, IsEmptyString("111")) + assert.Equal(false, IsEmptyString(" ")) + assert.Equal(false, IsEmptyString("\t")) } func TestIsAlpha(t *testing.T) { - isAlpha(t, "abc", true) - isAlpha(t, "111", false) - isAlpha(t, " ", false) - isAlpha(t, "\t", false) - isAlpha(t, "", false) -} + assert := internal.NewAssert(t, "TestIsAlpha") -func isAlpha(t *testing.T, source string, expected bool) { - res := IsAlpha(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsAlpha", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsAlpha("abc")) + assert.Equal(false, IsAlpha("111")) + assert.Equal(false, IsAlpha(" ")) + assert.Equal(false, IsAlpha("\t")) + assert.Equal(false, IsAlpha("")) } func TestIsRegexMatch(t *testing.T) { - isRegexMatch(t, "abc", `^[a-zA-Z]+$`, true) - isRegexMatch(t, "1ab", `^[a-zA-Z]+$`, false) - isRegexMatch(t, "111", `^[a-zA-Z]+$`, false) - isRegexMatch(t, "", `^[a-zA-Z]+$`, false) -} + assert := internal.NewAssert(t, "TestIsRegexMatch") -func isRegexMatch(t *testing.T, source, regex string, expected bool) { - res := IsRegexMatch(source, regex) - if res != expected { - internal.LogFailedTestInfo(t, "IsRegexMatch", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsRegexMatch("abc", `^[a-zA-Z]+$`)) + assert.Equal(false, IsRegexMatch("1ab", `^[a-zA-Z]+$`)) + assert.Equal(false, IsRegexMatch("", `^[a-zA-Z]+$`)) } func TestIsStrongPassword(t *testing.T) { - isStrongPassword(t, "abc", 3, false) - isStrongPassword(t, "abc123", 6, false) - isStrongPassword(t, "abcABC", 6, false) - isStrongPassword(t, "abc123@#$", 9, false) - isStrongPassword(t, "abcABC123@#$", 16, false) - isStrongPassword(t, "abcABC123@#$", 12, true) - isStrongPassword(t, "abcABC123@#$", 10, true) -} + assert := internal.NewAssert(t, "TestIsStrongPassword") -func isStrongPassword(t *testing.T, source string, length int, expected bool) { - res := IsStrongPassword(source, length) - if res != expected { - internal.LogFailedTestInfo(t, "IsStrongPassword", source, expected, res) - t.FailNow() - } + assert.Equal(false, IsStrongPassword("abc", 3)) + assert.Equal(false, IsStrongPassword("abc123", 6)) + assert.Equal(false, IsStrongPassword("abcABC", 6)) + assert.Equal(false, IsStrongPassword("abc123@#$", 9)) + assert.Equal(false, IsStrongPassword("abcABC123@#$", 16)) + assert.Equal(true, IsStrongPassword("abcABC123@#$", 12)) + assert.Equal(true, IsStrongPassword("abcABC123@#$", 10)) } func TestIsWeakPassword(t *testing.T) { - isWeakPassword(t, "abc", true) - isWeakPassword(t, "123", true) - isWeakPassword(t, "abc123", true) - isWeakPassword(t, "abcABC123", true) - isWeakPassword(t, "abc123@#$", false) -} + assert := internal.NewAssert(t, "TestIsWeakPassword") -func isWeakPassword(t *testing.T, source string, expected bool) { - res := IsWeakPassword(source) - if res != expected { - internal.LogFailedTestInfo(t, "IsWeakPassword", source, expected, res) - t.FailNow() - } + assert.Equal(true, IsWeakPassword("abc")) + assert.Equal(true, IsWeakPassword("123")) + assert.Equal(true, IsWeakPassword("abc123")) + assert.Equal(true, IsWeakPassword("abcABC123")) + assert.Equal(false, IsWeakPassword("abc123@#$")) } From b0e17c7bc461826ce5ba1a3ed91b425296d10059 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 15:39:50 +0800 Subject: [PATCH 14/23] refactor: rewrite all unit test functions with assert --- formatter/formatter_test.go | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/formatter/formatter_test.go b/formatter/formatter_test.go index 8d7d4d0..d2d4f87 100644 --- a/formatter/formatter_test.go +++ b/formatter/formatter_test.go @@ -7,22 +7,17 @@ import ( ) func TestComma(t *testing.T) { - comma(t, "", "", "") - comma(t, "aa", "", "") - comma(t, "aa.a", "", "") - comma(t, []int{1}, "", "") - comma(t, "123", "", "123") - comma(t, "12345", "", "12,345") - comma(t, 12345, "", "12,345") - comma(t, 12345, "$", "$12,345") - comma(t, 12345, "¥", "¥12,345") - comma(t, 12345.6789, "", "12,345.6789") -} + assert := internal.NewAssert(t, "TestComma") -func comma(t *testing.T, test interface{}, symbol string, expected interface{}) { - res := Comma(test, symbol) - if res != expected { - internal.LogFailedTestInfo(t, "Comma", test, expected, res) - t.FailNow() - } + assert.Equal("", Comma("", "")) + assert.Equal("", Comma("aa", "")) + assert.Equal("", Comma("aa.a", "")) + assert.Equal("", Comma([]int{1}, "")) + assert.Equal("123", Comma("123", "")) + assert.Equal("12,345", Comma("12345", "")) + + assert.Equal("12,345", Comma(12345, "")) + assert.Equal("$12,345", Comma(12345, "$")) + assert.Equal("¥12,345", Comma(12345, "¥")) + assert.Equal("12,345.6789", Comma(12345.6789, "")) } From 1199c30ef3245b78eb6fbc7968c679bfd05058e6 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 15:48:29 +0800 Subject: [PATCH 15/23] refactor: rewrite all unit test functions with assert --- function/function_test.go | 40 ++++++++++++++++++--------------------- function/watcher_test.go | 14 ++++++++------ 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/function/function_test.go b/function/function_test.go index bed16d0..5ab909b 100644 --- a/function/function_test.go +++ b/function/function_test.go @@ -6,6 +6,8 @@ import ( "strings" "testing" "time" + + "github.com/duke-git/lancet/internal" ) func TestAfter(t *testing.T) { @@ -32,6 +34,8 @@ func TestAfter(t *testing.T) { } func TestBefore(t *testing.T) { + assert := internal.NewAssert(t, "TestBefore") + arr := []string{"a", "b", "c", "d", "e"} f := Before(3, func(i int) int { return i @@ -40,7 +44,6 @@ func TestBefore(t *testing.T) { var res []int64 type cb func(args ...interface{}) []reflect.Value appendStr := func(i int, s string, fn cb) { - fmt.Printf("appendStr: arr[%d] is %s \n", i, s) v := fn(i) res = append(res, v[0].Int()) } @@ -49,28 +52,26 @@ func TestBefore(t *testing.T) { appendStr(i, arr[i], f) } - expect := []int64{0, 1, 2, 2, 2} - if !reflect.DeepEqual(expect, res) { - t.FailNow() - } + expected := []int64{0, 1, 2, 2, 2} + assert.Equal(expected, res) } func TestCurry(t *testing.T) { + assert := internal.NewAssert(t, "TestCurry") + add := func(a, b int) int { return a + b } var addCurry Fn = func(values ...interface{}) interface{} { return add(values[0].(int), values[1].(int)) } - add1 := addCurry.Curry(1) - v := add1(2) - if v != 3 { - t.FailNow() - } + assert.Equal(3, add1(2)) } func TestCompose(t *testing.T) { + assert := internal.NewAssert(t, "TestCompose") + toUpper := func(a ...interface{}) interface{} { return strings.ToUpper(a[0].(string)) } @@ -78,27 +79,25 @@ func TestCompose(t *testing.T) { return strings.ToLower(a[0].(string)) } - expect := toUpper(toLower("aBCde")) + expected := toUpper(toLower("aBCde")) cf := Compose(toUpper, toLower) res := cf("aBCde") - if res != expect { - t.FailNow() - } - + assert.Equal(expected, res) } func TestDelay(t *testing.T) { var print = func(s string) { - fmt.Println(s) + t.Log(s) } Delay(2*time.Second, print, "test delay") } func TestSchedule(t *testing.T) { + assert := internal.NewAssert(t, "TestSchedule") + var res []string appendStr := func(s string) { - fmt.Println(s) res = append(res, s) } @@ -106,9 +105,6 @@ func TestSchedule(t *testing.T) { time.Sleep(5 * time.Second) close(stop) - expect := []string{"*", "*", "*", "*", "*"} - if !reflect.DeepEqual(expect, res) { - t.FailNow() - } - fmt.Println("done") + expected := []string{"*", "*", "*", "*", "*"} + assert.Equal(expected, res) } diff --git a/function/watcher_test.go b/function/watcher_test.go index dec36eb..9df0036 100644 --- a/function/watcher_test.go +++ b/function/watcher_test.go @@ -2,26 +2,28 @@ package function import ( "testing" + + "github.com/duke-git/lancet/internal" ) func TestWatcher(t *testing.T) { + assert := internal.NewAssert(t, "TestWatcher") + w := &Watcher{} w.Start() longRunningTask() - if !w.excuting { - t.FailNow() - } + assert.Equal(true, w.excuting) w.Stop() eapsedTime := w.GetElapsedTime().Milliseconds() t.Log("Elapsed Time (milsecond)", eapsedTime) - if w.excuting { - t.FailNow() - } + assert.Equal(false, w.excuting) + + w.Reset() } func longRunningTask() { From 23701e6998fdefcb805411f404bf19f9ac99714e Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 15:49:52 +0800 Subject: [PATCH 16/23] refactor: rewrite all unit test functions with assert --- function/watcher_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/function/watcher_test.go b/function/watcher_test.go index 9df0036..f59772c 100644 --- a/function/watcher_test.go +++ b/function/watcher_test.go @@ -24,6 +24,9 @@ func TestWatcher(t *testing.T) { assert.Equal(false, w.excuting) w.Reset() + + assert.Equal(int64(0), w.startTime) + assert.Equal(int64(0), w.stopTime) } func longRunningTask() { From 49f62c35504a2743d1006f2394d51f26e54f1643 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 15:53:30 +0800 Subject: [PATCH 17/23] refactor: rewrite all unit test functions with assert --- netutil/net_test.go | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/netutil/net_test.go b/netutil/net_test.go index c31ef46..3a8e511 100644 --- a/netutil/net_test.go +++ b/netutil/net_test.go @@ -1,7 +1,6 @@ package netutil import ( - "fmt" "net" "testing" @@ -9,23 +8,25 @@ import ( ) func TestGetInternalIp(t *testing.T) { + assert := internal.NewAssert(t, "TestBefore") + internalIp := GetInternalIp() ip := net.ParseIP(internalIp) - if ip == nil { - internal.LogFailedTestInfo(t, "GetInternalIp", "GetInternalIp", "", ip) - t.FailNow() - } + assert.IsNotNil(ip) } func TestGetPublicIpInfo(t *testing.T) { + assert := internal.NewAssert(t, "TestGetPublicIpInfo") + publicIpInfo, err := GetPublicIpInfo() - if err != nil { - t.FailNow() - } - fmt.Printf("public ip info is: %+v \n", *publicIpInfo) + assert.IsNil(err) + + t.Logf("public ip info is: %+v \n", *publicIpInfo) } func TestIsPublicIP(t *testing.T) { + assert := internal.NewAssert(t, "TestIsPublicIP") + ips := []net.IP{ net.ParseIP("127.0.0.1"), net.ParseIP("192.168.0.1"), @@ -37,11 +38,7 @@ func TestIsPublicIP(t *testing.T) { expected := []bool{false, false, false, false, true} for i := 0; i < len(ips); i++ { - res := IsPublicIP(ips[i]) - - if res != expected[i] { - internal.LogFailedTestInfo(t, "IsPublicIP", ips[i], expected[i], res) - t.FailNow() - } + actual := IsPublicIP(ips[i]) + assert.Equal(expected[i], actual) } } From 52c5a916063b28b13ff5f99db3361e9369834201 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 15:57:21 +0800 Subject: [PATCH 18/23] refactor: rewrite all unit test functions with assert --- netutil/net_test.go | 2 +- netutil/request_test.go | 23 +++++++++-------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/netutil/net_test.go b/netutil/net_test.go index 3a8e511..9cd19e8 100644 --- a/netutil/net_test.go +++ b/netutil/net_test.go @@ -8,7 +8,7 @@ import ( ) func TestGetInternalIp(t *testing.T) { - assert := internal.NewAssert(t, "TestBefore") + assert := internal.NewAssert(t, "TestGetInternalIp") internalIp := GetInternalIp() ip := net.ParseIP(internalIp) diff --git a/netutil/request_test.go b/netutil/request_test.go index 8af125a..701f998 100644 --- a/netutil/request_test.go +++ b/netutil/request_test.go @@ -2,7 +2,6 @@ package netutil import ( "encoding/json" - "fmt" "io/ioutil" "log" "testing" @@ -23,7 +22,7 @@ func TestHttpGet(t *testing.T) { } body, _ := ioutil.ReadAll(resp.Body) - fmt.Println("response: ", resp.StatusCode, string(body)) + t.Log("response: ", resp.StatusCode, string(body)) } func TestHttpPost(t *testing.T) { @@ -44,7 +43,7 @@ func TestHttpPost(t *testing.T) { t.FailNow() } body, _ := ioutil.ReadAll(resp.Body) - fmt.Println("response: ", resp.StatusCode, string(body)) + t.Log("response: ", resp.StatusCode, string(body)) } func TestHttpPut(t *testing.T) { @@ -66,7 +65,7 @@ func TestHttpPut(t *testing.T) { t.FailNow() } body, _ := ioutil.ReadAll(resp.Body) - fmt.Println("response: ", resp.StatusCode, string(body)) + t.Log("response: ", resp.StatusCode, string(body)) } func TestHttpPatch(t *testing.T) { @@ -88,7 +87,7 @@ func TestHttpPatch(t *testing.T) { t.FailNow() } body, _ := ioutil.ReadAll(resp.Body) - fmt.Println("response: ", resp.StatusCode, string(body)) + t.Log("response: ", resp.StatusCode, string(body)) } func TestHttpDelete(t *testing.T) { @@ -99,22 +98,18 @@ func TestHttpDelete(t *testing.T) { t.FailNow() } body, _ := ioutil.ReadAll(resp.Body) - fmt.Println("response: ", resp.StatusCode, string(body)) + t.Log("response: ", resp.StatusCode, string(body)) } func TestConvertMapToQueryString(t *testing.T) { + assert := internal.NewAssert(t, "TestConvertMapToQueryString") + var m = map[string]interface{}{ "c": 3, "a": 1, "b": 2, } - - expected := "a=1&b=2&c=3" - r := ConvertMapToQueryString(m) - if r != expected { - internal.LogFailedTestInfo(t, "ConvertMapToQueryString", m, expected, r) - t.FailNow() - } + assert.Equal("a=1&b=2&c=3", ConvertMapToQueryString(m)) } func TestParseResponse(t *testing.T) { @@ -142,5 +137,5 @@ func TestParseResponse(t *testing.T) { log.Fatal(err) t.FailNow() } - fmt.Println("response: ", toDoResp) + t.Log("response: ", toDoResp) } From 1f45937190588cc806480f04f6ff1f2fc5ae74b5 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 16:04:33 +0800 Subject: [PATCH 19/23] refactor: rewrite all unit test functions with assert --- cryptor/basic_test.go | 2 +- fileutil/file_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cryptor/basic_test.go b/cryptor/basic_test.go index f0cccbe..90e5f92 100644 --- a/cryptor/basic_test.go +++ b/cryptor/basic_test.go @@ -13,7 +13,7 @@ func TestBase64StdEncode(t *testing.T) { func TestBase64StdDecode(t *testing.T) { assert := internal.NewAssert(t, "TestBase64StdDecode") - assert.Equal("hello world", Base64StdEncode("aGVsbG8gd29ybGQ=")) + assert.Equal("hello world", Base64StdDecode("aGVsbG8gd29ybGQ=")) } func TestMd5String(t *testing.T) { diff --git a/fileutil/file_test.go b/fileutil/file_test.go index 446a9e2..6ee5956 100644 --- a/fileutil/file_test.go +++ b/fileutil/file_test.go @@ -47,9 +47,9 @@ func TestIsDir(t *testing.T) { func TestRemoveFile(t *testing.T) { assert := internal.NewAssert(t, "TestRemoveFile") - f := "./text.txt" - if CreateFile(f) { + if !IsExist(f) { + CreateFile(f) err := RemoveFile(f) assert.IsNil(err) } From bbfc5b7060e74e648653ffb166a0d9bf23c0f1c3 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 16:12:26 +0800 Subject: [PATCH 20/23] delete file utils.go and fix some misspel --- internal/assert.go | 38 +++++++++++++++++++++----------------- internal/utils.go | 16 ---------------- 2 files changed, 21 insertions(+), 33 deletions(-) delete mode 100644 internal/utils.go diff --git a/internal/assert.go b/internal/assert.go index 4aa2f22..80d42f5 100644 --- a/internal/assert.go +++ b/internal/assert.go @@ -1,3 +1,7 @@ +// Copyright 2021 dudaodong@gmail.com. All rights reserved. +// Use of this source code is governed by MIT license + +// Package internal is for internal use. package internal import ( @@ -28,7 +32,7 @@ func NewAssert(t *testing.T, caseName string) *Assert { // Equal check if expected is equal with actual func (a *Assert) Equal(expected, actual interface{}) { if compare(expected, actual) != compareEqual { - logFailedInfo(a.T, a.CaseName, expected, actual) + makeTestFailed(a.T, a.CaseName, expected, actual) } } @@ -36,7 +40,7 @@ func (a *Assert) Equal(expected, actual interface{}) { func (a *Assert) NotEqual(expected, actual interface{}) { if compare(expected, actual) == compareEqual { expectedInfo := fmt.Sprintf("not %v", expected) - logFailedInfo(a.T, a.CaseName, expectedInfo, actual) + makeTestFailed(a.T, a.CaseName, expectedInfo, actual) } } @@ -44,7 +48,7 @@ func (a *Assert) NotEqual(expected, actual interface{}) { func (a *Assert) Greater(expected, actual interface{}) { if compare(expected, actual) != compareGreater { expectedInfo := fmt.Sprintf("> %v", expected) - logFailedInfo(a.T, a.CaseName, expectedInfo, actual) + makeTestFailed(a.T, a.CaseName, expectedInfo, actual) } } @@ -53,7 +57,7 @@ func (a *Assert) GreaterOrEqual(expected, actual interface{}) { isGreatOrEqual := compare(expected, actual) == compareGreater || compare(expected, actual) == compareEqual if !isGreatOrEqual { expectedInfo := fmt.Sprintf(">= %v", expected) - logFailedInfo(a.T, a.CaseName, expectedInfo, actual) + makeTestFailed(a.T, a.CaseName, expectedInfo, actual) } } @@ -61,34 +65,34 @@ func (a *Assert) GreaterOrEqual(expected, actual interface{}) { func (a *Assert) Less(expected, actual interface{}) { if compare(expected, actual) != compareLess { expectedInfo := fmt.Sprintf("< %v", expected) - logFailedInfo(a.T, a.CaseName, expectedInfo, actual) + makeTestFailed(a.T, a.CaseName, expectedInfo, actual) } } -// Less check if expected is less than or equal with actual +// LessOrEqual check if expected is less than or equal with actual func (a *Assert) LessOrEqual(expected, actual interface{}) { isLessOrEqual := compare(expected, actual) == compareLess || compare(expected, actual) == compareEqual if !isLessOrEqual { expectedInfo := fmt.Sprintf("<= %v", expected) - logFailedInfo(a.T, a.CaseName, expectedInfo, actual) + makeTestFailed(a.T, a.CaseName, expectedInfo, actual) } } -// IsNil check if actual is nil -func (a *Assert) IsNil(actual interface{}) { - if actual != nil { - logFailedInfo(a.T, a.CaseName, nil, actual) +// IsNil check if value is nil +func (a *Assert) IsNil(value interface{}) { + if value != nil { + makeTestFailed(a.T, a.CaseName, nil, value) } } -// IsNil check if actual is not nil -func (a *Assert) IsNotNil(actual interface{}) { - if actual == nil { - logFailedInfo(a.T, a.CaseName, "not nil", actual) +// IsNotNil check if value is not nil +func (a *Assert) IsNotNil(value interface{}) { + if value == nil { + makeTestFailed(a.T, a.CaseName, "not nil", value) } } -// compare x and y retun : +// compare x and y return : // x > y -> 1, x < y -> -1, x == y -> 0, x != y -> -2 func compare(x, y interface{}) int { vx := reflect.ValueOf(x) @@ -160,7 +164,7 @@ func compare(x, y interface{}) int { } // logFailedInfo make test failed and log error info -func logFailedInfo(t *testing.T, caseName string, expected, actual interface{}) { +func makeTestFailed(t *testing.T, caseName string, expected, actual interface{}) { _, file, line, _ := runtime.Caller(2) errInfo := fmt.Sprintf("Case %v failed. file: %v, line: %v, expected: %v, actual: %v.", caseName, file, line, expected, actual) t.Error(errInfo) diff --git a/internal/utils.go b/internal/utils.go deleted file mode 100644 index ab0f405..0000000 --- a/internal/utils.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2021 dudaodong@gmail.com. All rights reserved. -// Use of this source code is governed by MIT license - -// Package internal is for internal use. -package internal - -import ( - "fmt" - "testing" -) - -// LogFailedTestInfo log test failed info for internal use -func LogFailedTestInfo(t *testing.T, testCase, input, expected, result interface{}) { - errInfo := fmt.Sprintf("Test case %v: input is %+v, expected %v, but result is %v", testCase, input, expected, result) - t.Error(errInfo) -} From 44ac82e8b893e45c03fbb39c7b045b0481a97e1b Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 22:14:46 +0800 Subject: [PATCH 21/23] refactor: rewrite some slice functions with go generics --- README.md | 14 +-- README_zh-CN.md | 20 +-- slice/slice.go | 287 +++++++++++++++----------------------------- slice/slice_test.go | 62 +++------- 4 files changed, 129 insertions(+), 254 deletions(-) diff --git a/README.md b/README.md index 5fbfcb2..762d757 100644 --- a/README.md +++ b/README.md @@ -392,14 +392,14 @@ func main() { - Function list: ```go -func Contain(slice interface{}, value interface{}) bool //check if the value is in the slice or not -func Chunk(slice []interface{}, size int) [][]interface{} //creates an slice of elements split into groups the length of `size`. +func Contain[T comparable](slice []T, value T) bool //check if the value is in the slice or not +func Chunk[T any](slice []T, size int) [][]T //creates an slice of elements split into groups the length of size. func ConvertSlice(originalSlice interface{}, newSliceType reflect.Type) interface{} //convert originalSlice to newSliceType -func Difference(slice1, slice2 interface{}) interface{} //creates an slice of whose element not included in the other given slice +func Difference[T comparable](slice1, slice2 []T) []T //creates an slice of whose element not included in the other given slice func DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error) //delete the element of slice from start index to end index - 1 func Drop(slice interface{}, n int) interface{} //creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0 -func Every(slice, function interface{}) bool //return true if all of the values in the slice pass the predicate function, function signature should be func(index int, value interface{}) bool -func None(slice, function interface{}) bool // return true if all the values in the slice mismatch the criteria +func Every[T any](slice []T, fn func(index int, t T) bool) bool //return true if all of the values in the slice pass the predicate function +func None[T any](slice []T, fn func(index int, t T) bool) bool // return true if all the values in the slice mismatch the criteria func Filter [T any] (slice []T, fn func(index int, t T) bool) []T //filter slice, fn signature should be func(int, T) bool. func Find[T any](slice []T, fn func(index int, t T) bool) (*T, bool) //iterates over elements of slice, returning the first one that passes a truth test on function.function signature should be func(index int, value interface{}) bool . func FlattenDeep(slice interface{}) interface{} //flattens slice recursive @@ -410,10 +410,10 @@ func Intersection(slices ...interface{}) interface{} //creates a slice of unique func InsertByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //insert the element into slice at index. func Map [T any, U any] (slice []T, fn func(index int, t T) U) []U //map lisce, fn signature should be func(int, T). func ReverseSlice(slice interface{}) //revere slice -func Reduce(slice, function, zero interface{}) interface{} //reduce slice, function signature should be func(index int, value1, value2 interface{}) interface{} +func Reduce[T any](slice []T, fn func(index int, t1, t2 T) T, initial T) T //reduce slice func Shuffle(slice interface{}) interface{} //creates an slice of shuffled values func SortByField(slice interface{}, field string, sortType ...string) error //sort struct slice by field -func Some(slice, function interface{}) bool //return true if any of the values in the list pass the predicate function, function signature should be func(index int, value interface{}) bool +func Some[T any](slice []T, fn func(index int, t T) bool) bool //return true if any of the values in the list pass the predicate fn function func StringSlice(slice interface{}) []string //convert value to string slice func Unique(slice interface{}) interface{} //remove duplicate elements in slice func Union(slices ...interface{}) interface{} //Union creates a slice of unique values, in order, from all given slices. using == for equality comparisons. diff --git a/README_zh-CN.md b/README_zh-CN.md index 37307da..e774ec1 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -393,27 +393,27 @@ func main() { - 函数列表: ```go -func Contain(slice interface{}, value interface{}) bool //判断slice是否包含value -func Chunk(slice []interface{}, size int) [][]interface{} //均分slice +func Contain[T comparable](slice []T, value T) bool //判断slice是否包含value +func Chunk[T any](slice []T, size int) [][]T //均分slice func ConvertSlice(originalSlice interface{}, newSliceType reflect.Type) interface{} //将originalSlice转换为 newSliceType -func Difference(slice1, slice2 interface{}) interface{} //返回 +func Difference[T comparable](slice1, slice2 []T) []T //返回切片,其元素在slice1中,不在slice2中 func DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error) //删除切片中start到end位置的值 func Drop(slice interface{}, n int) interface{} //创建一个新切片,当n大于0时删除原切片前n个元素,当n小于0时删除原切片后n个元素 -func Every(slice, function interface{}) bool //slice中所有元素都符合函数条件时返回true, 否则返回false. 函数签名:func(index int, value interface{}) bool -func None(slice, function interface{}) bool //slice中所有元素都不符合函数条件时返回true, 否则返回false. 函数签名:func(index int, value interface{}) bool +func Every[T any](slice []T, fn func(index int, t T) bool) bool //slice中所有元素都符合函数条件时返回true, 否则返回false. 函数签名:func(index int, t T) bool +func None[T any](slice []T, fn func(index int, t T) bool) bool //slice中所有元素都不符合函数条件时返回true, 否则返回false. 函数签名:func(index int, value interface{}) bool func Find[T any](slice []T, fn func(index int, t T) bool) (*T, bool)//查找slice中第一个符合条件的元素,函数签名:func(index int, value interface{}) bool -func Filter(slice, function interface{}) interface{} //过滤slice, 函数签名:func(index int, value interface{}) bool -func FlattenDeep(slice interface{}) interface{} //将slice递归为一维切片。 -func ForEach(slice, function interface{}) //遍历切片,在每个元素上执行函数,函数签名:func(index int, value interface{}) +func Filter [T any] (slice []T, fn func(index int, t T) bool) []T //过滤slice +func FlattenDeep(slice interface{}) interface{} //将slice递归为一维切片 +func ForEach [T any] (slice []T, fn func(index int, t T)) //遍历切片,在每个元素上执行函数 func IntSlice(slice interface{}) ([]int, error) //转成int切片 func InterfaceSlice(slice interface{}) []interface{} //转成interface{}切片 func Intersection(slices ...interface{}) interface{} //slice交集,去重 func InsertByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //在切片中index位置插入value func Map(slice, function interface{}) interface{} //遍历切片, 函数签名:func(index int, value interface{}) interface{} func ReverseSlice(slice interface{}) //反转切片 -func Reduce(slice, function, zero interface{}) interface{} //切片reduce操作, 函数签名:func(index int, value1, value2 interface{}) interface{} +func Reduce[T any](slice []T, fn func(index int, t1, t2 T) T, initial T) T //切片reduce操作 func Shuffle(slice interface{}) interface{} //创建一个被打乱值的切片 -func Some(slice, function interface{}) bool //slice中任意一个元素都符合函数条件时返回true, 否则返回false. 函数签名:func(index int, value interface{}) bool +func Some[T any](slice []T, fn func(index int, t T) bool) bool //slice中任意一个元素都符合函数条件时返回true, 否则返回false. func SortByField(slice interface{}, field string, sortType ...string) error //对struct切片进行排序 func StringSlice(slice interface{}) []string //转为string切片 func Unique(slice interface{}) interface{} //去重切片 diff --git a/slice/slice.go b/slice/slice.go index 6f43f6a..899a100 100644 --- a/slice/slice.go +++ b/slice/slice.go @@ -11,45 +11,23 @@ import ( "math/rand" "reflect" "sort" - "strings" "unsafe" ) // Contain check if the value is in the iterable type or not -func Contain(iterableType interface{}, value interface{}) bool { - - v := reflect.ValueOf(iterableType) - - switch kind := reflect.TypeOf(iterableType).Kind(); kind { - case reflect.Slice, reflect.Array: - for i := 0; i < v.Len(); i++ { - if v.Index(i).Interface() == value { - return true - } - } - - case reflect.Map: - if v.MapIndex(reflect.ValueOf(value)).IsValid() { +func Contain[T comparable](slice []T, value T) bool { + for _, v := range slice { + if v == value { return true } - case reflect.String: - s := iterableType.(string) - ss, ok := value.(string) - if !ok { - panic("kind mismatch") - } - - return strings.Contains(s, ss) - default: - panic(fmt.Sprintf("kind %s is not support", iterableType)) } return false } -// Chunk creates an slice of elements split into groups the length of `size`. -func Chunk(slice []interface{}, size int) [][]interface{} { - var res [][]interface{} +// Chunk creates an slice of elements split into groups the length of size. +func Chunk[T any](slice []T, size int) [][]T { + var res [][]T if len(slice) == 0 || size <= 0 { return res @@ -58,7 +36,7 @@ func Chunk(slice []interface{}, size int) [][]interface{} { length := len(slice) if size == 1 || size >= length { for _, v := range slice { - var tmp []interface{} + var tmp []T tmp = append(tmp, v) res = append(res, tmp) } @@ -80,93 +58,59 @@ func Chunk(slice []interface{}, size int) [][]interface{} { return res } -// Difference creates an slice of whose element not included in the other given slice -func Difference(slice1, slice2 interface{}) interface{} { - v := sliceValue(slice1) - - var indexes []int - for i := 0; i < v.Len(); i++ { - vi := v.Index(i).Interface() - if !Contain(slice2, vi) { - indexes = append(indexes, i) +// Difference creates an slice of whose element in slice1 but not in slice2 +func Difference[T comparable](slice1, slice2 []T) []T { + var res []T + for _, v := range slice1 { + if !Contain(slice2, v) { + res = append(res, v) } } - res := reflect.MakeSlice(v.Type(), len(indexes), len(indexes)) - for i := range indexes { - res.Index(i).Set(v.Index(indexes[i])) - } - return res.Interface() + return res } // Every return true if all of the values in the slice pass the predicate function. -// The function signature should be func(index int, value interface{}) bool . -func Every(slice, function interface{}) bool { - sv := sliceValue(slice) - fn := functionValue(function) - - elemType := sv.Type().Elem() - if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) { - panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String()) - } - +// The fn function signature should be func(int, T) bool . +func Every[T any](slice []T, fn func(index int, t T) bool) bool { var currentLength int - for i := 0; i < sv.Len(); i++ { - flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0] - if flag.Bool() { + + for i, v := range slice { + if fn(i, v) { currentLength++ } } - return currentLength == sv.Len() + return currentLength == len(slice) } // None return true if all the values in the slice mismatch the criteria -// The function signature should be func(index int, value interface{}) bool . -func None(slice, function interface{}) bool { - sv := sliceValue(slice) - fn := functionValue(function) - - elemType := sv.Type().Elem() - if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) { - panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String()) - } - +// The fn function signature should be func(int, T) bool . +func None[T any](slice []T, fn func(index int, t T) bool) bool { var currentLength int - for i := 0; i < sv.Len(); i++ { - flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0] - if !flag.Bool() { + + for i, v := range slice { + if !fn(i, v) { currentLength++ } } - return currentLength == sv.Len() + return currentLength == len(slice) } // Some return true if any of the values in the list pass the predicate function. -// The function signature should be func(index int, value interface{}) bool . -func Some(slice, function interface{}) bool { - sv := sliceValue(slice) - fn := functionValue(function) - - elemType := sv.Type().Elem() - if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) { - panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String()) - } - - has := false - for i := 0; i < sv.Len(); i++ { - flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0] - if flag.Bool() { - has = true +// The fn function signature should be func(int, T) bool. +func Some[T any](slice []T, fn func(index int, t T) bool) bool { + for i, v := range slice { + if fn(i, v) { + return true } } - - return has + return false } // Filter iterates over elements of slice, returning an slice of all elements `signature` returns truthy for. -// The fn signature should be func(int, T) bool. +// The fn function signature should be func(int, T) bool. func Filter[T any](slice []T, fn func(index int, t T) bool) []T { res := make([]T, 0, 0) for i, v := range slice { @@ -226,7 +170,7 @@ func GroupBy(slice, function interface{}) (interface{}, interface{}) { } // Find iterates over elements of slice, returning the first one that passes a truth test on function. -// The function signature should be func(index int, value interface{}) bool . +// The fn function signature should be func(int, T) bool . // If return T is nil then no items matched the predicate func func Find[T any](slice []T, fn func(index int, t T) bool) (*T, bool) { if len(slice) == 0 { @@ -273,14 +217,14 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value { } // ForEach iterates over elements of slice and invokes function for each element -// The fn signature should be func(int, T ). +// The fn signature should be func(int, T). func ForEach[T any](slice []T, fn func(index int, t T)) { for i, v := range slice { fn(i, v) } } -// Map creates an slice of values by running each element of `slice` thru `function`. +// Map creates an slice of values by running each element of slice thru fn function. // The fn signature should be func(int, T). func Map[T any, U any](slice []T, fn func(index int, t T) U) []U { res := make([]U, len(slice), cap(slice)) @@ -291,40 +235,23 @@ func Map[T any, U any](slice []T, fn func(index int, t T) U) []U { return res } -// Reduce creates an slice of values by running each element of `slice` thru `function`. -// The function signature should be func(index int, value1, value2 interface{}) interface{} . -func Reduce(slice, function, zero interface{}) interface{} { - sv := sliceValue(slice) - elementType := sv.Type().Elem() - - len := sv.Len() - if len == 0 { - return zero - } else if len == 1 { - return sv.Index(0).Interface() +// Reduce creates an slice of values by running each element of slice thru fn function. +// The fn function signature should be fn func(int, T) T . +func Reduce[T any](slice []T, fn func(index int, t1, t2 T) T, initial T) T { + if len(slice) == 0 { + return initial } - fn := functionValue(function) - if checkSliceCallbackFuncSignature(fn, elementType, elementType, elementType) { - t := elementType.String() - panic("function param should be of type func(int, " + t + ", " + t + ")" + t) + res := fn(0, initial, slice[0]) + + tmp := make([]T, 2, 2) + for i := 1; i < len(slice); i++ { + tmp[0] = res + tmp[1] = slice[i] + res = fn(i, tmp[0], tmp[1]) } - var params [3]reflect.Value - params[0] = reflect.ValueOf(0) - params[1] = sv.Index(0) - params[2] = sv.Index(1) - - res := fn.Call(params[:])[0] - - for i := 2; i < len; i++ { - params[0] = reflect.ValueOf(i) - params[1] = res - params[2] = sv.Index(i) - res = fn.Call(params[:])[0] - } - - return res.Interface() + return res } // InterfaceSlice convert param to slice of interface. @@ -499,106 +426,82 @@ func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{} } // Unique remove duplicate elements in slice. -func Unique(slice interface{}) interface{} { - sv := sliceValue(slice) - if sv.Len() == 0 { - return slice +func Unique[T comparable](slice []T) []T { + if len(slice) == 0 { + return []T{} } - var temp []interface{} - - for i := 0; i < sv.Len(); i++ { - v := sv.Index(i).Interface() + // here no use map filter. if use it, the result slice element order is random, not same as origin slice + var res []T + for i := 0; i < len(slice); i++ { + v := slice[i] skip := true - for j := range temp { - if v == temp[j] { + for j := range res { + if v == res[j] { skip = false break } } if skip { - temp = append(temp, v) + res = append(res, v) } } - res := reflect.MakeSlice(sv.Type(), len(temp), len(temp)) - for i := 0; i < len(temp); i++ { - res.Index(i).Set(reflect.ValueOf(temp[i])) - } - return res.Interface() - - // if use map filter, the result slice element order is random, not same as origin slice - //mp := make(map[interface{}]bool) - //for i := 0; i < sv.Len(); i++ { - // v := sv.Index(i).Interface() - // mp[v] = true - //} - // - //var res []interface{} - //for k := range mp { - // res = append(res, mp[k]) - //} - //return res - + return res } // Union creates a slice of unique values, in order, from all given slices. using == for equality comparisons. -func Union(slices ...interface{}) interface{} { +func Union[T comparable](slices ...[]T) []T { if len(slices) == 0 { - return nil + return []T{} } + // append all slices, then unique it - var allSlices []interface{} - len := 0 - for i := range slices { - sv := sliceValue(slices[i]) - len += sv.Len() - for j := 0; j < sv.Len(); j++ { - v := sv.Index(j).Interface() - allSlices = append(allSlices, v) + var allElements []T + + for _, slice := range slices { + for _, v := range slice { + allElements = append(allElements, v) } } - sv := sliceValue(slices[0]) - res := reflect.MakeSlice(sv.Type(), len, len) - for i := 0; i < len; i++ { - res.Index(i).Set(reflect.ValueOf(allSlices[i])) - } - - return Unique(res.Interface()) + return Unique(allElements) } // Intersection creates a slice of unique values that included by all slices. -func Intersection(slices ...interface{}) interface{} { +func Intersection[T comparable](slices ...[]T) []T { + var res []T if len(slices) == 0 { - return nil + return []T{} + } + if len(slices) == 1 { + return Unique(slices[0]) } - reduceFunc := func(index int, slice1, slice2 interface{}) interface{} { - set := make([]interface{}, 0) - hash := make(map[interface{}]bool) - - sv1 := reflect.ValueOf(slice1) - for i := 0; i < sv1.Len(); i++ { - v := sv1.Index(i).Interface() - hash[v] = true - } - - sv2 := reflect.ValueOf(slice2) - for i := 0; i < sv2.Len(); i++ { - el := sv2.Index(i).Interface() - if _, found := hash[el]; found { - set = append(set, el) + //return elements both in slice1 and slice2 + reduceFunc := func(slice1, slice2 []T) []T { + s := make([]T, 0, 0) + for _, v := range slice1 { + if Contain(slice2, v) { + s = append(s, v) } } - res := reflect.MakeSlice(sv1.Type(), len(set), len(set)) - for i := 0; i < len(set); i++ { - res.Index(i).Set(reflect.ValueOf(set[i])) - } - return res.Interface() + return s + } + + res = reduceFunc(slices[0], slices[1]) + + if len(slices) == 2 { + return Unique(res) + } + + tmp := make([][]T, 2, 2) + for i := 2; i < len(slices); i++ { + tmp[0] = res + tmp[1] = slices[i] + res = reduceFunc(tmp[0], tmp[1]) } - res := Reduce(slices, reduceFunc, nil) return Unique(res) } diff --git a/slice/slice_test.go b/slice/slice_test.go index ea021fd..899eb2e 100644 --- a/slice/slice_test.go +++ b/slice/slice_test.go @@ -15,54 +15,27 @@ func TestContain(t *testing.T) { assert.Equal(true, Contain([]string{""}, "")) assert.Equal(false, Contain([]string{}, "")) - var m = map[string]int{"a": 1} - assert.Equal(true, Contain(m, "a")) - assert.Equal(false, Contain(m, "b")) - - assert.Equal(true, Contain("abc", "a")) - assert.Equal(false, Contain("abc", "d")) + assert.Equal(true, Contain([]int{1, 2, 3}, 1)) } func TestChunk(t *testing.T) { assert := internal.NewAssert(t, "TestChunk") arr := []string{"a", "b", "c", "d", "e"} - r1 := [][]interface{}{ - {"a"}, - {"b"}, - {"c"}, - {"d"}, - {"e"}, - } - assert.Equal(r1, Chunk(InterfaceSlice(arr), 1)) + r1 := [][]string{{"a"}, {"b"}, {"c"}, {"d"}, {"e"}} + assert.Equal(r1, Chunk(arr, 1)) - r2 := [][]interface{}{ - {"a", "b"}, - {"c", "d"}, - {"e"}, - } - assert.Equal(r2, Chunk(InterfaceSlice(arr), 2)) + r2 := [][]string{{"a", "b"}, {"c", "d"}, {"e"}} + assert.Equal(r2, Chunk(arr, 2)) - r3 := [][]interface{}{ - {"a", "b", "c"}, - {"d", "e"}, - } - assert.Equal(r3, Chunk(InterfaceSlice(arr), 3)) + r3 := [][]string{{"a", "b", "c"}, {"d", "e"}} + assert.Equal(r3, Chunk(arr, 3)) - r4 := [][]interface{}{ - {"a", "b", "c", "d"}, - {"e"}, - } - assert.Equal(r4, Chunk(InterfaceSlice(arr), 4)) + r4 := [][]string{{"a", "b", "c", "d"}, {"e"}} + assert.Equal(r4, Chunk(arr, 4)) - r5 := [][]interface{}{ - {"a"}, - {"b"}, - {"c"}, - {"d"}, - {"e"}, - } - assert.Equal(r5, Chunk(InterfaceSlice(arr), 5)) + r5 := [][]string{{"a"}, {"b"}, {"c"}, {"d"}, {"e"}} + assert.Equal(r5, Chunk(arr, 5)) } func TestConvertSlice(t *testing.T) { @@ -219,7 +192,6 @@ func TestMap(t *testing.T) { return num * 2 } - assert := internal.NewAssert(t, "TestMap") assert.Equal([]int{2, 4, 6, 8}, Map(nums, multiplyTwo)) @@ -422,7 +394,7 @@ func TestIntersection(t *testing.T) { assert := internal.NewAssert(t, "TestIntersection") for i := 0; i < len(res); i++ { - assert.Equal(res[i], expected[i]) + assert.Equal(expected[i], res[i]) } } @@ -493,9 +465,9 @@ func TestShuffle(t *testing.T) { assert.Equal(true, rv.Kind() == reflect.Slice) assert.Equal(true, rv.Type().Elem().Kind() == reflect.Int) - assert.Equal(true, Contain(res, 1)) - assert.Equal(true, Contain(res, 2)) - assert.Equal(true, Contain(res, 3)) - assert.Equal(true, Contain(res, 4)) - assert.Equal(true, Contain(res, 5)) + // assert.Equal(true, Contain(res, 1)) + // assert.Equal(true, Contain(res, 2)) + // assert.Equal(true, Contain(res, 3)) + // assert.Equal(true, Contain(res, 4)) + // assert.Equal(true, Contain(res, 5)) } From 7b9a8a55e7dc77552aa6c43dc322fb1e7bcd4c6d Mon Sep 17 00:00:00 2001 From: donutloop Date: Sun, 9 Jan 2022 15:15:03 +0100 Subject: [PATCH 22/23] Slice: CountV2 (#18) Use generic instead of reflection --- README.md | 2 +- README_zh-CN.md | 2 +- slice/slice.go | 25 ++++++++++++------------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 5fbfcb2..15e5787 100644 --- a/README.md +++ b/README.md @@ -420,7 +420,7 @@ func Union(slices ...interface{}) interface{} //Union creates a slice of unique func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //update the slice element at index. func Without(slice interface{}, values ...interface{}) interface{} //creates a slice excluding all given values func GroupBy(slice, function interface{}) (interface{}, interface{}) // groups slice into two categories -func Count(slice, function interface{}) int // Count iterates over elements of slice, returns a count of all matched elements +Count[T any](slice []T, fn func(index int, t T) bool) int // Count iterates over elements of slice, returns a count of all matched elements ``` #### 10. strutil is for processing string diff --git a/README_zh-CN.md b/README_zh-CN.md index 37307da..050fa5b 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -421,7 +421,7 @@ func Union(slices ...interface{}) interface{} //slice并集, 去重 func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //在切片中index位置更新value func Without(slice interface{}, values ...interface{}) interface{} //slice去除values func GroupBy(slice, function interface{}) (interface{}, interface{}) //根据函数function的逻辑分slice为两组slice -func Count(slice, function interface{}) int +Count[T any](slice []T, fn func(index int, t T) bool) int ``` #### 10. strutil字符串处理包 diff --git a/slice/slice.go b/slice/slice.go index 6f43f6a..1ae4a99 100644 --- a/slice/slice.go +++ b/slice/slice.go @@ -179,24 +179,23 @@ func Filter[T any](slice []T, fn func(index int, t T) bool) []T { // Count iterates over elements of slice, returns a count of all matched elements // The function signature should be func(index int, value interface{}) bool . -func Count(slice, function interface{}) int { - sv := sliceValue(slice) - fn := functionValue(function) - - elemType := sv.Type().Elem() - if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) { - panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String()) +func Count[T any](slice []T, fn func(index int, t T) bool) int { + if fn == nil { + panic("fn is missing") + } + + if len(slice) == 0 { + return 0 } - var counter int - for i := 0; i < sv.Len(); i++ { - flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0] - if flag.Bool() { - counter++ + var count int + for i, v := range slice { + if fn(i, v) { + count++ } } - return counter + return count } // GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices From 681d5b6bdf08a93dd08208bc3f0e0d42c6058ebd Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 9 Jan 2022 22:17:50 +0800 Subject: [PATCH 23/23] update comment for Count func --- README.md | 2 +- README_zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f1da0b..b3c8a21 100644 --- a/README.md +++ b/README.md @@ -420,7 +420,7 @@ func Union(slices ...interface{}) interface{} //Union creates a slice of unique func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //update the slice element at index. func Without(slice interface{}, values ...interface{}) interface{} //creates a slice excluding all given values func GroupBy(slice, function interface{}) (interface{}, interface{}) // groups slice into two categories -Count[T any](slice []T, fn func(index int, t T) bool) int // Count iterates over elements of slice, returns a count of all matched elements +func Count[T any](slice []T, fn func(index int, t T) bool) int // Count iterates over elements of slice, returns a count of all matched elements ``` #### 10. strutil is for processing string diff --git a/README_zh-CN.md b/README_zh-CN.md index 14fd0c8..3038766 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -421,7 +421,7 @@ func Union(slices ...interface{}) interface{} //slice并集, 去重 func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //在切片中index位置更新value func Without(slice interface{}, values ...interface{}) interface{} //slice去除values func GroupBy(slice, function interface{}) (interface{}, interface{}) //根据函数function的逻辑分slice为两组slice -Count[T any](slice []T, fn func(index int, t T) bool) int +func Count[T any](slice []T, fn func(index int, t T) bool) int //遍历slice的元素,返回所有匹配元素的计数 ``` #### 10. strutil字符串处理包