use std::sync::Arc;
use super::*;
#[test]
fn test_try_lock_never_blocks() {
let mutex = Arc::new(Mutex::new(9));
let _guard = mutex.try_lock().unwrap();
let result = mutex.try_lock();
assert!(result.is_none());
let result = mutex.clone().try_lock_owned();
assert!(result.is_none());
}
#[test]
fn test_get_mut_provides_exclusive_access() {
let mut mutex = Mutex::new(11);
let data = mutex.get_mut();
*data = 100;
assert_eq!(*mutex.get_mut(), 100);
let inner = mutex.into_inner();
assert_eq!(inner, 100);
}
#[tokio::test]
async fn test_guard_map_preserves_lock() {
let data = (99i32, vec![1, 2, 3]);
let mutex = Mutex::new(data);
let guard = mutex.lock().await;
let mut mapped_guard = MutexGuard::map(guard, |data| &mut data.0);
assert!(mutex.try_lock().is_none());
*mapped_guard = 100;
drop(mapped_guard);
let guard = mutex.try_lock().unwrap();
assert_eq!(guard.0, 100);
}
#[tokio::test]
async fn test_mapped_guard_holds_lock() {
let mutex = Arc::new(Mutex::new((10, 20)));
let guard = mutex.lock().await;
let mapped_guard = MutexGuard::map(guard, |data| &mut data.0);
assert!(
mutex.try_lock().is_none(),
"Lock should be held by the mapped guard"
);
assert_eq!(*mapped_guard, 10);
drop(mapped_guard);
assert!(
mutex.try_lock().is_some(),
"Lock should be released after mapped guard is dropped"
);
}
#[tokio::test]
async fn test_owned_mapped_guard_holds_lock() {
let mutex = Arc::new(Mutex::new((30, 40)));
let owned_guard = mutex.clone().lock_owned().await;
let mapped_owned_guard = OwnedMutexGuard::map(owned_guard, |data| &mut data.1);
assert!(
mutex.try_lock().is_none(),
"Lock should be held by the mapped owned guard"
);
assert_eq!(*mapped_owned_guard, 40);
drop(mapped_owned_guard);
assert!(
mutex.try_lock().is_some(),
"Lock should be released after mapped owned guard is dropped"
);
}
#[tokio::test]
async fn test_guard_filter_map_failure() {
let data: Vec<i32> = vec![];
let mutex = Mutex::new(data);
let guard = mutex.lock().await;
let result = MutexGuard::filter_map(guard, |vec| vec.get_mut(0));
assert!(result.is_err());
if let Err(mut original_guard) = result {
original_guard.push(100);
assert_eq!(*original_guard, vec![100]);
} else {
panic!("Expected Err, but got Ok");
}
}
#[tokio::test]
async fn test_owned_guard_filter_map_failure() {
let data: Vec<i32> = vec![];
let mutex = Arc::new(Mutex::new(data));
let guard = mutex.clone().lock_owned().await;
let result = OwnedMutexGuard::filter_map(guard, |vec| vec.get_mut(0));
assert!(result.is_err());
if let Err(mut original_guard) = result {
original_guard.push(200);
assert_eq!(*original_guard, vec![200]);
} else {
panic!("Expected Err, but got Ok");
}
}
#[tokio::test]
async fn test_multiple_map_operations() {
let data = vec![vec![1, 2], vec![3, 4]];
let mutex = Mutex::new(data);
let guard = mutex.lock().await;
let first_vec = MutexGuard::map(guard, |data| &mut data[0]);
let mut first_element = MappedMutexGuard::map(first_vec, |vec| &mut vec[0]);
*first_element = 100;
drop(first_element);
let guard = mutex.lock().await;
assert_eq!(guard[0][0], 100);
assert_eq!(guard[0][1], 2);
assert_eq!(guard[1][0], 3);
}
#[tokio::test]
async fn test_stress() {
let mutex = Arc::new(Mutex::new(0));
let mut handles = Vec::new();
for i in 0..1000 {
let mutex = mutex.clone();
handles.push(tokio::spawn(async move {
let mut guard = mutex.lock().await;
*guard += 1;
if i % 10 == 0 {
tokio::task::yield_now().await;
}
}));
}
for handle in handles {
handle.await.unwrap();
}
let final_value = *mutex.lock().await;
assert_eq!(final_value, 1000);
}
#[tokio::test]
async fn test_guard_prevents_concurrent_access() {
let mutex = Arc::new(Mutex::new(0));
let mutex_clone = mutex.clone();
let guard = mutex.lock().await;
assert!(
mutex.try_lock().is_none(),
"Lock should be held by the first guard"
);
let handle = tokio::spawn(async move {
let _guard2 = mutex_clone.lock().await;
123
});
tokio::task::yield_now().await;
assert!(
mutex.try_lock().is_none(),
"Lock should still be held after yielding"
);
drop(guard);
let result = handle.await.unwrap();
assert_eq!(result, 123);
assert!(
mutex.try_lock().is_some(),
"Lock should be available after all guards are dropped"
);
}
#[test]
fn test_lock_panic_safety() {
use std::panic::AssertUnwindSafe;
let mutex = Arc::new(Mutex::new(0));
let mutex_clone = mutex.clone();
let result = std::panic::catch_unwind(AssertUnwindSafe(move || {
let _guard = mutex_clone.try_lock().unwrap();
panic!("test panic");
}));
assert!(result.is_err());
assert!(mutex.try_lock().is_some());
}
#[tokio::test]
async fn test_async_lock_panic_safety() {
let mutex = Arc::new(Mutex::new(0));
let mutex_clone = mutex.clone();
let handle = tokio::spawn(async move {
let _guard = mutex_clone.lock().await;
panic!("async test panic");
});
assert!(handle.await.is_err());
let guard = mutex.try_lock();
assert!(guard.is_some());
}
#[tokio::test]
async fn test_owned_guard_panic_safety() {
let mutex = Arc::new(Mutex::new(0));
let mutex_clone = mutex.clone();
let handle = tokio::spawn(async move {
let _guard = mutex_clone.clone().lock_owned().await;
panic!("owned guard panic");
});
assert!(handle.await.is_err());
let guard = mutex.try_lock();
assert!(guard.is_some());
}
#[tokio::test]
async fn test_mapped_guard_panic_safety() {
let mutex = Arc::new(Mutex::new((66, vec![1, 2, 3])));
let mutex_clone = mutex.clone();
let handle = tokio::spawn(async move {
let guard = mutex_clone.lock().await;
let _mapped = MutexGuard::map(guard, |data| &mut data.0);
panic!("mapped guard panic");
});
assert!(handle.await.is_err());
let guard = mutex.try_lock();
assert!(guard.is_some());
}
#[tokio::test]
async fn test_memory_ordering_correctness() {
let mutex = Arc::new(Mutex::new(vec![1, 2, 3]));
let mutex_clone = mutex.clone();
let handle = tokio::spawn(async move {
let mut guard = mutex_clone.lock().await;
guard.push(4);
guard[0] = 100;
});
handle.await.unwrap();
let guard = mutex.lock().await;
assert_eq!(*guard, vec![100, 2, 3, 4]);
}
#[tokio::test]
async fn test_mutex_zst() {
let mutex = Arc::new(Mutex::new(()));
let mutex_clone = mutex.clone();
let handle = tokio::spawn(async move {
let guard = mutex_clone.lock().await;
*guard;
});
handle.await.unwrap();
let _owned_guard = mutex.clone().lock_owned().await;
assert!(mutex.try_lock().is_none());
drop(_owned_guard);
let guard = mutex.try_lock().unwrap();
*guard;
}
#[tokio::test]
async fn test_mapped_mutex_guard_send() {
#[derive(Debug)]
struct TestStruct {
field1: i32,
_field2: String,
}
let mutex = Arc::new(Mutex::new(TestStruct {
field1: 2,
_field2: "oh".to_owned(),
}));
let mutex_clone = mutex.clone();
let handle = tokio::spawn(async move {
let guard = mutex_clone.lock().await;
let mapped_guard = MutexGuard::map(guard, |data| &mut data.field1);
tokio::task::yield_now().await;
*mapped_guard
});
let result = handle.await.unwrap();
assert_eq!(result, 2);
}