Skip to content

Commit a660330

Browse files
committed
test: init
1 parent 7d4a1a3 commit a660330

File tree

3 files changed

+237
-73
lines changed

3 files changed

+237
-73
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#[macro_export]
2+
macro_rules! empty {
3+
() => {
4+
(std::iter::empty(), std::iter::empty())
5+
};
6+
}
7+
8+
#[macro_export]
9+
macro_rules! paths {
10+
($($path:expr),*) => {
11+
(vec![$(rspack_paths::ArcPath::from($path)),*].into_iter(), std::iter::empty())
12+
};
13+
}
14+
15+
#[macro_export]
16+
macro_rules! helper {
17+
($options:expr) => {
18+
helper!($options, Default::default())
19+
};
20+
($options:expr, $ignore:expr) => {
21+
crate::helpers::TestHelper::new(|| rspack_watcher::FsWatcher::new($options, $ignore))
22+
};
23+
}
24+
25+
#[macro_export]
26+
macro_rules! counter {
27+
() => {
28+
std::sync::atomic::AtomicU8::new(0)
29+
};
30+
}
31+
32+
#[macro_export]
33+
macro_rules! arc_counter {
34+
() => {
35+
std::sync::Arc::new(std::sync::atomic::AtomicU8::new(0))
36+
};
37+
}
38+
39+
#[macro_export]
40+
macro_rules! add {
41+
($c:expr) => {
42+
$c.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
43+
};
44+
}
45+
46+
#[macro_export]
47+
macro_rules! load {
48+
($c:expr) => {
49+
$c.load(std::sync::atomic::Ordering::SeqCst)
50+
};
51+
}
52+
53+
#[macro_export]
54+
macro_rules! watch {
55+
($helper:expr, $($files:expr),*) => {
56+
watch!(files @ $helper, $($files),*)
57+
};
58+
($helper:expr, _, $($dirs:expr),*) => {
59+
watch!(dirs @ $helper, $($dirs),*)
60+
};
61+
($helper:expr, _, _, $($missing:expr),*) => {
62+
watch!(missing @ $helper, $($missing),*)
63+
};
64+
65+
(files @ $helper:expr, $($files:expr),*) => {
66+
$helper.watch(paths!($($files),*), empty!(), empty!())
67+
};
68+
(dirs @ $helper:expr, $($dirs:expr),*) => {
69+
$helper.watch(empty!(), paths!($($dirs),*), empty!())
70+
};
71+
(missing @ $helper:expr, $($missing:expr),*) => {
72+
$helper.watch(empty!(), empty!(), paths!($($missing),*))
73+
};
74+
}
75+
76+
#[macro_export]
77+
macro_rules! assert_no_events {
78+
($change_events:expr, $aggregated_events:expr) => {
79+
assert_eq!(
80+
load!($change_events),
81+
0,
82+
"Expected no change events but got {}",
83+
load!($change_events)
84+
);
85+
assert_eq!(
86+
load!($aggregated_events),
87+
0,
88+
"Expected no aggregated events but got {}",
89+
load!($aggregated_events)
90+
);
91+
};
92+
}

crates/rspack_watcher/tests/helpers/mod.rs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#![allow(clippy::unwrap_used)]
22

3+
pub mod macros;
4+
35
use std::{
46
mem::ManuallyDrop,
57
path::PathBuf,
@@ -16,6 +18,8 @@ use rspack_watcher::{EventAggregateHandler, EventHandler, FsWatcher};
1618
use tempfile::TempDir;
1719
use tokio::sync::RwLock;
1820

21+
const TEST_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
22+
1923
pub struct TestHelper {
2024
/// Temporary directory for testing
2125
temp_dir: ManuallyDrop<TempDir>,
@@ -163,13 +167,19 @@ impl TestHelper {
163167
.unwrap();
164168
}
165169

166-
pub fn collect_events(
170+
/// Collects events from the receiver in a blocking manner.
171+
///
172+
/// The `on_changed` and `on_aggregated` callbacks are invoked for each respective event.
173+
/// If either callback sets the `abort` flag to `true`, the collection stops.
174+
///
175+
/// The function will timeout after a predefined duration (10s) if no events are received.
176+
pub fn collect_events_blocking(
167177
&self,
168178
rx: Receiver<Event>,
169179
mut on_changed: impl FnMut(&ChangedEvent, &mut bool),
170180
mut on_aggregated: impl FnMut(&AggregatedEvent, &mut bool),
171181
) {
172-
while let Ok(event) = rx.recv_timeout(std::time::Duration::from_secs(10)) {
182+
while let Ok(event) = rx.recv_timeout(TEST_TIMEOUT) {
173183
match event {
174184
Event::Aggregated(agg_event) => {
175185
let mut abort = false;
@@ -189,11 +199,50 @@ impl TestHelper {
189199
}
190200
}
191201

202+
/// Collects events from the receiver in a separate thread.
203+
///
204+
/// The `on_changed` and `on_aggregated` callbacks are invoked for each respective event.
205+
/// If either callback sets the `abort` flag to `true`, the collection stops.
206+
////
207+
/// The function will timeout after a predefined duration (10s) if no events are received.
208+
pub fn collect_events(
209+
&self,
210+
rx: Receiver<Event>,
211+
on_changed: impl Fn(&ChangedEvent, &mut bool) + Send + 'static,
212+
on_aggregated: impl Fn(&AggregatedEvent, &mut bool) + Send + 'static,
213+
) {
214+
std::thread::spawn(move || {
215+
while let Ok(event) = rx.recv_timeout(TEST_TIMEOUT) {
216+
match event {
217+
Event::Aggregated(agg_event) => {
218+
let mut abort = false;
219+
on_aggregated(&agg_event, &mut abort);
220+
if abort {
221+
break;
222+
}
223+
}
224+
Event::Changed(chg_event) => {
225+
let mut abort = false;
226+
on_changed(&chg_event, &mut abort);
227+
if abort {
228+
break;
229+
}
230+
}
231+
}
232+
}
233+
});
234+
}
235+
192236
pub fn tick(&self, f: impl FnOnce()) {
193237
std::thread::sleep(std::time::Duration::from_millis(200));
194238
f();
195239
}
196240

241+
pub fn tick_ms(&self, duration: u64, f: impl FnOnce()) {
242+
std::thread::sleep(std::time::Duration::from_millis(duration));
243+
f();
244+
}
245+
197246
/// Watches the specified files, directories, and missing paths.
198247
///
199248
/// All paths are relative to the temporary directory.
Lines changed: 94 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,120 @@
11
#![allow(dead_code)]
22

3-
use std::sync::atomic::AtomicU8;
3+
use std::sync::{Arc, atomic::AtomicU8};
44

55
use rspack_paths::ArcPath;
6-
use rspack_watcher::{FsWatcher, FsWatcherOptions};
6+
use rspack_regex::RspackRegex;
7+
use rspack_watcher::{FsWatcher, FsWatcherIgnored, FsWatcherOptions};
78

89
mod helpers;
910

10-
macro_rules! e {
11-
() => {
12-
(std::iter::empty(), std::iter::empty())
13-
};
14-
}
15-
16-
macro_rules! f {
17-
($($file:expr),*) => {
18-
(vec![$(ArcPath::from($file)),*].into_iter(), std::iter::empty())
19-
};
20-
}
21-
22-
macro_rules! h {
23-
($options:expr) => {
24-
h!($options, Default::default())
25-
};
26-
($options:expr, $ignore:expr) => {
27-
helpers::TestHelper::new(|| FsWatcher::new($options, $ignore))
28-
};
29-
}
30-
31-
macro_rules! c {
32-
() => {
33-
AtomicU8::new(0)
34-
};
35-
}
36-
37-
macro_rules! add {
38-
($c:expr) => {
39-
$c.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
40-
};
41-
}
42-
43-
macro_rules! load {
44-
($c:expr) => {
45-
$c.load(std::sync::atomic::Ordering::SeqCst)
46-
};
47-
}
48-
49-
macro_rules! watch {
50-
($helper:expr, $($files:expr),*) => {
51-
watch!(files @ $helper, $($files),*)
52-
};
53-
($helper:expr, _, $($dirs:expr),*) => {
54-
watch!(dirs @ $helper, $($dirs),*)
55-
};
56-
($helper:expr, _, _, $($missing:expr),*) => {
57-
watch!(missing @ $helper, $($missing),*)
58-
};
59-
60-
(files @ $helper:expr, $($files:expr),*) => {
61-
$helper.watch(f!($($files),*), e!(), e!())
62-
};
63-
(dirs @ $helper:expr, $($dirs:expr),*) => {
64-
$helper.watch(e!(), f!($($dirs),*), e!())
65-
};
66-
(missing @ $helper:expr, $($missing:expr),*) => {
67-
$helper.watch(e!(), e!(), f!($($missing),*))
68-
};
69-
}
70-
7111
#[test]
7212
fn should_watch_a_single_file() {
73-
let mut helper = h!(FsWatcherOptions {
13+
let mut h = helper!(FsWatcherOptions {
7414
aggregate_timeout: Some(1000),
7515
..Default::default()
7616
});
7717

78-
let rx = watch!(helper, "a");
18+
let rx = watch!(h, "a");
7919

80-
helper.tick(|| {
81-
helper.file("a");
20+
h.tick(|| {
21+
h.file("a");
8222
});
8323

84-
let change_events = c!();
85-
helper.collect_events(
24+
let change_events = counter!();
25+
26+
h.collect_events_blocking(
8627
rx,
8728
|file, _| {
88-
file.assert_path(helper.join("a"));
29+
file.assert_path(h.join("a"));
8930
add!(change_events);
9031
},
9132
|changes, abort| {
92-
changes.assert_changed(helper.join("a"));
33+
changes.assert_changed(h.join("a"));
9334
assert!(load!(change_events) > 0);
9435
*abort = true;
9536
},
9637
);
9738
}
39+
40+
#[test]
41+
fn should_not_watch_a_single_ignored_file_glob() {
42+
let mut h = helper!(
43+
FsWatcherOptions {
44+
aggregate_timeout: Some(300),
45+
..Default::default()
46+
},
47+
FsWatcherIgnored::Path("**/a".to_string())
48+
);
49+
50+
let rx = watch!(h, "a");
51+
52+
let change_events = arc_counter!();
53+
let aggregated_events = arc_counter!();
54+
55+
h.tick(|| {
56+
h.file("a");
57+
h.tick_ms(1000, || {
58+
{
59+
let change_events = change_events.clone();
60+
let aggregated_events = aggregated_events.clone();
61+
62+
h.collect_events(
63+
rx,
64+
move |_file, _abort| {
65+
add!(change_events);
66+
},
67+
move |_changes, _abort| {
68+
add!(aggregated_events);
69+
},
70+
);
71+
}
72+
73+
assert_no_events!(change_events, aggregated_events);
74+
});
75+
});
76+
}
77+
78+
#[test]
79+
fn should_not_watch_a_single_ignored_file_regexp() {
80+
let mut h = helper!(
81+
FsWatcherOptions {
82+
aggregate_timeout: Some(300),
83+
..Default::default()
84+
},
85+
FsWatcherIgnored::Regex(RspackRegex::new(r"/a$").unwrap())
86+
);
87+
88+
let rx = watch!(h, "a");
89+
90+
let change_events = arc_counter!();
91+
let aggregated_events = arc_counter!();
92+
93+
h.tick(|| {
94+
h.file("a");
95+
h.tick_ms(1000, || {
96+
{
97+
let change_events = change_events.clone();
98+
let aggregated_events = aggregated_events.clone();
99+
100+
h.collect_events(
101+
rx,
102+
move |_file, _abort| {
103+
add!(change_events);
104+
},
105+
move |_changes, _abort| {
106+
add!(aggregated_events);
107+
},
108+
);
109+
}
110+
111+
assert_no_events!(change_events, aggregated_events);
112+
});
113+
});
114+
}
115+
116+
#[test]
117+
#[ignore]
118+
fn should_not_watch_a_single_ignored_file_function() {
119+
todo!("FsWatcherIgnored::Function")
120+
}

0 commit comments

Comments
 (0)