neue Optionen (-r, Installskript) installiert

This commit is contained in:
Dieter Schlüter 2026-02-10 15:38:53 +01:00
commit d78e318d8a
15 changed files with 273 additions and 42 deletions

View file

@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.0] - 2025-02-10
### ⚠️ BREAKING CHANGES
- **Recursion is now opt-in**: By default, `ntu` only processes the specified
paths and their immediate children. Use `-r`/`--recursive` flag to enable
recursive directory traversal.
- Migration: Add `-r` to existing commands to preserve v0.x behavior
### Added
- **`--conf <FILE>` option**: Specify a single configuration file, bypassing
the default hierarchy (/etc → ~/.config → ./). Errors if file doesn't exist.
- **`-r/--recursive` flag**: Enable recursive directory processing
### Changed
- Default behavior is now non-recursive (use `-r` for recursive processing)
- All integration tests updated to explicitly use `-r` flag
### Migration Guide
```bash
# Old command (v0.x - always recursive):
ntu /path/to/files
# New equivalent (v1.x - explicit recursion):
ntu -r /path/to/files
```
## [0.3.0] - 2025-02-10 ## [0.3.0] - 2025-02-10
### Added ### Added

2
Cargo.lock generated
View file

@ -4,7 +4,7 @@ version = 4
[[package]] [[package]]
name = "NameToUnix" name = "NameToUnix"
version = "0.3.0" version = "1.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assert_cmd", "assert_cmd",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "NameToUnix" name = "NameToUnix"
version = "0.3.0" version = "1.0.0"
edition = "2021" edition = "2021"
authors = ["Dieter Schlüter <dieter.schlueter@linix.de>"] authors = ["Dieter Schlüter <dieter.schlueter@linix.de>"]
description = "Ein Tool zum Anpassen von Verzeichnis- und Dateinamen an Linux-Konventionen" description = "Ein Tool zum Anpassen von Verzeichnis- und Dateinamen an Linux-Konventionen"

View file

@ -27,6 +27,18 @@ Dies ist mein erstes Programm in Rust. (Bitte seid gnädig.)
(c) 2025 Dieter Schlüter <dieter.schlueter@linix.de> (c) 2025 Dieter Schlüter <dieter.schlueter@linix.de>
## ⚠️ BREAKING CHANGE in v1.0.0
**Recursion is now opt-in**: As of version 1.0.0, `ntu` processes only the
specified paths and their immediate children by default. Use the `-r` or
`--recursive` flag to enable recursive directory traversal.
**Migration**: Add `-r` to your existing commands:
```bash
# Old (v0.x): ntu /path/to/files
# New (v1.x): ntu -r /path/to/files
```
## Functions / Funktionen ## Functions / Funktionen
- Replaces spaces and special characters in file and directory names with underscores - Replaces spaces and special characters in file and directory names with underscores
@ -103,30 +115,36 @@ sudo mandb # Update man database
## Usage ## Usage
```bash ```bash
# Basic usage # Basic usage (non-recursive: only immediate children)
ntu /path/to/files ntu /path/to/files
# Recursive processing (process subdirectories)
ntu -r /path/to/files
# Dry-run: only preview the changes without actual renaming # Dry-run: only preview the changes without actual renaming
ntu --dry-run /path/to/files ntu --dry-run -r /path/to/files
ntu -n /path/to/files # Short form ntu -n -r /path/to/files # Short form
# Use specific config file
ntu --conf /path/to/custom.toml /path/to/files
# Process multiple paths # Process multiple paths
ntu /path1 /path2 /path3 ntu -r /path1 /path2 /path3
# Exclude specific files # Exclude specific files
ntu -e "*.tmp" -e "backup_*" /path/to/files ntu -r -e "*.tmp" -e "backup_*" /path/to/files
# Process symlinks and special files (normally skipped) # Process symlinks and special files (normally skipped)
ntu --special /path/to/files ntu -r --special /path/to/files
# Increase verbosity # Increase verbosity
ntu -v /path/to/files ntu -r -v /path/to/files
# Also rename the root directory # Also rename the root directory
ntu --modify-root /path/to/files ntu -r --modify-root /path/to/files
# Combine options # Combine options
ntu --dry-run -v --special /path/to/files ntu --dry-run -r -v --special /path/to/files
``` ```
@ -136,30 +154,36 @@ ntu --dry-run -v --special /path/to/files
## Verwendung ## Verwendung
```bash ```bash
# Grundlegende Verwendung # Grundlegende Verwendung (nicht-rekursiv: nur direkte Kinder)
ntu /pfad/zu/dateien ntu /pfad/zu/dateien
# Rekursive Verarbeitung (Unterverzeichnisse verarbeiten)
ntu -r /pfad/zu/dateien
# Dry-run: Nur Vorschau der Änderungen ohne tatsächliche Umbenennung # Dry-run: Nur Vorschau der Änderungen ohne tatsächliche Umbenennung
ntu --dry-run /pfad/zu/dateien ntu --dry-run -r /pfad/zu/dateien
ntu -n /pfad/zu/dateien # Kurzform ntu -n -r /pfad/zu/dateien # Kurzform
# Spezifische Config-Datei verwenden
ntu --conf /pfad/zu/custom.toml /pfad/zu/dateien
# Mehrere Pfade verarbeiten # Mehrere Pfade verarbeiten
ntu /pfad1 /pfad2 /pfad3 ntu -r /pfad1 /pfad2 /pfad3
# Bestimmte Dateien ausschließen # Bestimmte Dateien ausschließen
ntu -e "*.tmp" -e "backup_*" /pfad/zu/dateien ntu -r -e "*.tmp" -e "backup_*" /pfad/zu/dateien
# Symlinks und Special Files verarbeiten (normalerweise übersprungen) # Symlinks und Special Files verarbeiten (normalerweise übersprungen)
ntu --special /pfad/zu/dateien ntu -r --special /pfad/zu/dateien
# Verbosity erhöhen # Verbosity erhöhen
ntu -v /pfad/zu/dateien ntu -r -v /pfad/zu/dateien
# Auch das Wurzelverzeichnis umbenennen # Auch das Wurzelverzeichnis umbenennen
ntu --modify-root /pfad/zu/dateien ntu -r --modify-root /pfad/zu/dateien
# Optionen kombinieren # Optionen kombinieren
ntu --dry-run -v --special /pfad/zu/dateien ntu --dry-run -r -v --special /pfad/zu/dateien
``` ```

View file

@ -7,6 +7,8 @@ _ntu() {
typeset -A opt_args typeset -A opt_args
_arguments -C \ _arguments -C \
'(-r --recursive)'{-r,--recursive}'[Process directories recursively]' \
'--conf[Use specific configuration file]:config file:_files' \
'(-n --dry-run --no-changes)'{-n,--dry-run,--no-changes}'[Only preview changes without renaming]' \ '(-n --dry-run --no-changes)'{-n,--dry-run,--no-changes}'[Only preview changes without renaming]' \
'(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \
'(-f --force)'{-f,--force}'[Overwrite existing files]' \ '(-f --force)'{-f,--force}'[Overwrite existing files]' \
@ -14,6 +16,7 @@ _ntu() {
'(-v --verbose)'{-v,--verbose}'[Verbose debug output]' \ '(-v --verbose)'{-v,--verbose}'[Verbose debug output]' \
'--modify-root[Also rename root directory]' \ '--modify-root[Also rename root directory]' \
'--special[Process symlinks and special files]' \ '--special[Process symlinks and special files]' \
'--no-color[Disable colored output]' \
'(-h --help)'{-h,--help}'[Print help]' \ '(-h --help)'{-h,--help}'[Print help]' \
'(-V --version)'{-V,--version}'[Print version]' \ '(-V --version)'{-V,--version}'[Print version]' \
'*:path:_files' '*:path:_files'

View file

@ -7,7 +7,7 @@ _ntu_completion() {
prev="${COMP_WORDS[COMP_CWORD-1]}" prev="${COMP_WORDS[COMP_CWORD-1]}"
# All available options # All available options
opts="--dry-run --no-changes --quiet --force --exclude --verbose --modify-root --special --help --version -n -q -f -e -v -h -V" opts="--recursive --conf --dry-run --no-changes --quiet --force --exclude --verbose --modify-root --special --no-color --help --version -r -n -q -f -e -v -h -V"
# Handle options that require arguments # Handle options that require arguments
case "${prev}" in case "${prev}" in
@ -16,6 +16,11 @@ _ntu_completion() {
COMPREPLY=( $(compgen -W '"*.tmp" "*.log" "*.bak" "*.swp" "*~"' -- ${cur}) ) COMPREPLY=( $(compgen -W '"*.tmp" "*.log" "*.bak" "*.swp" "*~"' -- ${cur}) )
return 0 return 0
;; ;;
--conf)
# Suggest files for config option
COMPREPLY=( $(compgen -f -- ${cur}) )
return 0
;;
*) *)
;; ;;
esac esac

View file

@ -4,6 +4,8 @@
complete -c ntu -f -d 'Sanitize file and directory names to Unix conventions' complete -c ntu -f -d 'Sanitize file and directory names to Unix conventions'
# Options # Options
complete -c ntu -s r -l recursive -d 'Process directories recursively'
complete -c ntu -l conf -d 'Use specific configuration file' -r -F
complete -c ntu -s q -l quiet -d 'Suppress output (no rename information)' complete -c ntu -s q -l quiet -d 'Suppress output (no rename information)'
complete -c ntu -s n -l dry-run -d 'Show what would be renamed without making changes' complete -c ntu -s n -l dry-run -d 'Show what would be renamed without making changes'
complete -c ntu -l no-changes -d 'Alias for --dry-run' complete -c ntu -l no-changes -d 'Alias for --dry-run'

View file

@ -1,10 +1,10 @@
# Willkommen bei meinem Projekt # Willkommen bei meinem Projekt
NameToUnix - Rust Command line tool for cleaning up directory & file names according to Linux conventions. Recursively replacing offending characters or spaces. NameToUnix - Rust Command line tool for cleaning up directory & file names according to Linux conventions. Replacing offending characters or spaces (recursive with `-r` flag).
Dieses Projekt bietet unter Linux eine einfache Lösung für das automatische Umbenennen von Verzeichnissen und Dateien nach dem Entpacken von gezippten Windows-Dateien mit Leerzeichen oder Sonderzeichen im Namen. Dieses Projekt bietet unter Linux eine einfache Lösung für das automatische Umbenennen von Verzeichnissen und Dateien nach dem Entpacken von gezippten Windows-Dateien mit Leerzeichen oder Sonderzeichen im Namen.
## Zielsetzung ## Zielsetzung
Das Ziel ist es, diese unkonventionellen Dateinamen rekursiv und automatisch sinnvoll umzubenennen. Das Ziel ist es, diese unkonventionellen Dateinamen automatisch sinnvoll umzubenennen. Ab v1.0.0 ist die rekursive Verarbeitung opt-in (`-r` Flag erforderlich).
## Inhaltsverzeichnis ## Inhaltsverzeichnis

64
install.sh Executable file
View file

@ -0,0 +1,64 @@
#!/bin/bash
# Installation script for ntu (NameToUnix)
set -e
echo "=== NameToUnix Installation ==="
echo
# Check if binary exists
if [ ! -f "target/release/ntu" ]; then
echo "Error: Binary not found. Please run 'cargo build --release' first."
exit 1
fi
# Install binary
echo "Installing binary..."
sudo cp target/release/ntu /usr/local/bin/
sudo chmod 755 /usr/local/bin/ntu
echo "✓ Binary installed to /usr/local/bin/ntu"
# Install man page
echo "Installing man page..."
sudo cp man/ntu.1 /usr/share/man/man1/
sudo chmod 644 /usr/share/man/man1/ntu.1
sudo mandb -q
echo "✓ Man page installed to /usr/share/man/man1/ntu.1"
# Install config (user-specific)
echo "Installing configuration..."
mkdir -p ~/.config/NameToUnix/
cp .NameToUnix.conf ~/.config/NameToUnix/config.toml
echo "✓ Config installed to ~/.config/NameToUnix/config.toml"
# Install shell completions
echo "Installing shell completions..."
# Bash
if [ -d "/etc/bash_completion.d" ]; then
sudo cp completions/ntu.bash /etc/bash_completion.d/ntu
echo "✓ Bash completion installed"
fi
# Zsh
if [ -d "/usr/share/zsh/site-functions" ]; then
sudo cp completions/_ntu /usr/share/zsh/site-functions/_ntu
echo "✓ Zsh completion installed"
fi
# Fish
if [ -d "/usr/share/fish/vendor_completions.d" ]; then
sudo cp completions/ntu.fish /usr/share/fish/vendor_completions.d/ntu.fish
echo "✓ Fish completion installed"
fi
echo
echo "=== Installation complete ==="
echo
echo "Test the installation:"
echo " ntu --version"
echo " man ntu"
echo
echo "For shell completions to work, restart your shell or run:"
echo " source ~/.bashrc (Bash)"
echo " source ~/.zshrc (Zsh)"

View file

@ -1,4 +1,4 @@
.TH NTU 1 "2025-02-10" "NameToUnix 0.3.0" "User Commands" .TH NTU 1 "2025-02-10" "NameToUnix 1.0.0" "User Commands"
.SH NAME .SH NAME
ntu \- sanitize file and directory names to Unix conventions ntu \- sanitize file and directory names to Unix conventions
.SH SYNOPSIS .SH SYNOPSIS
@ -11,11 +11,19 @@ to make them compatible with Unix/Linux naming conventions. It replaces
spaces with underscores, converts German umlauts to their ASCII equivalents, spaces with underscores, converts German umlauts to their ASCII equivalents,
and removes or replaces problematic special characters. and removes or replaces problematic special characters.
.PP .PP
The tool processes files recursively, starting from the deepest level to By default, the tool processes only the specified paths and their immediate
avoid conflicts with parent directory renames. It preserves file extensions, children. Use the \fB\-r\fR flag to enable recursive processing of subdirectories.
including double extensions like .tar.gz, and handles hidden files correctly. When recursive, it starts from the deepest level to avoid conflicts with parent
directory renames. It preserves file extensions, including double extensions
like .tar.gz, and handles hidden files correctly.
.SH OPTIONS .SH OPTIONS
.TP .TP
.BR \-r ", " \-\-recursive
Process directories recursively (default: only immediate children)
.TP
.BR \-\-conf " \fIFILE\fR"
Use a specific configuration file instead of the default hierarchy
.TP
.BR \-q ", " \-\-quiet .BR \-q ", " \-\-quiet
Suppress output (no rename information on stdout) Suppress output (no rename information on stdout)
.TP .TP

View file

@ -13,6 +13,14 @@ pub struct Cli {
/// Pfade (Dateien und Verzeichnisse) zum rekursiven Anpassen /// Pfade (Dateien und Verzeichnisse) zum rekursiven Anpassen
pub paths: Vec<PathBuf>, pub paths: Vec<PathBuf>,
/// Explizite Konfigurationsdatei (bypassed Standard-Hierarchie)
#[clap(long = "conf", value_name = "FILE")]
pub config_file: Option<PathBuf>,
/// Rekursive Verarbeitung von Unterverzeichnissen aktivieren
#[clap(short = 'r', long)]
pub recursive: bool,
/// Ausgaben unterdrücken (keine Umbenennungsinfos auf stdout) /// Ausgaben unterdrücken (keine Umbenennungsinfos auf stdout)
#[clap(short, long)] #[clap(short, long)]
pub quiet: bool, pub quiet: bool,

View file

@ -57,6 +57,19 @@ impl Config {
} }
} }
} }
/// Lädt Konfiguration aus spezifischer Datei (fehlschlägt bei nicht-existierender Datei)
pub fn from_file(path: &Path, verbose: bool) -> Result<Self> {
if !path.exists() {
return Err(anyhow::anyhow!(
"Konfigurationsdatei nicht gefunden: {}",
path.display()
));
}
Self::load_internal(path, verbose)
}
/// Sucht nach Konfigurationsdateien in verschiedenen Orten und kombiniert sie /// Sucht nach Konfigurationsdateien in verschiedenen Orten und kombiniert sie
pub fn from_default_locations(verbose: bool) -> Result<Self> { pub fn from_default_locations(verbose: bool) -> Result<Self> {
// Prioritätenreihenfolge (später überschreibt früher): // Prioritätenreihenfolge (später überschreibt früher):

View file

@ -60,9 +60,13 @@ fn main() -> Result<()> {
colored::control::set_override(false); colored::control::set_override(false);
} }
// Optional Konfigurationsdatei laden // Config-Datei laden: entweder --conf oder Standard-Hierarchie
let config = Config::from_default_locations(args.verbose)?; let config = if let Some(config_path) = &args.config_file {
// let config = Config::load(".NameToUnix.conf", args.verbose)?; Config::from_file(config_path, args.verbose)
.with_context(|| format!("Fehler beim Laden der Konfiguration: {}", config_path.display()))?
} else {
Config::from_default_locations(args.verbose)?
};
// Ausschlussmuster (Glob-Patterns) vorbereiten - Default-Excludes + User-Excludes // Ausschlussmuster (Glob-Patterns) vorbereiten - Default-Excludes + User-Excludes
let mut all_excludes = DEFAULT_EXCLUDES let mut all_excludes = DEFAULT_EXCLUDES
@ -90,7 +94,16 @@ fn main() -> Result<()> {
for path in &args.paths { for path in &args.paths {
// Alle Einträge sammeln, damit zuerst die tiefsten umbenannt werden // Alle Einträge sammeln, damit zuerst die tiefsten umbenannt werden
let mut entries = Vec::new(); let mut entries = Vec::new();
for entry_result in WalkDir::new(path)
let walker = if args.recursive {
// Recursive: unbegrenzte Tiefe
WalkDir::new(path)
} else {
// Non-recursive: max_depth(1) verarbeitet nur direkte Kinder
WalkDir::new(path).max_depth(1)
};
for entry_result in walker
.into_iter() .into_iter()
.filter_entry(|e| !is_excluded(e, &exclude_patterns)) .filter_entry(|e| !is_excluded(e, &exclude_patterns))
{ {

View file

@ -1 +1 @@
{"rustc_fingerprint":18315677830234863098,"outputs":{"8185672236408668984":{"success":true,"status":"","code":0,"stdout":"rustc 1.90.0 (1159e78c4 2025-09-14)\nbinary: rustc\ncommit-hash: 1159e78c4747b02ef996e55082b704c09b970588\ncommit-date: 2025-09-14\nhost: x86_64-unknown-linux-gnu\nrelease: 1.90.0\nLLVM version: 20.1.8\n","stderr":""},"11742744481059712885":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/dschlueter/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}} {"rustc_fingerprint":4740973386762217857,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.90.0 (1159e78c4 2025-09-14)\nbinary: rustc\ncommit-hash: 1159e78c4747b02ef996e55082b704c09b970588\ncommit-date: 2025-09-14\nhost: x86_64-unknown-linux-gnu\nrelease: 1.90.0\nLLVM version: 20.1.8\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/dschlueter/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}

View file

@ -30,7 +30,7 @@ fn test_dry_run_no_changes() {
fs::write(&file_path, "test content").unwrap(); fs::write(&file_path, "test content").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu")); let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg("--dry-run").arg(temp_dir.path()); cmd.arg("--dry-run").arg("-r").arg(temp_dir.path());
cmd.assert().success(); cmd.assert().success();
// File should still have spaces (not renamed) // File should still have spaces (not renamed)
@ -45,7 +45,7 @@ fn test_actual_rename() {
fs::write(&file_path, "test content").unwrap(); fs::write(&file_path, "test content").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu")); let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg(temp_dir.path()); cmd.arg("-r").arg(temp_dir.path());
cmd.assert().success(); cmd.assert().success();
// File should be renamed // File should be renamed
@ -60,7 +60,7 @@ fn test_hidden_files_preserved() {
fs::write(&file_path, "*.tmp").unwrap(); fs::write(&file_path, "*.tmp").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu")); let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg(temp_dir.path()); cmd.arg("-r").arg(temp_dir.path());
cmd.assert().success(); cmd.assert().success();
// Hidden file should not be renamed // Hidden file should not be renamed
@ -74,7 +74,7 @@ fn test_hidden_file_with_spaces() {
fs::write(&file_path, "config content").unwrap(); fs::write(&file_path, "config content").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu")); let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg(temp_dir.path()); cmd.arg("-r").arg(temp_dir.path());
cmd.assert().success(); cmd.assert().success();
// Hidden file should be renamed but keep leading dot // Hidden file should be renamed but keep leading dot
@ -89,7 +89,7 @@ fn test_umlaut_conversion() {
fs::write(&file_path, "test").unwrap(); fs::write(&file_path, "test").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu")); let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg(temp_dir.path()); cmd.arg("-r").arg(temp_dir.path());
cmd.assert().success(); cmd.assert().success();
// Umlaut should be converted // Umlaut should be converted
@ -104,7 +104,7 @@ fn test_double_extension() {
fs::write(&file_path, "archive").unwrap(); fs::write(&file_path, "archive").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu")); let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg(temp_dir.path()); cmd.arg("-r").arg(temp_dir.path());
cmd.assert().success(); cmd.assert().success();
// Should keep .tar.gz intact // Should keep .tar.gz intact
@ -123,6 +123,7 @@ fn test_exclude_pattern() {
let mut cmd = Command::new(cargo_bin!("ntu")); let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg("--exclude") cmd.arg("--exclude")
.arg("*.tmp") .arg("*.tmp")
.arg("-r")
.arg(temp_dir.path()); .arg(temp_dir.path());
cmd.assert().success(); cmd.assert().success();
@ -139,7 +140,7 @@ fn test_quiet_mode() {
fs::write(&file_path, "test").unwrap(); fs::write(&file_path, "test").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu")); let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg("--quiet").arg(temp_dir.path()); cmd.arg("--quiet").arg("-r").arg(temp_dir.path());
cmd.assert() cmd.assert()
.success() .success()
.stdout(predicate::str::is_empty()); .stdout(predicate::str::is_empty());
@ -155,7 +156,7 @@ fn test_multiple_paths() {
fs::write(&file2, "test2").unwrap(); fs::write(&file2, "test2").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu")); let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg(temp_dir1.path()).arg(temp_dir2.path()); cmd.arg("-r").arg(temp_dir1.path()).arg(temp_dir2.path());
cmd.assert().success(); cmd.assert().success();
// Both files should be renamed // Both files should be renamed
@ -170,7 +171,7 @@ fn test_parentheses_removed() {
fs::write(&file_path, "test").unwrap(); fs::write(&file_path, "test").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu")); let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg(temp_dir.path()); cmd.arg("-r").arg(temp_dir.path());
cmd.assert().success(); cmd.assert().success();
// Parentheses should be replaced with underscores // Parentheses should be replaced with underscores
@ -185,10 +186,74 @@ fn test_special_identifiers_preserved() {
fs::write(&file_path, "test").unwrap(); fs::write(&file_path, "test").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu")); let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg(temp_dir.path()); cmd.arg("-r").arg(temp_dir.path());
cmd.assert().success(); cmd.assert().success();
// C++ should be preserved // C++ should be preserved
assert!(!file_path.exists()); assert!(!file_path.exists());
assert!(temp_dir.path().join("C++_Guide.pdf").exists()); assert!(temp_dir.path().join("C++_Guide.pdf").exists());
} }
#[test]
fn test_non_recursive_default() {
let temp_dir = TempDir::new().unwrap();
fs::create_dir(temp_dir.path().join("subdir")).unwrap();
let file1 = temp_dir.path().join("top file.txt");
let file2 = temp_dir.path().join("subdir").join("nested file.txt");
fs::write(&file1, "test1").unwrap();
fs::write(&file2, "test2").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg(temp_dir.path());
cmd.assert().success();
// Top-Level umbenannt
assert!(temp_dir.path().join("top_file.txt").exists());
// Nested NICHT umbenannt (non-recursive)
assert!(file2.exists());
}
#[test]
fn test_recursive_flag() {
let temp_dir = TempDir::new().unwrap();
fs::create_dir(temp_dir.path().join("subdir")).unwrap();
let file1 = temp_dir.path().join("top file.txt");
let file2 = temp_dir.path().join("subdir").join("nested file.txt");
fs::write(&file1, "test1").unwrap();
fs::write(&file2, "test2").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg("-r").arg(temp_dir.path());
cmd.assert().success();
// Beide umbenannt
assert!(temp_dir.path().join("top_file.txt").exists());
assert!(temp_dir.path().join("subdir").join("nested_file.txt").exists());
}
#[test]
fn test_conf_option_valid_file() {
let temp_dir = TempDir::new().unwrap();
let config_file = temp_dir.path().join("custom.toml");
fs::write(&config_file, "[replacements]\n\"test\" = \"xyz\"").unwrap();
let file_path = temp_dir.path().join("test_file.txt");
fs::write(&file_path, "content").unwrap();
let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg("--conf").arg(&config_file).arg(temp_dir.path());
cmd.assert().success();
assert!(temp_dir.path().join("xyz_file.txt").exists());
}
#[test]
fn test_conf_option_missing_file() {
let temp_dir = TempDir::new().unwrap();
let nonexistent = temp_dir.path().join("nonexistent.toml");
let mut cmd = Command::new(cargo_bin!("ntu"));
cmd.arg("--conf").arg(&nonexistent).arg(temp_dir.path());
cmd.assert()
.failure()
.stderr(predicate::str::contains("nicht gefunden"));
}