1use std::io::Write;
18use std::path::Path;
19use std::sync::OnceLock;
20
21pub use skipper_core::*;
22pub use skipper_macros::skipper;
23
24#[macro_export]
29macro_rules! skip_if_disabled {
30 () => {
31 $crate::skip_if_disabled!(())
32 };
33 ($ret:expr) => {{
34 fn __skipper_here() {}
35 let name = $crate::__fn_name(::core::any::type_name_of_val(&__skipper_here));
36 if $crate::__should_skip(::core::file!(), ::core::module_path!(), name) {
37 return $ret;
38 }
39 }};
40}
41
42#[doc(hidden)]
43pub fn __fn_name(type_name: &str) -> &str {
44 type_name
46 .split("::")
47 .filter(|s| *s != "__skipper_here" && !s.starts_with("{{"))
48 .last()
49 .unwrap_or(type_name)
50}
51
52fn resolver() -> Option<&'static SkipperResolver> {
53 static RESOLVER: OnceLock<Option<SkipperResolver>> = OnceLock::new();
54 RESOLVER
55 .get_or_init(|| match SkipperResolver::from_env() {
56 Ok(r) => r,
57 Err(e) => panic!("[skipper] cannot load spreadsheet: {e}"),
59 })
60 .as_ref()
61}
62
63pub fn test_id(file: &str, module_path: &str, name: &str) -> String {
65 let modules = module_path.split_once("::").map(|(_, rest)| rest);
66 match modules {
67 Some(m) if !m.is_empty() => build_test_id(file, &[m, name]),
68 _ => build_test_id(file, &[name]),
69 }
70}
71
72#[doc(hidden)]
73pub fn __should_skip(file: &str, module_path: &str, name: &str) -> bool {
74 let Some(resolver) = resolver() else {
75 return false;
76 };
77 let id = test_id(file, module_path, name);
78 if let Some(dir) = std::env::var_os("SKIPPER_DISCOVERED_DIR") {
79 if let Err(e) =
80 CacheManager::write_discovered_ids(Path::new(&dir), std::slice::from_ref(&id))
81 {
82 warn(format!("cannot record discovered test {id}: {e}"));
83 }
84 }
85 if resolver.is_test_enabled(&id) {
86 return false;
87 }
88 let _ = writeln!(std::io::stderr(), "{}", resolver.skip_message(&id));
90 true
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn test_id_drops_crate_name() {
99 assert_eq!(
100 test_id("tests/auth.rs", "auth", "login"),
101 "tests/auth.rs > login"
102 );
103 assert_eq!(
104 test_id("src/lib.rs", "my_crate::a::tests", "works"),
105 "src/lib.rs > a::tests > works"
106 );
107 }
108
109 #[test]
110 fn fn_name_from_type_name() {
111 assert_eq!(__fn_name("k::m::my_test::__skipper_here"), "my_test");
112 assert_eq!(
113 __fn_name("k::my_test::{{closure}}::__skipper_here"),
114 "my_test"
115 );
116 }
117}