#![allow(unused_imports, dead_code, unused_variables)] use assert_cmd::Command; use predicates::prelude::*; use std::fs; use std::io::{Read, Write}; use std::os::unix::fs::FileTypeExt; use std::path::Path; use std::process::Command as StdCommand; use tempfile::TempDir; /// Helper to check if we can run loop tests (need root and losetup) fn can_run_loop_test() -> bool { // Check if we are root and losetup exists if unsafe { libc::geteuid() } != 0 { return false; } StdCommand::new("which") .arg("losetup") .output() .map(|o| o.status.success()) .unwrap_or(false) } #[test] #[ignore] fn test_loop_device_zero_wipe() { if !can_run_loop_test() { eprintln!("Skipping loop test: need root and losetup"); return; } let dir = TempDir::new().unwrap(); let img_path = dir.path().join("test.img"); let size = 16 * 1024 * 1024; // 16 MiB // Create image file let file = fs::File::create(&img_path).unwrap(); file.set_len(size as u64).unwrap(); // Attach loop device let output = StdCommand::new("losetup") .args(["--find", "--show", img_path.to_str().unwrap()]) .output() .unwrap(); if !output.status.success() { eprintln!( "losetup failed: {}", String::from_utf8_lossy(&output.stderr) ); return; } let loop_dev = String::from_utf8_lossy(&output.stdout).trim().to_string(); assert!(Path::new(&loop_dev).exists()); // Ensure cleanup let cleanup = || { let _ = StdCommand::new("losetup").args(["-d", &loop_dev]).output(); let _ = fs::remove_file(&img_path); }; // Write known pattern { let mut f = fs::OpenOptions::new().write(true).open(&loop_dev).unwrap(); f.write_all(&vec![0xAB; 1024 * 1024]).unwrap(); f.flush().unwrap(); let _ = StdCommand::new("sync").output(); } // Run wipe with zero method let wipe_bin = assert_cmd::Command::cargo_bin("wipe") .unwrap() .get_program() .to_string_lossy() .to_string(); let output = StdCommand::new(&wipe_bin) .args([ &loop_dev, "--whole-disk", "--method", "zero", "--yes", "--buffer-size", "1M", ]) .output() .unwrap(); if !output.status.success() { eprintln!( "wipe failed: stdout={} stderr={}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr) ); cleanup(); panic!("wipe zero failed"); } // Verify zero { let mut f = fs::File::open(&loop_dev).unwrap(); let mut buf = vec![0u8; 1024 * 1024]; f.read_exact(&mut buf).unwrap(); assert!(buf.iter().all(|&b| b == 0x00), "device not zeroed"); } cleanup(); } #[test] fn test_dry_run_loop_sim_with_file_block() { // This is a lightweight integration test that doesn't need loop device // It tests that dry-run with a real block device (if available) doesn't modify let candidates = ["/dev/loop0", "/dev/loop1", "/dev/sda"]; for cand in candidates { if !Path::new(cand).exists() { continue; } if let Ok(meta) = fs::metadata(cand) { if !meta.file_type().is_block_device() { continue; } let output = Command::cargo_bin("wipe") .unwrap() .args([ cand, "--whole-disk", "--dry-run", "--yes", "--method", "zero", ]) .output() .unwrap(); // Should be success or known safety code, but not crash let code = output.status.code().unwrap_or(1); assert!(code == 0 || (2..=15).contains(&code)); break; } } }