use adaptor::*;
use futures::future::join_all;
use paste::paste;
use std::io::ErrorKind;
use tempfile::tempdir;
use tokio::fs::File;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
mod adaptor;
macro_rules! generate_tests {
($($blocking_first:ident)?, $prefix_first:ident; $($blocking_second:ident)?, $prefix_second:ident) => {
paste! {
#[tokio::test]
async fn [<$($blocking_first _)? $prefix_first _read_ $($blocking_second _)? $prefix_second _read_lock>]() {
let dir = tempdir().unwrap();
let path = dir.path().join("lockfile");
let l0 = $($blocking_first::)? file_create(&path).await.unwrap();
let l1 = $($blocking_second::)? file_open(path).await.unwrap();
let _g0 = l0.[<$prefix_first _lock_read_async>]().await.unwrap();
let _g1 = l1.[<$prefix_second _lock_read_async>]().await.unwrap();
}
#[tokio::test]
async fn [<$($blocking_first _)? $prefix_first _write_ $($blocking_second _)? $prefix_second _write_lock>]() {
let dir = tempdir().unwrap();
let path = dir.path().join("lockfile");
#[allow(unused_mut)]
let mut l0 = $($blocking_first::)? file_create(&path).await.unwrap();
#[allow(unused_mut)]
let mut l1 = $($blocking_second::)? file_open(path).await.unwrap();
let g0 = l0.[<$prefix_first _lock_write_async>]().await.unwrap();
let (l1, err) = l1.[<$prefix_second _lock_write_async>]().await.unwrap_err().into();
assert!(matches!(err.kind(), ErrorKind::WouldBlock));
drop(g0);
let _g1 = l1.[<$prefix_second _lock_write_async>]().await.unwrap();
}
#[tokio::test]
async fn [<$($blocking_first _)? $prefix_first _read_ $($blocking_second _)? $prefix_second _write_lock>]() {
let dir = tempdir().unwrap();
let path = dir.path().join("lockfile");
let l0 = $($blocking_first::)? file_create(&path).await.unwrap();
#[allow(unused_mut)]
let mut l1 = $($blocking_second::)? file_open(path).await.unwrap();
let g0 = l0.[<$prefix_first _lock_read_async>]().await.unwrap();
let (l1, err) = l1.[<$prefix_second _lock_write_async>]().await.unwrap_err().into();
assert!(matches!(err.kind(), ErrorKind::WouldBlock));
drop(g0);
let _g1 = l1.[<$prefix_second _lock_write_async>]().await.unwrap();
}
#[tokio::test]
async fn [<$($blocking_first _)? $prefix_first _write_ $($blocking_second _)? $prefix_second _read_lock>]() {
let dir = tempdir().unwrap();
let path = dir.path().join("lockfile");
#[allow(unused_mut)]
let mut l0 = $($blocking_first::)? file_create(&path).await.unwrap();
let l1 = $($blocking_second::)? file_open(path).await.unwrap();
let g0 = l0.[<$prefix_first _lock_write_async>]().await.unwrap();
let (l1, err) = l1.[<$prefix_second _lock_read_async>]().await.unwrap_err().into();
assert!(matches!(err.kind(), ErrorKind::WouldBlock));
drop(g0);
let _g1 = l1.[<$prefix_second _lock_read_async>]().await.unwrap();
}
}
};
}
generate_tests!(blocking, try; blocking, try);
generate_tests!(blocking, try; , try);
generate_tests!( , try; blocking, try);
generate_tests!( , try; , try);
generate_tests!(blocking, try; , timeout);
generate_tests!( , try; , timeout);
generate_tests!( , timeout; blocking, try);
generate_tests!( , timeout; , try);
generate_tests!( , timeout; , timeout);
#[tokio::test]
async fn io_read() {
const BYTES: &[u8] = b"Hello, world!";
let dir = tempdir().unwrap();
let path = dir.path().join("lockfile");
{
let file = tokio::fs::File::create(&path).await.unwrap(); let mut guard = file.try_lock_write_async().await.unwrap();
{
let file = tokio::fs::File::open(&path).await.unwrap(); let _ = file.try_lock_write_async().await.unwrap_err();
}
guard.write_all(BYTES).await.unwrap();
}
{
let guards = join_all((0..5).map(|_| async {
let file = File::open(&path).await.unwrap(); file.try_lock_read_async().await.unwrap()
}))
.await;
join_all(guards.into_iter().map(|mut guard| async move {
let mut buffer = Vec::new();
guard.read_to_end(&mut buffer).await.unwrap();
assert_eq!(&buffer, BYTES);
}))
.await;
}
}
#[cfg(windows)]
mod windows {
use super::*;
use async_fd_lock::blocking::{LockRead, LockWrite};
use std::os::windows::fs::OpenOptionsExt;
#[test]
fn try_lock_error() {
let dir = tempdir().unwrap();
let path = dir.path().join("lockfile");
let l0 = std::fs::File::options()
.create(true)
.read(true)
.write(true)
.truncate(true)
.access_mode(0)
.open(path)
.unwrap();
let (l0, err1) = l0.try_lock_read().unwrap_err().into();
assert!(matches!(err1.kind(), ErrorKind::PermissionDenied));
let (_l0, err2) = l0.try_lock_write().unwrap_err().into();
assert!(matches!(err2.kind(), ErrorKind::PermissionDenied));
}
}