#[allow(clippy::unwrap_used)]
#[allow(clippy::panic)]
#[cfg(test)]
mod tests {
use crate::error::{
Error, FileSystemError, FileSystemResult, MonorepoError, MonorepoResult, Result,
WorkspaceError, WorkspaceResult,
};
use std::{
io,
path::{Path, PathBuf},
};
#[test]
fn test_filesystem_error_display() {
let not_found = FileSystemError::NotFound { path: "/test".into() };
assert_eq!(not_found.to_string(), "Path not found: /test");
let io_error = FileSystemError::from_io(io::Error::other("disk full"), "/data");
assert_eq!(io_error.to_string(), "I/O error accessing path '/data': disk full");
}
#[test]
fn test_validation_error() {
let validation_error = FileSystemError::validation("/a/../b", "Parent traversal");
assert_eq!(
validation_error.to_string(),
"Path validation failed for '/a/../b': Parent traversal"
);
}
#[test]
fn test_from_io_method() {
let not_found_error = io::Error::new(io::ErrorKind::NotFound, "file not found");
let fs_error = FileSystemError::from_io(not_found_error, "/missing/file.txt");
assert!(
matches!(fs_error, FileSystemError::NotFound { ref path } if path == Path::new("/missing/file.txt"))
);
let permission_error = io::Error::new(io::ErrorKind::PermissionDenied, "permission denied");
let fs_error = FileSystemError::from_io(permission_error, "/protected/file.txt");
assert!(
matches!(fs_error, FileSystemError::PermissionDenied { ref path } if path == Path::new("/protected/file.txt"))
);
let other_error = io::Error::other("unknown error");
let fs_error = FileSystemError::from_io(other_error, "/some/file.txt");
assert!(
matches!(fs_error, FileSystemError::Io { ref path, .. } if path == Path::new("/some/file.txt"))
);
}
#[test]
fn test_from_io_error_trait_implementation() {
let not_found_error = io::Error::new(io::ErrorKind::NotFound, "file not found");
let fs_error: FileSystemError = not_found_error.into();
assert!(
matches!(fs_error, FileSystemError::NotFound { ref path } if path == Path::new("<unknown>"))
);
let permission_error = io::Error::new(io::ErrorKind::PermissionDenied, "permission denied");
let fs_error: FileSystemError = permission_error.into();
assert!(
matches!(fs_error, FileSystemError::PermissionDenied { ref path } if path == Path::new("<unknown>"))
);
let other_error = io::Error::other("unknown error");
let fs_error: FileSystemError = other_error.into();
assert!(
matches!(fs_error, FileSystemError::Io { ref path, .. } if path == Path::new("<unknown>"))
);
}
#[test]
fn test_as_ref_implementation() {
let not_found = FileSystemError::NotFound { path: "/test".into() };
assert_eq!(not_found.as_ref(), "FileSystemError::NotFound");
let permission_denied = FileSystemError::PermissionDenied { path: "/test".into() };
assert_eq!(permission_denied.as_ref(), "FileSystemError::PermissionDenied");
let io_error =
FileSystemError::Io { path: "/test".into(), message: "test error".to_string() };
assert_eq!(io_error.as_ref(), "FileSystemError::Io");
let not_a_directory = FileSystemError::NotADirectory { path: "/test".into() };
assert_eq!(not_a_directory.as_ref(), "FileSystemError::NotADirectory");
let not_a_file = FileSystemError::NotAFile { path: "/test".into() };
assert_eq!(not_a_file.as_ref(), "FileSystemError::NotAFile");
let invalid_utf8 = vec![0xFF, 0xFF]; let utf8_error = String::from_utf8(invalid_utf8).unwrap_err();
let utf8_decode =
FileSystemError::Utf8Decode { path: "/test".into(), message: utf8_error.to_string() };
assert_eq!(utf8_decode.as_ref(), "FileSystemError::Utf8Decode");
let validation =
FileSystemError::Validation { path: "/test".into(), reason: "Invalid path".into() };
assert_eq!(validation.as_ref(), "FileSystemError::Validation");
}
#[test]
fn test_remaining_error_variants_display() {
let not_a_directory = FileSystemError::NotADirectory { path: "/test/dir".into() };
assert_eq!(not_a_directory.to_string(), "Expected a directory but found a file: /test/dir");
let not_a_file = FileSystemError::NotAFile { path: "/test/file".into() };
assert_eq!(not_a_file.to_string(), "Expected a file but found a directory: /test/file");
let invalid_utf8 = vec![0xFF, 0xFF]; let utf8_error = String::from_utf8(invalid_utf8).unwrap_err();
let utf8_decode = FileSystemError::Utf8Decode {
path: "/test/file.txt".into(),
message: utf8_error.to_string(),
};
assert!(
utf8_decode.to_string().starts_with(
"Failed to decode UTF-8 content in file: /test/file.txt - invalid utf-8"
)
);
let permission_denied =
FileSystemError::PermissionDenied { path: "/test/protected".into() };
assert_eq!(permission_denied.to_string(), "Permission denied for path: /test/protected");
}
#[test]
fn test_monorepo_error_variants() {
let fs_error = FileSystemError::NotFound { path: PathBuf::from("/missing/workspace.yaml") };
let detection_error = MonorepoError::Detection { source: fs_error };
assert!(detection_error.to_string().contains("Failed to detect monorepo type"));
let fs_error = FileSystemError::Utf8Decode {
path: PathBuf::from("/project/workspace.yaml"),
message: String::from_utf8(vec![0xFF, 0xFF]).unwrap_err().to_string(),
};
let parsing_error = MonorepoError::Parsing { source: fs_error };
assert!(parsing_error.to_string().contains("Failed to parse monorepo descriptor"));
let fs_error =
FileSystemError::PermissionDenied { path: PathBuf::from("/protected/workspace.yaml") };
let reading_error = MonorepoError::Reading { source: fs_error };
assert!(reading_error.to_string().contains("Failed to read monorepo descriptor"));
let fs_error = FileSystemError::Io {
path: PathBuf::from("/full/disk/workspace.yaml"),
message: "disk full".to_string(),
};
let writing_error = MonorepoError::Writing { source: fs_error };
assert!(writing_error.to_string().contains("Failed to write monorepo descriptor"));
let manager_not_found = MonorepoError::ManagerNotFound;
assert_eq!(manager_not_found.to_string(), "Failed to find package manager");
}
#[test]
fn test_monorepo_result_usage() {
fn find_workspace(path: &str) -> MonorepoResult<String> {
if path.is_empty() {
let fs_error = FileSystemError::Validation {
path: PathBuf::from("<empty>"),
reason: "Empty path provided".to_string(),
};
return Err(MonorepoError::Detection { source: fs_error });
}
Ok("Found workspace".to_string())
}
let result = find_workspace("/valid/path");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "Found workspace");
let result = find_workspace("");
assert!(result.is_err());
match result {
Err(MonorepoError::Detection { source }) => {
assert!(matches!(source, FileSystemError::Validation { .. }));
}
_ => panic!("Expected Detection error"),
}
}
#[test]
fn test_filesystem_to_monorepo_error_conversion() {
fn read_workspace_file(path: &str) -> MonorepoResult<String> {
let path_buf = PathBuf::from(path);
let fs_result: FileSystemResult<String> =
Err(FileSystemError::NotFound { path: path_buf.clone() });
fs_result.map_err(|e| MonorepoError::Reading { source: e })
}
let result = read_workspace_file("/missing/workspace.yaml");
assert!(result.is_err());
match result {
Err(MonorepoError::Reading { source }) => {
assert!(matches!(source, FileSystemError::NotFound { .. }));
}
_ => panic!("Expected Reading error with NotFound source"),
}
}
#[test]
fn test_workspace_error_variants() {
let invalid_json = WorkspaceError::InvalidPackageJson("Missing name field".to_string());
assert_eq!(invalid_json.to_string(), "Invalid package json format: Missing name field");
let invalid_pattern =
WorkspaceError::InvalidWorkspacesPattern("Invalid glob pattern".to_string());
assert_eq!(invalid_pattern.to_string(), "Invalid workspaces pattern: Invalid glob pattern");
let invalid_pnpm = WorkspaceError::InvalidPnpmWorkspace("Invalid YAML syntax".to_string());
assert_eq!(invalid_pnpm.to_string(), "Invalid workspaces pattern: Invalid YAML syntax");
let pkg_not_found = WorkspaceError::PackageNotFound("ui-components".to_string());
assert_eq!(pkg_not_found.to_string(), "Package not found: ui-components");
let workspace_not_found = WorkspaceError::WorkspaceNotFound("frontend".to_string());
assert_eq!(workspace_not_found.to_string(), "Workspace not found: frontend");
let config_missing =
WorkspaceError::WorkspaceConfigMissing("No workspaces field".to_string());
assert_eq!(config_missing.to_string(), "Workspace config is missing: No workspaces field");
}
#[test]
fn test_workspace_error_conversion_to_error() {
let workspace_error = WorkspaceError::PackageNotFound("test-pkg".to_string());
let error: Error = workspace_error.into();
match error {
Error::Workspace(inner) => {
assert!(matches!(inner, WorkspaceError::PackageNotFound(_)));
if let WorkspaceError::PackageNotFound(name) = inner {
assert_eq!(name, "test-pkg");
} else {
panic!("Wrong error variant");
}
}
_ => panic!("Expected Workspace error variant"),
}
}
#[test]
fn test_workspace_result_usage() {
fn validate_workspace_name(name: &str) -> WorkspaceResult<String> {
if name.is_empty() {
return Err(WorkspaceError::WorkspaceNotFound("Empty name provided".to_string()));
}
if name.contains(' ') {
return Err(WorkspaceError::InvalidWorkspacesPattern(
"Spaces not allowed".to_string(),
));
}
Ok(format!("Valid workspace: {name}"))
}
let result = validate_workspace_name("test-workspace");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "Valid workspace: test-workspace");
let result = validate_workspace_name("");
assert!(result.is_err());
match result {
Err(WorkspaceError::WorkspaceNotFound(_)) => { }
_ => panic!("Expected WorkspaceNotFound error"),
}
let result = validate_workspace_name("invalid workspace");
assert!(result.is_err());
match result {
Err(WorkspaceError::InvalidWorkspacesPattern(_)) => { }
_ => panic!("Expected InvalidWorkspacesPattern error"),
}
}
#[test]
fn test_workspace_error_to_composite_error() {
fn process_workspace(valid: bool) -> Result<()> {
if !valid {
return Err(
WorkspaceError::WorkspaceConfigMissing("Required config".to_string()).into()
);
}
Ok(())
}
let result = process_workspace(true);
assert!(result.is_ok());
let result = process_workspace(false);
assert!(result.is_err());
match result {
Err(Error::Workspace(inner)) => {
assert!(matches!(inner, WorkspaceError::WorkspaceConfigMissing(_)));
}
_ => panic!("Expected Workspace error variant"),
}
}
}