feat: FTPS, AppError, Site Manager, tests, multi-window, auto-clear, CI/CD, virtual scroll
- FTPS: реализован FtpsClient через suppaftp + async-native-tls - AppError: кастомный enum с Serialize вместо Result<T, String> - Site Manager UI: создание/редактирование/удаление сайтов - Тесты: 53 тестов (domain, storage, transfer, fs, remote) - Multi-window: новое окно + сохранение геометрии - Auto-clear: воркер чистит завершённые задачи по таймеру - CI/CD: 3-ступенчатый пайплайн (lint→build→test) с кэшированием - Virtual scroll: fileTable с рендером только видимых строк - UI: исправлены close-кнопки, color-scheme для select, скриншоты в README
This commit is contained in:
parent
545dd4ed0b
commit
e188fbef36
52 changed files with 5188 additions and 523 deletions
|
|
@ -23,3 +23,81 @@ impl RemoteRegistry {
|
|||
self.connections.lock().unwrap().remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::domain::file_entry::{EntryKind, FileEntry};
|
||||
use crate::protocols::ProgressAction;
|
||||
|
||||
struct MockFs;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl RemoteFs for MockFs {
|
||||
async fn list(&self, _path: &str) -> anyhow::Result<Vec<FileEntry>> {
|
||||
Ok(vec![])
|
||||
}
|
||||
async fn upload_with_progress(
|
||||
&self,
|
||||
_local: &str,
|
||||
_remote: &str,
|
||||
_on_progress: Option<Box<dyn Fn(u64) -> ProgressAction + Send>>,
|
||||
) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
async fn download_with_progress(
|
||||
&self,
|
||||
_remote: &str,
|
||||
_local: &str,
|
||||
_on_progress: Option<Box<dyn Fn(u64) -> ProgressAction + Send>>,
|
||||
) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
async fn mkdir(&self, _path: &str) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
async fn rename(&self, _from: &str, _to: &str) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
async fn delete(&self, _path: &str) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
async fn stat(&self, _path: &str) -> anyhow::Result<FileEntry> {
|
||||
Ok(FileEntry {
|
||||
name: "test".into(),
|
||||
path: "/test".into(),
|
||||
kind: EntryKind::File,
|
||||
size: None,
|
||||
modified: None,
|
||||
permissions: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_insert_get_remove() {
|
||||
let registry = RemoteRegistry::default();
|
||||
let mock = Arc::new(MockFs);
|
||||
|
||||
registry.insert("conn-1".into(), mock.clone());
|
||||
assert!(registry.get("conn-1").is_some());
|
||||
|
||||
registry.remove("conn-1");
|
||||
assert!(registry.get("conn-1").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_nonexistent() {
|
||||
let registry = RemoteRegistry::default();
|
||||
assert!(registry.get("unknown").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_insert_multiple() {
|
||||
let registry = RemoteRegistry::default();
|
||||
registry.insert("a".into(), Arc::new(MockFs));
|
||||
registry.insert("b".into(), Arc::new(MockFs));
|
||||
assert!(registry.get("a").is_some());
|
||||
assert!(registry.get("b").is_some());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue