use std::fs;
use std::path::PathBuf;
use tempfile::TempDir;
use xchecker::error::UserFriendlyError;
use xchecker::source::{SourceError, SourceResolver, SourceType};
#[test]
fn test_github_source_resolution_valid() {
let result = SourceResolver::resolve_github("rust-lang", "rust", "12345");
assert!(
result.is_ok(),
"Valid GitHub source should resolve successfully"
);
let content = result.unwrap();
assert!(content.content.contains("GitHub issue #12345"));
assert!(content.content.contains("rust-lang/rust"));
assert_eq!(
content.metadata.get("owner"),
Some(&"rust-lang".to_string())
);
assert_eq!(content.metadata.get("repo"), Some(&"rust".to_string()));
assert_eq!(content.metadata.get("issue_id"), Some(&"12345".to_string()));
match content.source_type {
SourceType::GitHub { owner, repo } => {
assert_eq!(owner, "rust-lang");
assert_eq!(repo, "rust");
}
_ => panic!("Expected GitHub source type"),
}
}
#[test]
fn test_github_source_resolution_with_special_characters() {
let result = SourceResolver::resolve_github("my-org", "my-repo-123", "999");
assert!(
result.is_ok(),
"GitHub source with hyphens and numbers should work"
);
let content = result.unwrap();
assert_eq!(content.metadata.get("owner"), Some(&"my-org".to_string()));
assert_eq!(
content.metadata.get("repo"),
Some(&"my-repo-123".to_string())
);
}
#[test]
fn test_github_validation_empty_owner() {
let result = SourceResolver::resolve_github("", "repo", "123");
assert!(result.is_err(), "Empty owner should fail validation");
match result.unwrap_err() {
SourceError::InvalidFormat { reason } => {
assert!(reason.contains("owner"));
assert!(reason.contains("repo"));
}
_ => panic!("Expected InvalidFormat error"),
}
}
#[test]
fn test_github_validation_empty_repo() {
let result = SourceResolver::resolve_github("owner", "", "123");
assert!(result.is_err(), "Empty repo should fail validation");
match result.unwrap_err() {
SourceError::InvalidFormat { reason } => {
assert!(reason.contains("owner"));
assert!(reason.contains("repo"));
}
_ => panic!("Expected InvalidFormat error"),
}
}
#[test]
fn test_github_validation_invalid_issue_id_non_numeric() {
let result = SourceResolver::resolve_github("owner", "repo", "invalid");
assert!(
result.is_err(),
"Non-numeric issue ID should fail validation"
);
match result.unwrap_err() {
SourceError::InvalidFormat { reason } => {
assert!(reason.contains("valid number"));
}
_ => panic!("Expected InvalidFormat error"),
}
}
#[test]
fn test_github_validation_invalid_issue_id_with_letters() {
let result = SourceResolver::resolve_github("owner", "repo", "123abc");
assert!(
result.is_err(),
"Issue ID with letters should fail validation"
);
match result.unwrap_err() {
SourceError::InvalidFormat { reason } => {
assert!(reason.contains("valid number"));
}
_ => panic!("Expected InvalidFormat error"),
}
}
#[test]
fn test_github_validation_negative_issue_id() {
let result = SourceResolver::resolve_github("owner", "repo", "-123");
assert!(result.is_err(), "Negative issue ID should fail validation");
}
#[test]
fn test_github_validation_zero_issue_id() {
let result = SourceResolver::resolve_github("owner", "repo", "0");
assert!(result.is_ok(), "Zero issue ID should be valid");
}
#[test]
fn test_github_validation_large_issue_id() {
let result = SourceResolver::resolve_github("owner", "repo", "999999999");
assert!(result.is_ok(), "Large issue ID should be valid");
}
#[test]
fn test_filesystem_source_resolution_file() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.txt");
let test_content = "This is a test file for source resolution.";
fs::write(&file_path, test_content).unwrap();
let result = SourceResolver::resolve_filesystem(&file_path);
assert!(
result.is_ok(),
"Valid file source should resolve successfully"
);
let content = result.unwrap();
assert_eq!(content.content, test_content);
assert_eq!(
content.metadata.get("path"),
Some(&file_path.display().to_string())
);
assert_eq!(content.metadata.get("type"), Some(&"file".to_string()));
match content.source_type {
SourceType::FileSystem { path } => {
assert_eq!(path, file_path);
}
_ => panic!("Expected FileSystem source type"),
}
}
#[test]
fn test_filesystem_source_resolution_directory() {
let temp_dir = TempDir::new().unwrap();
let dir_path = temp_dir.path().to_path_buf();
let result = SourceResolver::resolve_filesystem(&dir_path);
assert!(
result.is_ok(),
"Valid directory source should resolve successfully"
);
let content = result.unwrap();
assert!(content.content.contains("Directory source"));
assert!(content.content.contains(&dir_path.display().to_string()));
assert_eq!(
content.metadata.get("path"),
Some(&dir_path.display().to_string())
);
assert_eq!(content.metadata.get("type"), Some(&"directory".to_string()));
}
#[test]
fn test_filesystem_source_resolution_file_with_unicode() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("unicode.txt");
let test_content = "Unicode content: ä½ å¥½ä¸–ç•Œ 🚀 Привет мир";
fs::write(&file_path, test_content).unwrap();
let result = SourceResolver::resolve_filesystem(&file_path);
assert!(
result.is_ok(),
"File with unicode should resolve successfully"
);
let content = result.unwrap();
assert_eq!(content.content, test_content);
}
#[test]
fn test_filesystem_source_resolution_empty_file() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("empty.txt");
fs::write(&file_path, "").unwrap();
let result = SourceResolver::resolve_filesystem(&file_path);
assert!(result.is_ok(), "Empty file should resolve successfully");
let content = result.unwrap();
assert_eq!(content.content, "");
}
#[test]
fn test_filesystem_validation_path_not_found() {
let nonexistent_path = PathBuf::from("/nonexistent/path/to/file.txt");
let result = SourceResolver::resolve_filesystem(&nonexistent_path);
assert!(result.is_err(), "Non-existent path should fail validation");
match result.unwrap_err() {
SourceError::FileSystemNotFound { path } => {
assert!(path.contains("nonexistent"));
}
_ => panic!("Expected FileSystemNotFound error"),
}
}
#[test]
fn test_filesystem_validation_relative_path_not_found() {
let nonexistent_path = PathBuf::from("./this/does/not/exist.txt");
let result = SourceResolver::resolve_filesystem(&nonexistent_path);
assert!(
result.is_err(),
"Non-existent relative path should fail validation"
);
}
#[test]
fn test_filesystem_source_resolution_nested_directory() {
let temp_dir = TempDir::new().unwrap();
let nested_dir = temp_dir.path().join("level1").join("level2");
fs::create_dir_all(&nested_dir).unwrap();
let result = SourceResolver::resolve_filesystem(&nested_dir);
assert!(
result.is_ok(),
"Nested directory should resolve successfully"
);
}
#[test]
fn test_stdin_validation_empty_input() {
let error = SourceError::EmptyInput;
match error {
SourceError::EmptyInput => {
}
_ => panic!("Expected EmptyInput error"),
}
}
#[test]
fn test_github_error_user_friendly_message() {
let error = SourceError::GitHubRepoNotFound {
owner: "owner".to_string(),
repo: "repo".to_string(),
};
let message = error.user_message();
assert!(message.contains("GitHub repository"));
assert!(message.contains("owner/repo"));
}
#[test]
fn test_github_error_context() {
let error = SourceError::GitHubRepoNotFound {
owner: "owner".to_string(),
repo: "repo".to_string(),
};
let context = error.context();
assert!(context.is_some());
assert!(context.unwrap().contains("GitHub source resolution"));
}
#[test]
fn test_github_error_suggestions_authentication() {
let error = SourceError::GitHubAuthFailed {
reason: "authentication failed".to_string(),
};
let suggestions = error.suggestions();
assert!(!suggestions.is_empty());
assert!(suggestions.iter().any(|s| s.contains("gh auth login")));
assert!(suggestions.iter().any(|s| s.contains("token")));
}
#[test]
fn test_github_error_suggestions_not_found() {
let error = SourceError::GitHubRepoNotFound {
owner: "owner".to_string(),
repo: "repo".to_string(),
};
let suggestions = error.suggestions();
assert!(!suggestions.is_empty());
assert!(
suggestions
.iter()
.any(|s| s.contains("https://github.com/owner/repo"))
);
assert!(suggestions.iter().any(|s| s.contains("public")));
}
#[test]
fn test_github_error_suggestions_rate_limit() {
let error = SourceError::GitHubApiError {
status: 403,
message: "rate limit exceeded".to_string(),
};
let suggestions = error.suggestions();
assert!(!suggestions.is_empty());
assert!(
suggestions
.iter()
.any(|s| s.contains("Rate limit exceeded"))
);
}
#[test]
fn test_filesystem_error_user_friendly_message() {
let error = SourceError::FileSystemNotFound {
path: "/path/to/file.txt".to_string(),
};
let message = error.user_message();
assert!(message.contains("does not exist"));
assert!(message.contains("/path/to/file.txt"));
}
#[test]
fn test_filesystem_error_context() {
let error = SourceError::FileSystemNotFound {
path: "/path/to/file.txt".to_string(),
};
let context = error.context();
assert!(context.is_some());
assert!(context.unwrap().contains("Filesystem source resolution"));
}
#[test]
fn test_filesystem_error_suggestions() {
let error = SourceError::FileSystemNotFound {
path: "/path/to/file.txt".to_string(),
};
let suggestions = error.suggestions();
assert!(!suggestions.is_empty());
assert!(suggestions.iter().any(|s| s.contains("mkdir -p")));
assert!(suggestions.iter().any(|s| s.contains("/path/to/file.txt")));
assert!(suggestions.iter().any(|s| s.contains("absolute path")));
}
#[test]
fn test_stdin_error_user_friendly_message() {
let error = SourceError::EmptyInput;
let message = error.user_message();
assert!(message.contains("No input provided"));
}
#[test]
fn test_stdin_error_context() {
let error = SourceError::EmptyInput;
let context = error.context();
assert!(context.is_some());
assert!(context.unwrap().contains("problem statement"));
}
#[test]
fn test_stdin_error_suggestions() {
let error = SourceError::EmptyInput;
let suggestions = error.suggestions();
assert!(!suggestions.is_empty());
assert!(suggestions.iter().any(|s| s.contains("stdin")));
assert!(suggestions.iter().any(|s| s.contains("--source fs")));
}
#[test]
fn test_invalid_configuration_error_user_friendly_message() {
let error = SourceError::InvalidFormat {
reason: "Missing required parameter".to_string(),
};
let message = error.user_message();
assert!(message.contains("Input format is invalid"));
assert!(message.contains("Missing required parameter"));
}
#[test]
fn test_invalid_configuration_error_suggestions() {
let error = SourceError::InvalidFormat {
reason: "Unknown source type".to_string(),
};
let suggestions = error.suggestions();
assert!(!suggestions.is_empty());
assert!(suggestions.iter().any(|s| s.contains("single-line")));
assert!(suggestions.iter().any(|s| s.contains("plain English")));
}
#[test]
fn test_github_metadata_tracking() {
let result = SourceResolver::resolve_github("test-owner", "test-repo", "42");
assert!(result.is_ok());
let content = result.unwrap();
assert!(content.metadata.contains_key("owner"));
assert!(content.metadata.contains_key("repo"));
assert!(content.metadata.contains_key("issue_id"));
assert_eq!(content.metadata.get("owner").unwrap(), "test-owner");
assert_eq!(content.metadata.get("repo").unwrap(), "test-repo");
assert_eq!(content.metadata.get("issue_id").unwrap(), "42");
}
#[test]
fn test_filesystem_file_metadata_tracking() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("metadata_test.txt");
fs::write(&file_path, "test content").unwrap();
let result = SourceResolver::resolve_filesystem(&file_path);
assert!(result.is_ok());
let content = result.unwrap();
assert!(content.metadata.contains_key("path"));
assert!(content.metadata.contains_key("type"));
assert_eq!(content.metadata.get("type").unwrap(), "file");
assert!(
content
.metadata
.get("path")
.unwrap()
.contains("metadata_test.txt")
);
}
#[test]
fn test_filesystem_directory_metadata_tracking() {
let temp_dir = TempDir::new().unwrap();
let dir_path = temp_dir.path().to_path_buf();
let result = SourceResolver::resolve_filesystem(&dir_path);
assert!(result.is_ok());
let content = result.unwrap();
assert!(content.metadata.contains_key("path"));
assert!(content.metadata.contains_key("type"));
assert_eq!(content.metadata.get("type").unwrap(), "directory");
}
#[test]
fn test_error_category_configuration() {
use xchecker::error::ErrorCategory;
let errors = vec![
SourceError::GitHubRepoNotFound {
owner: "owner".to_string(),
repo: "repo".to_string(),
},
SourceError::FileSystemNotFound {
path: "test".to_string(),
},
SourceError::EmptyInput,
SourceError::InvalidFormat {
reason: "test".to_string(),
},
];
for error in errors {
assert_eq!(error.category(), ErrorCategory::Configuration);
}
}
#[test]
fn test_source_resolution_workflow_github() {
let result = SourceResolver::resolve_github("microsoft", "vscode", "100");
assert!(result.is_ok());
let content = result.unwrap();
assert!(!content.content.is_empty());
assert!(!content.metadata.is_empty());
match content.source_type {
SourceType::GitHub { .. } => {}
_ => panic!("Expected GitHub source type"),
}
}
#[test]
fn test_source_resolution_workflow_filesystem() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("workflow_test.txt");
fs::write(&file_path, "Workflow test content").unwrap();
let result = SourceResolver::resolve_filesystem(&file_path);
assert!(result.is_ok());
let content = result.unwrap();
assert!(!content.content.is_empty());
assert!(!content.metadata.is_empty());
match content.source_type {
SourceType::FileSystem { .. } => {}
_ => panic!("Expected FileSystem source type"),
}
}
#[test]
fn test_multiple_source_resolutions() {
let temp_dir = TempDir::new().unwrap();
let file1 = temp_dir.path().join("file1.txt");
let file2 = temp_dir.path().join("file2.txt");
fs::write(&file1, "Content 1").unwrap();
fs::write(&file2, "Content 2").unwrap();
let result1 = SourceResolver::resolve_filesystem(&file1);
let result2 = SourceResolver::resolve_filesystem(&file2);
let result3 = SourceResolver::resolve_github("owner1", "repo1", "1");
let result4 = SourceResolver::resolve_github("owner2", "repo2", "2");
assert!(result1.is_ok());
assert!(result2.is_ok());
assert!(result3.is_ok());
assert!(result4.is_ok());
assert_ne!(result1.unwrap().content, result2.unwrap().content);
assert_ne!(
result3.unwrap().metadata.get("owner"),
result4.unwrap().metadata.get("owner")
);
}