1use alloc::string::String;
2use core::fmt;
3use core::num::ParseIntError;
4
5pub mod lang;
6pub(crate) mod messages;
7
8#[derive(Debug, PartialEq)]
22pub enum Error {
23 InvalidData(String),
25 Signal(String),
27 Message(String),
29 Dbc(String),
31 Version(String),
33 Nodes(String),
35}
36
37impl fmt::Display for Error {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 Error::InvalidData(msg) => {
41 write!(f, "{}", messages::format_invalid_data(msg))
43 }
44 Error::Signal(msg) => {
45 write!(f, "{}", messages::format_signal_error(msg))
47 }
48 Error::Message(msg) => {
49 write!(f, "{}", messages::format_message_error(msg))
50 }
51 Error::Dbc(msg) => {
52 write!(f, "{}", messages::format_dbc_error(msg))
53 }
54 Error::Version(msg) => {
55 write!(f, "{}", messages::format_version_error(msg))
56 }
57 Error::Nodes(msg) => {
58 write!(f, "{}", messages::format_nodes_error(msg))
59 }
60 }
61 }
62}
63
64impl From<ParseIntError> for Error {
65 fn from(err: ParseIntError) -> Self {
66 Error::InvalidData(messages::parse_number_failed(err))
67 }
68}
69
70#[cfg(feature = "std")]
71impl std::error::Error for Error {
72 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
73 None
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::Error;
80 use crate::error::lang;
81 use alloc::string::ToString;
82
83 #[test]
84 fn test_from_parse_int_error() {
85 let parse_error = "invalid".parse::<u32>().unwrap_err();
87 let error: Error = parse_error.into();
88
89 match error {
90 Error::InvalidData(msg) => {
91 assert!(msg.contains(lang::FORMAT_PARSE_NUMBER_FAILED.split(':').next().unwrap()))
92 }
93 _ => panic!("Expected InvalidData error"),
94 }
95 }
96
97 #[test]
98 fn test_display_invalid_data() {
99 let error = Error::InvalidData("Test error message".to_string());
100 let display = error.to_string();
101 assert!(display.starts_with(lang::INVALID_DATA_CATEGORY));
102 assert!(display.contains("Test error message"));
103 }
104
105 #[test]
106 fn test_display_signal_error() {
107 let error = Error::Signal(lang::SIGNAL_NAME_EMPTY.to_string());
108 let display = error.to_string();
109 assert!(display.starts_with(lang::SIGNAL_ERROR_CATEGORY));
110 assert!(display.contains(lang::SIGNAL_NAME_EMPTY));
111 }
112
113 #[test]
114 fn test_display_formatting() {
115 let error = Error::InvalidData(
117 "Duplicate message ID: 256 (messages 'EngineData' and 'BrakeData')".to_string(),
118 );
119 let display = error.to_string();
120 assert!(display.starts_with(lang::INVALID_DATA_CATEGORY));
121 assert!(display.contains("256"));
122 assert!(display.contains("EngineData"));
123 assert!(display.contains("BrakeData"));
124 }
125
126 #[test]
127 fn test_display_parse_error() {
128 let parse_error = "not_a_number".parse::<u32>().unwrap_err();
129 let error: Error = parse_error.into();
130 let display = error.to_string();
131
132 assert!(display.starts_with(lang::INVALID_DATA_CATEGORY));
133 assert!(display.contains(lang::FORMAT_PARSE_NUMBER_FAILED.split(':').next().unwrap()));
134 }
135
136 #[cfg(feature = "std")]
137 #[test]
138 fn test_std_error_trait() {
139 use std::error::Error as StdError;
140
141 let error = Error::InvalidData("Test".to_string());
142 let _: &dyn StdError = &error;
144
145 assert!(error.source().is_none());
147 }
148}