Critical: undo toast now trashes only batch output files (not entire dir), JPEG scanline write errors propagated, selective metadata write result returned. High: zero-dimension guards in ResizeConfig/fit_within, negative aspect ratio rejection, FM integration toggle infinite recursion guard, saturating counter arithmetic in executor. Medium: PNG compression level passed to oxipng, pct mode updates job_config, external file loading updates step indicator, CLI undo removes history entries, watch config write failures reported, fast-copy path reads image dimensions for rename templates, discovery excludes unprocessable formats (heic/svg/ico/jxl), CLI warns on invalid algorithm/overwrite values, resolve_collision trailing dot fix, generation guards on all preview threads to cancel stale results, default DPI aligned to 0, watermark text width uses char count not byte length. Low: binary path escaped in Nautilus extension, file dialog filter aligned with discovery, reset_wizard clears preset_mode and output_dir.
281 lines
6.6 KiB
Rust
281 lines
6.6 KiB
Rust
use pixstrip_core::operations::rename::{
|
|
apply_template, apply_regex_replace, apply_space_replacement,
|
|
apply_special_chars, apply_case_conversion, resolve_collision,
|
|
};
|
|
|
|
#[test]
|
|
fn template_basic_variables() {
|
|
let result = apply_template(
|
|
"{name}_{counter:3}.{ext}",
|
|
"sunset",
|
|
"jpg",
|
|
1,
|
|
None,
|
|
);
|
|
assert_eq!(result, "sunset_001.jpg");
|
|
}
|
|
|
|
#[test]
|
|
fn template_with_prefix() {
|
|
let result = apply_template(
|
|
"blog_{name}.{ext}",
|
|
"photo",
|
|
"webp",
|
|
1,
|
|
None,
|
|
);
|
|
assert_eq!(result, "blog_photo.webp");
|
|
}
|
|
|
|
#[test]
|
|
fn template_counter_padding() {
|
|
let result = apply_template(
|
|
"{name}_{counter:4}.{ext}",
|
|
"img",
|
|
"png",
|
|
42,
|
|
None,
|
|
);
|
|
assert_eq!(result, "img_0042.png");
|
|
}
|
|
|
|
#[test]
|
|
fn template_counter_no_padding() {
|
|
let result = apply_template(
|
|
"{name}_{counter}.{ext}",
|
|
"img",
|
|
"png",
|
|
42,
|
|
None,
|
|
);
|
|
assert_eq!(result, "img_42.png");
|
|
}
|
|
|
|
#[test]
|
|
fn template_width_height() {
|
|
let result = apply_template(
|
|
"{name}_{width}x{height}.{ext}",
|
|
"photo",
|
|
"jpg",
|
|
1,
|
|
Some((1920, 1080)),
|
|
);
|
|
assert_eq!(result, "photo_1920x1080.jpg");
|
|
}
|
|
|
|
#[test]
|
|
fn collision_adds_suffix() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let base = dir.path().join("photo.jpg");
|
|
std::fs::write(&base, b"exists").unwrap();
|
|
|
|
let resolved = resolve_collision(&base);
|
|
assert_eq!(
|
|
resolved.file_name().unwrap().to_str().unwrap(),
|
|
"photo_1.jpg"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn collision_increments() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
std::fs::write(dir.path().join("photo.jpg"), b"exists").unwrap();
|
|
std::fs::write(dir.path().join("photo_1.jpg"), b"exists").unwrap();
|
|
|
|
let resolved = resolve_collision(&dir.path().join("photo.jpg"));
|
|
assert_eq!(
|
|
resolved.file_name().unwrap().to_str().unwrap(),
|
|
"photo_2.jpg"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn no_collision_returns_same() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("unique.jpg");
|
|
let resolved = resolve_collision(&path);
|
|
assert_eq!(resolved, path);
|
|
}
|
|
|
|
// --- Regex replace tests ---
|
|
|
|
#[test]
|
|
fn regex_replace_basic() {
|
|
let result = apply_regex_replace("hello_world", "_", "-");
|
|
assert_eq!(result, "hello-world");
|
|
}
|
|
|
|
#[test]
|
|
fn regex_replace_pattern() {
|
|
let result = apply_regex_replace("IMG_20260307_001", r"\d{8}", "DATE");
|
|
assert_eq!(result, "IMG_DATE_001");
|
|
}
|
|
|
|
#[test]
|
|
fn regex_replace_invalid_pattern_returns_original() {
|
|
let result = apply_regex_replace("hello", "[invalid", "x");
|
|
assert_eq!(result, "hello");
|
|
}
|
|
|
|
#[test]
|
|
fn regex_replace_empty_find_returns_original() {
|
|
let result = apply_regex_replace("hello", "", "x");
|
|
assert_eq!(result, "hello");
|
|
}
|
|
|
|
// --- Space replacement tests ---
|
|
|
|
#[test]
|
|
fn space_replacement_none() {
|
|
assert_eq!(apply_space_replacement("hello world", 0), "hello world");
|
|
}
|
|
|
|
#[test]
|
|
fn space_replacement_underscore() {
|
|
assert_eq!(apply_space_replacement("hello world", 1), "hello_world");
|
|
}
|
|
|
|
#[test]
|
|
fn space_replacement_hyphen() {
|
|
assert_eq!(apply_space_replacement("hello world", 2), "hello-world");
|
|
}
|
|
|
|
#[test]
|
|
fn space_replacement_dot() {
|
|
assert_eq!(apply_space_replacement("hello world", 3), "hello.world");
|
|
}
|
|
|
|
#[test]
|
|
fn space_replacement_camelcase() {
|
|
assert_eq!(apply_space_replacement("hello world", 4), "helloWorld");
|
|
}
|
|
|
|
#[test]
|
|
fn space_replacement_remove() {
|
|
assert_eq!(apply_space_replacement("hello world", 5), "helloworld");
|
|
}
|
|
|
|
// --- Special chars tests ---
|
|
|
|
#[test]
|
|
fn special_chars_keep_all() {
|
|
assert_eq!(apply_special_chars("file<name>.txt", 0), "file<name>.txt");
|
|
}
|
|
|
|
#[test]
|
|
fn special_chars_filesystem_safe() {
|
|
assert_eq!(apply_special_chars("file<name>", 1), "filename");
|
|
}
|
|
|
|
#[test]
|
|
fn special_chars_web_safe() {
|
|
assert_eq!(apply_special_chars("file name!@#", 2), "filename");
|
|
}
|
|
|
|
#[test]
|
|
fn special_chars_alphanumeric_only() {
|
|
assert_eq!(apply_special_chars("file-name_123", 5), "filename123");
|
|
}
|
|
|
|
// --- Case conversion tests ---
|
|
|
|
#[test]
|
|
fn case_conversion_none() {
|
|
assert_eq!(apply_case_conversion("Hello World", 0), "Hello World");
|
|
}
|
|
|
|
#[test]
|
|
fn case_conversion_lowercase() {
|
|
assert_eq!(apply_case_conversion("Hello World", 1), "hello world");
|
|
}
|
|
|
|
#[test]
|
|
fn case_conversion_uppercase() {
|
|
assert_eq!(apply_case_conversion("Hello World", 2), "HELLO WORLD");
|
|
}
|
|
|
|
#[test]
|
|
fn case_conversion_title_case() {
|
|
assert_eq!(apply_case_conversion("hello world", 3), "Hello World");
|
|
}
|
|
|
|
#[test]
|
|
fn case_conversion_title_preserves_separators() {
|
|
assert_eq!(apply_case_conversion("hello-world_foo", 3), "Hello-World_Foo");
|
|
}
|
|
|
|
// --- RenameConfig::apply_simple edge cases ---
|
|
|
|
use pixstrip_core::operations::RenameConfig;
|
|
|
|
fn default_rename_config() -> RenameConfig {
|
|
RenameConfig {
|
|
prefix: String::new(),
|
|
suffix: String::new(),
|
|
counter_start: 1,
|
|
counter_padding: 3,
|
|
counter_enabled: false,
|
|
counter_position: 3,
|
|
template: None,
|
|
case_mode: 0,
|
|
replace_spaces: 0,
|
|
special_chars: 0,
|
|
regex_find: String::new(),
|
|
regex_replace: String::new(),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn apply_simple_no_changes() {
|
|
let cfg = default_rename_config();
|
|
assert_eq!(cfg.apply_simple("photo", "jpg", 1), "photo.jpg");
|
|
}
|
|
|
|
#[test]
|
|
fn apply_simple_with_prefix_suffix() {
|
|
let mut cfg = default_rename_config();
|
|
cfg.prefix = "web_".into();
|
|
cfg.suffix = "_final".into();
|
|
assert_eq!(cfg.apply_simple("photo", "jpg", 1), "web_photo_final.jpg");
|
|
}
|
|
|
|
#[test]
|
|
fn apply_simple_counter_after_suffix() {
|
|
let mut cfg = default_rename_config();
|
|
cfg.counter_enabled = true;
|
|
cfg.counter_position = 3;
|
|
assert_eq!(cfg.apply_simple("photo", "jpg", 1), "photo_001.jpg");
|
|
}
|
|
|
|
#[test]
|
|
fn apply_simple_counter_replaces_name() {
|
|
let mut cfg = default_rename_config();
|
|
cfg.counter_enabled = true;
|
|
cfg.counter_position = 4;
|
|
assert_eq!(cfg.apply_simple("photo", "jpg", 1), "001.jpg");
|
|
}
|
|
|
|
#[test]
|
|
fn apply_simple_empty_name() {
|
|
let cfg = default_rename_config();
|
|
assert_eq!(cfg.apply_simple("", "png", 1), ".png");
|
|
}
|
|
|
|
#[test]
|
|
fn apply_simple_case_lowercase() {
|
|
let mut cfg = default_rename_config();
|
|
cfg.case_mode = 1;
|
|
assert_eq!(cfg.apply_simple("MyPhoto", "JPG", 1), "myphoto.JPG");
|
|
}
|
|
|
|
#[test]
|
|
fn apply_simple_large_counter_padding_capped() {
|
|
let mut cfg = default_rename_config();
|
|
cfg.counter_enabled = true;
|
|
cfg.counter_padding = 100; // should be capped to 10
|
|
cfg.counter_position = 3;
|
|
let result = cfg.apply_simple("photo", "jpg", 1);
|
|
// Counter portion should be at most 10 digits
|
|
assert!(result.len() <= 22); // "photo_" + 10 digits + ".jpg"
|
|
}
|