mirror of
https://github.com/cheat/cheat.git
synced 2026-03-07 03:03:32 +01:00
chore: bump version to 4.5.0
Bug fixes: - Fix inverted pager detection logic (returned error instead of path) - Fix repo.Clone ignoring destination directory parameter - Fix sheet loading using append on pre-sized slices - Clean up partial files on copy failure - Trim whitespace from editor config Security: - Add path traversal protection for cheatsheet names Performance: - Move regex compilation outside search loop - Replace string concatenation with strings.Join in search Build: - Remove go:generate; embed config and usage as string literals - Parallelize release builds - Add fuzz testing infrastructure Testing: - Improve test coverage from 38.9% to 50.2% - Add fuzz tests for search, filter, tags, and validation Documentation: - Fix inaccurate code examples in HACKING.md - Add missing --conf and --all options to man page - Add ADRs for path traversal, env parsing, and search parallelization - Update CONTRIBUTING.md to reflect project policy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
136
internal/display/write_test.go
Normal file
136
internal/display/write_test.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/cheat/cheat/internal/config"
|
||||
)
|
||||
|
||||
// TestWriteToPager tests the writeToPager function
|
||||
func TestWriteToPager(t *testing.T) {
|
||||
// Skip these tests in CI/CD environments where interactive commands might not work
|
||||
if os.Getenv("CI") != "" {
|
||||
t.Skip("Skipping pager tests in CI environment")
|
||||
}
|
||||
|
||||
// Note: We can't easily test os.Exit calls, so we focus on testing writeToPager
|
||||
// which contains the core logic
|
||||
|
||||
t.Run("successful pager execution", func(t *testing.T) {
|
||||
// Save original stdout
|
||||
oldStdout := os.Stdout
|
||||
defer func() {
|
||||
os.Stdout = oldStdout
|
||||
}()
|
||||
|
||||
// Create pipe for capturing output
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
// Use 'cat' as a simple pager that just outputs input
|
||||
conf := config.Config{
|
||||
Pager: "cat",
|
||||
}
|
||||
|
||||
// This will call os.Exit on error, so we need to be careful
|
||||
// We're using 'cat' which should always succeed
|
||||
input := "Test output\n"
|
||||
|
||||
// Run in a goroutine to avoid blocking
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
writeToPager(input, conf)
|
||||
done <- true
|
||||
}()
|
||||
|
||||
// Wait for completion or timeout
|
||||
select {
|
||||
case <-done:
|
||||
// Success
|
||||
}
|
||||
|
||||
// Close write end and read output
|
||||
w.Close()
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, r)
|
||||
|
||||
// Verify output
|
||||
if buf.String() != input {
|
||||
t.Errorf("expected output %q, got %q", input, buf.String())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("pager with arguments", func(t *testing.T) {
|
||||
// Save original stdout
|
||||
oldStdout := os.Stdout
|
||||
defer func() {
|
||||
os.Stdout = oldStdout
|
||||
}()
|
||||
|
||||
// Create pipe for capturing output
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
// Use 'cat' with '-A' flag (shows non-printing characters)
|
||||
conf := config.Config{
|
||||
Pager: "cat -A",
|
||||
}
|
||||
|
||||
input := "Test\toutput\n"
|
||||
|
||||
// Run in a goroutine
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
writeToPager(input, conf)
|
||||
done <- true
|
||||
}()
|
||||
|
||||
// Wait for completion
|
||||
select {
|
||||
case <-done:
|
||||
// Success
|
||||
}
|
||||
|
||||
// Close write end and read output
|
||||
w.Close()
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, r)
|
||||
|
||||
// cat -A shows tabs as ^I and line endings as $
|
||||
expected := "Test^Ioutput$\n"
|
||||
if buf.String() != expected {
|
||||
t.Errorf("expected output %q, got %q", expected, buf.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestWriteToPagerError tests error handling in writeToPager
|
||||
func TestWriteToPagerError(t *testing.T) {
|
||||
if os.Getenv("TEST_PAGER_ERROR_SUBPROCESS") == "1" {
|
||||
// This is the subprocess - run the actual test
|
||||
conf := config.Config{Pager: "/nonexistent/command"}
|
||||
writeToPager("test", conf)
|
||||
return
|
||||
}
|
||||
|
||||
// Run test in subprocess to handle os.Exit
|
||||
cmd := exec.Command(os.Args[0], "-test.run=^TestWriteToPagerError$")
|
||||
cmd.Env = append(os.Environ(), "TEST_PAGER_ERROR_SUBPROCESS=1")
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
|
||||
// Should exit with error
|
||||
if err == nil {
|
||||
t.Error("expected process to exit with error")
|
||||
}
|
||||
|
||||
// Should contain error message
|
||||
if !strings.Contains(string(output), "failed to write to pager") {
|
||||
t.Errorf("expected error message about pager failure, got %q", string(output))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user