completely rewrote test suite for top level src files and all builtin files
This commit is contained in:
@@ -101,6 +101,21 @@ pub fn complete_vars(start: &str) -> Vec<String> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn complete_vars_raw(raw: &str) -> Vec<String> {
|
||||
if !read_vars(|v| v.get_var(raw)).is_empty() {
|
||||
return vec![];
|
||||
}
|
||||
// if we are here, we have a variable substitution that isn't complete
|
||||
// so let's try to complete it
|
||||
read_vars(|v| {
|
||||
v.flatten_vars()
|
||||
.keys()
|
||||
.filter(|k| k.starts_with(raw) && *k != raw)
|
||||
.map(|k| k.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn extract_var_name(text: &str) -> Option<(String, usize, usize)> {
|
||||
let mut chars = text.chars().peekable();
|
||||
let mut name = String::new();
|
||||
@@ -422,7 +437,7 @@ impl CompSpec for BashCompSpec {
|
||||
candidates.extend(complete_commands(&expanded));
|
||||
}
|
||||
if self.vars {
|
||||
candidates.extend(complete_vars(&expanded));
|
||||
candidates.extend(complete_vars_raw(&expanded));
|
||||
}
|
||||
if self.users {
|
||||
candidates.extend(complete_users(&expanded));
|
||||
|
||||
@@ -466,3 +466,125 @@ impl History {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{state, testutil::TestGuard};
|
||||
use scopeguard::guard;
|
||||
use std::{env, fs, path::Path, sync::Mutex};
|
||||
use tempfile::tempdir;
|
||||
|
||||
fn with_env_var(key: &str, val: &str) -> impl Drop {
|
||||
let prev = env::var(key).ok();
|
||||
unsafe {
|
||||
env::set_var(key, val);
|
||||
}
|
||||
guard(prev, move |p| match p {
|
||||
Some(v) => unsafe {
|
||||
env::set_var(key, v)
|
||||
},
|
||||
None => unsafe {
|
||||
env::remove_var(key)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Temporarily mutate shell options for a test and restore the
|
||||
/// previous values when the returned guard is dropped.
|
||||
fn with_shopts(modifier: impl FnOnce(&mut crate::shopt::ShOpts)) -> impl Drop {
|
||||
let original = state::read_shopts(|s| s.clone());
|
||||
state::write_shopts(|s| modifier(s));
|
||||
guard(original, |orig| {
|
||||
state::write_shopts(|s| *s = orig);
|
||||
})
|
||||
}
|
||||
|
||||
fn write_history_file(path: &Path) {
|
||||
fs::write(
|
||||
path,
|
||||
[
|
||||
": 1;1;first\n",
|
||||
": 2;1;second\n",
|
||||
": 3;1;third\n",
|
||||
]
|
||||
.concat(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn history_new_respects_max_hist_limit() {
|
||||
let _lock = TestGuard::new();
|
||||
let tmp = tempdir().unwrap();
|
||||
let hist_path = tmp.path().join("history");
|
||||
write_history_file(&hist_path);
|
||||
|
||||
let _env_guard = with_env_var("SHEDHIST", hist_path.to_str().unwrap());
|
||||
let _opts_guard = with_shopts(|s| {
|
||||
s.core.max_hist = 2;
|
||||
s.core.hist_ignore_dupes = true;
|
||||
});
|
||||
|
||||
let history = History::new().unwrap();
|
||||
|
||||
assert_eq!(history.entries.len(), 2);
|
||||
assert_eq!(history.search_mask.len(), 2);
|
||||
assert_eq!(history.cursor, 2);
|
||||
assert_eq!(history.max_size, Some(2));
|
||||
assert!(history.ignore_dups);
|
||||
assert!(history.pending.is_none());
|
||||
assert_eq!(history.entries[0].command(), "second");
|
||||
assert_eq!(history.entries[1].command(), "third");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn history_new_keeps_all_when_unlimited() {
|
||||
let _lock = TestGuard::new();
|
||||
let tmp = tempdir().unwrap();
|
||||
let hist_path = tmp.path().join("history");
|
||||
write_history_file(&hist_path);
|
||||
|
||||
let _env_guard = with_env_var("SHEDHIST", hist_path.to_str().unwrap());
|
||||
let _opts_guard = with_shopts(|s| {
|
||||
s.core.max_hist = -1;
|
||||
s.core.hist_ignore_dupes = false;
|
||||
});
|
||||
|
||||
let history = History::new().unwrap();
|
||||
|
||||
assert_eq!(history.entries.len(), 3);
|
||||
assert_eq!(history.search_mask.len(), 3);
|
||||
assert_eq!(history.cursor, 3);
|
||||
assert_eq!(history.max_size, None);
|
||||
assert!(!history.ignore_dups);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn history_new_dedupes_search_mask_to_latest_occurrence() {
|
||||
let _lock = TestGuard::new();
|
||||
let tmp = tempdir().unwrap();
|
||||
let hist_path = tmp.path().join("history");
|
||||
fs::write(
|
||||
&hist_path,
|
||||
[
|
||||
": 1;1;repeat\n",
|
||||
": 2;1;unique\n",
|
||||
": 3;1;repeat\n",
|
||||
]
|
||||
.concat(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let _env_guard = with_env_var("SHEDHIST", hist_path.to_str().unwrap());
|
||||
let _opts_guard = with_shopts(|s| {
|
||||
s.core.max_hist = 10;
|
||||
});
|
||||
|
||||
let history = History::new().unwrap();
|
||||
|
||||
let masked: Vec<_> = history.search_mask.iter().map(|e| e.command()).collect();
|
||||
assert_eq!(masked, vec!["unique", "repeat"]);
|
||||
assert_eq!(history.cursor, history.search_mask.len());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user