Skip to main content

cargo_quality/
error.rs

1// SPDX-FileCopyrightText: 2025 RAprogramm <andrey.rozanov.vl@gmail.com>
2// SPDX-License-Identifier: MIT
3
4//! Error types for cargo-quality operations.
5//!
6//! All errors convert to `masterror::AppError` for consistent error handling.
7//! Includes errors for IO operations, parsing, configuration, and file access.
8
9use std::io;
10
11use masterror::AppError;
12
13/// IO operation failed.
14///
15/// Wraps standard IO errors that occur during file operations.
16#[derive(Debug)]
17pub struct IoError {
18    source: io::Error
19}
20
21impl From<IoError> for AppError {
22    fn from(err: IoError) -> Self {
23        AppError::internal(format!("IO error: {}", err.source))
24    }
25}
26
27/// Syntax parsing failed.
28///
29/// Wraps syn parsing errors when processing Rust source code.
30#[derive(Debug)]
31pub struct ParseError {
32    source: syn::Error
33}
34
35impl From<ParseError> for AppError {
36    fn from(err: ParseError) -> Self {
37        AppError::bad_request(format!("Parse error: {}", err.source))
38    }
39}
40
41/// Invalid configuration.
42///
43/// Indicates configuration validation failure.
44#[derive(Debug)]
45pub struct InvalidConfigError {
46    message: String
47}
48
49impl From<InvalidConfigError> for AppError {
50    fn from(err: InvalidConfigError) -> Self {
51        AppError::bad_request(format!("Invalid configuration: {}", err.message))
52    }
53}
54
55/// File not found.
56///
57/// Indicates requested file does not exist.
58#[derive(Debug)]
59pub struct FileNotFoundError {
60    path: String
61}
62
63impl From<FileNotFoundError> for AppError {
64    fn from(err: FileNotFoundError) -> Self {
65        AppError::not_found(format!("File not found: {}", err.path))
66    }
67}
68
69impl From<io::Error> for IoError {
70    fn from(source: io::Error) -> Self {
71        Self {
72            source
73        }
74    }
75}
76
77impl From<syn::Error> for ParseError {
78    fn from(source: syn::Error) -> Self {
79        Self {
80            source
81        }
82    }
83}
84
85impl InvalidConfigError {
86    /// Create new configuration error with message.
87    ///
88    /// # Arguments
89    ///
90    /// * `message` - Error description
91    pub fn new(message: String) -> Self {
92        Self {
93            message
94        }
95    }
96}
97
98impl FileNotFoundError {
99    /// Create new file not found error with path.
100    ///
101    /// # Arguments
102    ///
103    /// * `path` - File path that was not found
104    pub fn new(path: String) -> Self {
105        Self {
106            path
107        }
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use std::io;
114
115    use super::*;
116
117    #[test]
118    fn test_io_error_from_std_io() {
119        let std_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
120        let io_error = IoError::from(std_err);
121        let _app_error: AppError = io_error.into();
122    }
123
124    #[test]
125    fn test_parse_error_from_syn() {
126        let syn_err = syn::Error::new(proc_macro2::Span::call_site(), "parse failed");
127        let parse_error = ParseError::from(syn_err);
128        let _app_error: AppError = parse_error.into();
129    }
130
131    #[test]
132    fn test_invalid_config_error_new() {
133        let config_err = InvalidConfigError::new("invalid setting".to_string());
134        let _app_error: AppError = config_err.into();
135    }
136
137    #[test]
138    fn test_file_not_found_error_new() {
139        let not_found_err = FileNotFoundError::new("/path/to/file.rs".to_string());
140        let _app_error: AppError = not_found_err.into();
141    }
142}