soma_cli_core/
confirmation.rs1use std::io::{self, BufRead, Write};
9
10pub fn confirm_typed<R, W>(
17 writer: &mut W,
18 reader: &mut R,
19 prompt: &str,
20 expected: &str,
21) -> io::Result<bool>
22where
23 R: BufRead,
24 W: Write,
25{
26 write!(writer, "{prompt}")?;
27 writer.flush()?;
28
29 let mut input = String::new();
30 reader.read_line(&mut input)?;
31 Ok(input.trim() == expected)
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37
38 #[test]
39 fn confirm_typed_writes_prompt_and_matches_input() {
40 let mut input = io::Cursor::new(b"yes\n".to_vec());
41 let mut output = Vec::new();
42 let confirmed = confirm_typed(&mut output, &mut input, "Type yes: ", "yes").unwrap();
43 assert!(confirmed);
44 assert_eq!(String::from_utf8(output).unwrap(), "Type yes: ");
45 }
46
47 #[test]
48 fn confirm_typed_reports_mismatch_without_erroring() {
49 let mut input = io::Cursor::new(b"nope\n".to_vec());
50 let mut output = Vec::new();
51 let confirmed = confirm_typed(&mut output, &mut input, "Type yes: ", "yes").unwrap();
52 assert!(!confirmed);
53 }
54
55 #[test]
56 fn confirm_typed_trims_trailing_whitespace() {
57 let mut input = io::Cursor::new(b"yes \r\n".to_vec());
58 let mut output = Vec::new();
59 let confirmed = confirm_typed(&mut output, &mut input, "Type yes: ", "yes").unwrap();
60 assert!(confirmed);
61 }
62
63 #[test]
64 fn confirm_typed_treats_closed_stdin_as_a_non_match() {
65 let mut input = io::Cursor::new(Vec::new());
70 let mut output = Vec::new();
71 let confirmed = confirm_typed(&mut output, &mut input, "Type yes: ", "yes").unwrap();
72 assert!(!confirmed);
73 }
74}