rapace_testkit/
helper_binary.rs1use std::path::PathBuf;
36
37pub fn enforce_prebuilt_helpers() -> bool {
42 matches!(
43 std::env::var("RAPACE_PREBUILT_HELPERS"),
44 Ok(v) if v.to_lowercase() == "1" || v.to_lowercase() == "true"
45 )
46}
47
48pub fn find_helper_binary(binary_name: &str) -> Result<PathBuf, String> {
68 let enforce = enforce_prebuilt_helpers();
69
70 let current_exe =
72 std::env::current_exe().map_err(|e| format!("failed to get current executable: {}", e))?;
73
74 let mut search_dir = current_exe
77 .parent()
78 .ok_or_else(|| "could not find parent directory".to_string())?;
79
80 for _ in 0..3 {
82 let candidate_path = search_dir.join(binary_name);
83 if candidate_path.exists() {
84 return Ok(candidate_path);
85 }
86
87 if let Some(parent) = search_dir.parent() {
88 search_dir = parent;
89 } else {
90 break;
91 }
92 }
93
94 let profile_dir = match current_exe.parent().and_then(|p| p.parent()) {
96 Some(dir) => dir.to_path_buf(),
97 None => {
98 return Err(format!(
99 "Could not determine target directory from executable path: {:?}",
100 current_exe
101 ));
102 }
103 };
104
105 let binary_path = profile_dir.join(binary_name);
106
107 let error_msg = format!(
108 "helper binary '{}' not found. Searched in: {:?}. \
109 Run 'cargo xtask test' or build helpers with 'cargo build --bin {} -p <package>'",
110 binary_name, binary_path, binary_name
111 );
112
113 if enforce {
114 panic!(
115 "RAPACE_PREBUILT_HELPERS is set: {}\n\
116 To build helpers manually: cargo xtask test --no-run\n\
117 Then use: RAPACE_PREBUILT_HELPERS=1 cargo test",
118 error_msg
119 );
120 }
121
122 Err(error_msg)
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 fn env_lock() -> &'static std::sync::Mutex<()> {
130 static LOCK: std::sync::OnceLock<std::sync::Mutex<()>> = std::sync::OnceLock::new();
131 LOCK.get_or_init(|| std::sync::Mutex::new(()))
132 }
133
134 fn get_prebuilt_helpers_var() -> Option<std::ffi::OsString> {
135 std::env::var_os("RAPACE_PREBUILT_HELPERS")
136 }
137
138 fn set_prebuilt_helpers_var(value: &str) {
139 unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", value) };
143 }
144
145 fn remove_prebuilt_helpers_var() {
146 unsafe { std::env::remove_var("RAPACE_PREBUILT_HELPERS") };
148 }
149
150 #[test]
151 fn test_enforce_prebuilt_helpers_off_by_default() {
152 let _guard = env_lock().lock().unwrap();
153 let prev = get_prebuilt_helpers_var();
154 remove_prebuilt_helpers_var();
155
156 assert!(!enforce_prebuilt_helpers());
158
159 match prev {
160 Some(v) => unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", v) },
161 None => remove_prebuilt_helpers_var(),
162 }
163 }
164
165 #[test]
166 fn test_enforce_prebuilt_helpers_true() {
167 let _guard = env_lock().lock().unwrap();
168 let prev = get_prebuilt_helpers_var();
169 set_prebuilt_helpers_var("true");
170
171 assert!(enforce_prebuilt_helpers());
172
173 match prev {
174 Some(v) => unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", v) },
175 None => remove_prebuilt_helpers_var(),
176 }
177 }
178
179 #[test]
180 fn test_enforce_prebuilt_helpers_1() {
181 let _guard = env_lock().lock().unwrap();
182 let prev = get_prebuilt_helpers_var();
183 set_prebuilt_helpers_var("1");
184
185 assert!(enforce_prebuilt_helpers());
186
187 match prev {
188 Some(v) => unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", v) },
189 None => remove_prebuilt_helpers_var(),
190 }
191 }
192
193 #[test]
194 fn test_enforce_prebuilt_helpers_false() {
195 let _guard = env_lock().lock().unwrap();
196 let prev = get_prebuilt_helpers_var();
197 set_prebuilt_helpers_var("false");
198
199 assert!(!enforce_prebuilt_helpers());
200
201 match prev {
202 Some(v) => unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", v) },
203 None => remove_prebuilt_helpers_var(),
204 }
205 }
206
207 #[test]
208 fn test_find_helper_binary_not_found_not_enforced() {
209 let _guard = env_lock().lock().unwrap();
210 let prev = get_prebuilt_helpers_var();
211 remove_prebuilt_helpers_var();
212
213 let result = find_helper_binary("nonexistent-binary");
215 assert!(result.is_err());
216
217 match prev {
218 Some(v) => unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", v) },
219 None => remove_prebuilt_helpers_var(),
220 }
221 }
222}