diff --git a/trial.go b/trial.go index f85d12d..d7aa30f 100644 --- a/trial.go +++ b/trial.go @@ -3,6 +3,7 @@ package trial import ( "context" "fmt" + "os" "reflect" "runtime/debug" "strings" @@ -12,6 +13,41 @@ import ( var localTest = false +var colorEnabled bool + +func init() { + // Respect NO_COLOR standard (https://no-color.org/) + if _, noColor := os.LookupEnv("NO_COLOR"); noColor { + colorEnabled = false + return + } + // Force colors if requested + if _, forceColor := os.LookupEnv("FORCE_COLOR"); forceColor { + colorEnabled = true + return + } + // Check TERM environment variable (most terminals set this) + // Empty or "dumb" means no color support + t := os.Getenv("TERM") + colorEnabled = t != "" && t != "dumb" +} + +// colorRed wraps text in red ANSI color codes if colors are enabled. +func colorRed(s string) string { + if colorEnabled { + return "\033[31m" + s + "\033[0m" + } + return s +} + +// colorGreen wraps text in green ANSI color codes if colors are enabled. +func colorGreen(s string) string { + if colorEnabled { + return "\033[32m" + s + "\033[0m" + } + return s +} + type ( // TestFunc a wrapper function used to setup the method being tested. TestFunc func(in Input) (result interface{}, err error) @@ -107,7 +143,7 @@ func (t *Trial[In, Out]) SubTest(tst testing.TB) { if !r.Success { s := strings.Replace(r.Message, "\""+msg+"\"", "", 1) s = strings.Replace(s, "FAIL:", "", 1) - tb.Error("\033[31m" + strings.TrimLeft(s, " \n") + "\033[39m") + tb.Error(colorRed(strings.TrimLeft(s, " \n"))) } }) } @@ -128,9 +164,9 @@ func (t *Trial[In, Out]) Test(tst testing.TB) { for msg, test := range t.cases { r := t.testCase(msg, test) if r.Success { - tst.Log(r.Message) + tst.Log(colorGreen(r.Message)) } else { - tst.Error("\033[31m" + r.Message + "\033[39m") + tst.Error(colorRed(r.Message)) } } } diff --git a/trial_test.go b/trial_test.go index baaadcc..ebbb35a 100644 --- a/trial_test.go +++ b/trial_test.go @@ -2,6 +2,7 @@ package trial import ( "errors" + "os" "strings" "testing" "time" @@ -167,9 +168,9 @@ func TestTrial_TestCase(t *testing.T) { for msg, test := range cases { r := test.trial.testCase(msg, test.Case) if r.Success != test.expResult.Success || !strings.Contains(r.Message, test.expResult.Message) { - t.Errorf("\033[31mFAIL: %q\n%v\033[39m", msg, r.string()) + t.Errorf(colorRed("FAIL: %q\n%v"), msg, r.string()) } else { - t.Logf("PASS: %q", msg) + t.Logf(colorGreen("PASS: %q"), msg) } } } @@ -273,7 +274,6 @@ func TestInput(t *testing.T) { "[]string": { fn: func() interface{} { in := newInput([]string{"ab", "cd", "ef", "g"}) - in.Slice(0).String() return in.Slice(2).String() }, expected: "ef", @@ -332,30 +332,21 @@ func TestParallel(t *testing.T) { } // Test that Parallel() returns the Trial for chaining - tr := New(fn, cases).Parallel() - if tr == nil { - t.Fatal("Parallel() should return the Trial") - } - - // Test that parallel subtests execute correctly - tr.SubTest(t) + New(fn, cases).Parallel().SubTest(t) } -func TestParallel_Chaining(t *testing.T) { - fn := func(in int) (int, error) { - return in, nil - } - - cases := map[string]Case[int, int]{ - "pass through": {Input: 42, Expected: 42}, +func TestColorDiagnostics(t *testing.T) { + if colorEnabled { + t.Log("Color Enabled " + colorGreen("GREEN") + " " + colorRed("RED")) + } else { + reason := "TERM not set" + if _, ok := os.LookupEnv("NO_COLOR"); ok { + reason = "NO_COLOR" + } else if term := os.Getenv("TERM"); term == "dumb" { + reason = "TERM=dumb" + } + t.Logf("Color Disabled based on %s", reason) } - - // Test chaining with other methods - New(fn, cases). - Parallel(). - Timeout(time.Second). - Comparer(Equal). - SubTest(t) } /*