Skip to content

Commit 2e64cc7

Browse files
committed
test: add pet-homebrew locator coverage (Fixes #393)
1 parent d40b4bc commit 2e64cc7

File tree

3 files changed

+218
-0
lines changed

3 files changed

+218
-0
lines changed

crates/pet-homebrew/src/environment_locations.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,61 @@ pub fn get_homebrew_prefix_bin(env_vars: &EnvVariables) -> Vec<PathBuf> {
4848

4949
homebrew_prefixes
5050
}
51+
52+
#[cfg(test)]
53+
mod tests {
54+
use super::*;
55+
use std::{
56+
fs,
57+
time::{SystemTime, UNIX_EPOCH},
58+
};
59+
60+
fn create_unique_prefix(name: &str) -> PathBuf {
61+
let unique = SystemTime::now()
62+
.duration_since(UNIX_EPOCH)
63+
.unwrap()
64+
.as_nanos();
65+
std::env::temp_dir().join(format!(
66+
"pet-homebrew-{name}-{}-{unique}",
67+
std::process::id()
68+
))
69+
}
70+
71+
#[test]
72+
fn homebrew_prefix_bin_uses_existing_homebrew_prefix_env_var() {
73+
let homebrew_prefix = create_unique_prefix("prefix");
74+
let homebrew_bin = homebrew_prefix.join("bin");
75+
fs::create_dir_all(&homebrew_bin).unwrap();
76+
let env_vars = EnvVariables {
77+
home: None,
78+
root: None,
79+
path: None,
80+
homebrew_prefix: Some(homebrew_prefix.to_string_lossy().to_string()),
81+
known_global_search_locations: vec![],
82+
};
83+
84+
let prefix_bins = get_homebrew_prefix_bin(&env_vars);
85+
86+
assert!(prefix_bins.contains(&homebrew_bin));
87+
88+
fs::remove_dir_all(homebrew_prefix).unwrap();
89+
}
90+
91+
#[test]
92+
fn homebrew_prefix_bin_ignores_missing_homebrew_prefix_env_var() {
93+
let missing_homebrew_prefix = create_unique_prefix("missing-prefix");
94+
let env_vars = EnvVariables {
95+
home: None,
96+
root: None,
97+
path: None,
98+
homebrew_prefix: Some(missing_homebrew_prefix.to_string_lossy().to_string()),
99+
known_global_search_locations: vec![],
100+
};
101+
102+
let prefix_bins = get_homebrew_prefix_bin(&env_vars);
103+
104+
assert!(!prefix_bins
105+
.iter()
106+
.any(|path| path == &missing_homebrew_prefix.join("bin")));
107+
}
108+
}

crates/pet-homebrew/src/lib.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,127 @@ impl Locator for Homebrew {
170170
});
171171
}
172172
}
173+
174+
#[cfg(all(test, unix))]
175+
mod tests {
176+
use super::*;
177+
use std::time::{SystemTime, UNIX_EPOCH};
178+
179+
struct TestEnvironment {
180+
homebrew_prefix: Option<String>,
181+
}
182+
183+
impl Environment for TestEnvironment {
184+
fn get_user_home(&self) -> Option<PathBuf> {
185+
None
186+
}
187+
188+
fn get_root(&self) -> Option<PathBuf> {
189+
None
190+
}
191+
192+
fn get_env_var(&self, key: String) -> Option<String> {
193+
if key == "HOMEBREW_PREFIX" {
194+
self.homebrew_prefix.clone()
195+
} else {
196+
None
197+
}
198+
}
199+
200+
fn get_know_global_search_locations(&self) -> Vec<PathBuf> {
201+
vec![]
202+
}
203+
}
204+
205+
fn create_test_dir(name: &str) -> PathBuf {
206+
let unique = SystemTime::now()
207+
.duration_since(UNIX_EPOCH)
208+
.unwrap()
209+
.as_nanos();
210+
let directory = std::env::temp_dir().join(format!(
211+
"pet-homebrew-{name}-{}-{unique}",
212+
std::process::id()
213+
));
214+
fs::create_dir_all(&directory).unwrap();
215+
directory
216+
}
217+
218+
#[test]
219+
fn homebrew_locator_reports_kind_and_supported_category() {
220+
let locator = Homebrew::from(&TestEnvironment {
221+
homebrew_prefix: None,
222+
});
223+
224+
assert_eq!(locator.get_kind(), LocatorKind::Homebrew);
225+
assert_eq!(
226+
locator.supported_categories(),
227+
vec![PythonEnvironmentKind::Homebrew]
228+
);
229+
}
230+
231+
#[test]
232+
fn try_from_identifies_linuxbrew_python_executable() {
233+
let locator = Homebrew::from(&TestEnvironment {
234+
homebrew_prefix: None,
235+
});
236+
let env = PythonEnv::new(
237+
PathBuf::from("/home/linuxbrew/.linuxbrew/Cellar/python@3.12/3.12.4/bin/python3.12"),
238+
None,
239+
None,
240+
);
241+
242+
let homebrew_env = locator.try_from(&env).unwrap();
243+
244+
assert_eq!(homebrew_env.kind, Some(PythonEnvironmentKind::Homebrew));
245+
assert_eq!(
246+
homebrew_env.executable,
247+
Some(PathBuf::from("/home/linuxbrew/.linuxbrew/bin/python3.12"))
248+
);
249+
assert_eq!(homebrew_env.version, Some("3.12.4".to_string()));
250+
assert_eq!(homebrew_env.prefix, None);
251+
assert!(homebrew_env
252+
.symlinks
253+
.as_ref()
254+
.unwrap()
255+
.contains(&PathBuf::from(
256+
"/home/linuxbrew/.linuxbrew/Cellar/python@3.12/3.12.4/bin/python3.12"
257+
)));
258+
}
259+
260+
#[test]
261+
fn try_from_rejects_non_homebrew_python() {
262+
let locator = Homebrew::from(&TestEnvironment {
263+
homebrew_prefix: None,
264+
});
265+
let env = PythonEnv::new(PathBuf::from("/usr/bin/python3.12"), None, None);
266+
267+
assert!(locator.try_from(&env).is_none());
268+
}
269+
270+
#[test]
271+
fn try_from_rejects_virtualenv_and_conda_prefixes() {
272+
let locator = Homebrew::from(&TestEnvironment {
273+
homebrew_prefix: None,
274+
});
275+
276+
let venv_root = create_test_dir("venv-reject");
277+
let venv_bin = venv_root.join("bin");
278+
fs::create_dir_all(&venv_bin).unwrap();
279+
fs::write(venv_bin.join("activate"), b"").unwrap();
280+
let venv_executable = venv_bin.join("python3.12");
281+
fs::write(&venv_executable, b"").unwrap();
282+
let venv = PythonEnv::new(venv_executable, Some(venv_root.clone()), None);
283+
assert!(locator.try_from(&venv).is_none());
284+
285+
let conda_root = create_test_dir("conda-reject");
286+
fs::create_dir_all(conda_root.join("conda-meta")).unwrap();
287+
let conda_executable = conda_root.join("bin").join("python3.12");
288+
fs::create_dir_all(conda_executable.parent().unwrap()).unwrap();
289+
fs::write(&conda_executable, b"").unwrap();
290+
let conda = PythonEnv::new(conda_executable, Some(conda_root.clone()), None);
291+
assert!(locator.try_from(&conda).is_none());
292+
293+
fs::remove_dir_all(venv_root).unwrap();
294+
fs::remove_dir_all(conda_root).unwrap();
295+
}
296+
}

crates/pet-homebrew/src/sym_links.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,39 @@ pub fn get_known_symlinks_impl(
243243
vec![]
244244
}
245245
}
246+
247+
#[cfg(test)]
248+
mod tests {
249+
use super::*;
250+
251+
#[test]
252+
fn homebrew_python_paths_are_recognized_across_supported_prefixes() {
253+
assert!(is_homebrew_python(Path::new(
254+
"/opt/homebrew/Cellar/python@3.12/3.12.4/bin/python3.12"
255+
)));
256+
assert!(is_homebrew_python(Path::new(
257+
"/usr/local/Cellar/python@3.11/3.11.9/bin/python3.11"
258+
)));
259+
assert!(is_homebrew_python(Path::new(
260+
"/home/linuxbrew/.linuxbrew/Cellar/python@3.12/3.12.4/bin/python3.12"
261+
)));
262+
assert!(!is_homebrew_python(Path::new("/usr/bin/python3.12")));
263+
}
264+
265+
#[test]
266+
fn known_symlink_templates_include_expected_paths_for_linuxbrew() {
267+
let resolved_exe =
268+
PathBuf::from("/home/linuxbrew/.linuxbrew/Cellar/python@3.12/3.12.4/bin/python3.12");
269+
let symlinks = get_known_symlinks_impl(&resolved_exe, &"3.12.4".to_string());
270+
271+
assert!(symlinks.contains(&resolved_exe));
272+
}
273+
274+
#[test]
275+
fn known_symlink_templates_return_empty_for_unrecognized_paths() {
276+
assert!(
277+
get_known_symlinks_impl(Path::new("/usr/bin/python3.12"), &"3.12.4".to_string())
278+
.is_empty()
279+
);
280+
}
281+
}

0 commit comments

Comments
 (0)