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 | |
| parent | 0140f58043a2a00312d31907253cc718985e1e6c (diff) | |
Unit testing
Diffstat (limited to 'src/collection')
| -rw-r--r-- | src/collection/boxed.rs | 34 | ||||
| -rw-r--r-- | src/collection/guard.rs | 16 | ||||
| -rw-r--r-- | src/collection/owned.rs | 17 | ||||
| -rw-r--r-- | src/collection/ref.rs | 34 | ||||
| -rw-r--r-- | src/collection/retry.rs | 127 |
5 files changed, 209 insertions, 19 deletions
diff --git a/src/collection/boxed.rs b/src/collection/boxed.rs index b0d1e3b..c359098 100644 --- a/src/collection/boxed.rs +++ b/src/collection/boxed.rs @@ -532,3 +532,37 @@ where self.into_iter() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{Mutex, ThreadKey}; + + #[test] + fn non_duplicates_allowed() { + let mutex1 = Mutex::new(0); + let mutex2 = Mutex::new(1); + assert!(BoxedLockCollection::try_new([&mutex1, &mutex2]).is_some()) + } + + #[test] + fn duplicates_not_allowed() { + let mutex1 = Mutex::new(0); + assert!(BoxedLockCollection::try_new([&mutex1, &mutex1]).is_none()) + } + + #[test] + fn works_in_collection() { + let key = ThreadKey::get().unwrap(); + let mutex1 = Mutex::new(0); + let mutex2 = Mutex::new(1); + let collection = + BoxedLockCollection::try_new(BoxedLockCollection::try_new([&mutex1, &mutex2]).unwrap()) + .unwrap(); + + let guard = collection.lock(key); + assert!(mutex1.is_locked()); + assert!(mutex2.is_locked()); + drop(guard); + } +} diff --git a/src/collection/guard.rs b/src/collection/guard.rs index 8857c5f..0b8a583 100644 --- a/src/collection/guard.rs +++ b/src/collection/guard.rs @@ -42,3 +42,19 @@ impl<'key, Guard, Key: Keyable> AsMut<Guard> for LockGuard<'key, Guard, Key> { &mut self.guard } } + +#[cfg(test)] +mod tests { + use crate::collection::OwnedLockCollection; + use crate::{RwLock, ThreadKey}; + + use super::*; + + #[test] + fn guard_display_works() { + let key = ThreadKey::get().unwrap(); + let lock = OwnedLockCollection::new(RwLock::new("Hello, world!")); + let guard = lock.read(key); + assert_eq!(guard.to_string(), "Hello, world!".to_string()); + } +} diff --git a/src/collection/owned.rs b/src/collection/owned.rs index f2b6cc9..9aa7460 100644 --- a/src/collection/owned.rs +++ b/src/collection/owned.rs @@ -393,3 +393,20 @@ impl<L: Sharable> OwnedLockCollection<L> { guard.key } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::Mutex; + + #[test] + fn can_be_extended() { + let mutex1 = Mutex::new(0); + let mutex2 = Mutex::new(1); + let mut collection = OwnedLockCollection::new(vec![mutex1, mutex2]); + + collection.extend([Mutex::new(2)]); + + assert_eq!(collection.data.len(), 3); + } +} diff --git a/src/collection/ref.rs b/src/collection/ref.rs index 8b9e0f8..60abdfa 100644 --- a/src/collection/ref.rs +++ b/src/collection/ref.rs @@ -436,3 +436,37 @@ where self.into_iter() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{Mutex, ThreadKey}; + + #[test] + fn non_duplicates_allowed() { + let mutex1 = Mutex::new(0); + let mutex2 = Mutex::new(1); + assert!(RefLockCollection::try_new(&[&mutex1, &mutex2]).is_some()) + } + + #[test] + fn duplicates_not_allowed() { + let mutex1 = Mutex::new(0); + assert!(RefLockCollection::try_new(&[&mutex1, &mutex1]).is_none()) + } + + #[test] + fn works_in_collection() { + let key = ThreadKey::get().unwrap(); + let mutex1 = Mutex::new(0); + let mutex2 = Mutex::new(1); + let collection0 = [&mutex1, &mutex2]; + let collection1 = RefLockCollection::try_new(&collection0).unwrap(); + let collection = RefLockCollection::try_new(&collection1).unwrap(); + + let guard = collection.lock(key); + assert!(mutex1.is_locked()); + assert!(mutex2.is_locked()); + drop(guard); + } +} 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); + } +} |
