- Fix compilation error in path_utils.rs where path.display() was used after the path was moved into spawn_blocking closure - Add 12 tests for handle_undo handler covering no undo log, no completed moves, custom paths, dry run, invalid paths, etc. - Add 16 tests for validate_and_normalize_path covering path validation, directories, normalization, edge cases - Add 21 tests for cache module covering key generation, hit/miss behavior, eviction, persistence, etc. All 86 tests pass successfully.
278 lines
8.3 KiB
Rust
278 lines
8.3 KiB
Rust
//! Unit tests for path_utils module
|
|
//!
|
|
//! Tests the validate_and_normalize_path function including:
|
|
//! - Non-existent paths
|
|
//! - File paths (not directories)
|
|
//! - Directory validation
|
|
//! - Successful canonicalization
|
|
//! - Permission/access errors
|
|
|
|
use noentropy::cli::path_utils::validate_and_normalize_path;
|
|
use std::fs::{self, File};
|
|
use std::path::Path;
|
|
use tempfile::TempDir;
|
|
|
|
// ============================================================================
|
|
// NON-EXISTENT PATH TESTS
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_nonexistent_path() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let nonexistent = temp_dir.path().join("this_does_not_exist");
|
|
|
|
let result = validate_and_normalize_path(&nonexistent).await;
|
|
|
|
assert!(result.is_err());
|
|
let err = result.unwrap_err();
|
|
assert!(err.contains("does not exist"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_deeply_nested_nonexistent() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let nonexistent = temp_dir
|
|
.path()
|
|
.join("a")
|
|
.join("b")
|
|
.join("c")
|
|
.join("d")
|
|
.join("nonexistent");
|
|
|
|
let result = validate_and_normalize_path(&nonexistent).await;
|
|
|
|
assert!(result.is_err());
|
|
assert!(result.unwrap_err().contains("does not exist"));
|
|
}
|
|
|
|
// ============================================================================
|
|
// FILE PATH TESTS (NOT DIRECTORY)
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_file_path_is_not_directory() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let file_path = temp_dir.path().join("test_file.txt");
|
|
File::create(&file_path).unwrap();
|
|
|
|
let result = validate_and_normalize_path(&file_path).await;
|
|
|
|
assert!(result.is_err());
|
|
let err = result.unwrap_err();
|
|
assert!(err.contains("not a directory"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_file_path_with_nested_structure() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let nested_dir = temp_dir.path().join("dir1").join("dir2");
|
|
fs::create_dir_all(&nested_dir).unwrap();
|
|
|
|
let file_in_nested = nested_dir.join("file.txt");
|
|
File::create(&file_in_nested).unwrap();
|
|
|
|
let result = validate_and_normalize_path(&file_in_nested).await;
|
|
|
|
assert!(result.is_err());
|
|
assert!(result.unwrap_err().contains("not a directory"));
|
|
}
|
|
|
|
// ============================================================================
|
|
// DIRECTORY VALIDATION TESTS
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_empty_directory() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let empty_dir = temp_dir.path();
|
|
|
|
let result = validate_and_normalize_path(empty_dir).await;
|
|
|
|
assert!(result.is_ok());
|
|
let normalized = result.unwrap();
|
|
// Should be canonicalized to an absolute path
|
|
assert!(normalized.is_absolute());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_directory_with_files() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let dir_path = temp_dir.path();
|
|
|
|
// Create some files
|
|
File::create(dir_path.join("file1.txt")).unwrap();
|
|
File::create(dir_path.join("file2.txt")).unwrap();
|
|
|
|
let result = validate_and_normalize_path(dir_path).await;
|
|
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_directory_with_subdirectories() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let dir_path = temp_dir.path();
|
|
|
|
// Create nested directory structure
|
|
fs::create_dir_all(dir_path.join("subdir1").join("subdir2")).unwrap();
|
|
File::create(dir_path.join("file.txt")).unwrap();
|
|
|
|
let result = validate_and_normalize_path(dir_path).await;
|
|
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_directory_with_hidden_files() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let dir_path = temp_dir.path();
|
|
|
|
// Create hidden files
|
|
File::create(dir_path.join(".gitignore")).unwrap();
|
|
File::create(dir_path.join(".config")).unwrap();
|
|
|
|
let result = validate_and_normalize_path(dir_path).await;
|
|
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
// ============================================================================
|
|
// PATH NORMALIZATION TESTS
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_normalizes_relative_path() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let dir_path = temp_dir.path();
|
|
|
|
// Get canonical path first
|
|
let canonical = dir_path.canonicalize().unwrap();
|
|
|
|
let result = validate_and_normalize_path(dir_path).await;
|
|
|
|
assert!(result.is_ok());
|
|
let normalized = result.unwrap();
|
|
// The normalized path should be equivalent to canonicalized path
|
|
assert_eq!(normalized, canonical);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_resolves_dot_path() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let original_cwd = std::env::current_dir().unwrap();
|
|
|
|
// Change to temp directory
|
|
std::env::set_current_dir(temp_dir.path()).unwrap();
|
|
|
|
// Test with "./" path
|
|
let dot_path = Path::new(".");
|
|
let result = validate_and_normalize_path(dot_path).await;
|
|
|
|
// Restore original directory
|
|
std::env::set_current_dir(&original_cwd).unwrap();
|
|
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_directory_symlink_if_available() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let dir_path = temp_dir.path();
|
|
|
|
// Create a real directory
|
|
let real_dir = dir_path.join("real_dir");
|
|
fs::create_dir_all(&real_dir).unwrap();
|
|
|
|
// Create a symlink to it (may not work on all platforms)
|
|
#[cfg(unix)]
|
|
{
|
|
let symlink_path = dir_path.join("symlink_dir");
|
|
if let Ok(()) = std::os::unix::fs::symlink(&real_dir, &symlink_path) {
|
|
let result = validate_and_normalize_path(&symlink_path).await;
|
|
// Should resolve to the canonical path of the real directory
|
|
assert!(result.is_ok());
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// EDGE CASE TESTS
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_root_directory() {
|
|
// Test with root directory (may not be readable on all systems)
|
|
let root_path = Path::new("/");
|
|
|
|
let result = validate_and_normalize_path(root_path).await;
|
|
|
|
// On most systems, root should be accessible
|
|
// If it fails, it's likely due to permissions, not path validation
|
|
match result {
|
|
Ok(_) => {
|
|
// Root is accessible and canonicalizable
|
|
}
|
|
Err(e) => {
|
|
// Should be an access error, not "does not exist" or "not a directory"
|
|
assert!(!e.contains("does not exist"));
|
|
assert!(!e.contains("not a directory"));
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_current_directory() {
|
|
let current_dir = Path::new(".");
|
|
|
|
let result = validate_and_normalize_path(current_dir).await;
|
|
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_parent_directory() {
|
|
let parent_dir = Path::new("..");
|
|
|
|
let result = validate_and_normalize_path(parent_dir).await;
|
|
|
|
// Parent directory should be valid (assuming we have read access)
|
|
match result {
|
|
Ok(normalized) => {
|
|
// Should be an absolute path
|
|
assert!(normalized.is_absolute());
|
|
}
|
|
Err(e) => {
|
|
// If it fails, it should be an access error
|
|
assert!(e.contains("Cannot access") || e.contains("access"));
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_directory_with_special_characters() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let dir_path = temp_dir.path();
|
|
|
|
// Create directory with special characters in name
|
|
let special_dir = dir_path.join("dir-with-dashes_and_underscores");
|
|
fs::create_dir_all(&special_dir).unwrap();
|
|
|
|
let result = validate_and_normalize_path(&special_dir).await;
|
|
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_unicode_directory_name() {
|
|
let temp_dir = TempDir::new().unwrap();
|
|
let dir_path = temp_dir.path();
|
|
|
|
// Create directory with unicode characters
|
|
let unicode_dir = dir_path.join("测试目录");
|
|
fs::create_dir_all(&unicode_dir).unwrap();
|
|
|
|
let result = validate_and_normalize_path(&unicode_dir).await;
|
|
|
|
assert!(result.is_ok());
|
|
}
|