package tools import ( "os" "os/exec" "strings" "testing" ) // TestShellQuote covers the standard case and apostrophes: a value // containing ' must still be safely shell-quoted (the '\” trick). func TestShellQuote(t *testing.T) { for _, in := range []string{"", "hello", "don't", "it's a 'test'", "a'b'c"} { got := shellQuote(in) if !strings.HasPrefix(got, "'") || !strings.HasSuffix(got, "'") { t.Errorf("shellQuote(%q) = %q: not single-quoted", in, got) } } } // TestSedInPlaceEscapesApostrophe ensures that a replace whose text // contains an apostrophe doesn't break the shell quoting. This runs the // generated command for real against a temp file. func TestSedInPlaceEscapesApostrophe(t *testing.T) { dir := t.TempDir() path := dir + "/app.conf" if err := os.WriteFile(path, []byte("name: don't panic\n"), 0o644); err != nil { t.Fatal(err) } expr := "s/don't/can't/" cmd := sedInPlace("", expr, path) out, err := exec.Command("sh", "-c", cmd).CombinedOutput() if err != nil { t.Fatalf("sed command failed: %v\n%s\ncmd=%s", err, out, cmd) } content, err := os.ReadFile(path) if err != nil { t.Fatal(err) } if !strings.Contains(string(content), "can't panic") { t.Errorf("expected replacement with apostrophe, got %q", content) } }