use loom::sync::Arc;
use loom::thread;
use rust_tango::{Fctl, Fseq, ReadResult};
#[test]
fn loom_fseq_increment() {
loom::model(|| {
let fseq = Arc::new(Fseq::new(0));
let fseq1 = fseq.clone();
let t1 = thread::spawn(move || fseq1.next());
let fseq2 = fseq.clone();
let t2 = thread::spawn(move || fseq2.next());
let s1 = t1.join().unwrap();
let s2 = t2.join().unwrap();
assert_ne!(s1, s2);
assert!(s1 < 2 && s2 < 2);
assert_eq!(fseq.current(), 2);
});
}
#[test]
fn loom_fctl_acquire_race() {
loom::model(|| {
let fctl = Arc::new(Fctl::new(1));
let fctl1 = fctl.clone();
let t1 = thread::spawn(move || fctl1.acquire(1));
let fctl2 = fctl.clone();
let t2 = thread::spawn(move || fctl2.acquire(1));
let r1 = t1.join().unwrap();
let r2 = t2.join().unwrap();
assert!(
(r1 && !r2) || (!r1 && r2),
"expected exactly one success, got r1={}, r2={}",
r1,
r2
);
});
}
#[test]
fn loom_fctl_release_acquire() {
loom::model(|| {
let fctl = Arc::new(Fctl::new(0));
let fctl1 = fctl.clone();
let t1 = thread::spawn(move || {
fctl1.release(1); });
let fctl2 = fctl.clone();
let t2 = thread::spawn(move || {
fctl2.acquire(1)
});
t1.join().unwrap();
let acquired = t2.join().unwrap();
if !acquired {
assert_eq!(fctl.available(), 1);
} else {
assert_eq!(fctl.available(), 0);
}
});
}
#[test]
fn loom_fctl_multi_credit() {
loom::model(|| {
let fctl = Arc::new(Fctl::new(2));
let fctl1 = fctl.clone();
let t1 = thread::spawn(move || fctl1.acquire(1));
let fctl2 = fctl.clone();
let t2 = thread::spawn(move || fctl2.acquire(1));
let fctl3 = fctl.clone();
let t3 = thread::spawn(move || fctl3.acquire(1));
let r1 = t1.join().unwrap();
let r2 = t2.join().unwrap();
let r3 = t3.join().unwrap();
let successes = [r1, r2, r3].iter().filter(|&&x| x).count();
assert_eq!(successes, 2, "expected 2 successes with 2 credits");
});
}
#[test]
fn loom_read_result_variants() {
loom::model(|| {
let ok: ReadResult<u32> = ReadResult::Ok(42);
let not_ready: ReadResult<u32> = ReadResult::NotReady;
let overrun: ReadResult<u32> = ReadResult::Overrun;
assert!(matches!(ok, ReadResult::Ok(42)));
assert!(matches!(not_ready, ReadResult::NotReady));
assert!(matches!(overrun, ReadResult::Overrun));
});
}