proptest/arbitrary/_std/
sync.rs

1//-
2// Copyright 2017, 2018 The proptest developers
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! Arbitrary implementations for `std::sync`.
11
12use std::fmt;
13use std::sync::mpsc::*;
14use std::sync::*;
15use std::thread;
16use std::time::Duration;
17
18use crate::arbitrary::*;
19use crate::strategy::statics::static_map;
20use crate::strategy::*;
21
22// OnceState can not escape Once::call_once_force.
23// PoisonError depends implicitly on the lifetime on MutexGuard, etc.
24// This transitively applies to TryLockError.
25
26// Not doing Weak because .upgrade() would always return None.
27
28#[cfg(not(feature = "unstable"))]
29wrap_ctor!(Mutex);
30#[cfg(feature = "unstable")]
31wrap_from!(Mutex);
32
33#[cfg(not(feature = "unstable"))]
34wrap_ctor!(RwLock);
35#[cfg(feature = "unstable")]
36wrap_from!(RwLock);
37
38arbitrary!(Barrier, SMapped<u16, Self>;  // usize would be extreme!
39    static_map(any::<u16>(), |n| Barrier::new(n as usize))
40);
41
42arbitrary!(BarrierWaitResult,
43    TupleUnion<(WA<LazyJustFn<Self>>, WA<LazyJustFn<Self>>)>;
44    prop_oneof![LazyJust::new(bwr_true), LazyJust::new(bwr_false)]
45);
46
47lazy_just!(
48    Condvar, Default::default;
49    Once, Once::new
50);
51
52arbitrary!(WaitTimeoutResult, TupleUnion<(WA<Just<Self>>, WA<Just<Self>>)>;
53    prop_oneof![Just(wtr_true()), Just(wtr_false())]
54);
55
56fn bwr_true() -> BarrierWaitResult {
57    Barrier::new(1).wait()
58}
59
60fn bwr_false() -> BarrierWaitResult {
61    let barrier = Arc::new(Barrier::new(2));
62    let b2 = barrier.clone();
63    let jh = thread::spawn(move || b2.wait());
64    let bwr1 = barrier.wait();
65    let bwr2 = jh.join().unwrap();
66    if bwr1.is_leader() {
67        bwr2
68    } else {
69        bwr1
70    }
71}
72
73fn wtr_false() -> WaitTimeoutResult {
74    let cvar = Arc::new(Condvar::new());
75    let cvar2 = cvar.clone();
76    thread::spawn(move || {
77        cvar2.notify_one();
78    });
79    let lock = Mutex::new(());
80    let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(1));
81    let (_unused, wtr) = wt.unwrap();
82    wtr
83}
84
85fn wtr_true() -> WaitTimeoutResult {
86    let cvar = Condvar::new();
87    let lock = Mutex::new(());
88    let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(0));
89    let (_unused, wtr) = wt.unwrap();
90    wtr
91}
92
93arbitrary!(RecvError; RecvError);
94
95arbitrary!([T: Arbitrary] SendError<T>, SMapped<T, Self>, T::Parameters;
96    args => static_map(any_with::<T>(args), SendError)
97);
98
99arbitrary!(RecvTimeoutError, TupleUnion<(WA<Just<Self>>, WA<Just<Self>>)>;
100    prop_oneof![
101        Just(RecvTimeoutError::Disconnected),
102        Just(RecvTimeoutError::Timeout)
103    ]
104);
105
106arbitrary!(TryRecvError, TupleUnion<(WA<Just<Self>>, WA<Just<Self>>)>;
107    prop_oneof![
108        Just(TryRecvError::Disconnected),
109        Just(TryRecvError::Empty)
110    ]
111);
112
113arbitrary!(
114    [P: Clone + Default, T: Arbitrary<Parameters = P>] TrySendError<T>,
115    TupleUnion<(WA<SMapped<T, Self>>, WA<SMapped<T, Self>>)>, P;
116    args => prop_oneof![
117        static_map(any_with::<T>(args.clone()), TrySendError::Disconnected),
118        static_map(any_with::<T>(args), TrySendError::Full),
119    ]
120);
121
122// If only half of a pair is generated then you will get a hang-up.
123// Thus the only meaningful impls are in pairs.
124arbitrary!([A] (Sender<A>, Receiver<A>), LazyJustFn<Self>;
125    LazyJust::new(channel)
126);
127
128arbitrary!([A: fmt::Debug] (Sender<A>, IntoIter<A>), LazyJustFn<Self>;
129    LazyJust::new(|| {
130        let (rx, tx) = channel();
131        (rx, tx.into_iter())
132    })
133);
134
135arbitrary!([A] (SyncSender<A>, Receiver<A>), SMapped<u16, Self>;
136    static_map(any::<u16>(), |size| sync_channel(size as usize))
137);
138
139arbitrary!([A: fmt::Debug] (SyncSender<A>, IntoIter<A>), SMapped<u16, Self>;
140    static_map(any::<u16>(), |size| {
141        let (rx, tx) = sync_channel(size as usize);
142        (rx, tx.into_iter())
143    })
144);
145
146#[cfg(test)]
147mod test {
148    no_panic_test!(
149        mutex => Mutex<u8>,
150        rw_lock => RwLock<u8>,
151        barrier => Barrier,
152        barrier_wait_result => BarrierWaitResult,
153        condvar => Condvar,
154        once => Once,
155        wait_timeout_result => WaitTimeoutResult,
156        recv_error => RecvError,
157        send_error => SendError<u8>,
158        recv_timeout_error => RecvTimeoutError,
159        try_recv_error => TryRecvError,
160        try_send_error => TrySendError<u8>,
161        rx_tx => (Sender<u8>, Receiver<u8>),
162        rx_txiter => (Sender<u8>, IntoIter<u8>),
163        syncrx_tx => (SyncSender<u8>, Receiver<u8>),
164        syncrx_txiter => (SyncSender<u8>, IntoIter<u8>)
165    );
166}