f7a720204a
- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用 - 添加所有子项目的完整源代码 - 保留原始 .git 为 .git.bak 备份
187 lines
7.3 KiB
Rust
187 lines
7.3 KiB
Rust
use std::sync::Arc;
|
|
|
|
use nomifun_api_types::ToolType;
|
|
use nomifun_shell::{NoopSystemOpener, ShellService};
|
|
|
|
fn service() -> ShellService {
|
|
ShellService::new(Arc::new(NoopSystemOpener))
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SH-2: open_file — file does not exist
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn sh2_open_file_not_found() {
|
|
let err = service().open_file("/nonexistent/file.txt").await.unwrap_err();
|
|
let msg = err.to_string();
|
|
assert!(
|
|
msg.contains("not found") || msg.contains("does not exist"),
|
|
"expected 'not found', got: {msg}"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SH-4: show_item_in_folder — path does not exist
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn sh4_show_item_in_folder_not_found() {
|
|
let err = service().show_item_in_folder("/nonexistent/path").await.unwrap_err();
|
|
let msg = err.to_string();
|
|
assert!(msg.contains("not found"), "expected 'not found', got: {msg}");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SH-6: open_external — command injection attempt
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn sh6_open_external_command_injection() {
|
|
let err = service().open_external("; rm -rf /").await.unwrap_err();
|
|
let msg = err.to_string();
|
|
assert!(
|
|
msg.to_lowercase().contains("invalid") || msg.to_lowercase().contains("url"),
|
|
"expected 'invalid' or 'URL', got: {msg}"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SH-7: open_external — disallowed scheme (file://)
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn sh7_open_external_file_scheme() {
|
|
let err = service().open_external("file:///etc/passwd").await.unwrap_err();
|
|
let msg = err.to_string();
|
|
assert!(
|
|
msg.contains("scheme") || msg.to_lowercase().contains("not allowed"),
|
|
"expected scheme error, got: {msg}"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SH-8: check_tool_installed — terminal always true
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn sh8_check_tool_terminal_always_true() {
|
|
assert!(service().check_tool_installed(ToolType::Terminal).await);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SH-9: check_tool_installed — explorer always true
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn sh9_check_tool_explorer_always_true() {
|
|
assert!(service().check_tool_installed(ToolType::Explorer).await);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SH-10: check_tool_installed — vscode (environment-dependent)
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn sh10_check_tool_vscode_returns_bool() {
|
|
let _installed = service().check_tool_installed(ToolType::Vscode).await;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SH-12: open_folder_with — directory does not exist
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn sh12_open_folder_with_dir_not_found() {
|
|
let err = service()
|
|
.open_folder_with("/nonexistent/dir", ToolType::Explorer)
|
|
.await
|
|
.unwrap_err();
|
|
let msg = err.to_string();
|
|
assert!(msg.contains("not found"), "expected 'not found', got: {msg}");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SH-13: open_file — missing filePath (tested via empty string)
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn sh13_open_file_empty_path() {
|
|
let err = service().open_file("").await.unwrap_err();
|
|
let msg = err.to_string();
|
|
assert!(
|
|
msg.contains("not found"),
|
|
"expected 'not found' for empty path, got: {msg}"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SH-14: open_external — empty string
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn sh14_open_external_empty_url() {
|
|
let err = service().open_external("").await.unwrap_err();
|
|
let msg = err.to_string();
|
|
assert!(
|
|
msg.to_lowercase().contains("invalid") || msg.to_lowercase().contains("url"),
|
|
"expected invalid URL error, got: {msg}"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Additional: open_folder_with — file path instead of directory
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn open_folder_with_file_path_rejected() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let file = dir.path().join("test.txt");
|
|
std::fs::write(&file, "data").unwrap();
|
|
let err = service()
|
|
.open_folder_with(file.to_str().unwrap(), ToolType::Explorer)
|
|
.await
|
|
.unwrap_err();
|
|
let msg = err.to_string();
|
|
assert!(
|
|
msg.contains("directory not found"),
|
|
"expected 'directory not found', got: {msg}"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Additional: open_external — ftp scheme rejected
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn open_external_ftp_scheme_rejected() {
|
|
let err = service().open_external("ftp://evil.com/file").await.unwrap_err();
|
|
let msg = err.to_string();
|
|
assert!(msg.contains("scheme"), "expected scheme error, got: {msg}");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Additional: open_external — javascript scheme rejected
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn open_external_javascript_scheme_rejected() {
|
|
let err = service().open_external("javascript:alert(1)").await.unwrap_err();
|
|
let msg = err.to_string();
|
|
assert!(
|
|
msg.contains("scheme") || msg.to_lowercase().contains("invalid"),
|
|
"expected scheme or invalid error, got: {msg}"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Error conversion: ShellError → AppError mapping
|
|
// ---------------------------------------------------------------------------
|
|
#[test]
|
|
fn shell_error_converts_to_app_error() {
|
|
use nomifun_common::AppError;
|
|
use nomifun_shell::ShellError;
|
|
|
|
let err: AppError = ShellError::FileNotFound("/tmp/x".into()).into();
|
|
assert!(matches!(err, AppError::BadRequest(_)));
|
|
|
|
let err: AppError = ShellError::DirectoryNotFound("/tmp/y".into()).into();
|
|
assert!(matches!(err, AppError::BadRequest(_)));
|
|
|
|
let err: AppError = ShellError::InvalidUrl("bad".into()).into();
|
|
assert!(matches!(err, AppError::BadRequest(_)));
|
|
|
|
let err: AppError = ShellError::ToolNotInstalled("vscode".into()).into();
|
|
assert!(matches!(err, AppError::BadRequest(_)));
|
|
|
|
let err: AppError = ShellError::CommandFailed("oops".into()).into();
|
|
assert!(matches!(err, AppError::Internal(_)));
|
|
}
|