mod r#async; mod sync; pub use r#async::*; pub use sync::*; #[cfg(test)] mod async_tests { use tokio::io; use super::*; use crate::rola_test_sandbox; #[tokio::test] async fn copy_to_new_location() { let sandbox = rola_test_sandbox("async_copy_to_new_location"); let src = sandbox.join("src.txt"); let dst = sandbox.join("dst.txt"); tokio::fs::write(&src, b"hello").await.unwrap(); copy_with_temp_rename_async(&src, &dst).await.unwrap(); let content = tokio::fs::read_to_string(&dst).await.unwrap(); assert_eq!(content, "hello"); } #[tokio::test] async fn overwrite_existing_destination() { let sandbox = rola_test_sandbox("async_overwrite_existing_dst"); let src = sandbox.join("src.txt"); let dst = sandbox.join("dst.txt"); tokio::fs::write(&src, b"new content").await.unwrap(); tokio::fs::write(&dst, b"old content").await.unwrap(); copy_with_temp_rename_async(&src, &dst).await.unwrap(); let content = tokio::fs::read_to_string(&dst).await.unwrap(); assert_eq!(content, "new content"); } #[tokio::test] async fn source_not_found() { let sandbox = rola_test_sandbox("async_source_not_found"); let src = sandbox.join("nonexistent.txt"); let dst = sandbox.join("dst.txt"); let err = copy_with_temp_rename_async(&src, &dst).await.unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::NotFound); } #[tokio::test] async fn copy_same_file() { let sandbox = rola_test_sandbox("async_copy_same_file"); let file = sandbox.join("file.txt"); tokio::fs::write(&file, b"content").await.unwrap(); copy_with_temp_rename_async(&file, &file).await.unwrap(); let content = tokio::fs::read_to_string(&file).await.unwrap(); assert_eq!(content, "content"); } #[tokio::test] async fn source_is_directory() { let sandbox = rola_test_sandbox("async_source_is_directory"); let src = sandbox.join("a_dir"); let dst = sandbox.join("dst.txt"); tokio::fs::create_dir(&src).await.unwrap(); let err = copy_with_temp_rename_async(&src, &dst).await.unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::InvalidInput); } #[tokio::test] async fn destination_is_directory() { let sandbox = rola_test_sandbox("async_dest_is_directory"); let src = sandbox.join("src.txt"); let dst = sandbox.join("a_dir"); tokio::fs::write(&src, b"content").await.unwrap(); tokio::fs::create_dir(&dst).await.unwrap(); let err = copy_with_temp_rename_async(&src, &dst).await.unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::InvalidInput); } #[tokio::test] async fn create_parent_directory() { let sandbox = rola_test_sandbox("async_create_parent_dir"); let src = sandbox.join("src.txt"); let dst = sandbox.join("sub/deep/dst.txt"); tokio::fs::write(&src, b"hello").await.unwrap(); copy_with_temp_rename_async(&src, &dst).await.unwrap(); assert!(tokio::fs::try_exists(&dst).await.unwrap()); let content = tokio::fs::read_to_string(&dst).await.unwrap(); assert_eq!(content, "hello"); } #[tokio::test] async fn content_is_atomic() { let sandbox = rola_test_sandbox("async_content_is_atomic"); let src = sandbox.join("src.txt"); let dst = sandbox.join("dst.txt"); tokio::fs::write(&src, b"final content").await.unwrap(); tokio::fs::write(&dst, b"initial").await.unwrap(); copy_with_temp_rename_async(&src, &dst).await.unwrap(); let content = tokio::fs::read_to_string(&dst).await.unwrap(); assert_eq!(content, "final content"); } } #[cfg(test)] mod sync_tests { use super::*; use crate::rola_test_sandbox; use std::{fs, io}; #[test] fn copy_to_new_location() { let sandbox = rola_test_sandbox("copy_to_new_location"); let src = sandbox.join("src.txt"); let dst = sandbox.join("dst.txt"); fs::write(&src, b"hello").unwrap(); copy_with_temp_rename(&src, &dst).unwrap(); assert_eq!(fs::read_to_string(&dst).unwrap(), "hello"); } #[test] fn overwrite_existing_destination() { let sandbox = rola_test_sandbox("overwrite_existing_dst"); let src = sandbox.join("src.txt"); let dst = sandbox.join("dst.txt"); fs::write(&src, b"new content").unwrap(); fs::write(&dst, b"old content").unwrap(); copy_with_temp_rename(&src, &dst).unwrap(); assert_eq!(fs::read_to_string(&dst).unwrap(), "new content"); } #[test] fn source_not_found() { let sandbox = rola_test_sandbox("source_not_found"); let src = sandbox.join("nonexistent.txt"); let dst = sandbox.join("dst.txt"); let err = copy_with_temp_rename(&src, &dst).unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::NotFound); } #[test] fn copy_same_file() { let sandbox = rola_test_sandbox("copy_same_file"); let file = sandbox.join("file.txt"); fs::write(&file, b"content").unwrap(); copy_with_temp_rename(&file, &file).unwrap(); assert_eq!(fs::read_to_string(&file).unwrap(), "content"); } #[test] fn source_is_directory() { let sandbox = rola_test_sandbox("source_is_directory"); let src = sandbox.join("a_dir"); let dst = sandbox.join("dst.txt"); fs::create_dir(&src).unwrap(); let err = copy_with_temp_rename(&src, &dst).unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::InvalidInput); } #[test] fn destination_is_directory() { let sandbox = rola_test_sandbox("dest_is_directory"); let src = sandbox.join("src.txt"); let dst = sandbox.join("a_dir"); fs::write(&src, b"content").unwrap(); fs::create_dir(&dst).unwrap(); let err = copy_with_temp_rename(&src, &dst).unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::InvalidInput); } #[test] fn create_parent_directory() { let sandbox = rola_test_sandbox("create_parent_dir"); let src = sandbox.join("src.txt"); let dst = sandbox.join("sub/deep/dst.txt"); fs::write(&src, b"hello").unwrap(); copy_with_temp_rename(&src, &dst).unwrap(); assert!(dst.exists()); assert_eq!(fs::read_to_string(&dst).unwrap(), "hello"); } #[test] fn content_is_atomic() { let sandbox = rola_test_sandbox("content_is_atomic"); let src = sandbox.join("src.txt"); let dst = sandbox.join("dst.txt"); fs::write(&src, b"final content").unwrap(); fs::write(&dst, b"initial").unwrap(); copy_with_temp_rename(&src, &dst).unwrap(); // After the operation, dst must contain exactly the source content // (never partial/empty, thanks to temp+rename) assert_eq!(fs::read_to_string(&dst).unwrap(), "final content"); } }