1use mmdvm_core::{MmdvmError, ModemMode, NakReason};
4use thiserror::Error;
5
6#[derive(Debug, Error)]
8#[non_exhaustive]
9pub enum ShellError {
10 #[error("MMDVM session task has exited")]
13 SessionClosed,
14 #[error(transparent)]
16 Core(#[from] MmdvmError),
17 #[error("MMDVM transport I/O error: {0}")]
19 Io(#[from] std::io::Error),
20 #[error("MMDVM TX buffer full for mode {mode:?}; frame dropped")]
24 BufferFull {
25 mode: ModemMode,
27 },
28 #[error("modem rejected command 0x{command:02X}: {reason:?}")]
30 Nak {
31 command: u8,
33 reason: NakReason,
35 },
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn session_closed_display() {
44 let err = ShellError::SessionClosed;
45 assert_eq!(err.to_string(), "MMDVM session task has exited");
46 }
47
48 #[test]
49 fn buffer_full_reports_mode() {
50 let err = ShellError::BufferFull {
51 mode: ModemMode::DStar,
52 };
53 assert!(err.to_string().contains("DStar"));
54 }
55
56 #[test]
57 fn nak_formats_command_in_hex() {
58 let err = ShellError::Nak {
59 command: 0x10,
60 reason: NakReason::BufferFull,
61 };
62 assert!(err.to_string().contains("0x10"));
63 assert!(err.to_string().contains("BufferFull"));
64 }
65
66 #[test]
67 fn core_error_transparent() {
68 let core_err = MmdvmError::InvalidStartByte { got: 0xFF };
69 let shell_err: ShellError = core_err.into();
70 assert!(matches!(shell_err, ShellError::Core(_)));
71 }
72}