use std::path::PathBuf;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum SearchError {
#[error("Invalid regex pattern: {pattern}")]
InvalidPattern {
pattern: String,
#[source]
source: regex::Error,
},
#[error("File not found: {path}")]
FileNotFound { path: PathBuf },
#[error("Directory not found: {path}")]
DirectoryNotFound { path: PathBuf },
#[error("I/O error: {message}")]
IoError {
message: String,
#[source]
source: std::io::Error,
},
#[error("Cache error: {message}")]
CacheError { message: String },
#[error("Search cancelled")]
Cancelled,
#[error("Maximum results limit exceeded: {limit}")]
MaxResultsExceeded { limit: usize },
#[error("Invalid search options: {message}")]
InvalidOptions { message: String },
}
#[derive(Error, Debug)]
pub enum AnalysisError {
#[error("Failed to parse file: {path}")]
ParseError {
path: PathBuf,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("Unsupported file type: {extension}")]
UnsupportedFileType { extension: String },
#[error("Invalid input: {message}")]
InvalidInput { message: String },
#[error("Complexity calculation failed: {message}")]
ComplexityError { message: String },
#[error("I/O error during analysis: {message}")]
IoError {
message: String,
#[source]
source: std::io::Error,
},
}
#[derive(Error, Debug)]
pub enum GraphError {
#[error("Failed to build graph: {message}")]
BuildError { message: String },
#[error("Invalid graph structure: {message}")]
InvalidStructure { message: String },
#[error("Node not found: {node_id}")]
NodeNotFound { node_id: String },
#[error("Cycle detected in graph")]
CycleDetected,
#[error("Failed to export graph: {format}")]
ExportError { format: String },
}
#[derive(Error, Debug)]
pub enum RemoteError {
#[error("Network request failed: {url}")]
NetworkError {
url: String,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("Authentication failed")]
AuthenticationFailed,
#[error("API rate limit exceeded")]
RateLimitExceeded,
#[error("Repository not found: {repo}")]
RepositoryNotFound { repo: String },
#[error("Failed to clone repository: {repo}")]
CloneFailed { repo: String },
}
impl From<std::io::Error> for SearchError {
fn from(err: std::io::Error) -> Self {
SearchError::IoError {
message: err.to_string(),
source: err,
}
}
}
impl From<regex::Error> for SearchError {
fn from(err: regex::Error) -> Self {
SearchError::InvalidPattern {
pattern: String::new(),
source: err,
}
}
}
impl From<std::io::Error> for AnalysisError {
fn from(err: std::io::Error) -> Self {
AnalysisError::IoError {
message: err.to_string(),
source: err,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::error::Error;
#[test]
fn test_search_error_display() {
let err = SearchError::FileNotFound {
path: PathBuf::from("/test/file.rs"),
};
assert_eq!(err.to_string(), "File not found: /test/file.rs");
}
#[test]
fn test_analysis_error_display() {
let err = AnalysisError::UnsupportedFileType {
extension: "xyz".to_string(),
};
assert_eq!(err.to_string(), "Unsupported file type: xyz");
}
#[test]
fn test_graph_error_display() {
let err = GraphError::NodeNotFound {
node_id: "node123".to_string(),
};
assert_eq!(err.to_string(), "Node not found: node123");
}
#[test]
fn test_remote_error_display() {
let err = RemoteError::RepositoryNotFound {
repo: "user/repo".to_string(),
};
assert_eq!(err.to_string(), "Repository not found: user/repo");
}
#[test]
fn test_io_error_conversion() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let search_err: SearchError = io_err.into();
assert!(matches!(search_err, SearchError::IoError { .. }));
}
#[test]
fn test_error_source_chain() {
let regex_err = regex::Regex::new("[").unwrap_err();
let search_err = SearchError::InvalidPattern {
pattern: "[".to_string(),
source: regex_err,
};
assert!(search_err.source().is_some());
}
}