1use std::{collections::HashSet, env, fs};
2
3pub fn get_executables() -> HashSet<String> {
6 let serialized_paths = env::var("PATH").expect("Could not read PATH variable");
7 let deserialized_paths = serialized_paths.split(":");
8 let mut results: HashSet<String> = HashSet::new();
9
10 for path in deserialized_paths {
11 if let Ok(entries) = fs::read_dir(path) {
12 for entry in entries {
13 if !entry.is_ok() {
14 continue;
15 }
16
17 let path = entry.unwrap().path();
18 let command_name = path
19 .file_name()
20 .expect("Could not get file name")
21 .to_os_string()
22 .into_string()
23 .expect("Could not convert file name to string");
24
25 if !path.is_file() {
26 continue;
27 }
28
29 if is_executable::is_executable(path) {
30 results.insert(command_name);
31 }
32 }
33 }
34 }
35
36 results
37}
38
39pub fn iterate_executables() -> impl Iterator<Item = String> {
43 get_executables().into_iter()
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn returns_commands_that_definitely_exist_on_the_system() {
60 let result = get_executables();
61 assert!(result.contains("ls"));
62 assert!(result.contains("mkdir"));
63 assert!(result.contains("kill"));
64 assert!(result.contains("man"));
65 }
66
67 #[test]
68 fn does_not_return_commands_that_dont_exist_in_the_system() {
69 let result = get_executables();
70 assert!(!result.contains("asdfsdfadsfasdfdasfadsfadsfadsfafafdsfasf"));
71 }
72
73 #[test]
74 fn iteration_and_hashmap_have_the_same_results() {
75 let mut results_from_iterator: HashSet<String> = HashSet::new();
76 for command in iterate_executables() {
77 results_from_iterator.insert(command);
78 }
79
80 assert_eq!(results_from_iterator, get_executables());
81 }
82}