Skip to content

Commit

Permalink
fs: add more tests for filesystem functionality (#5493)
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Brody authored Feb 26, 2023
1 parent ca9f7ee commit cadcd5d
Show file tree
Hide file tree
Showing 13 changed files with 462 additions and 38 deletions.
22 changes: 22 additions & 0 deletions tokio/tests/fs_canonicalize_dir.rs
Original file line number Diff line number Diff line change
@@ -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:\\"));
}
2 changes: 1 addition & 1 deletion tokio/tests/fs_copy.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
41 changes: 40 additions & 1 deletion tokio/tests/fs_dir.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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());
}
105 changes: 103 additions & 2 deletions tokio/tests/fs_file.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -87,20 +87,121 @@ 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();

let file = File::create(tempfile.path()).await.unwrap();
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() {
Expand Down
59 changes: 26 additions & 33 deletions tokio/tests/fs_link.rs
Original file line number Diff line number Diff line change
@@ -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]
Expand All @@ -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)]
Expand All @@ -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();
}

let src_2 = src.clone();
let dst_2 = dst.clone();

assert!(fs::symlink(src_2.clone(), dst_2.clone()).await.is_ok());
std::fs::File::create(&src)
.unwrap()
.write_all(b"hello")
.unwrap();

let mut content = String::new();
fs::symlink(&src, &dst).await.unwrap();

{
let file = std::fs::File::open(dst.clone()).unwrap();
let mut reader = BufReader::new(file);
reader.read_to_string(&mut content).unwrap();
}
std::fs::File::create(&src)
.unwrap()
.write_all(b"new-data")
.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);
Expand Down
80 changes: 80 additions & 0 deletions tokio/tests/fs_open_options.rs
Original file line number Diff line number Diff line change
@@ -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,")
);
}
Loading

0 comments on commit cadcd5d

Please sign in to comment.