]> git.lizzy.rs Git - rust.git/blob - library/std/src/thread/tests.rs
Rollup merge of #93497 - willcrichton:rustdoc-scrape-test, r=GuillaumeGomez
[rust.git] / library / std / src / thread / tests.rs
1 use super::Builder;
2 use crate::any::Any;
3 use crate::mem;
4 use crate::panic::panic_any;
5 use crate::result;
6 use crate::sync::{
7     mpsc::{channel, Sender},
8     Arc, Barrier,
9 };
10 use crate::thread::{self, ThreadId};
11 use crate::time::Duration;
12 use crate::time::Instant;
13
14 // !!! These tests are dangerous. If something is buggy, they will hang, !!!
15 // !!! instead of exiting cleanly. This might wedge the buildbots.       !!!
16
17 #[test]
18 fn test_unnamed_thread() {
19     thread::spawn(move || {
20         assert!(thread::current().name().is_none());
21     })
22     .join()
23     .ok()
24     .expect("thread panicked");
25 }
26
27 #[test]
28 fn test_named_thread() {
29     Builder::new()
30         .name("ada lovelace".to_string())
31         .spawn(move || {
32             assert!(thread::current().name().unwrap() == "ada lovelace".to_string());
33         })
34         .unwrap()
35         .join()
36         .unwrap();
37 }
38
39 #[test]
40 #[should_panic]
41 fn test_invalid_named_thread() {
42     let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {});
43 }
44
45 #[test]
46 fn test_run_basic() {
47     let (tx, rx) = channel();
48     thread::spawn(move || {
49         tx.send(()).unwrap();
50     });
51     rx.recv().unwrap();
52 }
53
54 #[test]
55 fn test_is_running() {
56     let b = Arc::new(Barrier::new(2));
57     let t = thread::spawn({
58         let b = b.clone();
59         move || {
60             b.wait();
61             1234
62         }
63     });
64
65     // Thread is definitely running here, since it's still waiting for the barrier.
66     assert_eq!(t.is_running(), true);
67
68     // Unblock the barrier.
69     b.wait();
70
71     // Now check that t.is_running() becomes false within a reasonable time.
72     let start = Instant::now();
73     while t.is_running() {
74         assert!(start.elapsed() < Duration::from_secs(2));
75         thread::sleep(Duration::from_millis(15));
76     }
77
78     // Joining the thread should not block for a significant time now.
79     let join_time = Instant::now();
80     assert_eq!(t.join().unwrap(), 1234);
81     assert!(join_time.elapsed() < Duration::from_secs(2));
82 }
83
84 #[test]
85 fn test_join_panic() {
86     match thread::spawn(move || panic!()).join() {
87         result::Result::Err(_) => (),
88         result::Result::Ok(()) => panic!(),
89     }
90 }
91
92 #[test]
93 fn test_spawn_sched() {
94     let (tx, rx) = channel();
95
96     fn f(i: i32, tx: Sender<()>) {
97         let tx = tx.clone();
98         thread::spawn(move || {
99             if i == 0 {
100                 tx.send(()).unwrap();
101             } else {
102                 f(i - 1, tx);
103             }
104         });
105     }
106     f(10, tx);
107     rx.recv().unwrap();
108 }
109
110 #[test]
111 fn test_spawn_sched_childs_on_default_sched() {
112     let (tx, rx) = channel();
113
114     thread::spawn(move || {
115         thread::spawn(move || {
116             tx.send(()).unwrap();
117         });
118     });
119
120     rx.recv().unwrap();
121 }
122
123 fn avoid_copying_the_body<F>(spawnfn: F)
124 where
125     F: FnOnce(Box<dyn Fn() + Send>),
126 {
127     let (tx, rx) = channel();
128
129     let x: Box<_> = box 1;
130     let x_in_parent = (&*x) as *const i32 as usize;
131
132     spawnfn(Box::new(move || {
133         let x_in_child = (&*x) as *const i32 as usize;
134         tx.send(x_in_child).unwrap();
135     }));
136
137     let x_in_child = rx.recv().unwrap();
138     assert_eq!(x_in_parent, x_in_child);
139 }
140
141 #[test]
142 fn test_avoid_copying_the_body_spawn() {
143     avoid_copying_the_body(|v| {
144         thread::spawn(move || v());
145     });
146 }
147
148 #[test]
149 fn test_avoid_copying_the_body_thread_spawn() {
150     avoid_copying_the_body(|f| {
151         thread::spawn(move || {
152             f();
153         });
154     })
155 }
156
157 #[test]
158 fn test_avoid_copying_the_body_join() {
159     avoid_copying_the_body(|f| {
160         let _ = thread::spawn(move || f()).join();
161     })
162 }
163
164 #[test]
165 fn test_child_doesnt_ref_parent() {
166     // If the child refcounts the parent thread, this will stack overflow when
167     // climbing the thread tree to dereference each ancestor. (See #1789)
168     // (well, it would if the constant were 8000+ - I lowered it to be more
169     // valgrind-friendly. try this at home, instead..!)
170     const GENERATIONS: u32 = 16;
171     fn child_no(x: u32) -> Box<dyn Fn() + Send> {
172         return Box::new(move || {
173             if x < GENERATIONS {
174                 thread::spawn(move || child_no(x + 1)());
175             }
176         });
177     }
178     thread::spawn(|| child_no(0)());
179 }
180
181 #[test]
182 fn test_simple_newsched_spawn() {
183     thread::spawn(move || {});
184 }
185
186 #[test]
187 fn test_try_panic_message_string_literal() {
188     match thread::spawn(move || {
189         panic!("static string");
190     })
191     .join()
192     {
193         Err(e) => {
194             type T = &'static str;
195             assert!(e.is::<T>());
196             assert_eq!(*e.downcast::<T>().unwrap(), "static string");
197         }
198         Ok(()) => panic!(),
199     }
200 }
201
202 #[test]
203 fn test_try_panic_any_message_owned_str() {
204     match thread::spawn(move || {
205         panic_any("owned string".to_string());
206     })
207     .join()
208     {
209         Err(e) => {
210             type T = String;
211             assert!(e.is::<T>());
212             assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string());
213         }
214         Ok(()) => panic!(),
215     }
216 }
217
218 #[test]
219 fn test_try_panic_any_message_any() {
220     match thread::spawn(move || {
221         panic_any(box 413u16 as Box<dyn Any + Send>);
222     })
223     .join()
224     {
225         Err(e) => {
226             type T = Box<dyn Any + Send>;
227             assert!(e.is::<T>());
228             let any = e.downcast::<T>().unwrap();
229             assert!(any.is::<u16>());
230             assert_eq!(*any.downcast::<u16>().unwrap(), 413);
231         }
232         Ok(()) => panic!(),
233     }
234 }
235
236 #[test]
237 fn test_try_panic_any_message_unit_struct() {
238     struct Juju;
239
240     match thread::spawn(move || panic_any(Juju)).join() {
241         Err(ref e) if e.is::<Juju>() => {}
242         Err(_) | Ok(()) => panic!(),
243     }
244 }
245
246 #[test]
247 fn test_park_timeout_unpark_before() {
248     for _ in 0..10 {
249         thread::current().unpark();
250         thread::park_timeout(Duration::from_millis(u32::MAX as u64));
251     }
252 }
253
254 #[test]
255 fn test_park_timeout_unpark_not_called() {
256     for _ in 0..10 {
257         thread::park_timeout(Duration::from_millis(10));
258     }
259 }
260
261 #[test]
262 fn test_park_timeout_unpark_called_other_thread() {
263     for _ in 0..10 {
264         let th = thread::current();
265
266         let _guard = thread::spawn(move || {
267             super::sleep(Duration::from_millis(50));
268             th.unpark();
269         });
270
271         thread::park_timeout(Duration::from_millis(u32::MAX as u64));
272     }
273 }
274
275 #[test]
276 fn sleep_ms_smoke() {
277     thread::sleep(Duration::from_millis(2));
278 }
279
280 #[test]
281 fn test_size_of_option_thread_id() {
282     assert_eq!(mem::size_of::<Option<ThreadId>>(), mem::size_of::<ThreadId>());
283 }
284
285 #[test]
286 fn test_thread_id_equal() {
287     assert!(thread::current().id() == thread::current().id());
288 }
289
290 #[test]
291 fn test_thread_id_not_equal() {
292     let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap();
293     assert!(thread::current().id() != spawned_id);
294 }
295
296 // NOTE: the corresponding test for stderr is in ui/thread-stderr, due
297 // to the test harness apparently interfering with stderr configuration.