fs: add more tests for filesystem functionality (#5493)

This commit is contained in:
Chris Brody
2023-02-26 16:48:09 +01:00
committed by GitHub
parent ca9f7ee9f4
commit cadcd5da5e
13 changed files with 462 additions and 38 deletions
+22
View File
@@ -0,0 +1,22 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
use tokio::fs;
#[tokio::test]
#[cfg(unix)]
async fn canonicalize_root_dir_unix() {
assert_eq!(fs::canonicalize("/.").await.unwrap().to_str().unwrap(), "/");
}
#[tokio::test]
#[cfg(windows)]
async fn canonicalize_root_dir_windows() {
// 2-step let bindings due to Rust memory semantics
let dir_path = fs::canonicalize("C:\\.\\").await.unwrap();
let dir_name = dir_path.to_str().unwrap();
assert!(dir_name.starts_with("\\\\"));
assert!(dir_name.ends_with("C:\\"));
}
+1 -1
View File
@@ -1,5 +1,5 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // Wasi does not support file operations
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
use tempfile::tempdir;
use tokio::fs;
+40 -1
View File
@@ -1,5 +1,5 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // Wasi does not support directory operations
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
use tokio::fs;
use tokio_test::{assert_err, assert_ok};
@@ -45,6 +45,27 @@ async fn build_dir() {
);
}
#[tokio::test]
#[cfg(unix)]
async fn build_dir_mode_read_only() {
let base_dir = tempdir().unwrap();
let new_dir = base_dir.path().join("abc");
assert_ok!(
fs::DirBuilder::new()
.recursive(true)
.mode(0o444)
.create(&new_dir)
.await
);
assert!(fs::metadata(new_dir)
.await
.expect("metadata result")
.permissions()
.readonly());
}
#[tokio::test]
async fn remove() {
let base_dir = tempdir().unwrap();
@@ -85,3 +106,21 @@ async fn read_inherent() {
vec!["aa".to_string(), "bb".to_string(), "cc".to_string()]
);
}
#[tokio::test]
async fn read_dir_entry_info() {
let temp_dir = tempdir().unwrap();
let file_path = temp_dir.path().join("a.txt");
fs::write(&file_path, b"Hello File!").await.unwrap();
let mut dir = fs::read_dir(temp_dir.path()).await.unwrap();
let first_entry = dir.next_entry().await.unwrap().unwrap();
assert_eq!(first_entry.path(), file_path);
assert_eq!(first_entry.file_name(), "a.txt");
assert!(first_entry.metadata().await.unwrap().is_file());
assert!(first_entry.file_type().await.unwrap().is_file());
}
+103 -2
View File
@@ -1,5 +1,5 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // Wasi does not support file operations
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
use std::io::prelude::*;
use tempfile::NamedTempFile;
@@ -87,13 +87,93 @@ async fn coop() {
panic!("did not yield");
}
#[tokio::test]
async fn write_to_clone() {
let tempfile = tempfile();
let file = File::create(tempfile.path()).await.unwrap();
let mut clone = file.try_clone().await.unwrap();
clone.write_all(HELLO).await.unwrap();
clone.flush().await.unwrap();
let contents = std::fs::read(tempfile.path()).unwrap();
assert_eq!(contents, HELLO);
}
#[tokio::test]
async fn write_into_std() {
let tempfile = tempfile();
let file = File::create(tempfile.path()).await.unwrap();
let mut std_file = file.into_std().await;
std_file.write_all(HELLO).unwrap();
let contents = std::fs::read(tempfile.path()).unwrap();
assert_eq!(contents, HELLO);
}
#[tokio::test]
async fn write_into_std_immediate() {
let tempfile = tempfile();
let file = File::create(tempfile.path()).await.unwrap();
let mut std_file = file.try_into_std().unwrap();
std_file.write_all(HELLO).unwrap();
let contents = std::fs::read(tempfile.path()).unwrap();
assert_eq!(contents, HELLO);
}
#[tokio::test]
async fn read_file_from_std() {
let mut tempfile = tempfile();
tempfile.write_all(HELLO).unwrap();
let std_file = std::fs::File::open(tempfile.path()).unwrap();
let mut file = File::from(std_file);
let mut buf = [0; 1024];
let n = file.read(&mut buf).await.unwrap();
assert_eq!(n, HELLO.len());
assert_eq!(&buf[..n], HELLO);
}
fn tempfile() -> NamedTempFile {
NamedTempFile::new().unwrap()
}
#[tokio::test]
#[cfg(unix)]
async fn unix_fd() {
async fn file_debug_fmt() {
let tempfile = tempfile();
let file = File::open(tempfile.path()).await.unwrap();
assert_eq!(
&format!("{:?}", file)[0..33],
"tokio::fs::File { std: File { fd:"
);
}
#[tokio::test]
#[cfg(windows)]
async fn file_debug_fmt() {
let tempfile = tempfile();
let file = File::open(tempfile.path()).await.unwrap();
assert_eq!(
&format!("{:?}", file)[0..37],
"tokio::fs::File { std: File { handle:"
);
}
#[tokio::test]
#[cfg(unix)]
async fn unix_fd_is_valid() {
use std::os::unix::io::AsRawFd;
let tempfile = tempfile();
@@ -101,6 +181,27 @@ async fn unix_fd() {
assert!(file.as_raw_fd() as u64 > 0);
}
#[tokio::test]
#[cfg(unix)]
async fn read_file_from_unix_fd() {
use std::os::unix::io::AsRawFd;
use std::os::unix::io::FromRawFd;
let mut tempfile = tempfile();
tempfile.write_all(HELLO).unwrap();
let file1 = File::open(tempfile.path()).await.unwrap();
let raw_fd = file1.as_raw_fd();
assert!(raw_fd > 0);
let mut file2 = unsafe { File::from_raw_fd(raw_fd) };
let mut buf = [0; 1024];
let n = file2.read(&mut buf).await.unwrap();
assert_eq!(n, HELLO.len());
assert_eq!(&buf[..n], HELLO);
}
#[tokio::test]
#[cfg(windows)]
async fn windows_handle() {
+26 -33
View File
@@ -1,10 +1,9 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // Wasi does not support file operations
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
use tokio::fs;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Write;
use tempfile::tempdir;
#[tokio::test]
@@ -13,24 +12,23 @@ async fn test_hard_link() {
let src = dir.path().join("src.txt");
let dst = dir.path().join("dst.txt");
{
let mut file = std::fs::File::create(&src).unwrap();
file.write_all(b"hello").unwrap();
}
std::fs::File::create(&src)
.unwrap()
.write_all(b"hello")
.unwrap();
let dst_2 = dst.clone();
fs::hard_link(&src, &dst).await.unwrap();
assert!(fs::hard_link(src, dst_2.clone()).await.is_ok());
std::fs::File::create(&src)
.unwrap()
.write_all(b"new-data")
.unwrap();
let mut content = String::new();
let content = fs::read(&dst).await.unwrap();
assert_eq!(content, b"new-data");
{
let file = std::fs::File::open(dst).unwrap();
let mut reader = BufReader::new(file);
reader.read_to_string(&mut content).unwrap();
}
assert!(content == "hello");
// test that this is not a symlink:
assert!(fs::read_link(&dst).await.is_err());
}
#[cfg(unix)]
@@ -40,25 +38,20 @@ async fn test_symlink() {
let src = dir.path().join("src.txt");
let dst = dir.path().join("dst.txt");
{
let mut file = std::fs::File::create(&src).unwrap();
file.write_all(b"hello").unwrap();
}
std::fs::File::create(&src)
.unwrap()
.write_all(b"hello")
.unwrap();
let src_2 = src.clone();
let dst_2 = dst.clone();
fs::symlink(&src, &dst).await.unwrap();
assert!(fs::symlink(src_2.clone(), dst_2.clone()).await.is_ok());
std::fs::File::create(&src)
.unwrap()
.write_all(b"new-data")
.unwrap();
let mut content = String::new();
{
let file = std::fs::File::open(dst.clone()).unwrap();
let mut reader = BufReader::new(file);
reader.read_to_string(&mut content).unwrap();
}
assert!(content == "hello");
let content = fs::read(&dst).await.unwrap();
assert_eq!(content, b"new-data");
let read = fs::read_link(dst.clone()).await.unwrap();
assert!(read == src);
+80
View File
@@ -0,0 +1,80 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
use std::io::Write;
use tempfile::NamedTempFile;
use tokio::fs::OpenOptions;
use tokio::io::AsyncReadExt;
const HELLO: &[u8] = b"hello world...";
#[tokio::test]
async fn open_with_open_options_and_read() {
let mut tempfile = NamedTempFile::new().unwrap();
tempfile.write_all(HELLO).unwrap();
let mut file = OpenOptions::new().read(true).open(tempfile).await.unwrap();
let mut buf = [0; 1024];
let n = file.read(&mut buf).await.unwrap();
assert_eq!(n, HELLO.len());
assert_eq!(&buf[..n], HELLO);
}
#[tokio::test]
async fn open_options_write() {
// TESTING HACK: use Debug output to check the stored data
assert!(format!("{:?}", OpenOptions::new().write(true)).contains("write: true"));
}
#[tokio::test]
async fn open_options_append() {
// TESTING HACK: use Debug output to check the stored data
assert!(format!("{:?}", OpenOptions::new().append(true)).contains("append: true"));
}
#[tokio::test]
async fn open_options_truncate() {
// TESTING HACK: use Debug output to check the stored data
assert!(format!("{:?}", OpenOptions::new().truncate(true)).contains("truncate: true"));
}
#[tokio::test]
async fn open_options_create() {
// TESTING HACK: use Debug output to check the stored data
assert!(format!("{:?}", OpenOptions::new().create(true)).contains("create: true"));
}
#[tokio::test]
async fn open_options_create_new() {
// TESTING HACK: use Debug output to check the stored data
assert!(format!("{:?}", OpenOptions::new().create_new(true)).contains("create_new: true"));
}
#[tokio::test]
#[cfg(unix)]
async fn open_options_mode() {
// TESTING HACK: use Debug output to check the stored data
assert!(format!("{:?}", OpenOptions::new().mode(0o644)).contains("mode: 420 "));
}
#[tokio::test]
#[cfg(target_os = "linux")]
async fn open_options_custom_flags_linux() {
// TESTING HACK: use Debug output to check the stored data
assert!(
format!("{:?}", OpenOptions::new().custom_flags(libc::O_TRUNC))
.contains("custom_flags: 512,")
);
}
#[tokio::test]
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
async fn open_options_custom_flags_bsd_family() {
// TESTING HACK: use Debug output to check the stored data
assert!(
format!("{:?}", OpenOptions::new().custom_flags(libc::O_NOFOLLOW))
.contains("custom_flags: 256,")
);
}
+51
View File
@@ -0,0 +1,51 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
#![cfg(windows)]
use tokio::fs::OpenOptions;
use windows_sys::Win32::Storage::FileSystem;
#[tokio::test]
#[cfg(windows)]
async fn open_options_windows_access_mode() {
// TESTING HACK: use Debug output to check the stored data
assert!(format!("{:?}", OpenOptions::new().access_mode(0)).contains("access_mode: Some(0)"));
}
#[tokio::test]
#[cfg(windows)]
async fn open_options_windows_share_mode() {
// TESTING HACK: use Debug output to check the stored data
assert!(format!("{:?}", OpenOptions::new().share_mode(0)).contains("share_mode: 0,"));
}
#[tokio::test]
#[cfg(windows)]
async fn open_options_windows_custom_flags() {
// TESTING HACK: use Debug output to check the stored data
assert!(format!(
"{:?}",
OpenOptions::new().custom_flags(FileSystem::FILE_FLAG_DELETE_ON_CLOSE)
)
.contains("custom_flags: 67108864,"));
}
#[tokio::test]
#[cfg(windows)]
async fn open_options_windows_attributes() {
assert!(format!(
"{:?}",
OpenOptions::new().attributes(FileSystem::FILE_ATTRIBUTE_HIDDEN)
)
.contains("attributes: 2,"));
}
#[tokio::test]
#[cfg(windows)]
async fn open_options_windows_security_qos_flags() {
assert!(format!(
"{:?}",
OpenOptions::new().security_qos_flags(FileSystem::SECURITY_IDENTIFICATION)
)
.contains("security_qos_flags: 1114112,"));
}
+31
View File
@@ -0,0 +1,31 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
use tempfile::tempdir;
use tokio::fs;
#[tokio::test]
async fn remove_dir_all() {
let temp_dir = tempdir().unwrap();
let test_dir = temp_dir.path().join("test");
fs::create_dir(&test_dir).await.unwrap();
let file_path = test_dir.as_path().join("a.txt");
fs::write(&file_path, b"Hello File!").await.unwrap();
fs::remove_dir_all(test_dir.as_path()).await.unwrap();
// test dir should no longer exist
match fs::try_exists(test_dir).await {
Ok(exists) => assert!(!exists),
Err(_) => println!("ignored try_exists error after remove_dir_all"),
};
// contents should no longer exist
match fs::try_exists(file_path).await {
Ok(exists) => assert!(!exists),
Err(_) => println!("ignored try_exists error after remove_dir_all"),
};
}
+24
View File
@@ -0,0 +1,24 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
use tempfile::tempdir;
use tokio::fs;
#[tokio::test]
async fn remove_file() {
let temp_dir = tempdir().unwrap();
let file_path = temp_dir.path().join("a.txt");
fs::write(&file_path, b"Hello File!").await.unwrap();
assert!(fs::try_exists(&file_path).await.unwrap());
fs::remove_file(&file_path).await.unwrap();
// should no longer exist
match fs::try_exists(file_path).await {
Ok(exists) => assert!(!exists),
Err(_) => println!("ignored try_exists error after remove_file"),
};
}
+28
View File
@@ -0,0 +1,28 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
use tempfile::tempdir;
use tokio::fs;
#[tokio::test]
async fn rename_file() {
let temp_dir = tempdir().unwrap();
let file_path = temp_dir.path().join("a.txt");
fs::write(&file_path, b"Hello File!").await.unwrap();
assert!(fs::try_exists(&file_path).await.unwrap());
let new_file_path = temp_dir.path().join("b.txt");
fs::rename(&file_path, &new_file_path).await.unwrap();
assert!(fs::try_exists(new_file_path).await.unwrap());
// original file should no longer exist
match fs::try_exists(file_path).await {
Ok(exists) => assert!(!exists),
Err(_) => println!("ignored try_exists error after rename"),
};
}
+31
View File
@@ -0,0 +1,31 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
#![cfg(windows)]
use tempfile::tempdir;
use tokio::fs;
#[tokio::test]
async fn symlink_file_windows() {
const FILE_NAME: &str = "abc.txt";
let temp_dir = tempdir().unwrap();
let dir1 = temp_dir.path().join("a");
fs::create_dir(&dir1).await.unwrap();
let file1 = dir1.as_path().join(FILE_NAME);
fs::write(&file1, b"Hello File!").await.unwrap();
let dir2 = temp_dir.path().join("b");
fs::symlink_dir(&dir1, &dir2).await.unwrap();
fs::write(&file1, b"new data!").await.unwrap();
let file2 = dir2.as_path().join(FILE_NAME);
let from = fs::read(&file1).await.unwrap();
let to = fs::read(&file2).await.unwrap();
assert_eq!(from, to);
}
+24
View File
@@ -0,0 +1,24 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
#![cfg(windows)]
use tempfile::tempdir;
use tokio::fs;
#[tokio::test]
async fn symlink_file_windows() {
let dir = tempdir().unwrap();
let source_path = dir.path().join("foo.txt");
let dest_path = dir.path().join("bar.txt");
fs::write(&source_path, b"Hello File!").await.unwrap();
fs::symlink_file(&source_path, &dest_path).await.unwrap();
fs::write(&source_path, b"new data!").await.unwrap();
let from = fs::read(&source_path).await.unwrap();
let to = fs::read(&dest_path).await.unwrap();
assert_eq!(from, to);
}
+1 -1
View File
@@ -1,5 +1,5 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // Wasi does not support file operations
#![cfg(all(feature = "full", not(tokio_wasi)))] // WASI does not support all fs operations
use tempfile::tempdir;
use tokio::fs;