use crate::{OrgMode, OrgModeError, config::OrgConfig};
use std::fs;
use tempfile::TempDir;
#[test]
fn test_invalid_directory_error() {
let result = OrgMode::new(OrgConfig {
org_directory: "/completely/nonexistent/directory/path".to_string(),
..OrgConfig::default()
});
assert!(result.is_err());
let err = result.unwrap_err();
match err {
OrgModeError::ConfigError(msg) => {
assert!(msg.contains("/completely/nonexistent/directory/path"));
}
_ => panic!("Root directory does not exist: {:?}", err),
}
}
#[test]
fn test_file_not_found_error() {
let temp_dir = TempDir::new().unwrap();
let config = OrgConfig {
org_directory: temp_dir.path().to_str().unwrap().to_string(),
..OrgConfig::default()
};
let org_mode = OrgMode::new(config).unwrap();
let result = org_mode.read_file("nonexistent.org");
assert!(result.is_err());
let err = result.unwrap_err();
match err {
OrgModeError::IoError(_) => {
}
_ => panic!("Expected IoError for file not found, got: {:?}", err),
}
}
#[test]
fn test_invalid_heading_path_error() {
let temp_dir = TempDir::new().unwrap();
let temp_path = temp_dir.path();
fs::write(
temp_path.join("test.org"),
r#"* First Heading
Content here.
* Second Heading
More content.
"#,
)
.unwrap();
let config = OrgConfig {
org_directory: temp_path.to_str().unwrap().to_string(),
..OrgConfig::default()
};
let org_mode = OrgMode::new(config).unwrap();
let result = org_mode.get_heading("test.org", "Nonexistent Heading");
assert!(result.is_err());
let err = result.unwrap_err();
match err {
OrgModeError::InvalidHeadingPath(path) => {
assert!(path.contains("Nonexistent Heading"));
}
_ => panic!("Expected InvalidHeadingPath error, got: {:?}", err),
}
}
#[test]
fn test_invalid_element_id_error() {
let temp_dir = TempDir::new().unwrap();
let temp_path = temp_dir.path();
fs::write(
temp_path.join("test.org"),
r#"* Heading
:PROPERTIES:
:ID: real-id-123
:END:
Some content.
"#,
)
.unwrap();
let config = OrgConfig {
org_directory: temp_path.to_str().unwrap().to_string(),
..OrgConfig::default()
};
let org_mode = OrgMode::new(config).unwrap();
let result = org_mode.get_element_by_id("nonexistent-id");
assert!(result.is_err());
let err = result.unwrap_err();
match err {
OrgModeError::InvalidElementId(id) => {
assert_eq!(id, "nonexistent-id");
}
_ => panic!("Expected InvalidElementId error, got: {:?}", err),
}
}
#[test]
fn test_parsing_error_handling() {
let temp_dir = TempDir::new().unwrap();
let temp_path = temp_dir.path();
fs::write(
temp_path.join("malformed.org"),
"This is not a valid org file with weird control characters: \x00\x01\x02",
)
.unwrap();
let config = OrgConfig {
org_directory: temp_path.to_str().unwrap().to_string(),
..OrgConfig::default()
};
let org_mode = OrgMode::new(config).unwrap();
let result = org_mode.read_file("malformed.org");
assert!(result.is_ok());
}
#[test]
fn test_empty_file_handling() {
let temp_dir = TempDir::new().unwrap();
let temp_path = temp_dir.path();
fs::write(temp_path.join("empty.org"), "").unwrap();
let config = OrgConfig {
org_directory: temp_path.to_str().unwrap().to_string(),
..OrgConfig::default()
};
let org_mode = OrgMode::new(config).unwrap();
let result = org_mode.read_file("empty.org");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "");
let outline_result = org_mode.get_outline("empty.org");
assert!(outline_result.is_ok());
let outline = outline_result.unwrap();
assert!(outline.children.is_empty());
}
#[test]
fn test_io_error_propagation() {
let temp_dir = TempDir::new().unwrap();
let temp_path = temp_dir.path();
fs::write(temp_path.join("test.org"), "* Test\nContent").unwrap();
let config = OrgConfig {
org_directory: temp_path.to_str().unwrap().to_string(),
..OrgConfig::default()
};
let org_mode = OrgMode::new(config).unwrap();
let result = org_mode.read_file("test.org");
assert!(result.is_ok());
}
#[test]
fn test_with_defaults_error_handling() {
let result = OrgMode::with_defaults();
match result {
Ok(_) => {
}
Err(err) => {
match err {
OrgModeError::InvalidDirectory(_) | OrgModeError::ConfigError(_) => {
}
_ => panic!("Unexpected error type: {:?}", err),
}
}
}
}
#[test]
fn test_error_display_formatting() {
let error = OrgModeError::InvalidDirectory("/some/path".to_string());
let display = format!("{}", error);
assert!(display.contains("/some/path"));
assert!(display.contains("Invalid or inaccessible directory"));
let error = OrgModeError::InvalidHeadingPath("Some/Path".to_string());
let display = format!("{}", error);
assert!(display.contains("Some/Path"));
assert!(display.contains("Invalid heading path"));
let error = OrgModeError::InvalidElementId("id-123".to_string());
let display = format!("{}", error);
assert!(display.contains("id-123"));
assert!(display.contains("Invalid element id"));
let error = OrgModeError::ShellExpansionError("~/path".to_string());
let display = format!("{}", error);
assert!(display.contains("~/path"));
assert!(display.contains("Failed to expand path"));
let error = OrgModeError::ConfigError("Invalid configuration".to_string());
let display = format!("{}", error);
assert!(display.contains("Invalid configuration"));
assert!(display.contains("Configuration error"));
}
#[test]
fn test_error_source_chain() {
use std::error::Error;
let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let org_error = OrgModeError::from(io_error);
assert!(org_error.source().is_some());
let io_error2 = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "permission denied");
let org_error2 = OrgModeError::IoError(io_error2);
assert!(org_error2.source().is_some());
let config_error = OrgModeError::ConfigError("test error".to_string());
assert!(config_error.source().is_none());
let invalid_dir = OrgModeError::InvalidDirectory("/path".to_string());
assert!(invalid_dir.source().is_none());
}
#[test]
fn test_config_error_conversion() {
use config::File;
let config_builder = config::Config::builder()
.add_source(File::from_str("invalid toml{{{", config::FileFormat::Toml));
let result = config_builder.build();
assert!(result.is_err());
let config_err = result.unwrap_err();
let org_error: OrgModeError = config_err.into();
match org_error {
OrgModeError::ConfigError(msg) => {
assert!(!msg.is_empty());
}
_ => panic!("Expected ConfigError variant"),
}
}
#[test]
fn test_glob_error_conversion_and_display() {
use globset::GlobBuilder;
let result = GlobBuilder::new("[invalid").build();
assert!(result.is_err());
let glob_err = result.unwrap_err();
let org_error: OrgModeError = glob_err.into();
match &org_error {
OrgModeError::GlobError(_) => {
let display = format!("{}", org_error);
assert!(display.contains("Error with glob pattern"));
}
_ => panic!("Expected GlobError variant, got: {:?}", org_error),
}
use std::error::Error;
assert!(org_error.source().is_none());
}
#[test]
fn test_invalid_agenda_view_type_error() {
let error = OrgModeError::InvalidAgendaViewType("invalid-view".to_string());
let display = format!("{}", error);
assert!(display.contains("Invalid agenda view type"));
assert!(display.contains("invalid-view"));
use std::error::Error;
assert!(error.source().is_none());
}
#[test]
fn test_walk_error_conversion_and_source() {
use ignore::WalkBuilder;
let walker = WalkBuilder::new("/nonexistent/path/that/does/not/exist").build();
for result in walker {
if let Err(walk_err) = result {
let org_error: OrgModeError = walk_err.into();
match &org_error {
OrgModeError::WalkError(_) => {
let display = format!("{}", org_error);
assert!(display.contains("Error walking directory"));
}
_ => panic!("Expected WalkError variant, got: {:?}", org_error),
}
use std::error::Error;
assert!(
org_error.source().is_some(),
"WalkError should have a source"
);
return;
}
}
}
#[test]
fn test_invalid_timestamp_display_includes_repeater_warning_grammar() {
let err = OrgModeError::InvalidTimestamp {
field: "scheduled",
value: "bad".to_string(),
};
let msg = err.to_string();
assert!(
msg.contains("repeater") || msg.contains("++") || msg.contains(".+"),
"error message should describe repeater syntax, got: {msg}"
);
assert!(
msg.contains("warning") || msg.contains("-N") || msg.contains("-3d"),
"error message should describe warning syntax, got: {msg}"
);
}