Lines
100 %
Functions
89.29 %
Branches
use std::path::{Path, PathBuf};
use crate::matcher::Matcher;
/// Try to find the best fuzzy match for the target component in the path.
/// Return a new path that ends at the target component. If the target component
/// is not found, return an Error.
///
/// # Examples
/// ```
/// let matcher = cdup::matcher::Matcher::default();
/// let cwd = std::path::Path::new("/home/rsprta/cdup");
/// let target = String::from("home");
/// let expected = Ok(std::path::Path::new("/home").to_path_buf());
/// assert_eq!(expected, cdup::cd::up_to_target(&matcher, &cwd, &target));
pub fn up_to_target(matcher: &Matcher, path: &Path, target: &str) -> Result<PathBuf, &'static str> {
let path_components: Vec<&str> = path
.iter()
.map(|component| component.to_str().unwrap())
.collect();
let target_index = matcher.best_match(&path_components, target);
match target_index {
Some(target_index) => {
let path_components: Vec<_> = path.components().collect();
Ok(path_components[..=target_index].iter().collect::<PathBuf>())
}
None => Err("No match found for target."),
/// Return path up by given number of components. If the level is greater than
/// the number of components in the path, return the first component of the
/// path.
/// let target: usize = 3;
/// let expected = Ok(std::path::Path::new("/").to_path_buf());
/// assert_eq!(expected, cdup::cd::up_by_count(&cwd, target));
pub fn up_by_count(path: &Path, level: usize) -> Result<PathBuf, &'static str> {
let path_length = path_components.len();
// If we jump by too much, return the first component of a path
let end_component = if level < path_length {
path_length - level
} else {
1
};
Ok(path_components[..end_component].iter().collect::<PathBuf>())
#[cfg(test)]
macro_rules! up_to_target {
($($name: ident: $value:expr,)*) => {
$(
#[test]
fn $name() {
// GIVEN a path and target component to jump to
let (original_path, target, expected) = $value;
let original_path = Path::new(original_path);
let target = String::from(target);
let expected = Ok(PathBuf::from(expected));
let matcher = Matcher::default();
// WHEN jumping up to target component
let actual = up_to_target(&matcher, &original_path, &target);
// THEN the new path should end there
assert_eq!(expected, actual);
)*
macro_rules! up_by_count {
// GIVEN a path and level to jump up by
let (original_path, level, expected) = $value;
// WHEN jumping up the path by given level
let actual = up_by_count(&original_path, level);
// THEN the new path should be shortened by that number of components
mod tests {
use super::*;
up_to_target! {
up_to_target_directory: ("/home/user/directory", "directory", "/home/user/directory"),
up_to_target_user: ("/home/user/directory", "user", "/home/user"),
up_to_target_home: ("/home/user/directory", "home", "/home"),
up_to_target_multiple: ("/multiple/multiple/dirs", "multiple", "/multiple/multiple"),
up_to_target_fuzzy: ("/home/user/directory", "usr", "/home/user"),
fn up_to_target_no_match() {
// GIVEN a path and non-existing target component to jump to
let original_path = Path::new("/home/user/directory");
let target = String::from("no_match");
// THEN we should get an error
let expected = Err("No match found for target.");
up_by_count! {
up_by_count_0: ("/home/user/directory", 0, "/home/user/directory"),
up_by_count_1: ("/home/user/directory", 1, "/home/user"),
up_by_count_2: ("/home/user/directory", 2, "/home"),
up_by_count_3: ("/home/user/directory", 3, "/"),
up_by_count_4: ("/home/user/directory", 4, "/"),