summaryrefslogtreecommitdiff
path: root/internal/cli/pager_test.go
blob: 4850e5e264c20d36e1c96faa295e53052d6b8b8f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package cli

import (
	"bytes"
	"testing"

	"github.com/lukaszkasprzak/lectio/internal/config"
)

// TestPagerRequested exercises pagerRequested's precedence: --no-pager beats
// -P beats a non-empty cfg.Pager; with nothing set, paging is off.
func TestPagerRequested(t *testing.T) {
	cases := []struct {
		name               string
		pagerFlag, noPager bool
		cfgPager           string
		want               bool
	}{
		{"nothing set", false, false, "", false},
		{"cfg.Pager set alone", false, false, "less -R", true},
		{"-P alone", true, false, "", true},
		{"-P overrides empty cfg", true, false, "", true},
		{"--no-pager beats -P", true, true, "", false},
		{"--no-pager beats cfg.Pager", false, true, "less -R", false},
		{"--no-pager beats both", true, true, "less -R", false},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			cfg := config.Config{Pager: c.cfgPager}
			got := pagerRequested(c.pagerFlag, c.noPager, cfg)
			if got != c.want {
				t.Errorf("pagerRequested(%v, %v, Pager=%q) = %v, want %v",
					c.pagerFlag, c.noPager, c.cfgPager, got, c.want)
			}
		})
	}
}

// TestPagerCommand exercises pagerCommand's fallback chain: cfg.Pager wins,
// then $PAGER, then the "less -R" built-in default. No exec happens here.
func TestPagerCommand(t *testing.T) {
	t.Run("cfg.Pager set", func(t *testing.T) {
		t.Setenv("PAGER", "most")
		cfg := config.Config{Pager: "more -c"}
		got := pagerCommand(cfg)
		want := []string{"more", "-c"}
		if !equalStrings(got, want) {
			t.Errorf("pagerCommand = %v, want %v", got, want)
		}
	})

	t.Run("cfg empty, PAGER set", func(t *testing.T) {
		t.Setenv("PAGER", "most")
		cfg := config.Config{}
		got := pagerCommand(cfg)
		want := []string{"most"}
		if !equalStrings(got, want) {
			t.Errorf("pagerCommand = %v, want %v", got, want)
		}
	})

	t.Run("both empty falls back to less -R", func(t *testing.T) {
		t.Setenv("PAGER", "")
		cfg := config.Config{}
		got := pagerCommand(cfg)
		want := []string{"less", "-R"}
		if !equalStrings(got, want) {
			t.Errorf("pagerCommand = %v, want %v", got, want)
		}
	})
}

func equalStrings(a, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

// TestIsTerminalWriterBuffer confirms a bytes.Buffer (what every test uses
// for stdout) is never treated as a terminal, so Run never pages in tests.
func TestIsTerminalWriterBuffer(t *testing.T) {
	if isTerminalWriter(&bytes.Buffer{}) {
		t.Error("isTerminalWriter(&bytes.Buffer{}) = true, want false")
	}
}

// TestPagerFlagDoesNotBreakBufferOutput confirms -P set against a
// bytes.Buffer stdout (non-TTY) still writes plainly -- pagerRequested may
// be true, but isTerminalWriter gates it off, so Run's existing dispatch
// runs unchanged.
func TestPagerFlagDoesNotBreakBufferOutput(t *testing.T) {
	t.Setenv("XDG_CONFIG_HOME", t.TempDir())
	var out, errb bytes.Buffer
	// (The former -o/--offline flag is gone: the daily view is always offline.)
	code := Run([]string{"-P", "-l", "trad", "2026-07-22"}, nil, &out, &errb)
	if code != 0 && code != 1 {
		t.Fatalf("-P run code=%d (stderr=%q)", code, errb.String())
	}
	// The key assertion: no hang, no panic, output goes to the buffer
	// directly (a real pager exec would have blocked/failed differently).
	if out.Len() == 0 && code == 0 {
		t.Errorf("-P run produced no stdout output on success")
	}
}