test: audit and clean up test suite

Delete tautological, no-assertion, and permanently-skipped tests.
Rewrite false-confidence tests that couldn't detect the bugs they
claimed to test. Decouple brittle assertions from error message
strings and third-party library output. Fix misleading test names
and error messages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Christopher Allen Lane
2026-02-15 12:42:11 -05:00
parent d4a8a79628
commit 971be88150
12 changed files with 67 additions and 301 deletions

View File

@@ -9,7 +9,6 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"testing" "testing"
"time"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
@@ -108,23 +107,15 @@ cheatpaths:
cmd := exec.Command(cheatBin, tc.args...) cmd := exec.Command(cheatBin, tc.args...)
cmd.Env = env cmd.Env = env
// Capture output to prevent spamming
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout cmd.Stdout = &stdout
cmd.Stderr = &stderr cmd.Stderr = &stderr
start := time.Now()
err := cmd.Run() err := cmd.Run()
elapsed := time.Since(start)
if err != nil { if err != nil {
b.Fatalf("Command failed: %v\nStderr: %s", err, stderr.String()) b.Fatalf("Command failed: %v\nStderr: %s", err, stderr.String())
} }
// Report custom metric
b.ReportMetric(float64(elapsed.Nanoseconds())/1e6, "ms/op")
// Ensure we got some results
if stdout.Len() == 0 { if stdout.Len() == 0 {
b.Fatal("No output from search") b.Fatal("No output from search")
} }

View File

@@ -88,26 +88,3 @@ func TestCheatpathValidate(t *testing.T) {
}) })
} }
} }
func TestCheatpathStruct(t *testing.T) {
// Test that the struct fields work as expected
cp := Cheatpath{
Name: "test",
Path: "/test/path",
ReadOnly: true,
Tags: []string{"tag1", "tag2"},
}
if cp.Name != "test" {
t.Errorf("expected Name to be 'test', got %q", cp.Name)
}
if cp.Path != "/test/path" {
t.Errorf("expected Path to be '/test/path', got %q", cp.Path)
}
if !cp.ReadOnly {
t.Error("expected ReadOnly to be true")
}
if len(cp.Tags) != 2 || cp.Tags[0] != "tag1" || cp.Tags[1] != "tag2" {
t.Errorf("expected Tags to be [tag1 tag2], got %v", cp.Tags)
}
}

View File

@@ -3,7 +3,6 @@ package config
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"testing" "testing"
"github.com/cheat/cheat/internal/mock" "github.com/cheat/cheat/internal/mock"
@@ -19,7 +18,7 @@ func TestConfigYAMLErrors(t *testing.T) {
defer os.RemoveAll(tempDir) defer os.RemoveAll(tempDir)
invalidYAML := filepath.Join(tempDir, "invalid.yml") invalidYAML := filepath.Join(tempDir, "invalid.yml")
err = os.WriteFile(invalidYAML, []byte("invalid: yaml: content:\n - no closing"), 0644) err = os.WriteFile(invalidYAML, []byte("cheatpaths: [{unclosed\n"), 0644)
if err != nil { if err != nil {
t.Fatalf("failed to write invalid yaml: %v", err) t.Fatalf("failed to write invalid yaml: %v", err)
} }
@@ -335,7 +334,10 @@ cheatpaths:
} }
// Verify symlink was resolved // Verify symlink was resolved
if len(conf.Cheatpaths) > 0 && conf.Cheatpaths[0].Path != targetDir { if len(conf.Cheatpaths) == 0 {
t.Fatal("expected at least one cheatpath, got none")
}
if conf.Cheatpaths[0].Path != targetDir {
t.Errorf("expected symlink to be resolved to %s, got %s", targetDir, conf.Cheatpaths[0].Path) t.Errorf("expected symlink to be resolved to %s, got %s", targetDir, conf.Cheatpaths[0].Path)
} }
} }
@@ -380,70 +382,3 @@ cheatpaths:
t.Errorf("expected broken cheatpath to be filtered out, got %d cheatpaths", len(conf.Cheatpaths)) t.Errorf("expected broken cheatpath to be filtered out, got %d cheatpaths", len(conf.Cheatpaths))
} }
} }
// TestConfigTildeExpansionError tests tilde expansion error handling
func TestConfigTildeExpansionError(t *testing.T) {
// This is tricky to test without mocking homedir.Expand
// We'll create a config with an invalid home reference
tempDir, err := os.MkdirTemp("", "cheat-config-test-*")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)
// Create config with user that likely doesn't exist
configContent := `---
editor: vim
cheatpaths:
- name: test
path: ~nonexistentuser12345/cheat
readonly: true
`
configFile := filepath.Join(tempDir, "config.yml")
err = os.WriteFile(configFile, []byte(configContent), 0644)
if err != nil {
t.Fatalf("failed to write config: %v", err)
}
// Load config - this may or may not fail depending on the system
// but we're testing that it doesn't panic
_, _ = New(map[string]interface{}{}, configFile, false)
}
// TestConfigGetCwdError tests error handling when os.Getwd fails
func TestConfigGetCwdError(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Windows does not allow removing the current directory")
}
// This is difficult to test without being able to break os.Getwd
// We'll create a scenario where the current directory is removed
// Create and enter a temp directory
tempDir, err := os.MkdirTemp("", "cheat-config-test-*")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
oldCwd, err := os.Getwd()
if err != nil {
t.Fatalf("failed to get cwd: %v", err)
}
defer os.Chdir(oldCwd)
err = os.Chdir(tempDir)
if err != nil {
t.Fatalf("failed to change dir: %v", err)
}
// Remove the directory we're in
err = os.RemoveAll(tempDir)
if err != nil {
t.Fatalf("failed to remove temp dir: %v", err)
}
// Now os.Getwd should fail
_, err = New(map[string]interface{}{}, mock.Path("conf/empty.yml"), false)
// This might not fail on all systems, so we just ensure no panic
_ = err
}

View File

@@ -4,7 +4,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings"
"testing" "testing"
) )
@@ -90,9 +89,6 @@ func TestInitWriteError(t *testing.T) {
if err == nil { if err == nil {
t.Error("expected error when writing to invalid path, got nil") t.Error("expected error when writing to invalid path, got nil")
} }
if err != nil && !strings.Contains(err.Error(), "failed to create") {
t.Errorf("expected 'failed to create' error, got: %v", err)
}
} }
// TestInitExistingFile tests that Init overwrites existing files // TestInitExistingFile tests that Init overwrites existing files

View File

@@ -2,6 +2,7 @@ package config
import ( import (
"os" "os"
"path/filepath"
"runtime" "runtime"
"testing" "testing"
) )
@@ -44,29 +45,20 @@ func TestPager(t *testing.T) {
os.Setenv("PAGER", "") os.Setenv("PAGER", "")
pager := Pager() pager := Pager()
// Should find one of the fallback pagers or return empty string if pager == "" {
return // no pager found is acceptable
}
// Should find one of the known fallback pagers
validPagers := map[string]bool{ validPagers := map[string]bool{
"": true, // no pager found
"pager": true, "pager": true,
"less": true, "less": true,
"more": true, "more": true,
} }
// Check if it's a path to one of these base := filepath.Base(pager)
found := false if !validPagers[base] {
for p := range validPagers { t.Errorf("unexpected pager value: %s (base: %s)", pager, base)
if p == "" && pager == "" {
found = true
break
}
if p != "" && (pager == p || len(pager) >= len(p) && pager[len(pager)-len(p):] == p) {
found = true
break
}
}
if !found {
t.Errorf("unexpected pager value: %s", pager)
} }
}) })

View File

@@ -71,19 +71,28 @@ func TestInvalidateMissingCheatpaths(t *testing.T) {
} }
} }
// TestMissingInvalidFormatters asserts that configs which contain invalid // TestInvalidateInvalidFormatter asserts that configs which contain invalid
// formatters are invalidated // formatters are invalidated
func TestMissingInvalidFormatters(t *testing.T) { func TestInvalidateInvalidFormatter(t *testing.T) {
// mock a config // mock a config with a valid editor and cheatpaths but invalid formatter
conf := Config{ conf := Config{
Colorize: true, Colorize: true,
Editor: "vim", Editor: "vim",
Formatter: "html",
Cheatpaths: []cheatpath.Cheatpath{
cheatpath.Cheatpath{
Name: "foo",
Path: "/foo",
ReadOnly: false,
Tags: []string{},
},
},
} }
// assert that no errors are returned // assert that the config is invalidated due to the formatter
if err := conf.Validate(); err == nil { if err := conf.Validate(); err == nil {
t.Errorf("failed to invalidate config without formatter") t.Errorf("failed to invalidate config with invalid formatter")
} }
} }

View File

@@ -1,7 +1,6 @@
package installer package installer
import ( import (
"fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
@@ -245,10 +244,10 @@ cheatpaths:
if strings.Contains(contentStr, "PERSONAL_PATH") { if strings.Contains(contentStr, "PERSONAL_PATH") {
t.Error("PERSONAL_PATH was not replaced") t.Error("PERSONAL_PATH was not replaced")
} }
if strings.Contains(contentStr, "EDITOR_PATH") && !strings.Contains(contentStr, fmt.Sprintf("editor: %s", "")) { if strings.Contains(contentStr, "EDITOR_PATH") {
t.Error("EDITOR_PATH was not replaced") t.Error("EDITOR_PATH was not replaced")
} }
if strings.Contains(contentStr, "PAGER_PATH") && !strings.Contains(contentStr, fmt.Sprintf("pager: %s", "")) { if strings.Contains(contentStr, "PAGER_PATH") {
t.Error("PAGER_PATH was not replaced") t.Error("PAGER_PATH was not replaced")
} }
if strings.Contains(contentStr, "WORK_PATH") { if strings.Contains(contentStr, "WORK_PATH") {

View File

@@ -1,6 +1,7 @@
package sheet package sheet
import ( import (
"strings"
"testing" "testing"
"github.com/cheat/cheat/internal/config" "github.com/cheat/cheat/internal/config"
@@ -16,45 +17,26 @@ func TestColorize(t *testing.T) {
} }
// mock a sheet // mock a sheet
original := "echo 'foo'"
s := Sheet{ s := Sheet{
Text: "echo 'foo'", Text: original,
} }
// colorize the sheet text // colorize the sheet text
s.Colorize(conf) s.Colorize(conf)
// initialize expectations // assert that the text was modified (colorization applied)
want := "echo" if s.Text == original {
want += " 'foo'" t.Error("Colorize did not modify sheet text")
}
// assert // assert that ANSI escape codes are present
if s.Text != want { if !strings.Contains(s.Text, "\x1b[") && !strings.Contains(s.Text, "[0m") {
t.Errorf("failed to colorize sheet: want: %s, got: %s", want, s.Text) t.Errorf("colorized text does not contain ANSI escape codes: %q", s.Text)
}
// assert that the original content is still present within the colorized output
if !strings.Contains(s.Text, "echo") || !strings.Contains(s.Text, "foo") {
t.Errorf("colorized text lost original content: %q", s.Text)
} }
} }
// TestColorizeError tests the error handling in Colorize
func TestColorizeError(_ *testing.T) {
// Create a sheet with content
sheet := Sheet{
Text: "some text",
Syntax: "invalidlexer12345", // Use an invalid lexer that might cause issues
}
// Create a config with invalid formatter/style
conf := config.Config{
Formatter: "invalidformatter",
Style: "invalidstyle",
}
// Store original text
originalText := sheet.Text
// Colorize should not panic even with invalid settings
sheet.Colorize(conf)
// The text might be unchanged if there was an error, or it might be colorized
// We're mainly testing that it doesn't panic
_ = sheet.Text
_ = originalText
}

View File

@@ -10,15 +10,12 @@ import (
// TestCopyErrors tests error cases for the Copy method // TestCopyErrors tests error cases for the Copy method
func TestCopyErrors(t *testing.T) { func TestCopyErrors(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
setup func() (*Sheet, string, func()) setup func() (*Sheet, string, func())
wantErr bool
errMsg string
}{ }{
{ {
name: "source file does not exist", name: "source file does not exist",
setup: func() (*Sheet, string, func()) { setup: func() (*Sheet, string, func()) {
// Create a sheet with non-existent path
sheet := &Sheet{ sheet := &Sheet{
Title: "test", Title: "test",
Path: "/non/existent/file.txt", Path: "/non/existent/file.txt",
@@ -30,13 +27,10 @@ func TestCopyErrors(t *testing.T) {
} }
return sheet, dest, cleanup return sheet, dest, cleanup
}, },
wantErr: true,
errMsg: "failed to open cheatsheet",
}, },
{ {
name: "destination directory creation fails", name: "destination directory creation fails",
setup: func() (*Sheet, string, func()) { setup: func() (*Sheet, string, func()) {
// Create a source file
src, err := os.CreateTemp("", "copy-test-src-*") src, err := os.CreateTemp("", "copy-test-src-*")
if err != nil { if err != nil {
t.Fatalf("failed to create temp file: %v", err) t.Fatalf("failed to create temp file: %v", err)
@@ -50,13 +44,11 @@ func TestCopyErrors(t *testing.T) {
CheatPath: "test", CheatPath: "test",
} }
// Create a file where we want a directory
blockerFile := filepath.Join(os.TempDir(), "copy-blocker-file") blockerFile := filepath.Join(os.TempDir(), "copy-blocker-file")
if err := os.WriteFile(blockerFile, []byte("blocker"), 0644); err != nil { if err := os.WriteFile(blockerFile, []byte("blocker"), 0644); err != nil {
t.Fatalf("failed to create blocker file: %v", err) t.Fatalf("failed to create blocker file: %v", err)
} }
// Try to create dest under the blocker file (will fail)
dest := filepath.Join(blockerFile, "subdir", "dest.txt") dest := filepath.Join(blockerFile, "subdir", "dest.txt")
cleanup := func() { cleanup := func() {
@@ -65,13 +57,10 @@ func TestCopyErrors(t *testing.T) {
} }
return sheet, dest, cleanup return sheet, dest, cleanup
}, },
wantErr: true,
errMsg: "failed to create directory",
}, },
{ {
name: "destination file creation fails", name: "destination file creation fails",
setup: func() (*Sheet, string, func()) { setup: func() (*Sheet, string, func()) {
// Create a source file
src, err := os.CreateTemp("", "copy-test-src-*") src, err := os.CreateTemp("", "copy-test-src-*")
if err != nil { if err != nil {
t.Fatalf("failed to create temp file: %v", err) t.Fatalf("failed to create temp file: %v", err)
@@ -85,7 +74,6 @@ func TestCopyErrors(t *testing.T) {
CheatPath: "test", CheatPath: "test",
} }
// Create a directory where we want the file
destDir := filepath.Join(os.TempDir(), "copy-test-dir") destDir := filepath.Join(os.TempDir(), "copy-test-dir")
if err := os.Mkdir(destDir, 0755); err != nil && !os.IsExist(err) { if err := os.Mkdir(destDir, 0755); err != nil && !os.IsExist(err) {
t.Fatalf("failed to create dest dir: %v", err) t.Fatalf("failed to create dest dir: %v", err)
@@ -97,8 +85,6 @@ func TestCopyErrors(t *testing.T) {
} }
return sheet, destDir, cleanup return sheet, destDir, cleanup
}, },
wantErr: true,
errMsg: "failed to create outfile",
}, },
} }
@@ -108,43 +94,27 @@ func TestCopyErrors(t *testing.T) {
defer cleanup() defer cleanup()
err := sheet.Copy(dest) err := sheet.Copy(dest)
if (err != nil) != tt.wantErr { if err == nil {
t.Errorf("Copy() error = %v, wantErr %v", err, tt.wantErr) t.Error("Copy() expected error, got nil")
return
}
if err != nil && tt.errMsg != "" {
if !contains(err.Error(), tt.errMsg) {
t.Errorf("Copy() error = %v, want error containing %q", err, tt.errMsg)
}
} }
}) })
} }
} }
// TestCopyIOError tests the io.Copy error case // TestCopyUnreadableSource verifies that Copy returns an error when the source
func TestCopyIOError(t *testing.T) { // file cannot be opened (e.g., permission denied).
// This is difficult to test without mocking io.Copy func TestCopyUnreadableSource(t *testing.T) {
// The error case would occur if the source file is modified
// or removed after opening but before copying
t.Skip("Skipping io.Copy error test - requires file system race condition")
}
// TestCopyCleanupOnError verifies that partially written files are cleaned up on error
func TestCopyCleanupOnError(t *testing.T) {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
t.Skip("chmod does not restrict reads on Windows") t.Skip("chmod does not restrict reads on Windows")
} }
// Create a source file that we'll make unreadable after opening src, err := os.CreateTemp("", "copy-test-unreadable-*")
src, err := os.CreateTemp("", "copy-test-cleanup-*")
if err != nil { if err != nil {
t.Fatalf("failed to create temp file: %v", err) t.Fatalf("failed to create temp file: %v", err)
} }
defer os.Remove(src.Name()) defer os.Remove(src.Name())
// Write some content if _, err := src.WriteString("test content"); err != nil {
content := "test content for cleanup"
if _, err := src.WriteString(content); err != nil {
t.Fatalf("failed to write content: %v", err) t.Fatalf("failed to write content: %v", err)
} }
src.Close() src.Close()
@@ -155,38 +125,21 @@ func TestCopyCleanupOnError(t *testing.T) {
CheatPath: "test", CheatPath: "test",
} }
// Destination path dest := filepath.Join(os.TempDir(), "copy-unreadable-test.txt")
dest := filepath.Join(os.TempDir(), "copy-cleanup-test.txt") defer os.Remove(dest)
defer os.Remove(dest) // Clean up if test fails
// Make the source file unreadable (simulating a read error during copy)
// This is platform-specific, but should work on Unix-like systems
if err := os.Chmod(src.Name(), 0000); err != nil { if err := os.Chmod(src.Name(), 0000); err != nil {
t.Skip("Cannot change file permissions on this platform") t.Skip("Cannot change file permissions on this platform")
} }
defer os.Chmod(src.Name(), 0644) // Restore permissions for cleanup defer os.Chmod(src.Name(), 0644)
// Attempt to copy - this should fail during io.Copy
err = sheet.Copy(dest) err = sheet.Copy(dest)
if err == nil { if err == nil {
t.Error("Expected Copy to fail with permission error") t.Error("expected Copy to fail with permission error")
} }
// Verify the destination file was cleaned up // Destination should not exist since the error occurs before it is created
if _, err := os.Stat(dest); !os.IsNotExist(err) { if _, err := os.Stat(dest); !os.IsNotExist(err) {
t.Error("Destination file should have been removed after copy failure") t.Error("destination file should not exist after open failure")
} }
} }
func contains(s, substr string) bool {
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsHelper(s, substr))
}
func containsHelper(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}

View File

@@ -38,7 +38,7 @@ To foo the bar: baz`
t.Errorf("failed to parse tags: want: %s, got: %s", want, fm.Tags[0]) t.Errorf("failed to parse tags: want: %s, got: %s", want, fm.Tags[0])
} }
if len(fm.Tags) != 1 { if len(fm.Tags) != 1 {
t.Errorf("failed to parse tags: want: len 0, got: len %d", len(fm.Tags)) t.Errorf("failed to parse tags: want: len 1, got: len %d", len(fm.Tags))
} }
} }

View File

@@ -122,69 +122,3 @@ func FuzzSearchRegex(f *testing.F) {
} }
}) })
} }
// FuzzSearchCatastrophicBacktracking specifically tests for regex patterns
// that could cause performance issues
func FuzzSearchCatastrophicBacktracking(f *testing.F) {
// Seed with patterns known to potentially cause issues
f.Add("a", 10, 5)
f.Add("x", 20, 3)
f.Fuzz(func(t *testing.T, char string, repeats int, groups int) {
// Limit the size to avoid memory issues in the test
if repeats > 30 || repeats < 0 || groups > 10 || groups < 0 || len(char) > 5 {
t.Skip("Skipping invalid or overly large test case")
}
// Construct patterns that might cause backtracking
patterns := []string{
strings.Repeat(char, repeats),
"(" + char + "+)+",
"(" + char + "*)*",
"(" + char + "|" + char + ")*",
}
// Add nested groups
if groups > 0 && groups < 10 {
nested := char
for i := 0; i < groups; i++ {
nested = "(" + nested + ")+"
}
patterns = append(patterns, nested)
}
// Test text that might trigger backtracking
testText := strings.Repeat(char, repeats) + "x"
for _, pattern := range patterns {
// Try to compile the pattern
reg, err := regexp.Compile(pattern)
if err != nil {
// Invalid pattern, skip
continue
}
// Test with timeout
done := make(chan bool, 1)
go func() {
defer func() {
if r := recover(); r != nil {
t.Errorf("Search panicked with backtracking pattern %q: %v", pattern, r)
}
done <- true
}()
sheet := Sheet{Text: testText}
_ = sheet.Search(reg)
}()
select {
case <-done:
// Completed successfully
case <-time.After(50 * time.Millisecond):
t.Logf("Warning: potential backtracking issue with pattern %q (completed slowly)", pattern)
}
}
})
}

View File

@@ -18,28 +18,26 @@ func TestFilterSingleTag(t *testing.T) {
map[string]sheet.Sheet{ map[string]sheet.Sheet{
"foo": sheet.Sheet{Title: "foo", Tags: []string{"alpha", "bravo"}}, "foo": sheet.Sheet{Title: "foo", Tags: []string{"alpha", "bravo"}},
"bar": sheet.Sheet{Title: "bar", Tags: []string{"bravo", "charlie"}}, "bar": sheet.Sheet{Title: "bar", Tags: []string{"charlie"}},
}, },
map[string]sheet.Sheet{ map[string]sheet.Sheet{
"baz": sheet.Sheet{Title: "baz", Tags: []string{"alpha", "bravo"}}, "baz": sheet.Sheet{Title: "baz", Tags: []string{"alpha"}},
"bat": sheet.Sheet{Title: "bat", Tags: []string{"bravo", "charlie"}}, "bat": sheet.Sheet{Title: "bat", Tags: []string{"bravo", "charlie"}},
}, },
} }
// filter the cheatsheets // filter the cheatsheets
filtered := Filter(cheatpaths, []string{"bravo"}) filtered := Filter(cheatpaths, []string{"alpha"})
// assert that the expect results were returned // assert that the expect results were returned
want := []map[string]sheet.Sheet{ want := []map[string]sheet.Sheet{
map[string]sheet.Sheet{ map[string]sheet.Sheet{
"foo": sheet.Sheet{Title: "foo", Tags: []string{"alpha", "bravo"}}, "foo": sheet.Sheet{Title: "foo", Tags: []string{"alpha", "bravo"}},
"bar": sheet.Sheet{Title: "bar", Tags: []string{"bravo", "charlie"}},
}, },
map[string]sheet.Sheet{ map[string]sheet.Sheet{
"baz": sheet.Sheet{Title: "baz", Tags: []string{"alpha", "bravo"}}, "baz": sheet.Sheet{Title: "baz", Tags: []string{"alpha"}},
"bat": sheet.Sheet{Title: "bat", Tags: []string{"bravo", "charlie"}},
}, },
} }