Skip to content

Commit 16074f1

Browse files
committed
Copy tests from the thread_local crate
Some behavioral modifications had to be made, but after I got it to compile, all the tests passed! I am rather surprised at this, but I guess that's the benefit of using safe code ;) Code is under the same license, so it should be fine.
1 parent 4b2e823 commit 16074f1

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed

tests/from_thread_local.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//! Tests copied from the [`thread_local`] crate.
2+
//!
3+
//! The following behavioral changes have been made:
4+
//! - Removed use of unsupported `clear` method (`same_thread` test)
5+
//! - Iteration should not expect to see values from dead value (`iter` test)
6+
//! - Remove `RefCell<String>` from test_sync - Currently `!Sync` types are unsupported
7+
use std::sync::Arc;
8+
use std::sync::atomic::AtomicUsize;
9+
use std::sync::atomic::Ordering::Relaxed;
10+
use std::thread;
11+
12+
use dropping_thread_local::DroppingThreadLocal;
13+
14+
fn make_create() -> Arc<dyn Fn() -> usize + Send + Sync> {
15+
let count = AtomicUsize::new(0);
16+
Arc::new(move || count.fetch_add(1, Relaxed))
17+
}
18+
19+
#[test]
20+
fn same_thread() {
21+
let create = make_create();
22+
let tls = DroppingThreadLocal::new();
23+
assert_eq!(None, tls.get());
24+
assert_eq!("DroppingThreadLocal { local_data: None }", format!("{:?}", &tls));
25+
assert_eq!(0, *tls.get_or_init(|| create()));
26+
assert_eq!(Some(&0), tls.get().as_deref());
27+
assert_eq!(0, *tls.get_or_init(|| create()));
28+
assert_eq!(Some(&0), tls.get().as_deref());
29+
assert_eq!(0, *tls.get_or_init(|| create()));
30+
assert_eq!(Some(&0), tls.get().as_deref());
31+
assert_eq!("DroppingThreadLocal { local_data: Some(0) }", format!("{:?}", &tls));
32+
// DroppingThreadLocal::clear is currently not implemented
33+
#[cfg(any())]
34+
{
35+
tls.clear();
36+
assert_eq!(None, tls.get());
37+
}
38+
}
39+
40+
#[test]
41+
fn different_thread() {
42+
let create = make_create();
43+
let tls = Arc::new(DroppingThreadLocal::new());
44+
assert_eq!(None, tls.get());
45+
assert_eq!(0, *tls.get_or_init(|| create()));
46+
assert_eq!(Some(&0), tls.get().as_deref());
47+
48+
let tls2 = tls.clone();
49+
let create2 = create.clone();
50+
thread::spawn(move || {
51+
assert_eq!(None, tls2.get());
52+
assert_eq!(1, *tls2.get_or_init(|| create2()));
53+
assert_eq!(Some(&1), tls2.get().as_deref());
54+
})
55+
.join()
56+
.unwrap();
57+
58+
assert_eq!(Some(&0), tls.get().as_deref());
59+
assert_eq!(0, *tls.get_or_init(|| create()));
60+
}
61+
62+
#[test]
63+
fn iter() {
64+
let tls = Arc::new(DroppingThreadLocal::new());
65+
tls.get_or_init(|| Box::new(1));
66+
67+
let tls2 = tls.clone();
68+
thread::spawn(move || {
69+
tls2.get_or_init(|| Box::new(2));
70+
let tls3 = tls2.clone();
71+
thread::spawn(move || {
72+
tls3.get_or_init(|| Box::new(3));
73+
})
74+
.join()
75+
.unwrap();
76+
drop(tls2);
77+
})
78+
.join()
79+
.unwrap();
80+
81+
let tls = Arc::try_unwrap(tls).unwrap();
82+
83+
let mut v = tls.snapshot_iter().map(|x| **x).collect::<Vec<i32>>();
84+
v.sort_unstable();
85+
// unlike the thread_local crate, dead values should be dropped b now
86+
assert_eq!(v, vec![1])
87+
}
88+
89+
#[test]
90+
fn test_drop_local() {
91+
let local = DroppingThreadLocal::new();
92+
struct Dropped(Arc<AtomicUsize>);
93+
impl Drop for Dropped {
94+
fn drop(&mut self) {
95+
self.0.fetch_add(1, Relaxed);
96+
}
97+
}
98+
99+
let dropped = Arc::new(AtomicUsize::new(0));
100+
local.get_or_init(|| Dropped(dropped.clone()));
101+
assert_eq!(dropped.load(Relaxed), 0);
102+
drop(local);
103+
assert_eq!(dropped.load(Relaxed), 1);
104+
}
105+
106+
#[test]
107+
fn is_sync() {
108+
fn foo<T: Sync>() {}
109+
foo::<DroppingThreadLocal<String>>();
110+
// currently, DroppingThreadLocal requires T: Sync
111+
#[cfg(any())]
112+
{
113+
foo::<DroppingThreadLocal<RefCell<String>>>();
114+
}
115+
}

0 commit comments

Comments
 (0)