diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-02 08:55:56 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-02 08:55:56 +0900 |
| commit | 2c3373a7466c31f5cce7c2867c00a91afaa8e128 (patch) | |
| tree | 754c7da92def5d14fc425230f9db41c654897b4f /crates/shirabe | |
| parent | 92f5c977b42d1322f3cebb260024179e1285b9d0 (diff) | |
| download | php-shirabe-2c3373a7466c31f5cce7c2867c00a91afaa8e128.tar.gz php-shirabe-2c3373a7466c31f5cce7c2867c00a91afaa8e128.tar.zst php-shirabe-2c3373a7466c31f5cce7c2867c00a91afaa8e128.zip | |
fix(io): propagate ask/select errors instead of panicking
IOInterface::ask/select now return anyhow::Result<PhpMixed>, and
ConsoleIO::ask_question forwards QuestionHelper errors (validator
failures, MissingInputException) instead of collapsing them with
.expect(). In PHP these exceptions propagate from QuestionHelper
through ConsoleIO to the caller, so callers such as UpdateCommand's
interactive package selection must be able to observe them; the
MissingInputException is wrapped with its concrete type preserved so
Application's ExceptionInterface downcast keeps working. All call
sites now propagate with `?` (Perforce::query_p4_user becomes
Result-returning: PHP declares it void but exceptions still escape),
and the previously ignored
test_interactive_mode_throws_if_no_package_entered passes.
ask_confirmation/ask_and_hide_answer still collapse errors; extending
propagation to them is left as TODO(phase-c) pending a decision.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe')
26 files changed, 104 insertions, 79 deletions
diff --git a/crates/shirabe/src/command/create_project_command.rs b/crates/shirabe/src/command/create_project_command.rs index 68024b69..545ed533 100644 --- a/crates/shirabe/src/command/create_project_command.rs +++ b/crates/shirabe/src/command/create_project_command.rs @@ -173,7 +173,7 @@ impl Command for CreateProjectCommand { ); input .borrow_mut() - .set_argument("directory", io.ask(prompt, PhpMixed::Null)); + .set_argument("directory", io.ask(prompt, PhpMixed::Null)?); } let repository_opt = input.borrow().get_option("repository")?; diff --git a/crates/shirabe/src/command/exec_command.rs b/crates/shirabe/src/command/exec_command.rs index 057c9eb2..63017cd1 100644 --- a/crates/shirabe/src/command/exec_command.rs +++ b/crates/shirabe/src/command/exec_command.rs @@ -128,7 +128,7 @@ impl Command for ExecCommand { PhpMixed::Int(1), "Invalid binary name \"%s\"".to_string(), false, - ); + )?; if let Some(idx) = binary.as_int() { input.borrow_mut().set_argument( diff --git a/crates/shirabe/src/command/init_command.rs b/crates/shirabe/src/command/init_command.rs index 1ff4089a..4523d910 100644 --- a/crates/shirabe/src/command/init_command.rs +++ b/crates/shirabe/src/command/init_command.rs @@ -595,7 +595,7 @@ impl Command for InitCommand { description_default .map(PhpMixed::String) .unwrap_or(PhpMixed::Null), - ); + )?; input.borrow_mut().set_option("description", description); let author = input @@ -701,7 +701,7 @@ impl Command for InitCommand { type_str ), type_val, - ); + )?; if type_value.as_string() == Some("") || matches!(type_value, PhpMixed::Bool(false)) { type_value = PhpMixed::Null; } @@ -734,7 +734,7 @@ impl Command for InitCommand { license.clone().unwrap_or_default() ), license.map(PhpMixed::String).unwrap_or(PhpMixed::Null), - ); + )?; let spdx = SpdxLicenses::new(); if !license.is_null() && !spdx.validate(license.as_string().unwrap_or("")) diff --git a/crates/shirabe/src/command/package_discovery_trait.rs b/crates/shirabe/src/command/package_discovery_trait.rs index 6fb83676..229d84e9 100644 --- a/crates/shirabe/src/command/package_discovery_trait.rs +++ b/crates/shirabe/src/command/package_discovery_trait.rs @@ -227,7 +227,7 @@ pub trait PackageDiscoveryTrait: BaseCommand { let io = self.get_io(); loop { - let package_input = io.ask("Search for a package: ".to_string(), PhpMixed::Null); + let package_input = io.ask("Search for a package: ".to_string(), PhpMixed::Null)?; let mut package = match package_input.as_string() { Some(s) => s.to_string(), None => break, @@ -694,7 +694,7 @@ pub trait PackageDiscoveryTrait: BaseCommand { PhpMixed::Int(1), "No package named \"%s\" is installed.".to_string(), false, - ); + )?; if let Some(idx_str) = result_mixed.as_string() && let Ok(idx) = idx_str.parse::<usize>() && let Some(selected) = similar.get(idx) diff --git a/crates/shirabe/src/command/run_script_command.rs b/crates/shirabe/src/command/run_script_command.rs index faa3a6dd..0887eb89 100644 --- a/crates/shirabe/src/command/run_script_command.rs +++ b/crates/shirabe/src/command/run_script_command.rs @@ -214,7 +214,7 @@ impl Command for RunScriptCommand { PhpMixed::Int(1), "Invalid script name \"%s\"".to_string(), false, - ); + )?; input.borrow_mut().set_argument("script", script)?; diff --git a/crates/shirabe/src/command/update_command.rs b/crates/shirabe/src/command/update_command.rs index 686e784d..5c0aae8a 100644 --- a/crates/shirabe/src/command/update_command.rs +++ b/crates/shirabe/src/command/update_command.rs @@ -715,7 +715,7 @@ impl UpdateCommand { PhpMixed::Int(1), "No package named \"%s\" is installed.".to_string(), true, - ); + )?; let packages: Vec<String> = match select_result { PhpMixed::List(l) => l .into_iter() diff --git a/crates/shirabe/src/downloader/git_downloader.rs b/crates/shirabe/src/downloader/git_downloader.rs index c2599d2b..fe725507 100644 --- a/crates/shirabe/src/downloader/git_downloader.rs +++ b/crates/shirabe/src/downloader/git_downloader.rs @@ -1265,7 +1265,7 @@ impl VcsDownloader for GitDownloader { if update { "s," } else { "" } ), PhpMixed::String("?".to_string()), - ) + )? .as_string() .map(|s| s.to_string()); let mut do_help = false; diff --git a/crates/shirabe/src/downloader/svn_downloader.rs b/crates/shirabe/src/downloader/svn_downloader.rs index e72bd40a..f5b7a833 100644 --- a/crates/shirabe/src/downloader/svn_downloader.rs +++ b/crates/shirabe/src/downloader/svn_downloader.rs @@ -308,7 +308,7 @@ impl VcsDownloader for SvnDownloader { .ask( " <info>Discard changes [y,n,v,?]?</info> ".to_string(), PhpMixed::String("?".to_string()), - ) + )? .as_string() { Some("y") => { diff --git a/crates/shirabe/src/io/buffer_io.rs b/crates/shirabe/src/io/buffer_io.rs index 491cd316..bbe1db9f 100644 --- a/crates/shirabe/src/io/buffer_io.rs +++ b/crates/shirabe/src/io/buffer_io.rs @@ -186,7 +186,7 @@ impl crate::io::IOInterfaceImmutable for BufferIO { self.inner .overwrite_error4(message, newline, size, verbosity) } - fn ask(&self, question: String, default: PhpMixed) -> PhpMixed { + fn ask(&self, question: String, default: PhpMixed) -> anyhow::Result<PhpMixed> { self.inner.ask(question, default) } fn ask_confirmation(&self, question: String, default: bool) -> bool { @@ -213,7 +213,7 @@ impl crate::io::IOInterfaceImmutable for BufferIO { attempts: PhpMixed, error_message: String, multiselect: bool, - ) -> PhpMixed { + ) -> anyhow::Result<PhpMixed> { self.inner.select( question, choices, diff --git a/crates/shirabe/src/io/console_io.rs b/crates/shirabe/src/io/console_io.rs index cf488855..83e84fd3 100644 --- a/crates/shirabe/src/io/console_io.rs +++ b/crates/shirabe/src/io/console_io.rs @@ -338,18 +338,17 @@ impl ConsoleIO { /// Delegates to `QuestionHelper::ask`. /// /// PHP: `$helper->ask($this->input, $this->getErrorOutput(), $question)`. - /// `QuestionHelper::ask` surfaces PHP exceptions; ConsoleIO does not catch them, so an - /// unrecoverable error here is a PHP fatal. The double `Result` is collapsed: the outer - /// `anyhow::Result` (fatal) and the inner `MissingInputException` (unhandled, hence also fatal - /// in PHP) both abort. - fn ask_question(&self, question: &impl QuestionInterface) -> PhpMixed { + /// `QuestionHelper::ask` surfaces PHP exceptions; ConsoleIO does not catch them, they + /// propagate to the caller. The double `Result` is flattened: the inner + /// `MissingInputException` is wrapped with its concrete type preserved so that + /// `Application`'s `instanceof ExceptionInterface` downcast still recognizes it. + fn ask_question(&self, question: &impl QuestionInterface) -> anyhow::Result<PhpMixed> { let error_output = self.get_error_output(); let mut question_helper = self.question_helper.borrow_mut(); let mut input = self.input.borrow_mut(); question_helper - .ask(&mut *input, error_output, question) - .expect("QuestionHelper::ask raised a fatal error") - .expect("QuestionHelper::ask returned no input") + .ask(&mut *input, error_output, question)? + .map_err(anyhow::Error::new) } } @@ -426,7 +425,7 @@ impl IOInterfaceImmutable for ConsoleIO { ); } - fn ask(&self, question: String, default: PhpMixed) -> PhpMixed { + fn ask(&self, question: String, default: PhpMixed) -> anyhow::Result<PhpMixed> { let sanitized_question = Self::sanitize(PhpMixed::String(question), true) .as_string() .unwrap_or("") @@ -441,6 +440,9 @@ impl IOInterfaceImmutable for ConsoleIO { self.ask_question(&question) } + // TODO(phase-c): ask_confirmation and ask_and_hide_answer still collapse ask_question + // errors with .expect() instead of propagating them; extending Result propagation to + // them is a further IOInterface signature change that has not been decided yet. fn ask_confirmation(&self, question: String, default: bool) -> bool { let sanitized = Self::sanitize(PhpMixed::String(question), true) .as_string() @@ -453,7 +455,9 @@ impl IOInterfaceImmutable for ConsoleIO { "/^no?$/i".to_string(), ); - let result = self.ask_question(&question); + let result = self + .ask_question(&question) + .expect("QuestionHelper::ask raised an error"); result.as_bool().unwrap_or(false) } @@ -499,7 +503,7 @@ impl IOInterfaceImmutable for ConsoleIO { .set_max_attempts(attempts) .map_err(|e| anyhow::anyhow!(e.0.message))?; - Ok(self.ask_question(&question)) + self.ask_question(&question) } fn ask_and_hide_answer(&self, question: String) -> Option<String> { @@ -513,7 +517,9 @@ impl IOInterfaceImmutable for ConsoleIO { .set_hidden(true) .expect("a freshly constructed question has no autocompleter"); - let result = self.ask_question(&question); + let result = self + .ask_question(&question) + .expect("QuestionHelper::ask raised an error"); result.as_string().map(|s| s.to_string()) } @@ -525,7 +531,7 @@ impl IOInterfaceImmutable for ConsoleIO { attempts: PhpMixed, error_message: String, multiselect: bool, - ) -> PhpMixed { + ) -> anyhow::Result<PhpMixed> { let sanitized_question = Self::sanitize(PhpMixed::String(question), true) .as_string() .unwrap_or("") @@ -563,7 +569,7 @@ impl IOInterfaceImmutable for ConsoleIO { question.set_error_message(error_message); question.set_multiselect(multiselect); - let result: PhpMixed = self.ask_question(&question); + let result: PhpMixed = self.ask_question(&question)?; // PHP: $isAssoc = (bool) \count(array_filter(array_keys($choices), 'is_string')); let choice_keys: Vec<String> = match &choices { @@ -574,7 +580,7 @@ impl IOInterfaceImmutable for ConsoleIO { let is_assoc = !choice_keys.is_empty() && choice_keys.iter().any(|k| k.parse::<i64>().is_err()); if is_assoc { - return result; + return Ok(result); } if !is_array(&result) { @@ -591,7 +597,9 @@ impl IOInterfaceImmutable for ConsoleIO { .collect(), _ => IndexMap::new(), }; - return PhpMixed::String(array_search(&result_str, &haystack).unwrap_or_default()); + return Ok(PhpMixed::String( + array_search(&result_str, &haystack).unwrap_or_default(), + )); } let mut results: Vec<String> = vec![]; @@ -611,7 +619,9 @@ impl IOInterfaceImmutable for ConsoleIO { } } - PhpMixed::List(results.into_iter().map(PhpMixed::String).collect()) + Ok(PhpMixed::List( + results.into_iter().map(PhpMixed::String).collect(), + )) } fn get_authentications(&self) -> IndexMap<String, IndexMap<String, Option<String>>> { diff --git a/crates/shirabe/src/io/io_interface.rs b/crates/shirabe/src/io/io_interface.rs index 33a2f017..b0271767 100644 --- a/crates/shirabe/src/io/io_interface.rs +++ b/crates/shirabe/src/io/io_interface.rs @@ -92,7 +92,10 @@ pub trait IOInterfaceImmutable: std::fmt::Debug { } fn overwrite_error4(&self, message: &str, newline: bool, size: Option<i64>, verbosity: i64); - fn ask(&self, question: String, default: PhpMixed) -> PhpMixed; + /// PHP: `@throws \RuntimeException If there is no data to read in the input stream`. + /// `QuestionHelper::ask` exceptions (validator errors, `MissingInputException`) propagate + /// to the caller, hence the `anyhow::Result` return type. + fn ask(&self, question: String, default: PhpMixed) -> anyhow::Result<PhpMixed>; fn ask_confirmation(&self, question: String, default: bool) -> bool; @@ -109,6 +112,10 @@ pub trait IOInterfaceImmutable: std::fmt::Debug { /// PHP `array $choices` may be a list (`PhpMixed::List`) or an associative /// array (`PhpMixed::Array`); list choices resolve to their index, while /// associative choices resolve to their key. + /// + /// PHP: `@throws \InvalidArgumentException` — the `ChoiceQuestion` validator error + /// propagates to the caller once `$attempts` is exhausted, hence the `anyhow::Result` + /// return type. fn select( &self, question: String, @@ -117,7 +124,7 @@ pub trait IOInterfaceImmutable: std::fmt::Debug { attempts: PhpMixed, error_message: String, multiselect: bool, - ) -> PhpMixed; + ) -> anyhow::Result<PhpMixed>; fn get_authentications(&self) -> IndexMap<String, IndexMap<String, Option<String>>>; @@ -278,7 +285,7 @@ impl IOInterfaceImmutable for std::rc::Rc<std::cell::RefCell<dyn IOInterface>> { .overwrite_error4(message, newline, size, verbosity) } - fn ask(&self, question: String, default: PhpMixed) -> PhpMixed { + fn ask(&self, question: String, default: PhpMixed) -> anyhow::Result<PhpMixed> { self.borrow().ask(question, default) } @@ -309,7 +316,7 @@ impl IOInterfaceImmutable for std::rc::Rc<std::cell::RefCell<dyn IOInterface>> { attempts: PhpMixed, error_message: String, multiselect: bool, - ) -> PhpMixed { + ) -> anyhow::Result<PhpMixed> { self.borrow().select( question, choices, diff --git a/crates/shirabe/src/io/null_io.rs b/crates/shirabe/src/io/null_io.rs index 71a81408..6db473ae 100644 --- a/crates/shirabe/src/io/null_io.rs +++ b/crates/shirabe/src/io/null_io.rs @@ -65,8 +65,8 @@ impl IOInterfaceImmutable for NullIO { ) { } - fn ask(&self, _question: String, default: PhpMixed) -> PhpMixed { - default + fn ask(&self, _question: String, default: PhpMixed) -> anyhow::Result<PhpMixed> { + Ok(default) } fn ask_confirmation(&self, _question: String, default: bool) -> bool { @@ -95,8 +95,8 @@ impl IOInterfaceImmutable for NullIO { _attempts: PhpMixed, _error_message: String, _multiselect: bool, - ) -> PhpMixed { - default + ) -> anyhow::Result<PhpMixed> { + Ok(default) } fn get_authentications( diff --git a/crates/shirabe/src/plugin/plugin_manager.rs b/crates/shirabe/src/plugin/plugin_manager.rs index 07b4438a..572bb3b6 100644 --- a/crates/shirabe/src/plugin/plugin_manager.rs +++ b/crates/shirabe/src/plugin/plugin_manager.rs @@ -875,7 +875,7 @@ impl PluginManager { let answer = self.io.ask( format!("Do you trust \"<fg=green;options=bold>{}</>\" to execute code and wish to enable it now? (writes \"allow-plugins\" to composer.json) [<comment>y,n,d,?</comment>] ", package), PhpMixed::String(default.to_string()), - ); + )?; let answer_str = answer.as_string().unwrap_or(""); match answer_str { "y" | "n" | "d" => { diff --git a/crates/shirabe/src/util/auth_helper.rs b/crates/shirabe/src/util/auth_helper.rs index 0a2dbf86..8a621eb1 100644 --- a/crates/shirabe/src/util/auth_helper.rs +++ b/crates/shirabe/src/util/auth_helper.rs @@ -168,7 +168,7 @@ impl AuthHelper { "After authorizing your token, confirm that you would like to retry the request" .to_string(), PhpMixed::Null, - ); + )?; return Ok(PromptAuthResult { retry: true, @@ -420,7 +420,9 @@ impl AuthHelper { true, io_interface::NORMAL, ); - let username = self.io.ask(" Username: ".to_string(), PhpMixed::Null); + let username = self + .io + .ask(" Username: ".to_string(), PhpMixed::Null)?; let password = self.io.ask_and_hide_answer(" Password: ".to_string()); self.io.borrow_mut().set_authentication( origin.to_string(), diff --git a/crates/shirabe/src/util/forgejo.rs b/crates/shirabe/src/util/forgejo.rs index 41d0dd3d..34d44b7b 100644 --- a/crates/shirabe/src/util/forgejo.rs +++ b/crates/shirabe/src/util/forgejo.rs @@ -80,7 +80,7 @@ impl Forgejo { let username = self .io - .ask("Username: ".to_string(), shirabe_php_shim::PhpMixed::Null) + .ask("Username: ".to_string(), shirabe_php_shim::PhpMixed::Null)? .as_string() .map(|s| s.trim().to_string()) .unwrap_or_default(); diff --git a/crates/shirabe/src/util/git.rs b/crates/shirabe/src/util/git.rs index 3e650fd1..1c3474ea 100644 --- a/crates/shirabe/src/util/git.rs +++ b/crates/shirabe/src/util/git.rs @@ -703,7 +703,7 @@ impl Git { default_username .map(PhpMixed::String) .unwrap_or(PhpMixed::Null), - ) + )? .as_string() .map(|s| s.to_string()), ); diff --git a/crates/shirabe/src/util/gitlab.rs b/crates/shirabe/src/util/gitlab.rs index 485d4126..2b23cdbf 100644 --- a/crates/shirabe/src/util/gitlab.rs +++ b/crates/shirabe/src/util/gitlab.rs @@ -419,7 +419,7 @@ impl GitLab { } fn create_token(&mut self, scheme: &str, origin_url: &str) -> anyhow::Result<PhpMixed> { - let username = match self.io.ask("Username: ".to_string(), PhpMixed::Null) { + let username = match self.io.ask("Username: ".to_string(), PhpMixed::Null)? { PhpMixed::String(s) => s, _ => String::new(), }; diff --git a/crates/shirabe/src/util/perforce.rs b/crates/shirabe/src/util/perforce.rs index 9cd804a4..e2591301 100644 --- a/crates/shirabe/src/util/perforce.rs +++ b/crates/shirabe/src/util/perforce.rs @@ -253,18 +253,18 @@ impl Perforce { self.p4_user = user; } - pub fn query_p4_user(&mut self) { + pub fn query_p4_user(&mut self) -> anyhow::Result<()> { let _ = self.get_user(); if strlen(&self.p4_user.clone().unwrap_or_default()) > 0 { - return; + return Ok(()); } self.p4_user = self.get_p4_variable("P4USER"); if strlen(&self.p4_user.clone().unwrap_or_default()) > 0 { - return; + return Ok(()); } self.p4_user = self .io - .ask("Enter P4 User:".to_string(), PhpMixed::Null) + .ask("Enter P4 User:".to_string(), PhpMixed::Null)? .as_string() .map(|s| s.to_string()); let command = if self.windows_flag { @@ -280,6 +280,8 @@ impl Perforce { ) }; self.execute_command(PhpMixed::String(command)); + + Ok(()) } pub(crate) fn get_p4_variable(&mut self, name: &str) -> Option<String> { @@ -554,7 +556,7 @@ impl Perforce { } pub fn p4_login(&mut self) -> anyhow::Result<()> { - self.query_p4_user(); + self.query_p4_user()?; if !self.is_logged_in()? { let password = self.query_p4_password(); if self.windows_flag { diff --git a/crates/shirabe/src/util/svn.rs b/crates/shirabe/src/util/svn.rs index 67501e5a..50315316 100644 --- a/crates/shirabe/src/util/svn.rs +++ b/crates/shirabe/src/util/svn.rs @@ -234,7 +234,7 @@ impl Svn { self.credentials = Some(SvnCredentials { username: self .io - .ask("Username: ".to_string(), PhpMixed::String("".to_string())) + .ask("Username: ".to_string(), PhpMixed::String("".to_string()))? .as_string() .unwrap_or("") .to_string(), diff --git a/crates/shirabe/tests/command/update_command_test.rs b/crates/shirabe/tests/command/update_command_test.rs index 1b36cadc..3aa42880 100644 --- a/crates/shirabe/tests/command/update_command_test.rs +++ b/crates/shirabe/tests/command/update_command_test.rs @@ -380,11 +380,6 @@ fn test_interactive_mode_throws_if_no_package_to_update() { #[test] #[serial] -#[ignore = "ConsoleIO::ask_question panics via .expect() on any QuestionHelper validator error \ - instead of propagating it, so io.select()'s \"No package named ...\" validation \ - error can't reach app_tester.run() as an Err; fixing this needs IOInterface::ask()/ \ - select() to return anyhow::Result, which ripples through ~18 ask() and ~4 select() \ - call sites (see project_console_io_ask_select_panics memory)"] fn test_interactive_mode_throws_if_no_package_entered() { let composer_json = serde_json::json!({ "repositories": { "packages": { "type": "package", "package": [ diff --git a/crates/shirabe/tests/common/io_mock.rs b/crates/shirabe/tests/common/io_mock.rs index a658c5bc..ad8d72cd 100644 --- a/crates/shirabe/tests/common/io_mock.rs +++ b/crates/shirabe/tests/common/io_mock.rs @@ -224,7 +224,7 @@ impl IOInterfaceImmutable for IOMock { .overwrite_error4(message, newline, size, verbosity) } - fn ask(&self, question: String, default: PhpMixed) -> PhpMixed { + fn ask(&self, question: String, default: PhpMixed) -> anyhow::Result<PhpMixed> { self.inner .ask(format!("{}{}", trim_eol(&question), PHP_EOL), default) } @@ -249,10 +249,13 @@ impl IOInterfaceImmutable for IOMock { fn ask_and_hide_answer(&self, question: String) -> Option<String> { // Do not hide the answer in tests because that blocks on Windows with // hiddeninput.exe, so PHP delegates to `ask` rather than the hidden variant. - let result = self.inner.ask( - format!("{}{}", trim_eol(&question), PHP_EOL), - PhpMixed::Null, - ); + let result = self + .inner + .ask( + format!("{}{}", trim_eol(&question), PHP_EOL), + PhpMixed::Null, + ) + .expect("QuestionHelper::ask raised an error"); result.as_string().map(|s| s.to_string()) } fn select( @@ -263,7 +266,7 @@ impl IOInterfaceImmutable for IOMock { attempts: PhpMixed, error_message: String, multiselect: bool, - ) -> PhpMixed { + ) -> anyhow::Result<PhpMixed> { self.inner.select( format!("{}{}", trim_eol(&question), PHP_EOL), choices, diff --git a/crates/shirabe/tests/common/io_stub.rs b/crates/shirabe/tests/common/io_stub.rs index b897305e..9feeb5a3 100644 --- a/crates/shirabe/tests/common/io_stub.rs +++ b/crates/shirabe/tests/common/io_stub.rs @@ -217,8 +217,8 @@ impl IOInterfaceImmutable for IOStub { ) { } - fn ask(&self, _question: String, default: PhpMixed) -> PhpMixed { - self.ask.clone().unwrap_or(default) + fn ask(&self, _question: String, default: PhpMixed) -> anyhow::Result<PhpMixed> { + Ok(self.ask.clone().unwrap_or(default)) } fn ask_confirmation(&self, _question: String, default: bool) -> bool { self.ask_confirmation.unwrap_or(default) @@ -251,8 +251,8 @@ impl IOInterfaceImmutable for IOStub { _attempts: PhpMixed, _error_message: String, _multiselect: bool, - ) -> PhpMixed { - default + ) -> anyhow::Result<PhpMixed> { + Ok(default) } fn get_authentications( diff --git a/crates/shirabe/tests/io/buffer_io_test.rs b/crates/shirabe/tests/io/buffer_io_test.rs index 5bb18014..c33fd804 100644 --- a/crates/shirabe/tests/io/buffer_io_test.rs +++ b/crates/shirabe/tests/io/buffer_io_test.rs @@ -19,9 +19,11 @@ fn test_set_user_inputs() { assert!(!buffer_io.ask_confirmation("Now please say no!".to_string(), true)); assert_eq!( PhpMixed::String("default".to_string()), - buffer_io.ask( - "Empty string last".to_string(), - PhpMixed::String("default".to_string()) - ) + buffer_io + .ask( + "Empty string last".to_string(), + PhpMixed::String("default".to_string()) + ) + .unwrap() ); } diff --git a/crates/shirabe/tests/io/console_io_test.rs b/crates/shirabe/tests/io/console_io_test.rs index 03307e51..15e7100b 100644 --- a/crates/shirabe/tests/io/console_io_test.rs +++ b/crates/shirabe/tests/io/console_io_test.rs @@ -196,7 +196,9 @@ fn test_ask() { // PHP asserts QuestionHelper::ask receives a Question. Behaviorally, an interactive input whose // stream yields the answer makes ConsoleIO::ask return that answer. let (console_io, _output) = make_console_io_with_answer("answer\n"); - let result = console_io.ask("Why?".to_string(), PhpMixed::String("default".to_string())); + let result = console_io + .ask("Why?".to_string(), PhpMixed::String("default".to_string())) + .unwrap(); assert_eq!(PhpMixed::String("answer".to_string()), result); } @@ -247,7 +249,7 @@ fn test_select() { ); assert_eq!( PhpMixed::List(vec![PhpMixed::String("1".to_string())]), - result + result.unwrap() ); } diff --git a/crates/shirabe/tests/io/null_io_test.rs b/crates/shirabe/tests/io/null_io_test.rs index 1627e91f..ced598b9 100644 --- a/crates/shirabe/tests/io/null_io_test.rs +++ b/crates/shirabe/tests/io/null_io_test.rs @@ -45,6 +45,7 @@ fn test_ask() { assert_eq!( PhpMixed::String("foo".to_string()), io.ask("bar".to_string(), PhpMixed::String("foo".to_string())) + .unwrap() ); } @@ -88,5 +89,6 @@ fn test_select() { "foo".to_string(), true ) + .unwrap() ); } diff --git a/crates/shirabe/tests/util/perforce_test.rs b/crates/shirabe/tests/util/perforce_test.rs index b63a5e0e..293e56d5 100644 --- a/crates/shirabe/tests/util/perforce_test.rs +++ b/crates/shirabe/tests/util/perforce_test.rs @@ -184,7 +184,7 @@ fn test_generate_p4_command() { fn test_query_p4_user_with_user_already_set() { let mut perforce = create_new_perforce_with_windows_flag(true); - perforce.query_p4_user(); + perforce.query_p4_user().unwrap(); assert_eq!(Some(TEST_P4USER.to_string()), perforce.get_user()); } @@ -205,7 +205,7 @@ fn test_query_p4_user_with_user_set_in_p4_variables_with_windows_os() { let mut perforce = create_perforce(true, process, io); perforce.set_user(None); - perforce.query_p4_user(); + perforce.query_p4_user().unwrap(); assert_eq!( Some("TEST_P4VARIABLE_USER".to_string()), perforce.get_user() @@ -229,7 +229,7 @@ fn test_query_p4_user_with_user_set_in_p4_variables_not_windows_os() { let mut perforce = create_perforce(false, process, io); perforce.set_user(None); - perforce.query_p4_user(); + perforce.query_p4_user().unwrap(); assert_eq!( Some("TEST_P4VARIABLE_USER".to_string()), perforce.get_user() @@ -248,7 +248,7 @@ fn test_query_p4_user_queries_for_user() { let mut perforce = create_perforce(true, process, io); perforce.set_user(None); - perforce.query_p4_user(); + perforce.query_p4_user().unwrap(); assert_eq!(Some("TEST_QUERY_USER".to_string()), perforce.get_user()); } @@ -270,7 +270,7 @@ fn test_query_p4_user_stores_response_to_query_for_user_with_windows() { let mut perforce = create_perforce(true, process, io); perforce.set_user(None); - perforce.query_p4_user(); + perforce.query_p4_user().unwrap(); } #[test] @@ -294,7 +294,7 @@ fn test_query_p4_user_stores_response_to_query_for_user_without_windows() { let mut perforce = create_perforce(false, process, io); perforce.set_user(None); - perforce.query_p4_user(); + perforce.query_p4_user().unwrap(); } #[test] @@ -315,7 +315,7 @@ fn test_query_p4_user_escapes_injection_on_windows() { let mut perforce = create_perforce(true, process, io); perforce.set_user(None); - perforce.query_p4_user(); + perforce.query_p4_user().unwrap(); } #[test] @@ -335,7 +335,7 @@ fn test_query_p4_user_escapes_injection_on_unix() { let mut perforce = create_perforce(false, process, io); perforce.set_user(None); - perforce.query_p4_user(); + perforce.query_p4_user().unwrap(); } #[test] |
