...

Source file src/github.com/muesli/termenv/termenv_test.go

Documentation: github.com/muesli/termenv

     1  package termenv
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"image/color"
     7  	"io/ioutil"
     8  	"os"
     9  	"strings"
    10  	"testing"
    11  	"text/template"
    12  )
    13  
    14  func TestLegacyTermEnv(t *testing.T) {
    15  	p := ColorProfile()
    16  	if p != TrueColor && p != Ascii {
    17  		t.Errorf("Expected %d, got %d", TrueColor, p)
    18  	}
    19  
    20  	fg := ForegroundColor()
    21  	fgseq := fg.Sequence(false)
    22  	fgexp := "97"
    23  	if fgseq != fgexp && fgseq != "" {
    24  		t.Errorf("Expected %s, got %s", fgexp, fgseq)
    25  	}
    26  
    27  	bg := BackgroundColor()
    28  	bgseq := bg.Sequence(true)
    29  	bgexp := "48;2;0;0;0"
    30  	if bgseq != bgexp && bgseq != "" {
    31  		t.Errorf("Expected %s, got %s", bgexp, bgseq)
    32  	}
    33  
    34  	_ = HasDarkBackground()
    35  }
    36  
    37  func TestTermEnv(t *testing.T) {
    38  	o := NewOutput(os.Stdout)
    39  	if o.Profile != TrueColor && o.Profile != Ascii {
    40  		t.Errorf("Expected %d, got %d", TrueColor, o.Profile)
    41  	}
    42  
    43  	fg := o.ForegroundColor()
    44  	fgseq := fg.Sequence(false)
    45  	fgexp := "97"
    46  	if fgseq != fgexp && fgseq != "" {
    47  		t.Errorf("Expected %s, got %s", fgexp, fgseq)
    48  	}
    49  
    50  	bg := o.BackgroundColor()
    51  	bgseq := bg.Sequence(true)
    52  	bgexp := "48;2;0;0;0"
    53  	if bgseq != bgexp && bgseq != "" {
    54  		t.Errorf("Expected %s, got %s", bgexp, bgseq)
    55  	}
    56  
    57  	_ = HasDarkBackground()
    58  }
    59  
    60  func TestRendering(t *testing.T) {
    61  	out := String("foobar")
    62  	if out.String() != "foobar" {
    63  		t.Errorf("Unstyled strings should be returned as plain text")
    64  	}
    65  
    66  	out = out.Foreground(TrueColor.Color("#abcdef"))
    67  	out = out.Background(TrueColor.Color("69"))
    68  	out = out.Bold()
    69  	out = out.Italic()
    70  	out = out.Faint()
    71  	out = out.Underline()
    72  	out = out.Blink()
    73  
    74  	exp := "\x1b[38;2;171;205;239;48;5;69;1;3;2;4;5mfoobar\x1b[0m"
    75  	if out.String() != exp {
    76  		t.Errorf("Expected %s, got %s", exp, out.String())
    77  	}
    78  
    79  	exp = "foobar"
    80  	mono := String(exp)
    81  	mono = mono.Foreground(Ascii.Color("#abcdef"))
    82  	if mono.String() != exp {
    83  		t.Errorf("Ascii profile should not apply color styles")
    84  	}
    85  }
    86  
    87  func TestColorConversion(t *testing.T) {
    88  	// ANSI color
    89  	a := ANSI.Color("7")
    90  	c := ConvertToRGB(a)
    91  
    92  	exp := "#c0c0c0"
    93  	if c.Hex() != exp {
    94  		t.Errorf("Expected %s, got %s", exp, c.Hex())
    95  	}
    96  
    97  	// ANSI-256 color
    98  	a256 := ANSI256.Color("91")
    99  	c = ConvertToRGB(a256)
   100  
   101  	exp = "#8700af"
   102  	if c.Hex() != exp {
   103  		t.Errorf("Expected %s, got %s", exp, c.Hex())
   104  	}
   105  
   106  	// hex color
   107  	hex := "#abcdef"
   108  	argb := TrueColor.Color(hex)
   109  	c = ConvertToRGB(argb)
   110  
   111  	if c.Hex() != hex {
   112  		t.Errorf("Expected %s, got %s", exp, c.Hex())
   113  	}
   114  }
   115  
   116  func TestFromColor(t *testing.T) {
   117  	// color.Color interface
   118  	c := TrueColor.FromColor(color.RGBA{255, 128, 0, 255})
   119  	exp := "38;2;255;128;0"
   120  	if c.Sequence(false) != exp {
   121  		t.Errorf("Expected %s, got %s", exp, c.Sequence(false))
   122  	}
   123  }
   124  
   125  func TestAscii(t *testing.T) {
   126  	c := Ascii.Color("#abcdef")
   127  	if c.Sequence(false) != "" {
   128  		t.Errorf("Expected empty sequence, got %s", c.Sequence(false))
   129  	}
   130  }
   131  
   132  func TestANSIProfile(t *testing.T) {
   133  	p := ANSI
   134  
   135  	c := p.Color("#e88388")
   136  	exp := "91"
   137  	if c.Sequence(false) != exp {
   138  		t.Errorf("Expected %s, got %s", exp, c.Sequence(false))
   139  	}
   140  	if _, ok := c.(ANSIColor); !ok {
   141  		t.Errorf("Expected type termenv.ANSIColor, got %T", c)
   142  	}
   143  
   144  	c = p.Color("82")
   145  	exp = "92"
   146  	if c.Sequence(false) != exp {
   147  		t.Errorf("Expected %s, got %s", exp, c.Sequence(false))
   148  	}
   149  	if _, ok := c.(ANSIColor); !ok {
   150  		t.Errorf("Expected type termenv.ANSIColor, got %T", c)
   151  	}
   152  
   153  	c = p.Color("2")
   154  	exp = "32"
   155  	if c.Sequence(false) != exp {
   156  		t.Errorf("Expected %s, got %s", exp, c.Sequence(false))
   157  	}
   158  	if _, ok := c.(ANSIColor); !ok {
   159  		t.Errorf("Expected type termenv.ANSIColor, got %T", c)
   160  	}
   161  }
   162  
   163  func TestANSI256Profile(t *testing.T) {
   164  	p := ANSI256
   165  
   166  	c := p.Color("#abcdef")
   167  	exp := "38;5;153"
   168  	if c.Sequence(false) != exp {
   169  		t.Errorf("Expected %s, got %s", exp, c.Sequence(false))
   170  	}
   171  	if _, ok := c.(ANSI256Color); !ok {
   172  		t.Errorf("Expected type termenv.ANSI256Color, got %T", c)
   173  	}
   174  
   175  	c = p.Color("139")
   176  	exp = "38;5;139"
   177  	if c.Sequence(false) != exp {
   178  		t.Errorf("Expected %s, got %s", exp, c.Sequence(false))
   179  	}
   180  	if _, ok := c.(ANSI256Color); !ok {
   181  		t.Errorf("Expected type termenv.ANSI256Color, got %T", c)
   182  	}
   183  
   184  	c = p.Color("2")
   185  	exp = "32"
   186  	if c.Sequence(false) != exp {
   187  		t.Errorf("Expected %s, got %s", exp, c.Sequence(false))
   188  	}
   189  	if _, ok := c.(ANSIColor); !ok {
   190  		t.Errorf("Expected type termenv.ANSIColor, got %T", c)
   191  	}
   192  }
   193  
   194  func TestTrueColorProfile(t *testing.T) {
   195  	p := TrueColor
   196  
   197  	c := p.Color("#abcdef")
   198  	exp := "38;2;171;205;239"
   199  	if c.Sequence(false) != exp {
   200  		t.Errorf("Expected %s, got %s", exp, c.Sequence(false))
   201  	}
   202  	if _, ok := c.(RGBColor); !ok {
   203  		t.Errorf("Expected type termenv.HexColor, got %T", c)
   204  	}
   205  
   206  	c = p.Color("139")
   207  	exp = "38;5;139"
   208  	if c.Sequence(false) != exp {
   209  		t.Errorf("Expected %s, got %s", exp, c.Sequence(false))
   210  	}
   211  	if _, ok := c.(ANSI256Color); !ok {
   212  		t.Errorf("Expected type termenv.ANSI256Color, got %T", c)
   213  	}
   214  
   215  	c = p.Color("2")
   216  	exp = "32"
   217  	if c.Sequence(false) != exp {
   218  		t.Errorf("Expected %s, got %s", exp, c.Sequence(false))
   219  	}
   220  	if _, ok := c.(ANSIColor); !ok {
   221  		t.Errorf("Expected type termenv.ANSIColor, got %T", c)
   222  	}
   223  }
   224  
   225  func TestStyles(t *testing.T) {
   226  	s := String("foobar").Foreground(TrueColor.Color("2"))
   227  
   228  	exp := "\x1b[32mfoobar\x1b[0m"
   229  	if s.String() != exp {
   230  		t.Errorf("Expected %s, got %s", exp, s.String())
   231  	}
   232  }
   233  
   234  func TestTemplateHelpers(t *testing.T) {
   235  	p := TrueColor
   236  
   237  	exp := String("Hello World")
   238  	basetpl := `{{ %s "Hello World" }}`
   239  	wraptpl := `{{ %s (%s "Hello World") }}`
   240  
   241  	tt := []struct {
   242  		Template string
   243  		Expected string
   244  	}{
   245  		{
   246  			Template: fmt.Sprintf(basetpl, "Bold"),
   247  			Expected: exp.Bold().String(),
   248  		},
   249  		{
   250  			Template: fmt.Sprintf(basetpl, "Faint"),
   251  			Expected: exp.Faint().String(),
   252  		},
   253  		{
   254  			Template: fmt.Sprintf(basetpl, "Italic"),
   255  			Expected: exp.Italic().String(),
   256  		},
   257  		{
   258  			Template: fmt.Sprintf(basetpl, "Underline"),
   259  			Expected: exp.Underline().String(),
   260  		},
   261  		{
   262  			Template: fmt.Sprintf(basetpl, "Overline"),
   263  			Expected: exp.Overline().String(),
   264  		},
   265  		{
   266  			Template: fmt.Sprintf(basetpl, "Blink"),
   267  			Expected: exp.Blink().String(),
   268  		},
   269  		{
   270  			Template: fmt.Sprintf(basetpl, "Reverse"),
   271  			Expected: exp.Reverse().String(),
   272  		},
   273  		{
   274  			Template: fmt.Sprintf(basetpl, "CrossOut"),
   275  			Expected: exp.CrossOut().String(),
   276  		},
   277  		{
   278  			Template: fmt.Sprintf(wraptpl, "Underline", "Bold"),
   279  			Expected: String(exp.Bold().String()).Underline().String(),
   280  		},
   281  		{
   282  			Template: `{{ Color "#ff0000" "foobar" }}`,
   283  			Expected: String("foobar").Foreground(p.Color("#ff0000")).String(),
   284  		},
   285  		{
   286  			Template: `{{ Color "#ff0000" "#0000ff" "foobar" }}`,
   287  			Expected: String("foobar").
   288  				Foreground(p.Color("#ff0000")).
   289  				Background(p.Color("#0000ff")).
   290  				String(),
   291  		},
   292  		{
   293  			Template: `{{ Foreground "#ff0000" "foobar" }}`,
   294  			Expected: String("foobar").Foreground(p.Color("#ff0000")).String(),
   295  		},
   296  		{
   297  			Template: `{{ Background "#ff0000" "foobar" }}`,
   298  			Expected: String("foobar").Background(p.Color("#ff0000")).String(),
   299  		},
   300  	}
   301  
   302  	for i, v := range tt {
   303  		tpl, err := template.New(fmt.Sprintf("test_%d", i)).Funcs(TemplateFuncs(p)).Parse(v.Template)
   304  		if err != nil {
   305  			t.Error(err)
   306  		}
   307  
   308  		var buf bytes.Buffer
   309  		err = tpl.Execute(&buf, nil)
   310  		if err != nil {
   311  			t.Error(err)
   312  		}
   313  
   314  		if buf.String() != v.Expected {
   315  			v1 := strings.Replace(v.Expected, "\x1b", "", -1)
   316  			v2 := strings.Replace(buf.String(), "\x1b", "", -1)
   317  			t.Errorf("Expected %s, got %s", v1, v2)
   318  		}
   319  	}
   320  }
   321  
   322  func TestEnvNoColor(t *testing.T) {
   323  	tests := []struct {
   324  		name     string
   325  		environ  []string
   326  		expected bool
   327  	}{
   328  		{"no env", nil, false},
   329  		{"no_color", []string{"NO_COLOR", "Y"}, true},
   330  		{"no_color+clicolor=1", []string{"NO_COLOR", "Y", "CLICOLOR", "1"}, true},
   331  		{"no_color+clicolor_force=1", []string{"NO_COLOR", "Y", "CLICOLOR_FORCE", "1"}, true},
   332  		{"clicolor=0", []string{"CLICOLOR", "0"}, true},
   333  		{"clicolor=1", []string{"CLICOLOR", "1"}, false},
   334  		{"clicolor_force=1", []string{"CLICOLOR_FORCE", "0"}, false},
   335  		{"clicolor_force=0", []string{"CLICOLOR_FORCE", "1"}, false},
   336  		{"clicolor=0+clicolor_force=1", []string{"CLICOLOR", "0", "CLICOLOR_FORCE", "1"}, false},
   337  		{"clicolor=1+clicolor_force=1", []string{"CLICOLOR", "1", "CLICOLOR_FORCE", "1"}, false},
   338  		{"clicolor=0+clicolor_force=0", []string{"CLICOLOR", "0", "CLICOLOR_FORCE", "0"}, true},
   339  		{"clicolor=1+clicolor_force=0", []string{"CLICOLOR", "1", "CLICOLOR_FORCE", "0"}, false},
   340  	}
   341  	for _, test := range tests {
   342  		t.Run(test.name, func(t *testing.T) {
   343  			defer func() {
   344  				os.Unsetenv("NO_COLOR")
   345  				os.Unsetenv("CLICOLOR")
   346  				os.Unsetenv("CLICOLOR_FORCE")
   347  			}()
   348  			for i := 0; i < len(test.environ); i += 2 {
   349  				os.Setenv(test.environ[i], test.environ[i+1])
   350  			}
   351  			out := NewOutput(os.Stdout)
   352  			actual := out.EnvNoColor()
   353  			if test.expected != actual {
   354  				t.Errorf("expected %t but was %t", test.expected, actual)
   355  			}
   356  		})
   357  	}
   358  }
   359  
   360  func TestPseudoTerm(t *testing.T) {
   361  	buf := &bytes.Buffer{}
   362  	o := NewOutput(buf)
   363  	if o.Profile != Ascii {
   364  		t.Errorf("Expected %d, got %d", Ascii, o.Profile)
   365  	}
   366  
   367  	fg := o.ForegroundColor()
   368  	fgseq := fg.Sequence(false)
   369  	if fgseq != "" {
   370  		t.Errorf("Expected empty response, got %s", fgseq)
   371  	}
   372  
   373  	bg := o.BackgroundColor()
   374  	bgseq := bg.Sequence(true)
   375  	if bgseq != "" {
   376  		t.Errorf("Expected empty response, got %s", bgseq)
   377  	}
   378  
   379  	exp := "foobar"
   380  	out := o.String(exp)
   381  	out = out.Foreground(o.Color("#abcdef"))
   382  	o.Write([]byte(out.String()))
   383  
   384  	if buf.String() != exp {
   385  		t.Errorf("Expected %s, got %s", exp, buf.String())
   386  	}
   387  }
   388  
   389  func TestCache(t *testing.T) {
   390  	o := NewOutput(os.Stdout, WithColorCache(true), WithProfile(TrueColor))
   391  
   392  	if o.cache != true {
   393  		t.Errorf("Expected cache to be active, got %t", o.cache)
   394  	}
   395  }
   396  
   397  func TestEnableVirtualTerminalProcessing(t *testing.T) {
   398  	// EnableVirtualTerminalProcessing should always return a non-nil
   399  	// restoreFunc, and in tests it should never return an error.
   400  	restoreFunc, err := EnableVirtualTerminalProcessing(NewOutput(os.Stdout))
   401  	if restoreFunc == nil || err != nil {
   402  		t.Fatalf("expected non-<nil>, <nil>, got %p, %v", restoreFunc, err)
   403  	}
   404  	// In tests, restoreFunc should never return an error.
   405  	if err := restoreFunc(); err != nil {
   406  		t.Fatalf("expected <nil>, got %v", err)
   407  	}
   408  }
   409  
   410  func TestWithTTY(t *testing.T) {
   411  	for _, v := range []bool{true, false} {
   412  		o := NewOutput(ioutil.Discard, WithTTY(v))
   413  		if o.isTTY() != v {
   414  			t.Fatalf("expected WithTTY(%t) to set isTTY to %t", v, v)
   415  		}
   416  	}
   417  }
   418  

View as plain text