Skip to main content

fallow_engine/health/
health_error.rs

1//! Typed health-pipeline error.
2
3/// A health-pipeline failure.
4///
5/// `Message` carries a CLI-facing message the CLI boundary renders; `Printed`
6/// marks an error a lower layer (the runtime-coverage seam) already printed, so
7/// the boundary must NOT re-print it, only honor its exit code.
8#[derive(Debug, Clone)]
9pub enum HealthError {
10    /// A failure the CLI boundary still needs to render.
11    Message {
12        /// CLI-facing error message.
13        message: String,
14        /// Exit code this failure terminates with.
15        exit_code: u8,
16    },
17    /// Already emitted by a lower layer; carry only the exit code.
18    Printed(u8),
19}
20
21impl HealthError {
22    /// Build a [`HealthError::Message`] from a message and exit code.
23    #[must_use]
24    pub fn message(message: impl Into<String>, exit_code: u8) -> Self {
25        Self::Message {
26            message: message.into(),
27            exit_code,
28        }
29    }
30
31    /// The exit code this failure terminates with.
32    #[must_use]
33    pub fn exit_code(&self) -> u8 {
34        match self {
35            Self::Message { exit_code, .. } => *exit_code,
36            Self::Printed(code) => *code,
37        }
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn message_carries_text_and_code() {
47        let err = HealthError::message("boom", 2);
48        assert_eq!(err.exit_code(), 2);
49        match err {
50            HealthError::Message { message, exit_code } => {
51                assert_eq!(message, "boom");
52                assert_eq!(exit_code, 2);
53            }
54            HealthError::Printed(_) => panic!("expected Message variant"),
55        }
56    }
57
58    #[test]
59    fn printed_carries_only_code() {
60        let err = HealthError::Printed(5);
61        assert_eq!(err.exit_code(), 5);
62        assert!(matches!(err, HealthError::Printed(5)));
63    }
64}