caldavpuller/tests/integration_tests.rs
Alvaro Soliverez 9fecd7d9c2 feat: implement comprehensive CalDAV event listing and debugging
Major refactoring to add robust event listing functionality with extensive debugging:

- Add CalDAV event listing with timezone support and proper XML parsing
- Implement comprehensive debug mode with request/response logging
- Add event filtering capabilities with date range and timezone conversion
- Refactor configuration to use structured TOML for better organization
- Add proper timezone handling with timezone database integration
- Improve error handling and logging throughout the application
- Add comprehensive test suite for event listing and filtering
- Create detailed testing documentation and usage examples

This enables debugging of CalDAV server connections and event retrieval
with proper timezone handling and detailed logging for troubleshooting.
2025-10-15 23:14:38 -03:00

287 lines
9.3 KiB
Rust

use caldav_sync::{Config, CalDavResult};
use chrono::Utc;
#[cfg(test)]
mod config_tests {
use super::*;
#[test]
fn test_default_config() -> CalDavResult<()> {
let config = Config::default();
assert_eq!(config.server.url, "https://caldav.example.com");
assert_eq!(config.calendar.name, "calendar");
assert_eq!(config.sync.interval, 300);
config.validate()?;
Ok(())
}
#[test]
fn test_config_validation() -> CalDavResult<()> {
let mut config = Config::default();
// Should fail with empty credentials
assert!(config.validate().is_err());
config.server.username = "test_user".to_string();
config.server.password = "test_pass".to_string();
// Should succeed now
assert!(config.validate().is_ok());
Ok(())
}
}
#[cfg(test)]
mod error_tests {
use caldav_sync::CalDavError;
#[test]
fn test_error_retryable() {
// Create a simple network error test - skip the reqwest::Error creation
let auth_error = CalDavError::Authentication("Invalid credentials".to_string());
assert!(!auth_error.is_retryable());
let config_error = CalDavError::Config("Missing URL".to_string());
assert!(!config_error.is_retryable());
// Just test that is_retryable works for different error types
assert!(!CalDavError::Authentication("test".to_string()).is_retryable());
assert!(!CalDavError::Config("test".to_string()).is_retryable());
}
#[test]
fn test_error_classification() {
let auth_error = CalDavError::Authentication("Invalid".to_string());
assert!(auth_error.is_auth_error());
let config_error = CalDavError::Config("Invalid".to_string());
assert!(config_error.is_config_error());
}
}
#[cfg(test)]
mod event_tests {
use caldav_sync::event::{Event, EventStatus, EventType};
use chrono::{DateTime, Utc, NaiveDate};
#[test]
fn test_event_creation() {
let start = Utc::now();
let end = start + chrono::Duration::hours(1);
let event = Event::new("Test Event".to_string(), start, end);
assert_eq!(event.summary, "Test Event");
assert_eq!(event.start, start);
assert_eq!(event.end, end);
assert!(!event.all_day);
assert_eq!(event.status, EventStatus::Confirmed);
assert_eq!(event.event_type, EventType::Public);
}
#[test]
fn test_all_day_event() {
let date = NaiveDate::from_ymd_opt(2023, 12, 25).unwrap();
let event = Event::new_all_day("Christmas".to_string(), date);
assert_eq!(event.summary, "Christmas");
assert!(event.all_day);
assert!(event.occurs_on(date));
}
#[test]
fn test_event_to_ical() -> caldav_sync::CalDavResult<()> {
let event = Event::new(
"Meeting".to_string(),
DateTime::from_naive_utc_and_offset(
chrono::NaiveDateTime::parse_from_str("20231225T100000", "%Y%m%dT%H%M%S").unwrap(),
Utc
),
DateTime::from_naive_utc_and_offset(
chrono::NaiveDateTime::parse_from_str("20231225T110000", "%Y%m%dT%H%M%S").unwrap(),
Utc
),
);
let ical = event.to_ical()?;
assert!(ical.contains("SUMMARY:Meeting"));
assert!(ical.contains("DTSTART:20231225T100000Z"));
assert!(ical.contains("DTEND:20231225T110000Z"));
assert!(ical.contains("BEGIN:VCALENDAR"));
assert!(ical.contains("END:VCALENDAR"));
Ok(())
}
}
#[cfg(test)]
mod timezone_tests {
use caldav_sync::timezone::TimezoneHandler;
use caldav_sync::CalDavResult;
use chrono::{DateTime, Utc};
#[test]
fn test_timezone_handler_creation() -> CalDavResult<()> {
let handler = TimezoneHandler::new(Some("UTC"))?;
assert_eq!(handler.default_timezone(), "UTC");
Ok(())
}
#[test]
fn test_timezone_validation() {
assert!(TimezoneHandler::validate_timezone("UTC"));
assert!(TimezoneHandler::validate_timezone("America/New_York"));
assert!(TimezoneHandler::validate_timezone("Europe/London"));
assert!(!TimezoneHandler::validate_timezone("Invalid/Timezone"));
}
#[test]
fn test_ical_formatting() -> CalDavResult<()> {
let mut handler = TimezoneHandler::default();
let dt = DateTime::from_naive_utc_and_offset(
chrono::NaiveDateTime::parse_from_str("20231225T100000", "%Y%m%dT%H%M%S").unwrap(),
Utc
);
let ical_utc = handler.format_ical_datetime(dt, false)?;
assert_eq!(ical_utc, "20231225T100000Z");
let ical_date = handler.format_ical_date(dt);
assert_eq!(ical_date, "20231225");
Ok(())
}
}
#[cfg(test)]
mod filter_tests {
use caldav_sync::calendar_filter::{
CalendarFilter, FilterRule, DateRangeFilter, KeywordFilter,
EventStatusFilter, FilterBuilder
};
use caldav_sync::event::{Event, EventStatus};
use chrono::{DateTime, Utc};
#[test]
fn test_date_range_filter() {
let start = DateTime::from_naive_utc_and_offset(
chrono::NaiveDateTime::parse_from_str("20231225T000000", "%Y%m%dT%H%M%S").unwrap(),
Utc
);
let end = DateTime::from_naive_utc_and_offset(
chrono::NaiveDateTime::parse_from_str("20231225T235959", "%Y%m%dT%H%M%S").unwrap(),
Utc
);
let filter = DateRangeFilter::new(start, end);
let event_start = DateTime::from_naive_utc_and_offset(
chrono::NaiveDateTime::parse_from_str("20231225T100000", "%Y%m%dT%H%M%S").unwrap(),
Utc
);
let event = Event::new("Test".to_string(), event_start, event_start + chrono::Duration::hours(1));
assert!(filter.matches_event(&event));
let event_outside = Event::new(
"Test".to_string(),
start - chrono::Duration::days(1),
start - chrono::Duration::hours(23),
);
assert!(!filter.matches_event(&event_outside));
}
#[test]
fn test_keyword_filter() {
let filter = KeywordFilter::new(vec!["meeting".to_string(), "important".to_string()], false);
let event1 = Event::new("Team Meeting".to_string(), Utc::now(), Utc::now());
assert!(filter.matches_event(&event1));
let event2 = Event::new("Lunch".to_string(), Utc::now(), Utc::now());
assert!(!filter.matches_event(&event2));
}
#[test]
fn test_calendar_filter() {
let mut filter = CalendarFilter::new(true); // OR logic
filter.add_rule(FilterRule::Keywords(KeywordFilter::new(vec!["meeting".to_string()], false)));
filter.add_rule(FilterRule::EventStatus(EventStatusFilter::new(vec![EventStatus::Cancelled])));
let event1 = Event::new("Team Meeting".to_string(), Utc::now(), Utc::now());
assert!(filter.matches_event(&event1)); // Matches keyword
let mut event2 = Event::new("Holiday".to_string(), Utc::now(), Utc::now());
event2.status = EventStatus::Cancelled;
assert!(filter.matches_event(&event2)); // Matches status
let event3 = Event::new("Lunch".to_string(), Utc::now(), Utc::now());
assert!(!filter.matches_event(&event3)); // Matches neither
}
#[test]
fn test_filter_builder() {
let filter = FilterBuilder::new()
.match_any(false) // AND logic
.keywords(vec!["meeting".to_string()])
.build();
let event = Event::new("Team Meeting".to_string(), Utc::now(), Utc::now());
assert!(filter.matches_event(&event)); // Matches condition
}
}
#[cfg(test)]
mod integration_tests {
use super::*;
#[test]
fn test_library_initialization() -> CalDavResult<()> {
caldav_sync::init()?;
Ok(())
}
#[test]
fn test_version() {
assert!(!caldav_sync::VERSION.is_empty());
}
#[test]
fn test_full_workflow() -> CalDavResult<()> {
// Initialize library
caldav_sync::init()?;
// Create configuration
let config = Config::default();
// Validate configuration
config.validate()?;
// Create some test events
let event1 = caldav_sync::event::Event::new(
"Test Meeting".to_string(),
Utc::now(),
Utc::now() + chrono::Duration::hours(1),
);
let event2 = caldav_sync::event::Event::new_all_day(
"Test Holiday".to_string(),
chrono::NaiveDate::from_ymd_opt(2023, 12, 25).unwrap(),
);
// Test event serialization
let ical1 = event1.to_ical()?;
let ical2 = event2.to_ical()?;
assert!(!ical1.is_empty());
assert!(!ical2.is_empty());
assert!(ical1.contains("SUMMARY:Test Meeting"));
assert!(ical2.contains("SUMMARY:Test Holiday"));
// Test filtering
let filter = caldav_sync::calendar_filter::FilterBuilder::new()
.keywords(vec!["test".to_string()])
.build();
assert!(filter.matches_event(&event1));
assert!(filter.matches_event(&event2));
Ok(())
}
}