fixes
Some checks failed
CI / Check (pull_request) Has been cancelled
CI / Format (pull_request) Has been cancelled
CI / Clippy (pull_request) Has been cancelled
CI / Build (macos-latest) (pull_request) Has been cancelled
CI / Build (ubuntu-latest) (pull_request) Has been cancelled
CI / Build (windows-latest) (pull_request) Has been cancelled
Some checks failed
CI / Check (pull_request) Has been cancelled
CI / Format (pull_request) Has been cancelled
CI / Clippy (pull_request) Has been cancelled
CI / Build (macos-latest) (pull_request) Has been cancelled
CI / Build (ubuntu-latest) (pull_request) Has been cancelled
CI / Build (windows-latest) (pull_request) Has been cancelled
This commit is contained in:
191
tests/account_switcher.rs
Normal file
191
tests/account_switcher.rs
Normal file
@@ -0,0 +1,191 @@
|
||||
// Integration tests for account switcher modal
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::app_builder::TestAppBuilder;
|
||||
use helpers::test_data::create_test_chat;
|
||||
use tele_tui::app::AccountSwitcherState;
|
||||
|
||||
// ============ Open/Close Tests ============
|
||||
|
||||
#[test]
|
||||
fn test_open_account_switcher() {
|
||||
let mut app = TestAppBuilder::new().build();
|
||||
assert!(app.account_switcher.is_none());
|
||||
|
||||
app.open_account_switcher();
|
||||
|
||||
assert!(app.account_switcher.is_some());
|
||||
match &app.account_switcher {
|
||||
Some(AccountSwitcherState::SelectAccount {
|
||||
accounts,
|
||||
selected_index,
|
||||
current_account,
|
||||
}) => {
|
||||
assert!(!accounts.is_empty());
|
||||
assert_eq!(*selected_index, 0);
|
||||
assert_eq!(current_account, "default");
|
||||
}
|
||||
_ => panic!("Expected SelectAccount state"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_close_account_switcher() {
|
||||
let mut app = TestAppBuilder::new().build();
|
||||
app.open_account_switcher();
|
||||
assert!(app.account_switcher.is_some());
|
||||
|
||||
app.close_account_switcher();
|
||||
assert!(app.account_switcher.is_none());
|
||||
}
|
||||
|
||||
// ============ Navigation Tests ============
|
||||
|
||||
#[test]
|
||||
fn test_account_switcher_navigate_down() {
|
||||
let mut app = TestAppBuilder::new().build();
|
||||
app.open_account_switcher();
|
||||
|
||||
// Initially at 0, navigate down to "Add account" item
|
||||
app.account_switcher_select_next();
|
||||
|
||||
match &app.account_switcher {
|
||||
Some(AccountSwitcherState::SelectAccount {
|
||||
selected_index,
|
||||
accounts,
|
||||
..
|
||||
}) => {
|
||||
// Should be at index 1 (the "Add account" item, since default config has 1 account)
|
||||
assert_eq!(*selected_index, accounts.len());
|
||||
}
|
||||
_ => panic!("Expected SelectAccount state"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_account_switcher_navigate_up() {
|
||||
let mut app = TestAppBuilder::new().build();
|
||||
app.open_account_switcher();
|
||||
|
||||
// Navigate down first
|
||||
app.account_switcher_select_next();
|
||||
// Navigate back up
|
||||
app.account_switcher_select_prev();
|
||||
|
||||
match &app.account_switcher {
|
||||
Some(AccountSwitcherState::SelectAccount { selected_index, .. }) => {
|
||||
assert_eq!(*selected_index, 0);
|
||||
}
|
||||
_ => panic!("Expected SelectAccount state"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_account_switcher_navigate_up_at_top() {
|
||||
let mut app = TestAppBuilder::new().build();
|
||||
app.open_account_switcher();
|
||||
|
||||
// Already at 0, navigate up should stay at 0
|
||||
app.account_switcher_select_prev();
|
||||
|
||||
match &app.account_switcher {
|
||||
Some(AccountSwitcherState::SelectAccount { selected_index, .. }) => {
|
||||
assert_eq!(*selected_index, 0);
|
||||
}
|
||||
_ => panic!("Expected SelectAccount state"),
|
||||
}
|
||||
}
|
||||
|
||||
// ============ Confirm Tests ============
|
||||
|
||||
#[test]
|
||||
fn test_confirm_current_account_closes_modal() {
|
||||
let mut app = TestAppBuilder::new().build();
|
||||
app.open_account_switcher();
|
||||
|
||||
// Confirm on the current account (default) should just close
|
||||
app.account_switcher_confirm();
|
||||
|
||||
assert!(app.account_switcher.is_none());
|
||||
assert!(app.pending_account_switch.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_confirm_add_account_transitions_to_add_state() {
|
||||
let mut app = TestAppBuilder::new().build();
|
||||
app.open_account_switcher();
|
||||
|
||||
// Navigate to "+ Add account"
|
||||
app.account_switcher_select_next();
|
||||
|
||||
// Confirm should transition to AddAccount
|
||||
app.account_switcher_confirm();
|
||||
|
||||
match &app.account_switcher {
|
||||
Some(AccountSwitcherState::AddAccount {
|
||||
name_input,
|
||||
cursor_position,
|
||||
error,
|
||||
}) => {
|
||||
assert!(name_input.is_empty());
|
||||
assert_eq!(*cursor_position, 0);
|
||||
assert!(error.is_none());
|
||||
}
|
||||
_ => panic!("Expected AddAccount state"),
|
||||
}
|
||||
}
|
||||
|
||||
// ============ Add Account State Tests ============
|
||||
|
||||
#[test]
|
||||
fn test_start_add_from_select() {
|
||||
let mut app = TestAppBuilder::new().build();
|
||||
app.open_account_switcher();
|
||||
|
||||
// Use quick shortcut
|
||||
app.account_switcher_start_add();
|
||||
|
||||
match &app.account_switcher {
|
||||
Some(AccountSwitcherState::AddAccount { .. }) => {}
|
||||
_ => panic!("Expected AddAccount state"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_back_from_add_to_select() {
|
||||
let mut app = TestAppBuilder::new().build();
|
||||
app.open_account_switcher();
|
||||
app.account_switcher_start_add();
|
||||
|
||||
// Go back
|
||||
app.account_switcher_back();
|
||||
|
||||
match &app.account_switcher {
|
||||
Some(AccountSwitcherState::SelectAccount { .. }) => {}
|
||||
_ => panic!("Expected SelectAccount state after back"),
|
||||
}
|
||||
}
|
||||
|
||||
// ============ Footer Tests ============
|
||||
|
||||
#[test]
|
||||
fn test_default_account_name() {
|
||||
let app = TestAppBuilder::new().build();
|
||||
assert_eq!(app.current_account_name, "default");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_custom_account_name() {
|
||||
let mut app = TestAppBuilder::new().build();
|
||||
app.current_account_name = "work".to_string();
|
||||
assert_eq!(app.current_account_name, "work");
|
||||
}
|
||||
|
||||
// ============ Pending Switch Tests ============
|
||||
|
||||
#[test]
|
||||
fn test_pending_switch_initially_none() {
|
||||
let app = TestAppBuilder::new().build();
|
||||
assert!(app.pending_account_switch.is_none());
|
||||
}
|
||||
182
tests/accounts.rs
Normal file
182
tests/accounts.rs
Normal file
@@ -0,0 +1,182 @@
|
||||
// Integration tests for accounts module
|
||||
|
||||
use tele_tui::accounts::{
|
||||
account_db_path, validate_account_name, AccountProfile, AccountsConfig,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_default_single_config() {
|
||||
let config = AccountsConfig::default_single();
|
||||
assert_eq!(config.default_account, "default");
|
||||
assert_eq!(config.accounts.len(), 1);
|
||||
assert_eq!(config.accounts[0].name, "default");
|
||||
assert_eq!(config.accounts[0].display_name, "Default");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_account_exists() {
|
||||
let config = AccountsConfig::default_single();
|
||||
let account = config.find_account("default");
|
||||
assert!(account.is_some());
|
||||
assert_eq!(account.unwrap().name, "default");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_account_not_found() {
|
||||
let config = AccountsConfig::default_single();
|
||||
assert!(config.find_account("work").is_none());
|
||||
assert!(config.find_account("").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_db_path_structure() {
|
||||
let path = account_db_path("default");
|
||||
let path_str = path.to_string_lossy();
|
||||
|
||||
assert!(path_str.contains("tele-tui"));
|
||||
assert!(path_str.contains("accounts"));
|
||||
assert!(path_str.contains("default"));
|
||||
assert!(path_str.ends_with("tdlib_data"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_db_path_per_account() {
|
||||
let path_default = account_db_path("default");
|
||||
let path_work = account_db_path("work");
|
||||
|
||||
assert_ne!(path_default, path_work);
|
||||
assert!(path_default.to_string_lossy().contains("default"));
|
||||
assert!(path_work.to_string_lossy().contains("work"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_account_profile_db_path() {
|
||||
let profile = AccountProfile {
|
||||
name: "test-account".to_string(),
|
||||
display_name: "Test".to_string(),
|
||||
};
|
||||
let path = profile.db_path();
|
||||
assert!(path.to_string_lossy().contains("test-account"));
|
||||
assert!(path.to_string_lossy().ends_with("tdlib_data"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_account_name_valid() {
|
||||
assert!(validate_account_name("default").is_ok());
|
||||
assert!(validate_account_name("work").is_ok());
|
||||
assert!(validate_account_name("my-account").is_ok());
|
||||
assert!(validate_account_name("account123").is_ok());
|
||||
assert!(validate_account_name("test_account").is_ok());
|
||||
assert!(validate_account_name("a").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_account_name_empty() {
|
||||
let err = validate_account_name("").unwrap_err();
|
||||
assert!(err.contains("empty"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_account_name_too_long() {
|
||||
let long_name = "a".repeat(33);
|
||||
let err = validate_account_name(&long_name).unwrap_err();
|
||||
assert!(err.contains("32"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_account_name_uppercase() {
|
||||
assert!(validate_account_name("MyAccount").is_err());
|
||||
assert!(validate_account_name("WORK").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_account_name_spaces() {
|
||||
assert!(validate_account_name("my account").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_account_name_starts_with_dash() {
|
||||
assert!(validate_account_name("-bad").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_account_name_starts_with_underscore() {
|
||||
assert!(validate_account_name("_bad").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_account_name_special_chars() {
|
||||
assert!(validate_account_name("foo@bar").is_err());
|
||||
assert!(validate_account_name("foo.bar").is_err());
|
||||
assert!(validate_account_name("foo/bar").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_account_default() {
|
||||
let config = AccountsConfig::default_single();
|
||||
let result = tele_tui::accounts::resolve_account(&config, None);
|
||||
assert!(result.is_ok());
|
||||
let (name, path) = result.unwrap();
|
||||
assert_eq!(name, "default");
|
||||
assert!(path.to_string_lossy().contains("default"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_account_explicit() {
|
||||
let config = AccountsConfig::default_single();
|
||||
let result = tele_tui::accounts::resolve_account(&config, Some("default"));
|
||||
assert!(result.is_ok());
|
||||
let (name, _) = result.unwrap();
|
||||
assert_eq!(name, "default");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_account_not_found() {
|
||||
let config = AccountsConfig::default_single();
|
||||
let result = tele_tui::accounts::resolve_account(&config, Some("work"));
|
||||
assert!(result.is_err());
|
||||
let err = result.unwrap_err();
|
||||
assert!(err.contains("work"));
|
||||
assert!(err.contains("not found"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_account_invalid_name() {
|
||||
let config = AccountsConfig::default_single();
|
||||
let result = tele_tui::accounts::resolve_account(&config, Some("BAD NAME"));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_accounts_config_serde_roundtrip() {
|
||||
let config = AccountsConfig::default_single();
|
||||
let toml_str = toml::to_string_pretty(&config).unwrap();
|
||||
let parsed: AccountsConfig = toml::from_str(&toml_str).unwrap();
|
||||
|
||||
assert_eq!(parsed.default_account, config.default_account);
|
||||
assert_eq!(parsed.accounts.len(), config.accounts.len());
|
||||
assert_eq!(parsed.accounts[0].name, config.accounts[0].name);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_accounts_config_multi_account_serde() {
|
||||
let config = AccountsConfig {
|
||||
default_account: "default".to_string(),
|
||||
accounts: vec![
|
||||
AccountProfile {
|
||||
name: "default".to_string(),
|
||||
display_name: "Default".to_string(),
|
||||
},
|
||||
AccountProfile {
|
||||
name: "work".to_string(),
|
||||
display_name: "Work".to_string(),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let toml_str = toml::to_string_pretty(&config).unwrap();
|
||||
let parsed: AccountsConfig = toml::from_str(&toml_str).unwrap();
|
||||
|
||||
assert_eq!(parsed.accounts.len(), 2);
|
||||
assert!(parsed.find_account("work").is_some());
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use super::fake_tdclient::FakeTdClient;
|
||||
use async_trait::async_trait;
|
||||
use std::path::PathBuf;
|
||||
use tdlib_rs::enums::{ChatAction, Update};
|
||||
use tele_tui::tdlib::{AuthState, ChatInfo, FolderInfo, MessageInfo, ProfileInfo, ReplyInfo, UserCache, UserOnlineStatus};
|
||||
use tele_tui::tdlib::TdClientTrait;
|
||||
@@ -314,6 +315,12 @@ impl TdClientTrait for FakeTdClient {
|
||||
// Not implemented for fake client (notifications are not tested)
|
||||
}
|
||||
|
||||
// ============ Account switching ============
|
||||
async fn recreate_client(&mut self, _db_path: PathBuf) -> Result<(), String> {
|
||||
// No-op for fake client
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ============ Update handling ============
|
||||
fn handle_update(&mut self, _update: Update) {
|
||||
// Not implemented for fake client
|
||||
|
||||
Reference in New Issue
Block a user