Skip to main content

clawless_core/prompt/
prompt_user_error.rs

1use thiserror::Error;
2
3use super::AnswerPromptError;
4use crate::event::SendError;
5
6/// The error returned when a command cannot get an answer from its user
7///
8/// No variant is an answer, so a command must not treat one as a yes, a no, or a default. Every
9/// variant carries the text of the question.
10///
11/// A later release can add variants, and it can add fields to a variant. Match with a wildcard
12/// arm, and bind the fields of a variant with `..`.
13#[derive(Debug, Error)]
14#[non_exhaustive]
15pub enum PromptUserError {
16    /// No user is present who can answer
17    ///
18    /// The [`Interactivity`] of the prompt is `NonInteractive`. The prompt sends no request.
19    ///
20    /// [`Interactivity`]: crate::context::Interactivity
21    #[error("no user is present to answer the prompt `{question}`")]
22    #[non_exhaustive]
23    AbsentUser {
24        /// The text of the question
25        question: String,
26    },
27
28    /// Cancellation stopped the prompt before the user answered
29    #[error("the prompt `{question}` was cancelled before the user answered")]
30    #[non_exhaustive]
31    CancelledPrompt {
32        /// The text of the question
33        question: String,
34    },
35
36    /// The command asked the user to select from no options
37    ///
38    /// The prompt sends no request.
39    #[error("the prompt `{question}` has no options to select from")]
40    #[non_exhaustive]
41    MissingOptions {
42        /// The text of the question
43        question: String,
44    },
45
46    /// The presenter returned no answer
47    ///
48    /// The source is the reason.
49    #[error("failed to get an answer to the prompt `{question}`")]
50    #[non_exhaustive]
51    UnansweredPrompt {
52        /// The text of the question
53        question: String,
54
55        /// The cause of the failure
56        source: AnswerPromptError,
57    },
58
59    /// The answer names an option that the prompt does not have
60    ///
61    /// The presenter sent a position beyond the options. The cause is a fault in the presenter,
62    /// or a script of a test that does not match the question.
63    #[error(
64        "the answer to the prompt `{question}` names option {index}, and the prompt has {count} options"
65    )]
66    #[non_exhaustive]
67    UnknownOption {
68        /// The text of the question
69        question: String,
70
71        /// The position that the answer names, where the first option has the position zero
72        index: usize,
73
74        /// The count of the options that the prompt has
75        count: usize,
76    },
77
78    /// The prompt could not be sent to the presenter
79    ///
80    /// The event channel is closed.
81    #[error("failed to send the prompt `{question}` to the presenter")]
82    #[non_exhaustive]
83    UndeliverablePrompt {
84        /// The text of the question
85        question: String,
86
87        /// The cause of the failure
88        source: SendError,
89    },
90}
91
92#[cfg(test)]
93mod tests {
94    // An assertion in a test panics by design. A `# Panics` section on every test
95    // would repeat that and give the reader no information.
96    #![allow(clippy::missing_panics_doc)]
97
98    use super::*;
99
100    #[test]
101    fn display_with_a_cancelled_prompt_names_the_question() {
102        let error = PromptUserError::CancelledPrompt {
103            question: "Release?".to_owned(),
104        };
105
106        let message = error.to_string();
107
108        assert_eq!(
109            message,
110            "the prompt `Release?` was cancelled before the user answered"
111        );
112    }
113
114    #[test]
115    fn display_with_an_absent_user_names_the_question() {
116        let error = PromptUserError::AbsentUser {
117            question: "Release?".to_owned(),
118        };
119
120        let message = error.to_string();
121
122        assert_eq!(
123            message,
124            "no user is present to answer the prompt `Release?`"
125        );
126    }
127
128    #[test]
129    fn display_with_an_unanswered_prompt_names_the_question() {
130        let error = PromptUserError::UnansweredPrompt {
131            question: "Release?".to_owned(),
132            source: AnswerPromptError::ClosedInput,
133        };
134
135        let message = error.to_string();
136
137        assert_eq!(message, "failed to get an answer to the prompt `Release?`");
138    }
139
140    #[test]
141    fn trait_send() {
142        fn assert_send<T: Send>() {}
143        assert_send::<PromptUserError>();
144    }
145
146    #[test]
147    fn trait_sync() {
148        fn assert_sync<T: Sync>() {}
149        assert_sync::<PromptUserError>();
150    }
151
152    #[test]
153    fn trait_unpin() {
154        fn assert_unpin<T: Unpin>() {}
155        assert_unpin::<PromptUserError>();
156    }
157}