ajhahn.de
← eeco
Go 150 lines
package guide

import (
	"bytes"
	"errors"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

func TestText_NonEmptyAndHeader(t *testing.T) {
	s := Text()
	if len(s) == 0 {
		t.Fatal("Text() is empty; usage.md missing from embed?")
	}
	if !strings.HasPrefix(s, `<div align="center">`) {
		t.Errorf("Text() does not start with the cross-repo-fingerprint header block; got %q", firstLine(s))
	}
	if !strings.Contains(s, "<h1>Usage</h1>") {
		t.Errorf("Text() is missing the <h1>Usage</h1> page title")
	}
}

// TestUsageMirrorsDocs is the drift gate. The in-package copy at
// internal/guide/usage.md must stay byte-identical to docs/USAGE.md;
// any USAGE.md edit that forgets to re-sync the mirror fails here in
// CI. Re-sync by re-running `make sync-guide` or copying the file by
// hand.
func TestUsageMirrorsDocs(t *testing.T) {
	root := repoRoot(t)
	want, err := os.ReadFile(filepath.Join(root, "docs", "USAGE.md"))
	if err != nil {
		t.Fatalf("read docs/USAGE.md: %v", err)
	}
	if !bytes.Equal([]byte(Text()), want) {
		t.Errorf("internal/guide/usage.md drifted from docs/USAGE.md — re-sync the mirror (cp docs/USAGE.md internal/guide/usage.md)")
	}
}

func TestDump_WritesEmbeddedText(t *testing.T) {
	var buf bytes.Buffer
	if err := Dump(&buf); err != nil {
		t.Fatalf("Dump returned %v", err)
	}
	if buf.String() != Text() {
		t.Error("Dump output != Text() — content diverged")
	}
}

func TestPagerCommand_HonoursPAGER(t *testing.T) {
	getenv := func(k string) string {
		if k == "PAGER" {
			return "mypager --quiet"
		}
		return ""
	}
	lookPath := func(name string) (string, error) {
		if name == "mypager" {
			return "/usr/local/bin/mypager", nil
		}
		return "", errors.New("not found")
	}
	cmd := PagerCommand("body", getenv, lookPath)
	if cmd == nil {
		t.Fatal("PagerCommand returned nil with PAGER set")
	}
	if cmd.Path != "/usr/local/bin/mypager" {
		t.Errorf("cmd.Path = %q, want %q", cmd.Path, "/usr/local/bin/mypager")
	}
	if len(cmd.Args) < 2 || cmd.Args[1] != "--quiet" {
		t.Errorf("cmd.Args = %v, want PAGER args parsed", cmd.Args)
	}
}

func TestPagerCommand_FallsBackToLess(t *testing.T) {
	getenv := func(string) string { return "" }
	lookPath := func(name string) (string, error) {
		if name == "less" {
			return "/usr/bin/less", nil
		}
		return "", errors.New("not found")
	}
	cmd := PagerCommand("body", getenv, lookPath)
	if cmd == nil {
		t.Fatal("PagerCommand returned nil with less on PATH")
	}
	if cmd.Path != "/usr/bin/less" {
		t.Errorf("cmd.Path = %q, want %q", cmd.Path, "/usr/bin/less")
	}
	if len(cmd.Args) != 2 || cmd.Args[1] != "-R" {
		t.Errorf("cmd.Args = %v, want less -R", cmd.Args)
	}
}

func TestPagerCommand_ReturnsNilWhenNoPager(t *testing.T) {
	getenv := func(string) string { return "" }
	lookPath := func(string) (string, error) {
		return "", errors.New("not found")
	}
	if cmd := PagerCommand("body", getenv, lookPath); cmd != nil {
		t.Errorf("PagerCommand = %v, want nil when no pager available", cmd)
	}
}

func TestPagerCommand_IgnoresUnresolvablePAGER(t *testing.T) {
	getenv := func(k string) string {
		if k == "PAGER" {
			return "no-such-binary"
		}
		return ""
	}
	lookPath := func(name string) (string, error) {
		if name == "less" {
			return "/usr/bin/less", nil
		}
		return "", errors.New("not found")
	}
	cmd := PagerCommand("body", getenv, lookPath)
	if cmd == nil || cmd.Path != "/usr/bin/less" {
		t.Errorf("expected fallback to less when PAGER unresolvable; got %v", cmd)
	}
}

// repoRoot walks up from the test file's working directory until it
// finds the repo's go.mod, returning the absolute path.
func repoRoot(t *testing.T) string {
	t.Helper()
	wd, err := os.Getwd()
	if err != nil {
		t.Fatalf("getwd: %v", err)
	}
	dir := wd
	for {
		if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
			return dir
		}
		parent := filepath.Dir(dir)
		if parent == dir {
			t.Fatalf("go.mod not found above %q", wd)
		}
		dir = parent
	}
}

func firstLine(s string) string {
	head, _, _ := strings.Cut(s, "\n")
	return head
}