From 0e3b2dca245a9088097359214f43d143ca1749ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Fri, 9 Feb 2024 12:56:21 +0100 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20ToStrin?= =?UTF-8?q?g:=20improve=20test=20and=20bench=20setup=20-=20add=20string=20?= =?UTF-8?q?slice=20case=20-=20add=20parallel=20instruction=20for=20child?= =?UTF-8?q?=20tests=20-=20benchmark=20table=20and=20parallel=20execution?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- convert_test.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/convert_test.go b/convert_test.go index ddc8c1a..f902083 100644 --- a/convert_test.go +++ b/convert_test.go @@ -92,10 +92,12 @@ func Test_ToString(t *testing.T) { {float64(3.14159), "3.14159"}, {time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC), "2000-01-01 12:34:56"}, {struct{ Name string }{"John"}, "{John}"}, + {[]string{"Hello", "World"}, "[Hello World]"}, } for _, tc := range tests { t.Run(reflect.TypeOf(tc.input).String(), func(t *testing.T) { + t.Parallel() res := ToString(tc.input) require.Equal(t, tc.expected, res) }) @@ -111,6 +113,7 @@ func Test_ToString(t *testing.T) { } for _, tc := range testsPtr { t.Run("pointer to "+reflect.TypeOf(tc.input).Elem().String(), func(t *testing.T) { + t.Parallel() res := ToString(tc.input) require.Equal(t, tc.expected, res) }) @@ -136,10 +139,16 @@ func Benchmark_ToString(b *testing.B) { float32(3.14), float64(3.14), time.Now(), + []string{"Hello", "World"}, } - for n := 0; n < b.N; n++ { - for _, value := range values { - _ = ToString(value) - } + for _, value := range values { + b.Run(reflect.TypeOf(value).String(), func(b *testing.B) { + b.ReportAllocs() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + _ = ToString(value) + } + }) + }) } } From 6171b84f5bc0d8107eccc15c13ad586124c7cfb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Fri, 9 Feb 2024 14:11:54 +0100 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20ToStrin?= =?UTF-8?q?g:=20improve=20test=20and=20bench=20setup=20-=20handle=20slices?= =?UTF-8?q?=20and=20arrays?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- convert.go | 13 +++++++++++++ convert_test.go | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/convert.go b/convert.go index bd73a2c..1926dcd 100644 --- a/convert.go +++ b/convert.go @@ -138,7 +138,20 @@ func ToString(arg any, timeFormat ...string) string { if rv.Kind() == reflect.Ptr && !rv.IsNil() { // Dereference the pointer and recursively call ToString return ToString(rv.Elem().Interface(), timeFormat...) + } else if rv.Kind() == reflect.Slice || rv.Kind() == reflect.Array { + // handle slices + var buf strings.Builder + buf.WriteString("[") + for i := 0; i < rv.Len(); i++ { + if i > 0 { + buf.WriteString(" ") + } + buf.WriteString(ToString(rv.Index(i).Interface())) + } + buf.WriteString("]") + return buf.String() } + // For types not explicitly handled, use fmt.Sprint to generate a string representation return fmt.Sprint(arg) } diff --git a/convert_test.go b/convert_test.go index f902083..7d0f839 100644 --- a/convert_test.go +++ b/convert_test.go @@ -93,9 +93,13 @@ func Test_ToString(t *testing.T) { {time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC), "2000-01-01 12:34:56"}, {struct{ Name string }{"John"}, "{John}"}, {[]string{"Hello", "World"}, "[Hello World]"}, + {[]int{42, 21}, "[42 21]"}, + {[2]int{42, 21}, "[42 21]"}, + {[]interface{}{[]int{42, 21}, 42, "Hello", true, []string{"Hello", "World"}}, "[[42 21] 42 Hello true [Hello World]]"}, } for _, tc := range tests { + tc := tc t.Run(reflect.TypeOf(tc.input).String(), func(t *testing.T) { t.Parallel() res := ToString(tc.input) @@ -112,6 +116,7 @@ func Test_ToString(t *testing.T) { {&intPtr, "42"}, } for _, tc := range testsPtr { + tc := tc t.Run("pointer to "+reflect.TypeOf(tc.input).Elem().String(), func(t *testing.T) { t.Parallel() res := ToString(tc.input) @@ -140,6 +145,9 @@ func Benchmark_ToString(b *testing.B) { float64(3.14), time.Now(), []string{"Hello", "World"}, + []int{42, 21}, + [2]int{42, 21}, + []interface{}{[]int{42, 21}, 42, "Hello", true, []string{"Hello", "World"}}, } for _, value := range values { b.Run(reflect.TypeOf(value).String(), func(b *testing.B) { From e00da2ac657e73d44e9822a72e943a24d70cbaac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Fri, 9 Feb 2024 14:40:44 +0100 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20ToStrin?= =?UTF-8?q?g:=20improve=20test=20and=20bench=20setup=20-=20sequential=20an?= =?UTF-8?q?d=20parallel=20benchmark?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- convert_test.go | 63 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/convert_test.go b/convert_test.go index 7d0f839..622412a 100644 --- a/convert_test.go +++ b/convert_test.go @@ -12,6 +12,33 @@ import ( "github.com/stretchr/testify/require" ) +var dataTypeExamples []interface{} + +func init() { + dataTypeExamples = []interface{}{ + 42, + int8(42), + int16(42), + int32(42), + int64(42), + uint(42), + uint8(42), + uint16(42), + uint32(42), + uint64(42), + "Hello, World!", + []byte("Hello, World!"), + true, + float32(3.14), + float64(3.14), + time.Now(), + []string{"Hello", "World"}, + []int{42, 21}, + [2]int{42, 21}, + []interface{}{[]int{42, 21}, 42, "Hello", true, []string{"Hello", "World"}}, + } +} + func Test_UnsafeString(t *testing.T) { t.Parallel() res := UnsafeString([]byte("Hello, World!")) @@ -127,31 +154,23 @@ func Test_ToString(t *testing.T) { // go test -v -run=^$ -bench=ToString -benchmem -count=4 func Benchmark_ToString(b *testing.B) { - values := []interface{}{ - 42, - int8(42), - int16(42), - int32(42), - int64(42), - uint(42), - uint8(42), - uint16(42), - uint32(42), - uint64(42), - "Hello, World!", - []byte("Hello, World!"), - true, - float32(3.14), - float64(3.14), - time.Now(), - []string{"Hello", "World"}, - []int{42, 21}, - [2]int{42, 21}, - []interface{}{[]int{42, 21}, 42, "Hello", true, []string{"Hello", "World"}}, + for _, value := range dataTypeExamples { + b.Run(reflect.TypeOf(value).String(), func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ToString(value) + } + }) } - for _, value := range values { +} + +// go test -v -run=^$ -bench=ToString_concurrency -benchmem -count=4 +func Benchmark_ToString_concurrency(b *testing.B) { + for _, value := range dataTypeExamples { b.Run(reflect.TypeOf(value).String(), func(b *testing.B) { b.ReportAllocs() + b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = ToString(value) From fb9aac5b7b2b1acb8146ae3445fcd33f811f3a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Fri, 9 Feb 2024 14:42:17 +0100 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20ToStrin?= =?UTF-8?q?g:=20improve=20test=20and=20bench=20setup=20-=20add=20[][]int?= =?UTF-8?q?=20case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- convert_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/convert_test.go b/convert_test.go index 622412a..b965cb0 100644 --- a/convert_test.go +++ b/convert_test.go @@ -35,6 +35,7 @@ func init() { []string{"Hello", "World"}, []int{42, 21}, [2]int{42, 21}, + [][]int{{42, 21}, {42, 21}}, []interface{}{[]int{42, 21}, 42, "Hello", true, []string{"Hello", "World"}}, } } @@ -122,6 +123,7 @@ func Test_ToString(t *testing.T) { {[]string{"Hello", "World"}, "[Hello World]"}, {[]int{42, 21}, "[42 21]"}, {[2]int{42, 21}, "[42 21]"}, + {[][]int{{42, 21}, {42, 21}}, "[[42 21] [42 21]]"}, {[]interface{}{[]int{42, 21}, 42, "Hello", true, []string{"Hello", "World"}}, "[[42 21] 42 Hello true [Hello World]]"}, }