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