Skip to content

Commit

Permalink
A bit more unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
janpipek committed Oct 4, 2024
1 parent ffb1e3e commit 4a1b511
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 44 deletions.
126 changes: 115 additions & 11 deletions src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::fmt::{Display, Formatter};
use std::path::{Path, PathBuf};
use crate::extensions::{find_extensions_from_content, has_correct_extension};
use colored::Colorize;
use regex::Regex;
use std::fmt::{Display, Formatter};
use std::path::{Path, PathBuf};
use unidecode::unidecode;
use crate::extensions::{find_extensions_from_content, has_correct_extension};

#[derive(Clone)]
pub struct RenameIntent {
Expand Down Expand Up @@ -33,14 +33,16 @@ impl Display for RenameIntent {
}
}


pub trait RenameCommand {
fn suggest_new_name(&self, old_name: &Path) -> PathBuf;

fn suggest_renames(&self, files: &[PathBuf]) -> Vec<RenameIntent> {
files
.iter()
.map(|path| RenameIntent { old_name: path.clone(), new_name: self.suggest_new_name(path) })
.map(|path| RenameIntent {
old_name: path.clone(),
new_name: self.suggest_new_name(path),
})
.collect()
}
}
Expand Down Expand Up @@ -151,13 +153,115 @@ mod tests {
use super::*;
use std::path::PathBuf;

/// Compare whether old_names are converted to new expected_names using command.
fn assert_renames_correctly(
command: &dyn RenameCommand,
old_names: &[&str],
expected_names: &[&str],
) {
let old: Vec<PathBuf> = old_names.iter().map(|&x| PathBuf::from(x)).collect();
let new_intents = command.suggest_renames(&old);
let new: Vec<PathBuf> = new_intents
.iter()
.map(|intent| intent.new_name.clone())
.collect();
let expected: Vec<PathBuf> = expected_names.iter().map(|&x| PathBuf::from(x)).collect();
assert_eq!(expected, new);
}

#[test]
fn test_set_prefix() {
let p = Prefix { prefix: String::from("a") };
let p = Prefix { prefix: String::from("a") };
let old_path = PathBuf::from("b");
assert_eq!(
p.suggest_new_name(&old_path),
PathBuf::from("ab")
)
assert_eq!(p.suggest_new_name(&old_path), PathBuf::from("ab"))
}

mod test_replace {
use super::*;

#[test]
fn test_regex() {
// Regex really matching
let replace = Replace {
pattern: String::from("\\d"),
replacement: String::from("a"),
is_regex: true,
};
let old_path = PathBuf::from("a222");
assert_eq!(replace.suggest_new_name(&old_path), PathBuf::from("aaaa"));

// Regex present as literal
let replace = Replace {
pattern: String::from("a$"),
replacement: String::from("a"),
is_regex: true,
};
let old_path = PathBuf::from("a$a");
assert_eq!(replace.suggest_new_name(&old_path), PathBuf::from("a$a"));
}

#[test]
fn test_non_regex() {
let command = Replace {
pattern: String::from("a.c"),
replacement: String::from("def"),
is_regex: false,
};
let old_path = PathBuf::from("a.cabc");
assert_eq!(command.suggest_new_name(&old_path), PathBuf::from("defabc"));
}
}
}

mod test_change_case {
use super::*;

#[test]
fn test_upper() {
assert_renames_correctly(
&ChangeCase { upper: true },
&["Abc", "hnědý", "Αθήνα", "mountAIN🗻"],
&["ABC", "HNĚDÝ", "ΑΘΉΝΑ", "MOUNTAIN🗻"]
);
}

#[test]
fn test_lower() {
assert_renames_correctly(
&ChangeCase { upper: false },
&["Abc", "hnědý", "Αθήνα", "mountAIN🗻"],
&["abc", "hnědý", "αθήνα", "mountain🗻"]
);
}
}

#[test]
fn test_normalize() {
assert_renames_correctly(
&Normalize,
&["Abc", "hnědý", "Αθήνα & Σπάρτη", "mountain🗻"],
&["Abc", "hnedy", "Athena_&_Sparte", "mountain"]
);
}

mod test_set_extension {
use super::*;

#[test]
fn test_no_extension() {
assert_renames_correctly(
&SetExtension{ extension: String::from("") },
&["a", "b", "c.jpg", ".gitignore"],
&["a", "b", "c", ".gitignore"],
);
}

#[test]
fn test_some_extension() {
assert_renames_correctly(
&SetExtension{ extension: String::from("jpg") },
&["a", "b", "c.jpg", ".gitignore"],
&["a.jpg", "b.jpg", "c.jpg", ".gitignore.jpg"],
);
}
}
}
28 changes: 20 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
pub mod extensions;
pub mod commands;
pub mod extensions;

use std::collections::HashSet;
use colored::Colorize;
use std::collections::HashSet;
use std::fs::rename;
use std::ops::Deref;
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -98,8 +98,11 @@ fn process_command(
};
}

fn contains_duplicates(intents: &Vec<RenameIntent>) -> bool {
let new_names: Vec<PathBuf> = intents.iter().map(|intent| intent.new_name.clone()).collect();
fn contains_duplicates(intents: &[RenameIntent]) -> bool {
let new_names: Vec<PathBuf> = intents
.iter()
.map(|intent| intent.new_name.clone())
.collect();
let mut uniq = HashSet::new();
!new_names.into_iter().all(move |x| uniq.insert(x))
}
Expand All @@ -120,12 +123,21 @@ mod test {

#[test]
fn test_contains_duplicates() {
let a_to_b = RenameIntent{ old_name: PathBuf::from("a"), new_name: PathBuf::from("b")};
let b_to_d = RenameIntent{ old_name: PathBuf::from("b"), new_name: PathBuf::from("d")};
let c_to_d = RenameIntent{ old_name: PathBuf::from("c"), new_name: PathBuf::from("d")};
let a_to_b = RenameIntent {
old_name: PathBuf::from("a"),
new_name: PathBuf::from("b"),
};
let b_to_d = RenameIntent {
old_name: PathBuf::from("b"),
new_name: PathBuf::from("d"),
};
let c_to_d = RenameIntent {
old_name: PathBuf::from("c"),
new_name: PathBuf::from("d"),
};

assert!(contains_duplicates(&vec![b_to_d, c_to_d.clone()]));
assert!(!contains_duplicates(&vec![a_to_b, c_to_d]));
assert!(!contains_duplicates(&Vec::new()));
}
}
}
54 changes: 29 additions & 25 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ use std::{env, path::PathBuf};

use clap::{arg, command, value_parser, Arg, ArgAction, ArgMatches, Command};

use muren::commands::{
ChangeCase, FixExtension, Normalize, Prefix, Remove, RenameCommand, Replace, SetExtension,
};
use muren::{run, Config};
use muren::commands::{SetExtension, RenameCommand, Remove, Normalize, FixExtension, Prefix, Replace, ChangeCase};

fn parse_config(matches: &ArgMatches) -> Config {
let command = extract_command(matches);
Expand All @@ -22,31 +24,33 @@ fn parse_config(matches: &ArgMatches) -> Config {
}

fn extract_command(args_matches: &ArgMatches) -> Box<dyn RenameCommand> {
match args_matches.subcommand()
{
match args_matches.subcommand() {
None => panic!("No command provided"),
Some((m, matches)) =>
match m {
"set-ext" => Box::new(SetExtension {
extension: matches.get_one::<String>("extension").unwrap().clone(),
}),
"remove" => Box::new(Remove {
pattern: matches.get_one::<String>("pattern").unwrap().clone(),
}),
"normalize" => Box::new(Normalize),
"fix-ext" => Box::new(FixExtension { append: matches.get_flag("append") }),
"prefix" => Box::new(Prefix {
prefix: matches.get_one::<String>("prefix").unwrap().clone(),
}),
"replace" => Box::new(Replace {
pattern: matches.get_one::<String>("pattern").unwrap().clone(),
replacement: matches.get_one::<String>("replacement").unwrap().clone(),
is_regex: matches.get_flag("regex"),
}),
"change-case" =>
Box::new(ChangeCase { upper: matches.get_flag("upper") }),
_ => panic!("Unknown command"),
}}
Some((m, matches)) => match m {
"set-ext" => Box::new(SetExtension {
extension: matches.get_one::<String>("extension").unwrap().clone(),
}),
"remove" => Box::new(Remove {
pattern: matches.get_one::<String>("pattern").unwrap().clone(),
}),
"normalize" => Box::new(Normalize),
"fix-ext" => Box::new(FixExtension {
append: matches.get_flag("append"),
}),
"prefix" => Box::new(Prefix {
prefix: matches.get_one::<String>("prefix").unwrap().clone(),
}),
"replace" => Box::new(Replace {
pattern: matches.get_one::<String>("pattern").unwrap().clone(),
replacement: matches.get_one::<String>("replacement").unwrap().clone(),
is_regex: matches.get_flag("regex"),
}),
"change-case" => Box::new(ChangeCase {
upper: matches.get_flag("upper"),
}),
_ => panic!("Unknown command"),
},
}
}

fn create_cli_command() -> Command {
Expand Down

0 comments on commit 4a1b511

Please sign in to comment.