Files
yyc12345 7834741d90 feat: improve object pool
- improve object pool
- add docstring for test coverage
2026-08-01 17:25:38 +08:00

103 lines
3.4 KiB
Rust

//! Integration tests for the `object_pool` module.
use sarasacw_omrf::object_pool::{ObjectPool, INVALID_TOKEN};
/// Coverage: the `INVALID_TOKEN` constant is `0`, the value the counter never produces.
#[test]
fn invalid_token_is_zero() {
assert_eq!(INVALID_TOKEN, 0);
}
/// Coverage: `allocate` returns distinct, non-zero tokens across successive calls.
#[test]
fn allocate_yields_distinct_nonzero_tokens() {
let pool: ObjectPool<i32> = ObjectPool::new();
let t1 = pool.allocate(10);
let t2 = pool.allocate(20);
let t3 = pool.allocate(30);
assert_ne!(t1, 0);
assert_ne!(t2, 0);
assert_ne!(t3, 0);
assert_ne!(t1, t2);
assert_ne!(t2, t3);
assert_ne!(t1, t3);
}
/// Coverage: the guard-style `get` reads and `get_mut` writes an entry, with changes observable
/// by a subsequent `get`.
#[test]
fn get_and_get_mut_round_trip() {
let pool: ObjectPool<i32> = ObjectPool::new();
let t = pool.allocate(7);
assert_eq!(*pool.get(t).unwrap(), 7);
*pool.get_mut(t).unwrap() = 99;
assert_eq!(*pool.get(t).unwrap(), 99);
}
/// Coverage: the deadlock-safe closure-based `get_with`/`get_mut_with` read and write an entry.
#[test]
fn get_with_and_get_mut_with_round_trip() {
let pool: ObjectPool<i32> = ObjectPool::new();
let t = pool.allocate(1);
assert_eq!(pool.get_with(t, |v| *v).unwrap(), 1);
pool.get_mut_with(t, |v| *v = 42).unwrap();
assert_eq!(pool.get_with(t, |v| *v).unwrap(), 42);
}
/// Coverage: `pop` returns the owned value and invalidates the token for any further access.
#[test]
fn pop_returns_owned_value_and_invalidates_token() {
let pool: ObjectPool<String> = ObjectPool::new();
let t = pool.allocate("hello".to_string());
let owned = pool.pop(t).unwrap();
assert_eq!(owned, "hello");
assert!(pool.get(t).is_err());
}
/// Coverage: `free` removes the entry; subsequent `get`/`get_mut` on the same token fail.
#[test]
fn free_invalidates_token() {
let pool: ObjectPool<i32> = ObjectPool::new();
let t = pool.allocate(5);
pool.free(t).unwrap();
assert!(pool.get(t).is_err());
assert!(pool.get_mut(t).is_err());
}
/// Coverage: every access/mutation/removal method rejects `INVALID_TOKEN` (and any absent token).
#[test]
fn invalid_token_errors_on_all_methods() {
let pool: ObjectPool<i32> = ObjectPool::new();
let bad = INVALID_TOKEN;
assert!(pool.get(bad).is_err());
assert!(pool.get_mut(bad).is_err());
assert!(pool.get_with(bad, |_| ()).is_err());
assert!(pool.get_mut_with(bad, |_| ()).is_err());
assert!(pool.free(bad).is_err());
assert!(pool.pop(bad).is_err());
}
/// Coverage: `clear` empties the pool; all previously-issued tokens become invalid.
#[test]
fn clear_removes_all_objects() {
let pool: ObjectPool<i32> = ObjectPool::new();
let t1 = pool.allocate(1);
let t2 = pool.allocate(2);
pool.clear();
assert!(pool.get(t1).is_err());
assert!(pool.get(t2).is_err());
}
/// Coverage: two distinct tokens can be mutated independently via sequential closure access, which
/// never holds two guards at once (the deadlock-safe pattern).
#[test]
fn two_tokens_modified_independently_via_closure() {
let pool: ObjectPool<i32> = ObjectPool::new();
let t1 = pool.allocate(0);
let t2 = pool.allocate(0);
pool.get_mut_with(t1, |v| *v = 11).unwrap();
pool.get_mut_with(t2, |v| *v = 22).unwrap();
assert_eq!(pool.get_with(t1, |v| *v).unwrap(), 11);
assert_eq!(pool.get_with(t2, |v| *v).unwrap(), 22);
}