use assert_cmd::Command; use std::cmp::max; use std::fs::File; use std::io::Write; use std::path::PathBuf; use std::str; use terminal_size::{terminal_size, Height, Width}; use unicode_width::UnicodeWidthStr; use tempfile::Builder; use tempfile::TempDir; // File sizes differ on both platform and on the format of the disk. // Windows: `ln` is not usually an available command; creation of symbolic links requires special enhanced permissions fn get_width_of_terminal() -> u16 { if let Some((Width(w), Height(_h))) = terminal_size() { max(w, 80) } else { 80 } } // Mac test runners create tmp files with very long names, hence it may be shortened in the output fn get_file_name(name: String) -> String { let terminal_plus_buffer = (get_width_of_terminal() - 14) as usize; if UnicodeWidthStr::width(&*name) > terminal_plus_buffer { let trimmed_name = name .chars() .take(terminal_plus_buffer - 2) .collect::(); trimmed_name + ".." } else { name } } fn build_temp_file(dir: &TempDir) -> PathBuf { let file_path = dir.path().join("notes.txt"); let mut file = File::create(&file_path).unwrap(); writeln!(file, "I am a temp file").unwrap(); file_path } #[cfg_attr(target_os = "windows", ignore)] #[test] pub fn test_soft_sym_link() { let dir = Builder::new().tempdir().unwrap(); let file = build_temp_file(&dir); let dir_s = dir.path().to_str().unwrap(); let file_path_s = file.to_str().unwrap(); let link_name = dir.path().join("the_link"); let link_name_s = link_name.to_str().unwrap(); let c = Command::new("ln") .arg("-s") .arg(file_path_s) .arg(link_name_s) .output(); assert!(c.is_ok()); let c = format!(" ├── {}", get_file_name(link_name_s.into())); let b = format!(" ┌── {}", get_file_name(file_path_s.into())); let a = format!("─┴ {}", dir_s); let mut cmd = Command::cargo_bin("dust").unwrap(); let output = cmd.arg("-p").arg("-c").arg("-s").arg(dir_s).unwrap().stdout; let output = str::from_utf8(&output).unwrap(); assert!(output.contains(a.as_str())); assert!(output.contains(b.as_str())); assert!(output.contains(c.as_str())); } #[cfg_attr(target_os = "windows", ignore)] #[test] pub fn test_hard_sym_link() { let dir = Builder::new().tempdir().unwrap(); let file = build_temp_file(&dir); let dir_s = dir.path().to_str().unwrap(); let file_path_s = file.to_str().unwrap(); let link_name = dir.path().join("the_link"); let link_name_s = link_name.to_str().unwrap(); let c = Command::new("ln") .arg(file_path_s) .arg(link_name_s) .output(); assert!(c.is_ok()); let link_output = format!(" ┌── {}", get_file_name(link_name_s.into())); let file_output = format!(" ┌── {}", get_file_name(file_path_s.into())); let dirs_output = format!("─┴ {}", dir_s); let mut cmd = Command::cargo_bin("dust").unwrap(); let output = cmd.arg("-p").arg("-c").arg(dir_s).unwrap().stdout; // Because this is a hard link the file and hard link look identical. Therefore // we cannot guarantee which version will appear first. let output = str::from_utf8(&output).unwrap(); assert!(output.contains(dirs_output.as_str())); assert!(output.contains(link_output.as_str()) || output.contains(file_output.as_str())); } #[cfg_attr(target_os = "windows", ignore)] #[test] pub fn test_recursive_sym_link() { let dir = Builder::new().tempdir().unwrap(); let dir_s = dir.path().to_str().unwrap(); let link_name = dir.path().join("the_link"); let link_name_s = link_name.to_str().unwrap(); let c = Command::new("ln") .arg("-s") .arg(dir_s) .arg(link_name_s) .output(); assert!(c.is_ok()); let a = format!("─┬ {}", dir_s); let b = format!(" └── {}", get_file_name(link_name_s.into())); let mut cmd = Command::cargo_bin("dust").unwrap(); let output = cmd .arg("-p") .arg("-c") .arg("-r") .arg("-s") .arg(dir_s) .unwrap() .stdout; let output = str::from_utf8(&output).unwrap(); assert!(output.contains(a.as_str())); assert!(output.contains(b.as_str())); }