// SPDX-License-Identifier: GPL-3.0-or-later package tui import ( "bytes" "os" "path/filepath" "strings" "testing" ) func TestColourNeedsTerminalAndNoNOCOLOR(t *testing.T) { var buf bytes.Buffer if Colour(&buf) { t.Error("colour on a non-terminal writer") } old := isTerminal t.Cleanup(func() { isTerminal = old }) isTerminal = func(fd int) bool { return true } t.Setenv("NO_COLOR", "") os.Unsetenv("NO_COLOR") if !Colour(os.Stdout) { t.Error("no colour on a terminal with NO_COLOR unset") } t.Setenv("NO_COLOR", "1") if Colour(os.Stdout) { t.Error("colour emitted with NO_COLOR set") } t.Setenv("NO_COLOR", "") if Colour(os.Stdout) { t.Error("NO_COLOR set to the empty string must still disable colour") } } func TestHeight(t *testing.T) { var buf bytes.Buffer if h := height(&buf); h != 0 { t.Errorf("height on a non-terminal writer = %d, want 0", h) } oldT, oldS := isTerminal, termSize t.Cleanup(func() { isTerminal, termSize = oldT, oldS }) isTerminal = func(fd int) bool { return true } termSize = func(fd int) (int, int, error) { return 80, 24, nil } if h := height(os.Stdout); h != 24 { t.Errorf("height = %d, want 24", h) } } // TestWidth: the terminal's column count, and 0 wherever there is no // terminal to wrap to, so a caller treats 0 as "never wrap". func TestWidth(t *testing.T) { var buf bytes.Buffer if w := Width(&buf); w != 0 { t.Errorf("Width on a non-terminal writer = %d, want 0", w) } oldT, oldS := isTerminal, termSize t.Cleanup(func() { isTerminal, termSize = oldT, oldS }) isTerminal = func(fd int) bool { return true } termSize = func(fd int) (int, int, error) { return 132, 24, nil } if w := Width(os.Stdout); w != 132 { t.Errorf("Width = %d, want 132", w) } termSize = func(fd int) (int, int, error) { return 0, 0, os.ErrInvalid } if w := Width(os.Stdout); w != 0 { t.Errorf("Width when the size cannot be read = %d, want 0", w) } } func TestPageUsesPagerOnlyWhenTaller(t *testing.T) { dir := t.TempDir() marker := filepath.Join(dir, "paged") // A pager that records what it was given. t.Setenv("PAGER", "tee "+marker) oldT, oldS := isTerminal, termSize t.Cleanup(func() { isTerminal, termSize = oldT, oldS }) isTerminal = func(fd int) bool { return true } termSize = func(fd int) (int, int, error) { return 80, 5, nil } var buf bytes.Buffer if err := Page(&buf, "one\ntwo\n"); err != nil { t.Fatal(err) } if _, err := os.Stat(marker); !os.IsNotExist(err) { t.Error("short text went through the pager") } if buf.String() != "one\ntwo\n" { t.Errorf("short text = %q", buf.String()) } tall := strings.Repeat("line\n", 20) if err := Page(&buf, tall); err != nil { t.Fatal(err) } b, err := os.ReadFile(marker) if err != nil { t.Fatalf("tall text did not reach the pager: %v", err) } if string(b) != tall { t.Errorf("the pager received %q", b) } } func TestPageCountsFinalLineWithoutTrailingNewline(t *testing.T) { dir := t.TempDir() marker := filepath.Join(dir, "paged") t.Setenv("PAGER", "tee "+marker) oldT, oldS := isTerminal, termSize t.Cleanup(func() { isTerminal, termSize = oldT, oldS }) isTerminal = func(fd int) bool { return true } termSize = func(fd int) (int, int, error) { return 80, 5, nil } // Six lines but only five newlines: one more line than the terminal's // height, with no trailing newline after the last one. text := "one\ntwo\nthree\nfour\nfive\nsix" var buf bytes.Buffer if err := Page(&buf, text); err != nil { t.Fatal(err) } b, err := os.ReadFile(marker) if err != nil { t.Fatalf("six lines with no trailing newline, one more than the terminal's height, did not reach the pager: %v", err) } if string(b) != text { t.Errorf("the pager received %q", b) } } func TestReadKeyOnAPipeReadsOneByte(t *testing.T) { r, w, err := os.Pipe() if err != nil { t.Fatal(err) } go func() { w.WriteString("ay"); w.Close() }() got, err := ReadKey(r) if err != nil { t.Fatal(err) } if got != 'a' { t.Errorf("key = %q, want 'a'", got) } }