From 5ea62b7427f618fa7937be241210219f20367a54 Mon Sep 17 00:00:00 2001 From: wuyangfan <1102042793@qq.com> Date: Sat, 30 May 2026 13:06:59 +0800 Subject: [PATCH] fix: reject empty or no-op find/replace arguments Refuse an empty FIND string and FIND equal to REPLACE before walking the tree, avoiding accidental per-rune substitution storms. Fixes #10 --- find_replace.go | 16 ++++++++++++++++ find_replace_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/find_replace.go b/find_replace.go index 9bdbe79..2f5bd94 100644 --- a/find_replace.go +++ b/find_replace.go @@ -73,6 +73,17 @@ func main() { // clean success, 1 if argument parsing failed or any traversal error was // recorded. Output documented in the README (Renaming/Rewriting lines) still // goes to log.Default(); usage and aggregated error summaries go to stderr. + +func validateFindReplace(find, replace string) error { + if find == "" { + return fmt.Errorf("FIND must not be empty") + } + if find == replace { + return fmt.Errorf("FIND and REPLACE must be different") + } + return nil +} + func run(args []string, stderr io.Writer) int { // Remove date/time from logging output. log.SetFlags(0) @@ -82,6 +93,11 @@ func run(args []string, stderr io.Writer) int { return 1 } + if err := validateFindReplace(args[1], args[2]); err != nil { + fmt.Fprintln(stderr, err) + return 1 + } + fr := findReplace{find: args[1], replace: args[2]} // Recursively explore the hierarchy depth first, rewrite files as needed, diff --git a/find_replace_test.go b/find_replace_test.go index 9a54564..5c85b72 100644 --- a/find_replace_test.go +++ b/find_replace_test.go @@ -3,6 +3,7 @@ package main import ( "bytes" "errors" + "io" "io/fs" "os" "os/exec" @@ -660,6 +661,29 @@ func withWorkingDir(t *testing.T, dir string) { t.Cleanup(func() { _ = os.Chdir(prev) }) } + +func TestValidateFindReplace(t *testing.T) { + cases := []struct { + find, replace string + wantErr bool + }{ + {"", "b", true}, + {"a", "a", true}, + {"a", "b", false}, + } + for _, tc := range cases { + if err := validateFindReplace(tc.find, tc.replace); (err != nil) != tc.wantErr { + t.Fatalf("validateFindReplace(%q,%q) err=%v; wantErr=%v", tc.find, tc.replace, err, tc.wantErr) + } + } +} + +func TestRunRejectsEmptyFind(t *testing.T) { + if code := run([]string{"find-replace", "", "b"}, io.Discard); code == 0 { + t.Fatal("expected non-zero exit for empty FIND") + } +} + func CloneRepoToTestDir(b *testing.B, repoUrl string) *File { b.Helper() d := newTestDir(b, "", "*")