dbc_rs/error/
error.rs

1use core::fmt;
2
3use crate::error::lang;
4
5/// Error type for DBC operations.
6///
7/// This enum represents all possible errors that can occur when working with DBC files.
8#[derive(Debug, PartialEq, Clone)]
9pub enum Error {
10    /// Unexpected end of input encountered.
11    UnexpectedEof,
12    /// Expected a specific token or value.
13    Expected(&'static str),
14    /// Invalid character encountered.
15    InvalidChar(char),
16    /// String length exceeds the maximum allowed length.
17    MaxStrLength(usize),
18    /// Version-related error.
19    Version(&'static str),
20    /// Message-related error.
21    Message(&'static str),
22    /// Receivers-related error.
23    Receivers(&'static str),
24    /// Nodes-related error.
25    Nodes(&'static str),
26    /// Signal-related error.
27    Signal(&'static str),
28    /// Decoding-related error.
29    Decoding(&'static str),
30    /// Validation-related error.
31    Validation(&'static str),
32}
33
34impl fmt::Display for Error {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            Error::UnexpectedEof => write!(f, "{}", lang::UNEXPECTED_EOF),
38            Error::Expected(msg) => write!(f, "Expected {}", msg),
39            Error::InvalidChar(c) => write!(f, "{}: {}", lang::INVALID_CHARACTER, c),
40            Error::MaxStrLength(max) => {
41                write!(f, "{}: {}", lang::STRING_LENGTH_EXCEEDS_MAX, max)
42            }
43            Error::Version(msg) => write!(f, "{}: {}", lang::VERSION_ERROR_PREFIX, msg),
44            Error::Message(msg) => write!(f, "{}: {}", lang::MESSAGE_ERROR_PREFIX, msg),
45            Error::Receivers(msg) => {
46                write!(f, "{}: {}", lang::RECEIVERS_ERROR_PREFIX, msg)
47            }
48            Error::Nodes(msg) => write!(f, "{}: {}", lang::NODES_ERROR_PREFIX, msg),
49            Error::Signal(msg) => write!(f, "{}: {}", lang::SIGNAL_ERROR_PREFIX, msg),
50            Error::Decoding(msg) => write!(f, "{}: {}", lang::DECODING_ERROR_PREFIX, msg),
51            Error::Validation(msg) => write!(f, "{}: {}", lang::VALIDATION_ERROR_PREFIX, msg),
52        }
53    }
54}
55
56impl From<core::num::ParseIntError> for Error {
57    fn from(_err: core::num::ParseIntError) -> Self {
58        Error::Expected(lang::PARSE_NUMBER_FAILED)
59    }
60}
61
62// std::error::Error is only available with std feature
63#[cfg(feature = "std")]
64impl std::error::Error for Error {
65    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
66        None
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    #![allow(clippy::float_cmp)]
73
74    // Tests that require std feature (for Display/ToString)
75    #[cfg(feature = "std")]
76    mod tests_with_std {
77        use super::super::Error;
78        use crate::error::lang;
79
80        #[test]
81        fn test_from_parse_int_error() {
82            // Create a ParseIntError by trying to parse an invalid string
83            let parse_error = "invalid".parse::<u32>().unwrap_err();
84            let error: Error = parse_error.into();
85
86            match error {
87                Error::Expected(msg) => {
88                    assert_eq!(msg, lang::PARSE_NUMBER_FAILED);
89                }
90                _ => panic!("Expected Error::Expected(lang::PARSE_NUMBER_FAILED)"),
91            }
92        }
93
94        #[test]
95        fn test_display_decoding_error() {
96            let error = Error::Decoding("Test error message");
97            let display = error.to_string();
98            assert!(display.starts_with(lang::DECODING_ERROR_PREFIX));
99            assert!(display.contains("Test error message"));
100        }
101
102        #[test]
103        fn test_display_signal_error() {
104            let error = Error::Signal("Test signal error");
105            let display = error.to_string();
106            assert!(display.starts_with(lang::SIGNAL_ERROR_PREFIX));
107            assert!(display.contains("Test signal error"));
108        }
109
110        #[test]
111        fn test_display_formatting() {
112            // Test that Display properly formats complex error messages
113            let error = Error::Decoding(
114                "Duplicate message ID: 256 (messages 'EngineData' and 'BrakeData')",
115            );
116            let display = error.to_string();
117            assert!(display.starts_with(lang::DECODING_ERROR_PREFIX));
118            assert!(display.contains("256"));
119            assert!(display.contains("EngineData"));
120            assert!(display.contains("BrakeData"));
121        }
122
123        #[test]
124        fn test_display_from_parse_int_error() {
125            let int_error = "not_a_number".parse::<u32>().unwrap_err();
126            let error: Error = int_error.into();
127            let display = error.to_string();
128
129            assert!(display.contains(lang::PARSE_NUMBER_FAILED));
130        }
131    }
132
133    // Tests that require std feature (for std::error::Error trait)
134    // Only available when std is enabled
135    #[cfg(feature = "std")]
136    mod tests_std {
137        use super::super::Error;
138        use std::error::Error as StdError;
139
140        #[test]
141        fn test_std_error_trait() {
142            let error = Error::Decoding("Test");
143            // Verify it implements std::error::Error
144            let _: &dyn StdError = &error;
145
146            // Verify source() returns None (no underlying error)
147            assert!(error.source().is_none());
148        }
149    }
150}