use rstest::rstest;
use crate::{
error::InquireResult,
ui::{
test::{FakeBackend, Token},
Key, KeyModifiers,
},
Confirm, InquireError,
};
#[test]
fn prompt_can_be_initialized_from_str() -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Enter]);
let result = Confirm::from("Question")
.with_default(true)
.prompt_with_backend(&mut backend)?;
assert!(result, "Answer was not the expected one");
Ok(())
}
#[rstest]
#[case('y', true)]
#[case('Y', true)]
#[case('n', false)]
#[case('N', false)]
fn prompt_correctly_handles_direct_hotkeys(
#[case] key_char: char,
#[case] expected_result: bool,
) -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Char(key_char, KeyModifiers::NONE)]);
let result = Confirm::from("Question")
.with_default(!expected_result) .prompt_with_backend(&mut backend)?;
assert_eq!(expected_result, result, "Answer was not the expected one");
Ok(())
}
#[rstest]
fn escape_after_successful_submit_has_no_effect() -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Char('y', KeyModifiers::NONE), Key::Escape]);
let result = Confirm::from("Question")
.with_default(false)
.prompt_with_backend(&mut backend)?;
assert!(result, "Answer was not the expected one");
Ok(())
}
#[rstest]
#[case(true)]
#[case(false)]
fn prompt_with_default_can_be_readily_submitted(#[case] default_value: bool) -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Enter]);
let result = Confirm::from("Question")
.with_default(default_value)
.prompt_with_backend(&mut backend)?;
assert_eq!(default_value, result, "Answer was not the expected one");
Ok(())
}
#[rstest]
#[case(true, "Y/n")]
#[case(false, "y/N")]
fn default_formatter_for_default_values_follows_convention(
#[case] default_value: bool,
#[case] expected_output: &str,
) -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Enter]);
let _ = Confirm::new("Question")
.with_default(default_value)
.prompt_with_backend(&mut backend)?;
let rendered_frames = backend.frames();
for (idx, frame) in rendered_frames.iter().enumerate() {
let is_last_frame = idx == rendered_frames.len() - 1;
if is_last_frame {
assert!(
frame
.tokens()
.iter()
.all(|t| !matches!(t, Token::DefaultValue(_))),
"Frame {} (last) contained a default value token when it should not have",
idx
);
} else {
assert!(
frame.has_token(&Token::DefaultValue(expected_output.into())),
"Frame {} did not contain a default value token",
idx
);
}
}
Ok(())
}
#[rstest]
#[case(true, "y")]
#[case(false, "n")]
fn custom_formatter_for_default_values_is_used(
#[case] default_value: bool,
#[case] expected_output: &str,
) -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Enter]);
let _ = Confirm::new("Question")
.with_default(default_value)
.prompt_with_backend(&mut backend)?;
let rendered_frames = backend.frames();
for (idx, frame) in rendered_frames.iter().enumerate() {
let is_last_frame = idx == rendered_frames.len() - 1;
if is_last_frame {
assert!(
frame
.tokens()
.iter()
.all(|t| !matches!(t, Token::DefaultValue(_))),
"Frame {} (last) contained a default value token when it should not have",
idx
);
} else {
assert!(
frame.has_token(&Token::DefaultValue(expected_output.into())),
"Frame {} did not contain a default value token",
idx
);
}
}
Ok(())
}
#[test]
fn default_help_message_does_not_exist_and_is_not_rendered() -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Enter]);
let _ = Confirm::new("Question")
.with_default(true)
.prompt_with_backend(&mut backend)?;
let rendered_frames = backend.frames();
for (idx, frame) in rendered_frames.iter().enumerate() {
let has_unexpected_help = frame.tokens().iter().any(|t| {
if let Token::HelpMessage(msg) = t {
!msg.is_empty() } else {
false
}
});
assert!(
!has_unexpected_help,
"Frame {} contained an unexpected active help message token",
idx
);
}
Ok(())
}
#[test]
fn custom_help_message_is_rendered() -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Enter]);
let _ = Confirm::new("Question")
.with_help_message("Custom help message")
.with_default(true)
.prompt_with_backend(&mut backend)?;
let rendered_frames = backend.frames();
for (idx, frame) in rendered_frames.iter().enumerate() {
let is_last_frame = idx == rendered_frames.len() - 1;
if is_last_frame {
assert!(
frame
.tokens()
.iter()
.all(|t| !matches!(t, Token::HelpMessage(_))),
"Frame {} (last) contained a help message token when it should not have",
idx
);
} else {
assert!(
frame.has_token(&Token::HelpMessage("Custom help message".into())),
"Frame {} did not contain a help message token",
idx
);
}
}
Ok(())
}
#[test]
fn custom_formatter_affects_final_output() -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Enter]);
let custom_formatter = |d: bool| format!("WOW! {}", d);
let result = Confirm::new("Question")
.with_default(true)
.with_formatter(&custom_formatter)
.prompt_with_backend(&mut backend)?;
assert!(
result,
"Answer selected (default) was not the expected true as default"
);
let final_frame = backend.frames().last().unwrap();
assert!(
final_frame.has_token(&Token::AnsweredPrompt(
"Question".into(),
"WOW! true".into()
)),
"Final frame did not contain the correct answer token"
);
Ok(())
}
#[test]
fn default_formatter_outputs_true_answer_as_yes() -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Enter]);
let result = Confirm::new("Question")
.with_default(true)
.prompt_with_backend(&mut backend)?;
assert!(
result,
"Answer selected (default) was not the expected true as default"
);
let final_frame = backend.frames().last().unwrap();
assert!(
final_frame.has_token(&Token::AnsweredPrompt("Question".into(), "Yes".into())),
"Final frame did not contain the correct answer token"
);
Ok(())
}
#[test]
fn default_formatter_outputs_false_answer_as_no() -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Enter]);
let result = Confirm::new("Question")
.with_default(false)
.prompt_with_backend(&mut backend)?;
assert!(
!result,
"Answer selected (default) was not the expected false as default"
);
let final_frame = backend.frames().last().unwrap();
assert!(
final_frame.has_token(&Token::AnsweredPrompt("Question".into(), "No".into())),
"Final frame did not contain the correct answer token"
);
Ok(())
}
#[test]
fn escape_raises_error() -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Escape]);
let result = Confirm::new("Question").prompt_with_backend(&mut backend);
assert!(result.is_err(), "Result was not an error");
assert!(
matches!(result.unwrap_err(), InquireError::OperationCanceled),
"Error message was not the expected one"
);
let final_frame = backend.frames().last().unwrap();
assert!(
final_frame.has_token(&Token::CanceledPrompt("Question".into())),
"Final frame did not contain the correct canceled prompt token"
);
Ok(())
}
#[test]
fn ctrl_c_interrupts_prompt() -> InquireResult<()> {
let mut backend = FakeBackend::new(vec![Key::Char('c', KeyModifiers::CONTROL)]);
let result = Confirm::new("Question").prompt_with_backend(&mut backend);
assert!(result.is_err(), "Result was not an error");
assert!(
matches!(result.unwrap_err(), InquireError::OperationInterrupted),
"Error message was not the expected one"
);
assert_eq!(
1,
backend.frames.len(),
"Only an initial frame should have been rendered",
);
let final_frame = backend.frames().last().unwrap();
assert!(
final_frame.has_token(&Token::Prompt("Question".into())),
"Final frame did not contain the expected prompt token"
);
Ok(())
}