diff --git a/internal/session/prompt.go b/internal/session/prompt.go new file mode 100644 index 0000000..be62c9e --- /dev/null +++ b/internal/session/prompt.go @@ -0,0 +1,32 @@ +package session + +import ( + "bufio" + "fmt" + "io" + "strings" +) + +// ConfirmYN prints prompt to out, reads one line from in, and returns: +// - true for "y"/"yes" (case-insensitive) +// - false for "n"/"no" (case-insensitive) +// - defaultYes for empty input +// - !defaultYes for any other input (treat unrecognized as the +// opposite of the default, i.e., the safer choice given the default) +func ConfirmYN(in io.Reader, out io.Writer, prompt string, defaultYes bool) bool { + fmt.Fprint(out, prompt) + reader := bufio.NewReader(in) + line, _ := reader.ReadString('\n') + answer := strings.TrimSpace(strings.ToLower(line)) + + if answer == "" { + return defaultYes + } + if answer == "y" || answer == "yes" { + return true + } + if answer == "n" || answer == "no" { + return false + } + return !defaultYes +} diff --git a/internal/session/prompt_test.go b/internal/session/prompt_test.go new file mode 100644 index 0000000..eec766c --- /dev/null +++ b/internal/session/prompt_test.go @@ -0,0 +1,45 @@ +package session + +import ( + "bytes" + "strings" + "testing" +) + +func TestConfirmYNAccepts(t *testing.T) { + cases := []struct { + in string + def bool + want bool + }{ + {"y\n", false, true}, + {"Y\n", false, true}, + {"yes\n", false, true}, + {"YES\n", false, true}, + {"n\n", false, false}, + {"no\n", false, false}, + {"\n", false, false}, + {"\n", true, true}, + {"garbage\n", true, false}, + {"garbage\n", false, true}, + } + + for _, c := range cases { + in := strings.NewReader(c.in) + var out bytes.Buffer + got := ConfirmYN(in, &out, "prompt? ", c.def) + if got != c.want { + t.Errorf("ConfirmYN(%q, default=%v) = %v, want %v", c.in, c.def, got, c.want) + } + } +} + +func TestConfirmYNPromptsUser(t *testing.T) { + in := strings.NewReader("y\n") + var out bytes.Buffer + ConfirmYN(in, &out, "really? [y/N] ", false) + + if !strings.Contains(out.String(), "really?") { + t.Errorf("expected prompt in output, got %q", out.String()) + } +}