use std::{
fs::OpenOptions,
os::unix::io::AsRawFd,
panic,
path::{Path, PathBuf},
};
use loopdev::{LoopControl, LoopDevice};
use tempfile::{self, TempDir};
use crate::testing::test_lib::clean_up;
pub(crate) struct LoopTestDev {
ld: LoopDevice,
}
impl LoopTestDev {
fn new(lc: &LoopControl, path: &Path) -> LoopTestDev {
OpenOptions::new()
.read(true)
.write(true)
.open(path)
.unwrap();
let ld = lc.next_free().unwrap();
ld.attach_file(path).unwrap();
LoopTestDev { ld }
}
fn path(&self) -> PathBuf {
self.ld.path().unwrap()
}
fn detach(&self) {
self.ld.detach().unwrap()
}
}
impl Drop for LoopTestDev {
fn drop(&mut self) {
self.detach()
}
}
fn get_devices(count: u8, dir: &TempDir) -> Vec<LoopTestDev> {
let lc = LoopControl::open().unwrap();
let mut loop_devices = Vec::new();
for index in 0..count {
let path = dir.path().join(format!("store{}", &index));
let f = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&path)
.unwrap();
nix::unistd::ftruncate(f.as_raw_fd(), 1_000_000_000).unwrap();
f.sync_all().unwrap();
let ltd = LoopTestDev::new(&lc, &path);
loop_devices.push(ltd);
}
loop_devices
}
pub(crate) fn test_with_spec<F>(count: u8, test: F)
where
F: Fn(&[&Path]) + panic::RefUnwindSafe,
{
clean_up().unwrap();
let tmpdir = tempfile::Builder::new()
.prefix("btrfsutil-")
.tempdir()
.unwrap();
let loop_devices: Vec<LoopTestDev> = get_devices(count, &tmpdir);
let device_paths: Vec<PathBuf> = loop_devices.iter().map(|x| x.path()).collect();
let device_paths: Vec<&Path> = device_paths.iter().map(|x| x.as_path()).collect();
let result = panic::catch_unwind(|| test(&device_paths));
let tear_down = clean_up();
result.unwrap();
tear_down.unwrap();
}