use crate::SwmrCell;
use std::prelude::v1::*;
use std::thread;
use std::vec;
#[test]
fn test_single_writer_multiple_readers_concurrent_reads() {
let cell = SwmrCell::new(0i32);
let mut handles = vec![];
for _ in 0..5 {
let local = cell.local_reader();
let handle = thread::spawn(move || {
for _ in 0..10 {
let guard = local.pin();
assert!(*guard >= 0);
}
});
handles.push(handle);
}
for handle in handles {
let _: std::thread::Result<()> = handle.join();
}
}
#[test]
fn test_writer_updates_readers_observe() {
let mut cell = SwmrCell::new(0i32);
let local = cell.local_reader();
let reader_thread = thread::spawn(move || {
{
let guard = local.pin();
assert_eq!(*guard, 0);
}
thread::sleep(std::time::Duration::from_millis(100));
{
let guard = local.pin();
assert_eq!(*guard, 100);
}
});
thread::sleep(std::time::Duration::from_millis(10));
cell.store(100);
reader_thread.join().unwrap();
}
#[test]
fn test_sequential_writer_operations() {
let mut cell = SwmrCell::new(1i32);
let local = cell.local_reader();
cell.store(2);
assert_eq!(*local.pin(), 2);
cell.store(3);
assert_eq!(*local.pin(), 3);
cell.store(4);
assert_eq!(*local.pin(), 4);
}
#[test]
fn test_readers_in_different_epochs() {
let mut cell = SwmrCell::new(0i32);
let reader1 = cell.local_reader();
let reader2 = cell.local_reader();
let guard1 = reader1.pin();
assert_eq!(*guard1, 0);
cell.store(10);
let guard2 = reader2.pin();
assert_eq!(*guard2, 10);
assert_eq!(*guard1, 0);
}
#[test]
fn test_garbage_collection_trigger() {
let mut cell = SwmrCell::builder()
.auto_reclaim_threshold(Some(64))
.build(0i32);
for i in 0..70 {
cell.store(i);
}
}
#[test]
fn test_active_reader_protects_garbage() {
let mut cell = SwmrCell::new(0i32);
let local = cell.local_reader();
let _guard = local.pin();
for i in 0..70 {
cell.store(i);
}
cell.collect();
}
#[test]
fn test_garbage_reclaimed_after_reader_drop() {
let mut cell = SwmrCell::new(0i32);
{
let local = cell.local_reader();
let _guard = local.pin();
for i in 0..70 {
cell.store(i);
}
}
cell.collect();
}
#[test]
fn test_min_epoch_calculation_multiple_readers() {
let mut cell = SwmrCell::new(0i32);
let reader1 = cell.local_reader();
let reader2 = cell.local_reader();
let _guard1 = reader1.pin();
cell.store(10);
let _guard2 = reader2.pin();
cell.store(20);
cell.collect();
}
#[test]
fn test_high_concurrency_reads() {
let cell = SwmrCell::new(42i32);
let mut handles = vec![];
for _ in 0..20 {
let local = cell.local_reader();
handles.push(thread::spawn(move || {
for _ in 0..100 {
let guard = local.pin();
assert_eq!(*guard, 42);
}
}));
}
for h in handles {
let _: std::thread::Result<()> = h.join();
}
}
#[test]
fn test_reader_thread_exit_cleanup() {
let mut cell = SwmrCell::new(0i32);
let local = cell.local_reader();
let t = thread::spawn(move || {
let _guard = local.pin();
});
t.join().unwrap();
cell.collect();
}
#[test]
fn test_interleaved_read_write_operations() {
let mut cell = SwmrCell::new(0i32);
let local = cell.local_reader();
for i in 0..10 {
cell.store(i);
assert_eq!(*local.pin(), i);
}
}
#[test]
fn test_reader_holds_guard_during_updates() {
let mut cell = SwmrCell::new(0i32);
let local = cell.local_reader();
let t = thread::spawn(move || {
let guard = local.pin();
let val = *guard;
thread::sleep(std::time::Duration::from_millis(50));
assert_eq!(*guard, val);
});
for i in 1..50 {
cell.store(i);
}
t.join().unwrap();
}
#[test]
fn test_version_consistency_across_threads() {
let mut cell = SwmrCell::new(0i32);
let local = cell.local_reader();
let t = thread::spawn(move || {
for _ in 0..10 {
let guard = local.pin();
let version = guard.version();
let value = *guard;
assert!(version as i32 >= value || value == 0);
thread::sleep(std::time::Duration::from_millis(5));
}
});
for i in 1..=20 {
cell.store(i);
thread::sleep(std::time::Duration::from_millis(2));
}
t.join().unwrap();
}
#[test]
fn test_is_pinned_correctness_in_threads() {
let cell = SwmrCell::new(0i32);
let local = cell.local_reader();
let t = thread::spawn(move || {
assert!(!local.is_pinned());
let guard = local.pin();
assert!(local.is_pinned());
drop(guard);
assert!(!local.is_pinned());
});
t.join().unwrap();
}
#[test]
fn test_get_and_store_interleaving() {
let mut cell = SwmrCell::new(0i32);
for i in 0..100 {
assert_eq!(*cell.get(), i);
cell.store(i + 1);
assert_eq!(*cell.get(), i + 1);
}
}
#[test]
fn test_update_with_concurrent_readers() {
let mut cell = SwmrCell::new(0i32);
let local = cell.local_reader();
let t = thread::spawn(move || {
for _ in 0..50 {
let guard = local.pin();
assert!(*guard >= 0);
}
});
for _ in 0..20 {
cell.update(|v| v + 1);
}
t.join().unwrap();
assert_eq!(*cell.get(), 20);
}
#[test]
fn test_local_reader_version_tracks_global() {
let mut cell = SwmrCell::new(0i32);
let local = cell.local_reader();
let t = thread::spawn(move || {
let mut last_version = 0;
for _ in 0..50 {
let current_version = local.version();
assert!(current_version >= last_version);
last_version = current_version;
thread::sleep(std::time::Duration::from_millis(1));
}
});
for i in 1..=30 {
cell.store(i);
thread::sleep(std::time::Duration::from_millis(1));
}
t.join().unwrap();
}