superwhich 3.0.1

Cross-platform smart which alternative
Documentation
use crossbeam::channel::unbounded;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use std::{
    borrow::Cow,
    collections::HashSet,
    fs::{create_dir_all, write},
    sync::Arc,
};
use superwhich::{FastLowercase, SearchCtx, find_files, par_find_files};
use tempfile::tempdir;

#[test]
fn test_fast_lowercase() {
    let a = "abc";
    let b = "aBc";

    let a_l = a.to_lowercase_fast();
    let b_l = b.to_lowercase_fast();

    assert_eq!(a_l, Cow::Borrowed("abc"));
    assert_eq!(b_l, Cow::<str>::Owned("abc".to_string()));
}

#[test]
fn test_find_files() {
    let temp_dir = tempdir().unwrap();
    let (dirs, files) = (100, 1000usize);
    let files_per_dir = files / dirs;
    let expected: HashSet<String> = ["grep.exe"]
        .iter()
        .map(|bin| {
            temp_dir
                .path()
                .join("dir42")
                .join(bin)
                .display()
                .to_string()
        })
        .collect();

    let mut paths = Vec::new();
    for i in 0..dirs {
        let dir_path = temp_dir.path().join(format!("dir{}", i + 1));
        create_dir_all(&dir_path).unwrap();

        for j in 0..files_per_dir {
            let path = dir_path.join(format!("file_{}_{}.exe", i + 1, j + 1));
            write(path, b"test").unwrap();
        }

        paths.push(dir_path);
    }

    let path = temp_dir.path().join("dir42").join("grep.exe");
    write(path, b"test").unwrap();

    let ctx = Arc::new(SearchCtx::new("GURE".to_string()).threshold(0.7));
    let (tx, rx) = unbounded();

    paths.into_par_iter().for_each(|path| {
        find_files(&path, &ctx, &tx);
    });

    let mut found = HashSet::new();
    while let Ok(p) = rx.try_recv() {
        found.insert(p);
    }

    assert_eq!(found, expected);
}

#[test]
fn test_par_find_files_linux() {
    let temp_dir = tempdir().unwrap();
    let example_bins = ["ll", "la", "lsx", "lsa", "as", "grep"];
    let expected: HashSet<String> = ["grep"]
        .iter()
        .map(|bin| temp_dir.path().join(bin).display().to_string())
        .collect();

    for bin in example_bins {
        let path = temp_dir.path().join(bin);
        write(&path, b"test").unwrap();
    }

    let ctx = Arc::new(SearchCtx::new("GURE".to_string()).threshold(0.7));
    let (tx, rx) = unbounded();

    par_find_files(temp_dir.path(), &ctx, &tx);

    let mut found = HashSet::new();
    while let Ok(p) = rx.try_recv() {
        found.insert(p);
    }

    assert_eq!(found, expected);
}

#[test]
fn test_par_find_files_windows() {
    let temp_dir = tempdir().unwrap();
    let example_bins = [
        "ll.exe", "la.bat", "lsx.com", "lsa.exe", "as.exe", "grep.exe",
    ];
    let expected: HashSet<String> = ["grep.exe"]
        .iter()
        .map(|bin| temp_dir.path().join(bin).display().to_string())
        .collect();

    for bin in example_bins {
        let path = temp_dir.path().join(bin);
        write(&path, b"test").unwrap();
    }

    let ctx = Arc::new(SearchCtx::new("GURE".to_string()).threshold(0.7));
    let (tx, rx) = unbounded();

    par_find_files(temp_dir.path(), &ctx, &tx);

    let mut found = HashSet::new();
    while let Ok(p) = rx.try_recv() {
        found.insert(p);
    }

    assert_eq!(found, expected);
}