use clickup_v2::error::{AuthError, AuthResult};
use clickup_v2::client::api::ClickUpClient;
use mockito::Server;
use serde_json::json;
#[test]
fn test_auth_error_creation_and_display() {
let token_error = AuthError::TokenExpired;
assert_eq!(token_error.to_string(), "Token de acesso expirado ou inválido");
let invalid_code = AuthError::InvalidCode("XYZ123".to_string());
assert_eq!(invalid_code.to_string(), "Código de autorização inválido: XYZ123");
let access_denied = AuthError::AccessDenied;
assert_eq!(access_denied.to_string(), "Acesso negado pelo usuário");
let invalid_state = AuthError::InvalidState;
assert_eq!(invalid_state.to_string(), "Estado OAuth2 inválido");
let timeout = AuthError::Timeout;
assert_eq!(timeout.to_string(), "Timeout durante autenticação");
}
#[test]
fn test_custom_error_constructors() {
let env_error = AuthError::env_error("ENV_VAR not found");
assert!(env_error.to_string().contains("ENV_VAR not found"));
let config_error = AuthError::config_error("Invalid config");
assert!(config_error.to_string().contains("Invalid config"));
let callback_error = AuthError::callback_error("Server error");
assert!(callback_error.to_string().contains("Server error"));
let browser_error = AuthError::browser_error("Cannot open browser");
assert!(browser_error.to_string().contains("Cannot open browser"));
let token_error = AuthError::token_error("Invalid token");
assert!(token_error.to_string().contains("Invalid token"));
let api_error = AuthError::api_error("API failed");
assert!(api_error.to_string().contains("API failed"));
let parse_error = AuthError::parse_error("Parse failed");
assert!(parse_error.to_string().contains("Parse failed"));
let generic_error = AuthError::generic("Something went wrong");
assert!(generic_error.to_string().contains("Something went wrong"));
}
#[test]
fn test_error_from_conversions() {
let url_error = url::Url::parse("invalid-url").unwrap_err();
let auth_error = AuthError::from(url_error);
assert!(auth_error.to_string().contains("Erro de parsing de URL"));
use std::io::{Error as IoError, ErrorKind};
let io_error = IoError::new(ErrorKind::NotFound, "File not found");
let auth_error = AuthError::from(io_error);
assert!(auth_error.to_string().contains("Erro de IO"));
let invalid_json = "{invalid json}";
let json_error = serde_json::from_str::<serde_json::Value>(invalid_json).unwrap_err();
let auth_error = AuthError::from(json_error);
assert!(auth_error.to_string().contains("Erro de serialização"));
}
#[test]
fn test_auth_result_type() {
fn success_function() -> AuthResult<String> {
Ok("Success".to_string())
}
fn error_function() -> AuthResult<String> {
Err(AuthError::TokenExpired)
}
let success = success_function();
assert!(success.is_ok());
assert_eq!(success.unwrap(), "Success");
let error = error_function();
assert!(error.is_err());
assert!(matches!(error.unwrap_err(), AuthError::TokenExpired));
}
#[tokio::test]
async fn test_api_error_handling_401() {
let mut server = Server::new_async().await;
let _mock = server.mock("GET", "/user")
.with_status(401)
.with_header("content-type", "application/json")
.with_body(json!({
"err": "Token is invalid",
"ECODE": "OAUTH_021"
}).to_string())
.create_async().await;
let client = ClickUpClient::new(
"invalid_token".to_string(),
server.url(),
);
let result = client.get_authorized_user().await;
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("401"));
}
#[tokio::test]
async fn test_api_error_handling_404() {
let mut server = Server::new_async().await;
let _mock = server.mock("GET", "/user")
.with_status(404)
.with_header("content-type", "application/json")
.with_body(json!({
"err": "User not found",
"ECODE": "NOT_FOUND"
}).to_string())
.create_async()
.await;
let client = ClickUpClient::new(
"test_token".to_string(),
server.url(),
);
let result = client.get_authorized_user().await;
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("não encontrado"));
}
#[tokio::test]
async fn test_api_error_handling_429_rate_limit() {
let mut server = Server::new_async().await;
let _mock = server.mock("GET", "/user")
.with_status(429)
.with_header("content-type", "application/json")
.with_header("x-ratelimit-limit", "100")
.with_header("x-ratelimit-remaining", "0")
.with_header("x-ratelimit-reset", "1567780450")
.with_body(json!({
"err": "Rate limit exceeded",
"ECODE": "RATE_LIMIT"
}).to_string())
.create_async().await;
let client = ClickUpClient::new(
"test_token".to_string(),
server.url(),
);
let result = client.get_authorized_user().await;
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("429"));
}
#[tokio::test]
async fn test_api_error_handling_500() {
let mut server = Server::new_async().await;
let _mock = server.mock("GET", "/user")
.with_status(500)
.with_header("content-type", "application/json")
.with_body(json!({
"err": "Internal server error",
"ECODE": "SERVER_ERROR"
}).to_string())
.create_async().await;
let client = ClickUpClient::new(
"test_token".to_string(),
server.url(),
);
let result = client.get_authorized_user().await;
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("500"));
}
#[tokio::test]
async fn test_api_error_handling_503() {
let mut server = Server::new_async().await;
let _mock = server.mock("GET", "/user")
.with_status(503)
.with_header("content-type", "application/json")
.with_body(json!({
"err": "Service temporarily unavailable",
"ECODE": "SERVICE_UNAVAILABLE"
}).to_string())
.create_async().await;
let client = ClickUpClient::new(
"test_token".to_string(),
server.url(),
);
let result = client.get_authorized_user().await;
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("503"));
}
#[tokio::test]
async fn test_network_error_handling() {
let client = ClickUpClient::new(
"test_token".to_string(),
"http://invalid-domain-that-does-not-exist-12345.com".to_string(),
);
let result = client.get_authorized_user().await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_malformed_json_response() {
let mut server = Server::new_async().await;
let _mock = server.mock("GET", "/user")
.with_status(200)
.with_header("content-type", "application/json")
.with_body("not valid json")
.create_async().await;
let client = ClickUpClient::new(
"test_token".to_string(),
server.url(),
);
let result = client.get_authorized_user().await;
if result.is_err() {
let error = result.unwrap_err();
assert!(error.to_string().contains("JSON") || error.to_string().contains("parse"));
}
}
#[test]
fn test_error_debug_format() {
let error = AuthError::InvalidCode("ABC123".to_string());
let debug_str = format!("{:?}", error);
assert!(debug_str.contains("InvalidCode"));
assert!(debug_str.contains("ABC123"));
let error = AuthError::TokenExpired;
let debug_str = format!("{:?}", error);
assert!(debug_str.contains("TokenExpired"));
}
#[test]
fn test_error_chaining() {
fn inner_function() -> AuthResult<String> {
Err(AuthError::token_error("Inner error"))
}
fn outer_function() -> AuthResult<String> {
inner_function().map_err(|e| AuthError::generic(format!("Outer error: {}", e)))
}
let result = outer_function();
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("Outer error"));
assert!(error.to_string().contains("Inner error"));
}
#[test]
fn test_error_pattern_matching() {
let errors = vec![
AuthError::TokenExpired,
AuthError::AccessDenied,
AuthError::InvalidState,
AuthError::Timeout,
];
for error in errors {
match error {
AuthError::TokenExpired => assert!(true),
AuthError::AccessDenied => assert!(true),
AuthError::InvalidState => assert!(true),
AuthError::Timeout => assert!(true),
_ => panic!("Unexpected error type"),
}
}
}