use rustdupe::duplicates::{DuplicateFinder, FinderConfig};
use rustdupe::scanner::WalkerConfig;
use std::fs::{self, File};
use std::io::Write;
use tempfile::tempdir;
#[test]
fn test_hardlinks_to_same_file_not_counted_as_duplicates() {
let dir = tempdir().unwrap();
let original = dir.path().join("original.txt");
let hardlink = dir.path().join("hardlink.txt");
File::create(&original)
.unwrap()
.write_all(b"identical content")
.unwrap();
if let Err(e) = fs::hard_link(&original, &hardlink) {
eprintln!("Skipping hardlink test: failed to create hardlink: {}", e);
return;
}
let finder = DuplicateFinder::with_defaults();
let (groups, summary) = finder.find_duplicates(dir.path()).unwrap();
if rustdupe::scanner::hardlink::HardlinkTracker::is_supported() {
assert!(
groups.is_empty(),
"Hardlinks should not be counted as duplicates on supported platforms"
);
assert_eq!(summary.total_files, 1);
} else {
assert_eq!(groups.len(), 1);
assert_eq!(summary.total_files, 2);
}
assert_eq!(
summary.duplicate_groups,
if rustdupe::scanner::hardlink::HardlinkTracker::is_supported() {
0
} else {
1
}
);
}
#[test]
fn test_symlinks_not_followed_by_default() {
let dir = tempdir().unwrap();
let original = dir.path().join("original.txt");
let symlink = dir.path().join("symlink.txt");
File::create(&original)
.unwrap()
.write_all(b"content")
.unwrap();
let symlink_res = {
#[cfg(unix)]
{
std::os::unix::fs::symlink(&original, &symlink)
}
#[cfg(windows)]
{
std::os::windows::fs::symlink_file(&original, &symlink)
}
#[cfg(not(any(unix, windows)))]
{
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Unsupported platform",
))
}
};
if let Err(e) = symlink_res {
eprintln!("Skipping symlink test: failed to create symlink: {}", e);
return;
}
let finder = DuplicateFinder::with_defaults();
let (groups, summary) = finder.find_duplicates(dir.path()).unwrap();
assert_eq!(summary.total_files, 1);
assert!(groups.is_empty());
}
#[test]
fn test_symlinks_followed_when_enabled() {
let dir = tempdir().unwrap();
let original = dir.path().join("original.txt");
let symlink = dir.path().join("symlink.txt");
File::create(&original)
.unwrap()
.write_all(b"content")
.unwrap();
let symlink_res = {
#[cfg(unix)]
{
std::os::unix::fs::symlink(&original, &symlink)
}
#[cfg(windows)]
{
std::os::windows::fs::symlink_file(&original, &symlink)
}
#[cfg(not(any(unix, windows)))]
{
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Unsupported platform",
))
}
};
if let Err(e) = symlink_res {
eprintln!("Skipping symlink test: failed to create symlink: {}", e);
return;
}
let walker_config = WalkerConfig::default().with_follow_symlinks(true);
let finder_config = FinderConfig::default().with_walker_config(walker_config);
let finder = DuplicateFinder::new(finder_config);
let (groups, summary) = finder.find_duplicates(dir.path()).unwrap();
if rustdupe::scanner::hardlink::HardlinkTracker::is_supported() {
assert_eq!(summary.total_files, 1);
assert!(groups.is_empty());
} else {
assert_eq!(summary.total_files, 2);
assert_eq!(groups.len(), 1);
}
}
#[test]
fn test_symlink_cycle_detection() {
#[cfg(unix)]
{
let dir = tempdir().unwrap();
let sub = dir.path().join("sub");
fs::create_dir(&sub).unwrap();
let link = sub.join("link");
if let Err(e) = std::os::unix::fs::symlink(&sub, &link) {
eprintln!("Skipping cycle test: failed to create symlink: {}", e);
return;
}
let walker_config = WalkerConfig::default().with_follow_symlinks(true);
let finder_config = FinderConfig::default().with_walker_config(walker_config);
let finder = DuplicateFinder::new(finder_config);
let (groups, summary) = finder.find_duplicates(dir.path()).unwrap();
assert!(groups.is_empty());
assert_eq!(summary.total_files, 0);
}
}