use crate::{UError, UResult}; use std::{env::temp_dir, fs, ops::Drop, os::unix::fs::PermissionsExt, path::PathBuf}; use uuid::Uuid; pub struct TempFile { path: PathBuf, } impl TempFile { pub fn get_path(&self) -> String { self.path.to_string_lossy().to_string() } pub fn new() -> Self { let name = Uuid::simple(&Uuid::new_v4()).to_string(); let mut path = temp_dir(); path.push(name); Self { path } } pub fn write_all(&self, data: &[u8]) -> UResult<()> { fs::write(&self.path, data).map_err(|e| UError::FSError(self.get_path(), e.to_string()))?; Ok(()) } pub fn write_exec(data: &[u8]) -> UResult { let this = Self::new(); let path = this.get_path(); dbg!(&path); this.write_all(data)?; let perms = fs::Permissions::from_mode(0o555); fs::set_permissions(&path, perms).map_err(|e| UError::FSError(path, e.to_string()))?; Ok(this) } } impl Drop for TempFile { fn drop(&mut self) { fs::remove_file(&self.path).unwrap(); } } #[cfg(test)] mod tests { use super::*; use crate::utils::bytes_to_string; use std::path::Path; use std::process::Command; #[test] fn test_file_is_not_busy() { let binary = include_bytes!("../../tests/fixtures/echoer"); for _ in 0..100 { let executable = TempFile::write_exec(binary).unwrap(); let path = executable.get_path(); let result = Command::new(path).arg("qwe").output().unwrap(); assert_eq!(bytes_to_string(result.stdout.as_ref()).trim(), "qwe"); } } #[test] fn test_file_removed_after_dropping() { let path; { let file = TempFile::new(); file.write_all(b"asdqwe").unwrap(); path = file.get_path(); assert!(Path::new(&path).exists()) } assert!(!Path::new(&path).exists()) } }