From ea246538866e4929d9edbb5232e5e5c9b34769c7 Mon Sep 17 00:00:00 2001 From: Hugo Borsoni Date: Wed, 6 Sep 2023 11:44:40 +0200 Subject: [PATCH 1/3] Add color in terminal output --- assert/assertions.go | 2 +- assert/colors.go | 28 ++++++++++++++++++++++++++++ go.mod | 3 +++ go.sum | 4 ++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 assert/colors.go diff --git a/assert/assertions.go b/assert/assertions.go index 782c8e5ce..8c1b021f7 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -421,7 +421,7 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) expected, actual = formatUnequalValues(expected, actual) return Fail(t, fmt.Sprintf("Not equal: \n"+ "expected: %s\n"+ - "actual : %s%s", expected, actual, diff), msgAndArgs...) + "actual : %s%s", greenColored(expected), redColored(actual), diff), msgAndArgs...) } return true diff --git a/assert/colors.go b/assert/colors.go new file mode 100644 index 000000000..cb0b9b2f5 --- /dev/null +++ b/assert/colors.go @@ -0,0 +1,28 @@ +package assert + +import ( + "fmt" + "os" + + "golang.org/x/term" +) + +const redMark = "\033[0;31m" +const greenMark = "\033[0;32m" +const endMark = "\033[0m" + +func redColored(i interface{}) interface{} { + if isTerminal { + return redMark + fmt.Sprintf("%s", i) + endMark + } + return i +} + +func greenColored(i interface{}) interface{} { + if isTerminal { + return greenMark + fmt.Sprintf("%s", i) + endMark + } + return i +} + +var isTerminal = term.IsTerminal(int(os.Stdout.Fd())) diff --git a/go.mod b/go.mod index d3c4d723b..0791cec06 100644 --- a/go.mod +++ b/go.mod @@ -8,5 +8,8 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/pmezard/go-difflib v1.0.0 github.com/stretchr/objx v0.5.0 + golang.org/x/term v0.12.0 gopkg.in/yaml.v3 v3.0.1 ) + +require golang.org/x/sys v0.12.0 // indirect diff --git a/go.sum b/go.sum index 4f3ced6f3..f3e522bde 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,10 @@ github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From a0f7a6988caf29811ab749d3577abfdb777c408c Mon Sep 17 00:00:00 2001 From: Hugo Borsoni Date: Wed, 6 Sep 2023 11:44:57 +0200 Subject: [PATCH 2/3] Benchmark colorizing function --- assert/colors_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 assert/colors_test.go diff --git a/assert/colors_test.go b/assert/colors_test.go new file mode 100644 index 000000000..c0b97bb8f --- /dev/null +++ b/assert/colors_test.go @@ -0,0 +1,20 @@ +package assert + +import "testing" + +func BenchmarkColored(b *testing.B) { + b.Run("benchMarkingString", func(b *testing.B) { + for i := 0; i < b.N; i++ { + greenColored("helloWorld") + } + }) + b.Run("benchMarkingStruct", func(b *testing.B) { + s := struct { + a int + b string + }{3, "helloWorld"} + for i := 0; i < b.N; i++ { + greenColored(s) + } + }) +} From 2d756387a42c1495ab6652ebceff37b5082b3cde Mon Sep 17 00:00:00 2001 From: EwenQuim Date: Wed, 6 Sep 2023 18:12:21 +0200 Subject: [PATCH 3/3] Better coloring performance This allows the compiler to inline the ANSI codes and to save 2 bytes/op, reduucing the perf at 7 bytes/op instead of 9 bytes/op. Knowing that the original code only uses 3 bytes/op, there is still space for improvement --- assert/colors.go | 16 +++++++++------- assert/colors_test.go | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/assert/colors.go b/assert/colors.go index cb0b9b2f5..aca02de41 100644 --- a/assert/colors.go +++ b/assert/colors.go @@ -7,22 +7,24 @@ import ( "golang.org/x/term" ) -const redMark = "\033[0;31m" -const greenMark = "\033[0;32m" -const endMark = "\033[0m" +const ( + redMark = "\033[0;31m" + greenMark = "\033[0;32m" + endMark = "\033[0m" +) + +var isTerminal = term.IsTerminal(int(os.Stdout.Fd())) func redColored(i interface{}) interface{} { if isTerminal { - return redMark + fmt.Sprintf("%s", i) + endMark + return fmt.Sprintf(redMark+"%s"+endMark, i) } return i } func greenColored(i interface{}) interface{} { if isTerminal { - return greenMark + fmt.Sprintf("%s", i) + endMark + return fmt.Sprintf(greenMark+"%s"+endMark, i) } return i } - -var isTerminal = term.IsTerminal(int(os.Stdout.Fd())) diff --git a/assert/colors_test.go b/assert/colors_test.go index c0b97bb8f..bb958da0f 100644 --- a/assert/colors_test.go +++ b/assert/colors_test.go @@ -1,6 +1,9 @@ package assert -import "testing" +import ( + "fmt" + "testing" +) func BenchmarkColored(b *testing.B) { b.Run("benchMarkingString", func(b *testing.B) { @@ -18,3 +21,33 @@ func BenchmarkColored(b *testing.B) { } }) } + +// Not benchmarking `Equal` but the string formatting +// because it will make the benchmark fail. +func BenchmarkEqual(b *testing.B) { + + s := struct { + a int + b string + }{3, "helloWorld"} + + b.Run("Base", func(b *testing.B) { + + for i := 0; i < b.N; i++ { + _ = fmt.Sprintf("Not equal: \n"+ + "expected: %v\n"+ + "actual : %v%s", s, s, "") + } + }) + + b.Run("Colored (test with and without terminal)", func(b *testing.B) { + // This benchmark give very different results whether the output is a terminal or not. + + for i := 0; i < b.N; i++ { + _ = fmt.Sprintf("Not equal: \n"+ + "expected: %s\n"+ + "actual : %s%s", greenColored(s), redColored(s), "") + } + }) + +}