// Integration tests for config flow use tele_tui::config::{ AudioConfig, ColorsConfig, Config, GeneralConfig, ImagesConfig, Keybindings, NotificationsConfig, }; /// Test: Дефолтные значения конфигурации #[test] fn test_config_default_values() { let config = Config::default(); // Проверяем дефолтный timezone assert_eq!(config.general.timezone, "+03:00"); // Проверяем дефолтные цвета assert_eq!(config.colors.incoming_message, "white"); assert_eq!(config.colors.outgoing_message, "green"); assert_eq!(config.colors.selected_message, "yellow"); assert_eq!(config.colors.reaction_chosen, "yellow"); assert_eq!(config.colors.reaction_other, "gray"); } /// Test: Создание конфига с кастомными значениями #[test] fn test_config_custom_values() { let config = Config { general: GeneralConfig { timezone: "+05:00".to_string() }, colors: ColorsConfig { incoming_message: "cyan".to_string(), outgoing_message: "blue".to_string(), selected_message: "red".to_string(), reaction_chosen: "green".to_string(), reaction_other: "white".to_string(), }, keybindings: Keybindings::default(), notifications: NotificationsConfig::default(), images: ImagesConfig::default(), audio: AudioConfig::default(), }; assert_eq!(config.general.timezone, "+05:00"); assert_eq!(config.colors.incoming_message, "cyan"); assert_eq!(config.colors.outgoing_message, "blue"); } /// Test: Парсинг валидных цветов #[test] fn test_parse_valid_colors() { use ratatui::style::Color; let config = Config::default(); assert_eq!(config.parse_color("red"), Color::Red); assert_eq!(config.parse_color("green"), Color::Green); assert_eq!(config.parse_color("blue"), Color::Blue); assert_eq!(config.parse_color("yellow"), Color::Yellow); assert_eq!(config.parse_color("cyan"), Color::Cyan); assert_eq!(config.parse_color("magenta"), Color::Magenta); assert_eq!(config.parse_color("white"), Color::White); assert_eq!(config.parse_color("black"), Color::Black); assert_eq!(config.parse_color("gray"), Color::Gray); assert_eq!(config.parse_color("grey"), Color::Gray); } /// Test: Парсинг light цветов #[test] fn test_parse_light_colors() { use ratatui::style::Color; let config = Config::default(); assert_eq!(config.parse_color("lightred"), Color::LightRed); assert_eq!(config.parse_color("lightgreen"), Color::LightGreen); assert_eq!(config.parse_color("lightblue"), Color::LightBlue); assert_eq!(config.parse_color("lightyellow"), Color::LightYellow); assert_eq!(config.parse_color("lightcyan"), Color::LightCyan); assert_eq!(config.parse_color("lightmagenta"), Color::LightMagenta); } /// Test: Парсинг невалидного цвета использует fallback (White) #[test] fn test_parse_invalid_color_fallback() { use ratatui::style::Color; let config = Config::default(); // Невалидные цвета должны возвращать White assert_eq!(config.parse_color("invalid_color"), Color::White); assert_eq!(config.parse_color(""), Color::White); assert_eq!(config.parse_color("purple"), Color::White); // purple не поддерживается assert_eq!(config.parse_color("Orange"), Color::White); // orange не поддерживается } /// Test: Case-insensitive парсинг цветов #[test] fn test_parse_color_case_insensitive() { use ratatui::style::Color; let config = Config::default(); assert_eq!(config.parse_color("RED"), Color::Red); assert_eq!(config.parse_color("Green"), Color::Green); assert_eq!(config.parse_color("BLUE"), Color::Blue); assert_eq!(config.parse_color("YeLLoW"), Color::Yellow); } /// Test: Сериализация и десериализация TOML #[test] fn test_config_toml_serialization() { let original_config = Config { general: GeneralConfig { timezone: "-05:00".to_string() }, colors: ColorsConfig { incoming_message: "cyan".to_string(), outgoing_message: "blue".to_string(), selected_message: "red".to_string(), reaction_chosen: "green".to_string(), reaction_other: "white".to_string(), }, keybindings: Keybindings::default(), notifications: NotificationsConfig::default(), images: ImagesConfig::default(), audio: AudioConfig::default(), }; // Сериализуем в TOML let toml_string = toml::to_string(&original_config).expect("Failed to serialize config"); // Десериализуем обратно let deserialized: Config = toml::from_str(&toml_string).expect("Failed to deserialize config"); // Проверяем что всё совпадает assert_eq!(deserialized.general.timezone, "-05:00"); assert_eq!(deserialized.colors.incoming_message, "cyan"); assert_eq!(deserialized.colors.outgoing_message, "blue"); assert_eq!(deserialized.colors.selected_message, "red"); } /// Test: Парсинг TOML с частичными данными использует дефолты #[test] fn test_config_partial_toml_uses_defaults() { // TOML только с timezone, без colors let toml_str = r#" [general] timezone = "+02:00" "#; let config: Config = toml::from_str(toml_str).expect("Failed to parse partial TOML"); // Timezone должен быть из TOML assert_eq!(config.general.timezone, "+02:00"); // Colors должны быть дефолтными assert_eq!(config.colors.incoming_message, "white"); assert_eq!(config.colors.outgoing_message, "green"); } #[cfg(test)] mod timezone_tests { use super::*; /// Test: Различные форматы timezone #[test] fn test_timezone_formats() { let positive = Config { general: GeneralConfig { timezone: "+03:00".to_string() }, ..Default::default() }; assert_eq!(positive.general.timezone, "+03:00"); let negative = Config { general: GeneralConfig { timezone: "-05:00".to_string() }, ..Default::default() }; assert_eq!(negative.general.timezone, "-05:00"); let zero = Config { general: GeneralConfig { timezone: "+00:00".to_string() }, ..Default::default() }; assert_eq!(zero.general.timezone, "+00:00"); } } #[cfg(test)] mod credentials_tests { use super::*; use std::env; /// Test: Загрузка credentials из переменных окружения #[test] fn test_load_credentials_from_env() { // Устанавливаем env переменные для теста unsafe { env::set_var("API_ID", "12345"); env::set_var("API_HASH", "test_hash_from_env"); } // Загружаем credentials let result = Config::load_credentials(); // Проверяем что загрузилось из env // Примечание: этот тест может зафейлиться если есть credentials файл, // так как он имеет приоритет. Для полноценного тестирования нужно // моковать файловую систему или использовать временные директории. if result.is_ok() { let (api_id, api_hash) = result.unwrap(); // Может быть либо из файла, либо из env assert!(api_id > 0); assert!(!api_hash.is_empty()); } // Очищаем env переменные после теста unsafe { env::remove_var("API_ID"); env::remove_var("API_HASH"); } } /// Test: Проверка формата ошибки когда credentials не найдены #[test] fn test_load_credentials_error_message() { // Проверяем есть ли credentials файл в системе let has_credentials_file = Config::credentials_path() .map(|p| p.exists()) .unwrap_or(false); // Если есть credentials файл, тест не может проверить ошибку if has_credentials_file { // Просто проверяем что credentials загружаются let result = Config::load_credentials(); assert!(result.is_ok(), "Credentials file exists but loading failed"); return; } // Временно сохраняем и удаляем env переменные let original_api_id = env::var("API_ID").ok(); let original_api_hash = env::var("API_HASH").ok(); unsafe { env::remove_var("API_ID"); env::remove_var("API_HASH"); } // Пытаемся загрузить credentials без файла и без env let result = Config::load_credentials(); // Должна быть ошибка if result.is_ok() { // Возможно env переменные установлены глобально и не удаляются // Тест пропускается eprintln!("Warning: credentials loaded despite removing env vars"); } else { // Проверяем формат ошибки let err_msg = result.unwrap_err(); assert!(!err_msg.is_empty(), "Error message should not be empty"); } // Восстанавливаем env переменные unsafe { if let Some(api_id) = original_api_id { env::set_var("API_ID", api_id); } if let Some(api_hash) = original_api_hash { env::set_var("API_HASH", api_hash); } } } }