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