]> git.lizzy.rs Git - rust.git/blob - library/std/src/lazy/tests.rs
Rollup merge of #93748 - klensy:vis-r, r=cjgillot
[rust.git] / library / std / src / lazy / tests.rs
1 use crate::{
2     lazy::{Lazy, SyncLazy, SyncOnceCell},
3     panic,
4     sync::{
5         atomic::{AtomicUsize, Ordering::SeqCst},
6         mpsc::channel,
7         Mutex,
8     },
9     thread,
10 };
11
12 #[test]
13 fn lazy_default() {
14     static CALLED: AtomicUsize = AtomicUsize::new(0);
15
16     struct Foo(u8);
17     impl Default for Foo {
18         fn default() -> Self {
19             CALLED.fetch_add(1, SeqCst);
20             Foo(42)
21         }
22     }
23
24     let lazy: Lazy<Mutex<Foo>> = <_>::default();
25
26     assert_eq!(CALLED.load(SeqCst), 0);
27
28     assert_eq!(lazy.lock().unwrap().0, 42);
29     assert_eq!(CALLED.load(SeqCst), 1);
30
31     lazy.lock().unwrap().0 = 21;
32
33     assert_eq!(lazy.lock().unwrap().0, 21);
34     assert_eq!(CALLED.load(SeqCst), 1);
35 }
36
37 #[test]
38 fn lazy_poisoning() {
39     let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
40     for _ in 0..2 {
41         let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
42         assert!(res.is_err());
43     }
44 }
45
46 fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
47     thread::spawn(f).join().unwrap()
48 }
49
50 #[test]
51 #[cfg_attr(target_os = "emscripten", ignore)]
52 fn sync_once_cell() {
53     static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new();
54
55     assert!(ONCE_CELL.get().is_none());
56
57     spawn_and_wait(|| {
58         ONCE_CELL.get_or_init(|| 92);
59         assert_eq!(ONCE_CELL.get(), Some(&92));
60     });
61
62     ONCE_CELL.get_or_init(|| panic!("Kabom!"));
63     assert_eq!(ONCE_CELL.get(), Some(&92));
64 }
65
66 #[test]
67 fn sync_once_cell_get_mut() {
68     let mut c = SyncOnceCell::new();
69     assert!(c.get_mut().is_none());
70     c.set(90).unwrap();
71     *c.get_mut().unwrap() += 2;
72     assert_eq!(c.get_mut(), Some(&mut 92));
73 }
74
75 #[test]
76 fn sync_once_cell_get_unchecked() {
77     let c = SyncOnceCell::new();
78     c.set(92).unwrap();
79     unsafe {
80         assert_eq!(c.get_unchecked(), &92);
81     }
82 }
83
84 #[test]
85 #[cfg_attr(target_os = "emscripten", ignore)]
86 fn sync_once_cell_drop() {
87     static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
88     struct Dropper;
89     impl Drop for Dropper {
90         fn drop(&mut self) {
91             DROP_CNT.fetch_add(1, SeqCst);
92         }
93     }
94
95     let x = SyncOnceCell::new();
96     spawn_and_wait(move || {
97         x.get_or_init(|| Dropper);
98         assert_eq!(DROP_CNT.load(SeqCst), 0);
99         drop(x);
100     });
101
102     assert_eq!(DROP_CNT.load(SeqCst), 1);
103 }
104
105 #[test]
106 fn sync_once_cell_drop_empty() {
107     let x = SyncOnceCell::<String>::new();
108     drop(x);
109 }
110
111 #[test]
112 fn clone() {
113     let s = SyncOnceCell::new();
114     let c = s.clone();
115     assert!(c.get().is_none());
116
117     s.set("hello".to_string()).unwrap();
118     let c = s.clone();
119     assert_eq!(c.get().map(String::as_str), Some("hello"));
120 }
121
122 #[test]
123 fn get_or_try_init() {
124     let cell: SyncOnceCell<String> = SyncOnceCell::new();
125     assert!(cell.get().is_none());
126
127     let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
128     assert!(res.is_err());
129     assert!(!cell.is_initialized());
130     assert!(cell.get().is_none());
131
132     assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
133
134     assert_eq!(cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), Ok(&"hello".to_string()));
135     assert_eq!(cell.get(), Some(&"hello".to_string()));
136 }
137
138 #[test]
139 fn from_impl() {
140     assert_eq!(SyncOnceCell::from("value").get(), Some(&"value"));
141     assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar"));
142 }
143
144 #[test]
145 fn partialeq_impl() {
146     assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value"));
147     assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar"));
148
149     assert!(SyncOnceCell::<String>::new() == SyncOnceCell::new());
150     assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned()));
151 }
152
153 #[test]
154 fn into_inner() {
155     let cell: SyncOnceCell<String> = SyncOnceCell::new();
156     assert_eq!(cell.into_inner(), None);
157     let cell = SyncOnceCell::new();
158     cell.set("hello".to_string()).unwrap();
159     assert_eq!(cell.into_inner(), Some("hello".to_string()));
160 }
161
162 #[test]
163 #[cfg_attr(target_os = "emscripten", ignore)]
164 fn sync_lazy_new() {
165     static CALLED: AtomicUsize = AtomicUsize::new(0);
166     static SYNC_LAZY: SyncLazy<i32> = SyncLazy::new(|| {
167         CALLED.fetch_add(1, SeqCst);
168         92
169     });
170
171     assert_eq!(CALLED.load(SeqCst), 0);
172
173     spawn_and_wait(|| {
174         let y = *SYNC_LAZY - 30;
175         assert_eq!(y, 62);
176         assert_eq!(CALLED.load(SeqCst), 1);
177     });
178
179     let y = *SYNC_LAZY - 30;
180     assert_eq!(y, 62);
181     assert_eq!(CALLED.load(SeqCst), 1);
182 }
183
184 #[test]
185 fn sync_lazy_default() {
186     static CALLED: AtomicUsize = AtomicUsize::new(0);
187
188     struct Foo(u8);
189     impl Default for Foo {
190         fn default() -> Self {
191             CALLED.fetch_add(1, SeqCst);
192             Foo(42)
193         }
194     }
195
196     let lazy: SyncLazy<Mutex<Foo>> = <_>::default();
197
198     assert_eq!(CALLED.load(SeqCst), 0);
199
200     assert_eq!(lazy.lock().unwrap().0, 42);
201     assert_eq!(CALLED.load(SeqCst), 1);
202
203     lazy.lock().unwrap().0 = 21;
204
205     assert_eq!(lazy.lock().unwrap().0, 21);
206     assert_eq!(CALLED.load(SeqCst), 1);
207 }
208
209 #[test]
210 #[cfg_attr(target_os = "emscripten", ignore)]
211 fn static_sync_lazy() {
212     static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| {
213         let mut xs = Vec::new();
214         xs.push(1);
215         xs.push(2);
216         xs.push(3);
217         xs
218     });
219
220     spawn_and_wait(|| {
221         assert_eq!(&*XS, &vec![1, 2, 3]);
222     });
223
224     assert_eq!(&*XS, &vec![1, 2, 3]);
225 }
226
227 #[test]
228 fn static_sync_lazy_via_fn() {
229     fn xs() -> &'static Vec<i32> {
230         static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new();
231         XS.get_or_init(|| {
232             let mut xs = Vec::new();
233             xs.push(1);
234             xs.push(2);
235             xs.push(3);
236             xs
237         })
238     }
239     assert_eq!(xs(), &vec![1, 2, 3]);
240 }
241
242 #[test]
243 fn sync_lazy_poisoning() {
244     let x: SyncLazy<String> = SyncLazy::new(|| panic!("kaboom"));
245     for _ in 0..2 {
246         let res = panic::catch_unwind(|| x.len());
247         assert!(res.is_err());
248     }
249 }
250
251 #[test]
252 fn is_sync_send() {
253     fn assert_traits<T: Send + Sync>() {}
254     assert_traits::<SyncOnceCell<String>>();
255     assert_traits::<SyncLazy<String>>();
256 }
257
258 #[test]
259 fn eval_once_macro() {
260     macro_rules! eval_once {
261         (|| -> $ty:ty {
262             $($body:tt)*
263         }) => {{
264             static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new();
265             fn init() -> $ty {
266                 $($body)*
267             }
268             ONCE_CELL.get_or_init(init)
269         }};
270     }
271
272     let fib: &'static Vec<i32> = eval_once! {
273         || -> Vec<i32> {
274             let mut res = vec![1, 1];
275             for i in 0..10 {
276                 let next = res[i] + res[i + 1];
277                 res.push(next);
278             }
279             res
280         }
281     };
282     assert_eq!(fib[5], 8)
283 }
284
285 #[test]
286 #[cfg_attr(target_os = "emscripten", ignore)]
287 fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
288     static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new();
289
290     let n_readers = 10;
291     let n_writers = 3;
292     const MSG: &str = "Hello, World";
293
294     let (tx, rx) = channel();
295
296     for _ in 0..n_readers {
297         let tx = tx.clone();
298         thread::spawn(move || {
299             loop {
300                 if let Some(msg) = ONCE_CELL.get() {
301                     tx.send(msg).unwrap();
302                     break;
303                 }
304                 #[cfg(target_env = "sgx")]
305                 crate::thread::yield_now();
306             }
307         });
308     }
309     for _ in 0..n_writers {
310         thread::spawn(move || {
311             let _ = ONCE_CELL.set(MSG.to_owned());
312         });
313     }
314
315     for _ in 0..n_readers {
316         let msg = rx.recv().unwrap();
317         assert_eq!(msg, MSG);
318     }
319 }
320
321 #[test]
322 fn dropck() {
323     let cell = SyncOnceCell::new();
324     {
325         let s = String::new();
326         cell.set(&s).unwrap();
327     }
328 }