diff options
| author | Mica White <botahamec@gmail.com> | 2024-12-01 15:28:44 -0500 |
|---|---|---|
| committer | Mica White <botahamec@gmail.com> | 2024-12-01 15:29:19 -0500 |
| commit | 48aaedad542b9c6cbdc85d22517cd0d151f38443 (patch) | |
| tree | b5b197c47476e88b9926852c73a84f24b6497c77 /src/collection/retry.rs | |
| parent | 0140f58043a2a00312d31907253cc718985e1e6c (diff) | |
Unit testing
Diffstat (limited to 'src/collection/retry.rs')
| -rw-r--r-- | src/collection/retry.rs | 127 |
1 files changed, 108 insertions, 19 deletions
diff --git a/src/collection/retry.rs b/src/collection/retry.rs index 7aa4ef4..8a10fc3 100644 --- a/src/collection/retry.rs +++ b/src/collection/retry.rs @@ -30,32 +30,41 @@ unsafe impl<L: Lockable + Send + Sync> RawLock for RetryingLockCollection<L> { let mut locks = Vec::new(); self.data.get_ptrs(&mut locks); - 'outer: loop { - // safety: we have the thread key - locks[first_index].lock(); - for (i, lock) in locks.iter().enumerate() { - if i == first_index { - continue; - } + if locks.is_empty() { + return; + } + unsafe { + 'outer: loop { // safety: we have the thread key - if !lock.try_lock() { - for lock in locks.iter().take(i) { - // safety: we already locked all of these - lock.unlock(); + locks[first_index].lock(); + for (i, lock) in locks.iter().enumerate() { + if i == first_index { + continue; } - if first_index >= i { - // safety: this is already locked and can't be unlocked - // by the previous loop - locks[first_index].unlock(); - } + // safety: we have the thread key + if !lock.try_lock() { + for lock in locks.iter().take(i) { + // safety: we already locked all of these + lock.unlock(); + } - first_index = i; - continue 'outer; + if first_index >= i { + // safety: this is already locked and can't be unlocked + // by the previous loop + locks[first_index].unlock(); + } + + first_index = i; + continue 'outer; + } } + + // safety: we locked all the data + break; } - } + }; } unsafe fn try_lock(&self) -> bool { @@ -771,3 +780,83 @@ where self.into_iter() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::collection::BoxedLockCollection; + use crate::{Mutex, RwLock, ThreadKey}; + use lock_api::{RawMutex, RawRwLock}; + + #[test] + fn nonduplicate_lock_references_are_allowed() { + let mutex1 = Mutex::new(0); + let mutex2 = Mutex::new(0); + assert!(RetryingLockCollection::try_new([&mutex1, &mutex2]).is_some()); + } + + #[test] + fn duplicate_lock_references_are_disallowed() { + let mutex = Mutex::new(0); + assert!(RetryingLockCollection::try_new([&mutex, &mutex]).is_none()); + } + + #[test] + fn locks_all_inner_mutexes() { + let key = ThreadKey::get().unwrap(); + let mutex1 = Mutex::new(0); + let mutex2 = Mutex::new(0); + let collection = RetryingLockCollection::try_new([&mutex1, &mutex2]).unwrap(); + + let guard = collection.lock(key); + + assert!(mutex1.is_locked()); + assert!(mutex2.is_locked()); + + drop(guard); + } + + #[test] + fn locks_all_inner_rwlocks() { + let key = ThreadKey::get().unwrap(); + let rwlock1 = RwLock::new(0); + let rwlock2 = RwLock::new(0); + let collection = RetryingLockCollection::try_new([&rwlock1, &rwlock2]).unwrap(); + // TODO Poisonable::read + + let guard = collection.read(key); + + assert!(rwlock1.is_locked()); + assert!(rwlock2.is_locked()); + + drop(guard); + } + + #[test] + fn works_with_other_collections() { + let key = ThreadKey::get().unwrap(); + let mutex1 = Mutex::new(0); + let mutex2 = Mutex::new(0); + let collection = BoxedLockCollection::try_new( + RetryingLockCollection::try_new([&mutex1, &mutex2]).unwrap(), + ) + .unwrap(); + + let guard = collection.lock(key); + + assert!(mutex1.is_locked()); + assert!(mutex2.is_locked()); + drop(guard); + } + + #[test] + fn extend_collection() { + let mutex1 = Mutex::new(0); + let mutex2 = Mutex::new(0); + let mut collection = RetryingLockCollection::new(vec![mutex1]); + + collection.extend([mutex2]); + + assert_eq!(collection.into_inner().len(), 2); + } +} |
