From b8155698b5f652382b86ec27a02f0991d46008eb Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Thu, 5 Nov 2026 07:49:25 -0800 Subject: [PATCH] Remove temporary test files after failures --- Cargo.lock | 2 ++ apps/vectorcraft-cli/Cargo.toml | 1 + apps/vectorcraft/Cargo.toml | 1 + apps/vectorcraft/src/clipboard.rs | 25 ++++++++++------ apps/vectorcraft/src/compositor_gpu.rs | 18 ++++++------ apps/vectorcraft/src/gpu/tests.rs | 38 ++++++++++++++++--------- apps/vectorcraft/src/host_services.rs | 38 +++++++------------------ apps/vectorcraft/src/logging/tests.rs | 29 +++++++++++++++---- apps/vectorcraft/src/mac_fonts.rs | 6 ++-- apps/vectorcraft/src/prefs.rs | 6 ++-- apps/vectorcraft/src/profile.rs | 25 +++++++++++----- apps/vectorcraft/src/single_instance.rs | 33 +++++++++++---------- apps/vectorcraft/src/system_fonts.rs | 5 ++-- apps/vectorcraft/src/tests.rs | 6 ++-- 14 files changed, 131 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae8a3ee6c..fcb4c1124 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6100,6 +6100,7 @@ dependencies = [ "serde_json", "smithay-clipboard", "socket2", + "tempfile", "vectorcraft-engine", "vectorcraft-render", "vectorcraft-text", @@ -6163,6 +6164,7 @@ dependencies = [ "objc2-core-foundation", "objc2-core-text", "serde_json", + "tempfile", "vectorcraft-color", "vectorcraft-doc", "vectorcraft-engine", diff --git a/apps/vectorcraft-cli/Cargo.toml b/apps/vectorcraft-cli/Cargo.toml index 8f39e3b58..f7faf7a92 100644 --- a/apps/vectorcraft-cli/Cargo.toml +++ b/apps/vectorcraft-cli/Cargo.toml @@ -45,5 +45,6 @@ objc2-core-foundation = { version = "0.3", default-features = false, features = objc2-core-text = { version = "0.3", default-features = false, features = ["std", "CTFontManager"] } [dev-dependencies] +tempfile = "3" vectorcraft-testkit = { workspace = true } serde_json = { workspace = true } diff --git a/apps/vectorcraft/Cargo.toml b/apps/vectorcraft/Cargo.toml index f46213231..170a7e5c7 100644 --- a/apps/vectorcraft/Cargo.toml +++ b/apps/vectorcraft/Cargo.toml @@ -119,6 +119,7 @@ zbus = "=5.19.0" winresource = "0.1" [dev-dependencies] +tempfile = "3" # Bound socket buffers in real loopback transport deadline regressions. socket2 = { workspace = true } # src/portal_save.rs's tests build and read the portal's D-Bus values on every system. diff --git a/apps/vectorcraft/src/clipboard.rs b/apps/vectorcraft/src/clipboard.rs index 1c0b4cd3c..b9be30689 100644 --- a/apps/vectorcraft/src/clipboard.rs +++ b/apps/vectorcraft/src/clipboard.rs @@ -978,10 +978,17 @@ mod tests { use super::*; - fn dir(name: &str) -> PathBuf { - let d = std::env::temp_dir().join(format!("vectorcraft-clipboard-{name}-{}", std::process::id())); - std::fs::create_dir_all(&d).unwrap(); - d + fn dir(name: &str) -> tempfile::TempDir { + tempfile::Builder::new().prefix(&format!("vectorcraft-clipboard-{name}-")).tempdir().unwrap() + } + + #[test] + fn test_directory_is_removed_when_its_handle_is_dropped() { + let dir = dir("cleanup"); + let path = dir.path().to_path_buf(); + assert!(path.exists()); + drop(dir); + assert!(!path.exists()); } fn png(w: u32, h: u32) -> Vec { @@ -993,12 +1000,12 @@ mod tests { #[test] fn the_first_copied_file_that_is_art_pastes() { let d = dir("art"); - let (notes, red, art) = (d.join("notes.txt"), d.join("red image.png"), d.join("art.svg")); + let (notes, red, art) = (d.path().join("notes.txt"), d.path().join("red image.png"), d.path().join("art.svg")); std::fs::write(¬es, "not art").unwrap(); std::fs::write(&red, png(3, 2)).unwrap(); std::fs::write(&art, "").unwrap(); // Missing files, folders and text are skipped. - let f = copied_file(vec![d.join("gone.png"), d.clone(), notes.clone(), red.clone(), art.clone()], &PASTE_ORDER).unwrap(); + let f = copied_file(vec![d.path().join("gone.png"), d.path().to_path_buf(), notes.clone(), red.clone(), art.clone()], &PASTE_ORDER).unwrap(); assert_eq!((f.mime, f.data), (PNG, png(3, 2))); assert_eq!(copied_file(vec![art.clone(), red.clone()], &PASTE_ORDER).map(|f| f.mime), Some(SVG)); // Only what Paste asks for. @@ -1032,7 +1039,8 @@ mod tests { /// An .eps file copied in a file manager pastes as EPS. #[test] fn a_copied_eps_file_pastes() { - let eps = dir("eps").join("equation.eps"); + let d = dir("eps"); + let eps = d.path().join("equation.eps"); std::fs::write(&eps, "%!PS-Adobe-3.0 EPSF-3.0\n%%BoundingBox: 0 0 10 10\n0 0 10 10 rectfill\n").unwrap(); assert_eq!(copied_file(vec![eps.clone()], &PASTE_ORDER).map(|f| f.mime), Some(EPS)); assert!(copied_file(vec![eps], &[BITMAP, TEXT]).is_none()); @@ -1040,7 +1048,8 @@ mod tests { #[test] fn a_crlf_left_by_the_uri_list_is_ignored() { - let red = dir("crlf").join("red.png"); + let d = dir("crlf"); + let red = d.path().join("red.png"); std::fs::write(&red, png(2, 2)).unwrap(); let with_cr = PathBuf::from(format!("{}\r", red.display())); assert_eq!(copied_file(vec![with_cr], &PASTE_ORDER).map(|f| f.mime), Some(PNG)); diff --git a/apps/vectorcraft/src/compositor_gpu.rs b/apps/vectorcraft/src/compositor_gpu.rs index 90e675b7f..a5d6ae85e 100644 --- a/apps/vectorcraft/src/compositor_gpu.rs +++ b/apps/vectorcraft/src/compositor_gpu.rs @@ -150,18 +150,16 @@ mod tests { #[cfg(target_os = "linux")] #[test] fn the_gpu_behind_a_device_number_comes_from_sysfs() -> std::io::Result<()> { - let dir = std::env::temp_dir().join(format!("vectorcraft-dev-char-{}", std::process::id())); - let _ = std::fs::remove_dir_all(&dir); + let dir = tempfile::Builder::new().prefix("vectorcraft-dev-char-").tempdir()?; // /sys/dev/char/226:128 links to the render node, whose `device` is the PCI GPU. - std::fs::create_dir_all(dir.join("226:128/device"))?; - std::fs::write(dir.join("226:128/device/vendor"), "0x10de\n")?; - std::fs::write(dir.join("226:128/device/device"), "0x25ac\n")?; + std::fs::create_dir_all(dir.path().join("226:128/device"))?; + std::fs::write(dir.path().join("226:128/device/vendor"), "0x10de\n")?; + std::fs::write(dir.path().join("226:128/device/device"), "0x25ac\n")?; // A device that isn't a PCI GPU (a virtual one) has no ids. - std::fs::create_dir_all(dir.join("226:0/device"))?; - let render = super::pci_ids(&dir, makedev(226, 128)); - let virtual_gpu = super::pci_ids(&dir, makedev(226, 0)); - let missing = super::pci_ids(&dir, makedev(226, 1)); - std::fs::remove_dir_all(&dir)?; + std::fs::create_dir_all(dir.path().join("226:0/device"))?; + let render = super::pci_ids(dir.path(), makedev(226, 128)); + let virtual_gpu = super::pci_ids(dir.path(), makedev(226, 0)); + let missing = super::pci_ids(dir.path(), makedev(226, 1)); assert_eq!(render, Some((0x10de, 0x25ac))); assert_eq!(virtual_gpu, None); assert_eq!(missing, None); diff --git a/apps/vectorcraft/src/gpu/tests.rs b/apps/vectorcraft/src/gpu/tests.rs index 40d84934f..40e6a555c 100644 --- a/apps/vectorcraft/src/gpu/tests.rs +++ b/apps/vectorcraft/src/gpu/tests.rs @@ -242,8 +242,8 @@ fn internal_panels_are_edp_lvds_and_dsi_connectors() { /// PCI ids. Each GPU is listed once, the one with the panel as primary. #[test] fn linux_display_gpus_come_from_the_connected_connectors() -> std::io::Result<()> { - let dir = std::env::temp_dir().join(format!("vectorcraft-drm-{}", std::process::id())); - let _ = std::fs::remove_dir_all(&dir); + let temp = tempfile::Builder::new().prefix("vectorcraft-drm-").tempdir()?; + let dir = temp.path(); let card = |name: &str, (vendor, device): (u32, u32)| -> std::io::Result<()> { std::fs::create_dir_all(dir.join(name).join("device"))?; std::fs::write(dir.join(name).join("device/vendor"), format!("{vendor:#06x}\n"))?; @@ -262,11 +262,11 @@ fn linux_display_gpus_come_from_the_connected_connectors() -> std::io::Result<() connector("card1-DP-2", "connected")?; connector("card2-Virtual-1", "connected")?; std::fs::write(dir.join("renderD128"), "")?; - let mut gpus = linux_display_gpus(&dir); + let mut gpus = linux_display_gpus(dir); gpus.sort_by_key(|g| g.pci); assert_eq!(gpus, [primary(AMD_IGPU), monitor(NVIDIA_3090)]); assert!(linux_display_gpus(&dir.join("no such dir")).is_empty()); - std::fs::remove_dir_all(&dir) + Ok(()) } #[test] @@ -616,11 +616,26 @@ fn a_normal_exit_or_another_failure_does_not_restart() { /// A log folder of its own for each test, and the guard that keeps other tests from starting a /// program while it runs: the test releases the start file's lock and takes it again, and a child /// starting meanwhile would keep it held (`crate::no_spawns`). -fn start_dir(tag: &str) -> (std::path::PathBuf, std::sync::RwLockReadGuard<'static, ()>) { +struct TestDir(tempfile::TempDir); + +impl std::ops::Deref for TestDir { + type Target = std::path::Path; + + fn deref(&self) -> &Self::Target { + self.0.path() + } +} + +impl AsRef for TestDir { + fn as_ref(&self) -> &std::path::Path { + self.0.path() + } +} + +fn start_dir(tag: &str) -> (TestDir, std::sync::RwLockReadGuard<'static, ()>) { let spawns = crate::no_spawns(); - let d = std::env::temp_dir().join(format!("vectorcraft-gpu-start-{tag}-{}", std::process::id())); - let _ = std::fs::remove_dir_all(&d); - (d, spawns) + let dir = tempfile::Builder::new().prefix(&format!("vectorcraft-gpu-start-{tag}-")).tempdir().unwrap(); + (TestDir(dir), spawns) } /// What a start in `dir` leaves out; it then ends without crashing. @@ -670,7 +685,6 @@ fn a_start_that_never_showed_a_frame_leaves_its_adapter_out_of_the_next() { assert_eq!(left_out.adapters, ["Dx12:8086:3184"], "kept"); assert_eq!(left_out.crash, None, "the note is shown once"); third.ended(); - let _ = std::fs::remove_dir_all(&dir); } /// A start whose first frame reached the screen, or that ended without crashing (a normal exit, @@ -693,7 +707,6 @@ fn a_start_that_showed_its_first_frame_or_ended_is_cleared() { assert!(finish(Ok(Ok(())), &first).is_ok()); drop(first); assert_eq!(next_start(&dir, false), LeftOut::default()); - let _ = std::fs::remove_dir_all(&dir); } /// The process ended while the adapters were being listed (wgpu's DX12 backend creates a @@ -721,7 +734,6 @@ fn a_crash_while_listing_lists_opengl_alone() { second.none_left(); second.ended(); assert_eq!(next_start(&dir, false), LeftOut::default()); - let _ = std::fs::remove_dir_all(&dir); } /// `WGPU_BACKEND` or `WGPU_ADAPTER_NAME` choose for a start whatever crashed before; when that @@ -742,7 +754,6 @@ fn wgpu_backend_or_adapter_name_ignores_the_crashes() { explicit.picked(&c[0].key, &c[0].name, true); explicit.presented(); assert_eq!(next_start(&dir, false), LeftOut::default(), "a new driver shows the window"); - let _ = std::fs::remove_dir_all(&dir); } /// A damaged record, a file that can't be opened and one another starting copy of the app holds @@ -777,10 +788,9 @@ fn a_damaged_or_unreadable_start_file_is_ignored() { assert_eq!(next_start(&dir, false).adapters, ["Dx12:8086:3184"]); // A folder in the file's place. - let _ = std::fs::remove_dir_all(&dir); + std::fs::remove_file(dir.join(START_FILE)).unwrap(); std::fs::create_dir_all(dir.join(START_FILE)).unwrap(); assert_eq!(next_start(&dir, false), LeftOut::default()); - let _ = std::fs::remove_dir_all(&dir); } #[test] diff --git a/apps/vectorcraft/src/host_services.rs b/apps/vectorcraft/src/host_services.rs index 21a94feb1..978308b9e 100644 --- a/apps/vectorcraft/src/host_services.rs +++ b/apps/vectorcraft/src/host_services.rs @@ -214,22 +214,9 @@ fn read_file_head(path: &str, max: usize) -> Result, String> { #[test] fn read_file_head_reads_no_more_than_it_is_asked_for() { use std::io::Write as _; - /// Removes the file when the test ends, a failed assertion included. - struct Remove(std::path::PathBuf); - impl Drop for Remove { - fn drop(&mut self) { - let _ = std::fs::remove_file(&self.0); - } - } - let path = std::env::temp_dir().join(format!("vectorcraft-read-head-{}", std::process::id())); - // A leftover file or link at the path is removed (never followed), and the new file is created - // exclusively. - let _ = std::fs::remove_file(&path); - let mut f = std::fs::OpenOptions::new().write(true).create_new(true).open(&path).unwrap(); - let guard = Remove(path); + let mut f = tempfile::Builder::new().prefix("vectorcraft-read-head-").tempfile().unwrap(); f.write_all(b"0123456789").unwrap(); - drop(f); - let p = guard.0.to_string_lossy(); + let p = f.path().to_string_lossy(); assert_eq!(read_file_head(&p, 4).unwrap(), b"0123"); assert_eq!(read_file_head(&p, 20).unwrap(), b"0123456789", "a shorter file is read whole"); assert!(read_file_head(&std::env::temp_dir().to_string_lossy(), 4).is_err(), "a folder is not read"); @@ -608,22 +595,20 @@ mod open_with_tests { use super::{check_app, find_photocraft, photocraft_candidates, registered_path, windows_candidates}; /// A fresh, empty folder under the system's temporary folder. - fn scratch(name: &str) -> std::path::PathBuf { - let d = std::env::temp_dir().join(format!("vc-open-with-{name}-{}", std::process::id())); - let _ = std::fs::remove_dir_all(&d); - std::fs::create_dir_all(&d).unwrap(); - d + fn scratch(name: &str) -> tempfile::TempDir { + tempfile::Builder::new().prefix(&format!("vc-open-with-{name}-")).tempdir().unwrap() } /// #5236: only an application counts as PhotoCraft, never a document, a folder or a missing /// path. #[test] fn only_applications_are_started() { - let d = scratch("check"); + let temp = scratch("check"); + let d = temp.path(); let doc = d.join("notes.txt"); std::fs::write(&doc, "hi").unwrap(); assert!(check_app(&doc).is_err(), "a document"); - assert!(check_app(&d).is_err(), "a folder"); + assert!(check_app(d).is_err(), "a folder"); assert!(check_app(&d.join("Missing.app")).is_err(), "a missing path"); if cfg!(target_os = "macos") { let app = d.join("Editor.app"); @@ -639,19 +624,19 @@ mod open_with_tests { std::fs::set_permissions(&tool, std::fs::Permissions::from_mode(0o755)).unwrap(); assert!(check_app(&tool).is_ok(), "an executable file"); } - let _ = std::fs::remove_dir_all(&d); } /// PhotoCraft is looked for only where it installs. #[test] fn photocraft_is_found_where_it_installs() { - let d = scratch("find"); + let temp = scratch("find"); + let d = temp.path(); if cfg!(target_os = "macos") { - let candidates = photocraft_candidates(Some(&d), None); + let candidates = photocraft_candidates(Some(d), None); assert_eq!(candidates.first().map(|p| p.to_string_lossy().into_owned()).as_deref(), Some("/Applications/PhotoCraft.app")); assert!(candidates.contains(&d.join("Applications/PhotoCraft.app")), "{candidates:?}"); std::fs::create_dir_all(d.join("Applications/PhotoCraft.app")).unwrap(); - assert!(find_photocraft(Some(&d), None).unwrap().ends_with("PhotoCraft.app")); + assert!(find_photocraft(Some(d), None).unwrap().ends_with("PhotoCraft.app")); } else { let bin = d.join("bin"); std::fs::create_dir_all(&bin).unwrap(); @@ -675,7 +660,6 @@ mod open_with_tests { assert_eq!(find_photocraft(None, Some(&path_var)), Some(exe)); } } - let _ = std::fs::remove_dir_all(&d); } /// #5327 review: on Windows PhotoCraft is looked for where its installer puts it: the path it diff --git a/apps/vectorcraft/src/logging/tests.rs b/apps/vectorcraft/src/logging/tests.rs index a1b54b353..78b08a67b 100644 --- a/apps/vectorcraft/src/logging/tests.rs +++ b/apps/vectorcraft/src/logging/tests.rs @@ -1,12 +1,29 @@ use super::*; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::{Duration, UNIX_EPOCH}; -fn temp_dir(tag: &str) -> PathBuf { - static N: AtomicUsize = AtomicUsize::new(0); - let d = std::env::temp_dir().join(format!("vectorcraft-logging-{tag}-{}-{}", std::process::id(), N.fetch_add(1, Ordering::Relaxed))); - let _ = std::fs::remove_dir_all(&d); - d +struct TestPath { + _parent: tempfile::TempDir, + path: PathBuf, +} + +impl std::ops::Deref for TestPath { + type Target = Path; + + fn deref(&self) -> &Self::Target { + &self.path + } +} + +impl AsRef for TestPath { + fn as_ref(&self) -> &Path { + &self.path + } +} + +fn temp_dir(tag: &str) -> TestPath { + let parent = tempfile::Builder::new().prefix(&format!("vectorcraft-logging-{tag}-")).tempdir().unwrap(); + let path = parent.path().join("log"); + TestPath { _parent: parent, path } } fn read(path: &Path) -> String { diff --git a/apps/vectorcraft/src/mac_fonts.rs b/apps/vectorcraft/src/mac_fonts.rs index a1b5b193c..36223c559 100644 --- a/apps/vectorcraft/src/mac_fonts.rs +++ b/apps/vectorcraft/src/mac_fonts.rs @@ -63,11 +63,10 @@ mod tests { /// fonts, is listed while it is registered. #[test] fn fonts_registered_from_other_folders_are_listed() { - let dir = std::env::temp_dir().join(format!("vectorcraft-mac-fonts-{}", std::process::id())); - std::fs::create_dir_all(&dir).unwrap(); + let dir = tempfile::Builder::new().prefix("vectorcraft-mac-fonts-").tempdir().unwrap(); // A space in the name: the URL's escapes are decoded. The bundled serif isn't a font macOS // installs. - let file = dir.join("Registered Font.ttf"); + let file = dir.path().join("Registered Font.ttf"); std::fs::copy(concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/fonts/SourceSerif4-Regular.ttf"), &file).unwrap(); let want = std::fs::canonicalize(&file).unwrap(); let listed = || super::font_files().iter().any(|f| f.ends_with("/Registered Font.ttf") && std::fs::canonicalize(f).is_ok_and(|p| p == want)); @@ -78,7 +77,6 @@ mod tests { let registered = listed(); // SAFETY: as above. unsafe { CTFontManagerUnregisterFontsForURL(&url, CTFontManagerScope::Process, std::ptr::null_mut()) }; - std::fs::remove_dir_all(&dir).unwrap(); assert!(registered); } } diff --git a/apps/vectorcraft/src/prefs.rs b/apps/vectorcraft/src/prefs.rs index a6daacb83..f03572ebb 100644 --- a/apps/vectorcraft/src/prefs.rs +++ b/apps/vectorcraft/src/prefs.rs @@ -335,13 +335,11 @@ mod tests { #[test] fn a_kept_preferences_copy_is_owner_only() { use std::os::unix::fs::PermissionsExt as _; - let dir = std::env::temp_dir().join(format!("vc-prefs-copy-{}", std::process::id())); - let _ = std::fs::remove_dir_all(&dir); - std::fs::create_dir_all(&dir).unwrap(); + let temp = tempfile::Builder::new().prefix("vc-prefs-copy-").tempdir().unwrap(); + let dir = temp.path(); super::keep_prefs_copy(&dir.join("ui.json"), b"{}", "ui.unreadable"); let mode = std::fs::metadata(dir.join("ui.unreadable.json")).unwrap().permissions().mode() & 0o777; assert_eq!(mode, 0o600); - let _ = std::fs::remove_dir_all(&dir); } #[test] diff --git a/apps/vectorcraft/src/profile.rs b/apps/vectorcraft/src/profile.rs index 8ef035583..0048323f0 100644 --- a/apps/vectorcraft/src/profile.rs +++ b/apps/vectorcraft/src/profile.rs @@ -192,7 +192,22 @@ fn copy_dir_into(from: &Path, to: &Path, skip: &mut impl FnMut(String)) { #[cfg(test)] mod tests { use super::*; - use std::sync::atomic::{AtomicUsize, Ordering}; + + struct TestDir(tempfile::TempDir); + + impl std::ops::Deref for TestDir { + type Target = Path; + + fn deref(&self) -> &Self::Target { + self.0.path() + } + } + + impl AsRef for TestDir { + fn as_ref(&self) -> &Path { + self.0.path() + } + } fn environment(key: &str) -> Option { match key { @@ -287,12 +302,8 @@ mod tests { assert_eq!(install_dir("macos", mounted, &appimage), Some("/tmp/.mount_vc/usr/bin".into())); } - fn temp(tag: &str) -> PathBuf { - static N: AtomicUsize = AtomicUsize::new(0); - let d = std::env::temp_dir().join(format!("vectorcraft-profile-{tag}-{}-{}", std::process::id(), N.fetch_add(1, Ordering::Relaxed))); - let _ = std::fs::remove_dir_all(&d); - std::fs::create_dir_all(&d).unwrap(); - d + fn temp(tag: &str) -> TestDir { + TestDir(tempfile::Builder::new().prefix(&format!("vectorcraft-profile-{tag}-")).tempdir().unwrap()) } #[test] diff --git a/apps/vectorcraft/src/single_instance.rs b/apps/vectorcraft/src/single_instance.rs index f7026131c..5ced4aef3 100644 --- a/apps/vectorcraft/src/single_instance.rs +++ b/apps/vectorcraft/src/single_instance.rs @@ -263,15 +263,23 @@ mod tests { use super::*; + struct TestDir(tempfile::TempDir); + + impl std::ops::Deref for TestDir { + type Target = Path; + + fn deref(&self) -> &Self::Target { + self.0.path() + } + } + /// A fresh folder for one test, with an existing file in it. - fn folder(name: &str) -> (PathBuf, PathBuf, String) { - let dir = std::env::temp_dir().join(format!("vc-single-instance-{}-{name}", std::process::id())); - let _ = fs::remove_dir_all(&dir); - fs::create_dir_all(&dir).unwrap(); - let file = dir.join("a b.svg"); + fn folder(name: &str) -> (PathBuf, TestDir, String) { + let dir = tempfile::Builder::new().prefix(&format!("vc-single-instance-{name}-")).tempdir().unwrap(); + let file = dir.path().join("a b.svg"); fs::write(&file, "").unwrap(); let file = file.to_string_lossy().into_owned(); - (dir.join(FILE_NAME), dir, file) + (dir.path().join(FILE_NAME), TestDir(dir), file) } fn primary(path: &Path) -> (Primary, mpsc::Receiver>) { @@ -303,12 +311,11 @@ mod tests { assert_eq!(rx.recv_timeout(CLIENT_TIMEOUT).unwrap(), [file]); drop(primary); assert!(!path.exists(), "the endpoint file goes with the app"); - let _ = fs::remove_dir_all(dir); } #[test] fn a_wrong_token_garbage_and_oversized_messages_are_refused() { - let (path, dir, file) = folder("refused"); + let (path, _dir, file) = folder("refused"); let (_primary, rx) = primary(&path); let token = read_endpoint(&path).unwrap().token; let wrong = format!("{}\n", json!({ "token": "0".repeat(token.len()), "files": [file] })); @@ -323,12 +330,11 @@ mod tests { // The listener still serves a launch with the right token. forward(&path, std::slice::from_ref(&file)).unwrap(); assert_eq!(rx.recv_timeout(CLIENT_TIMEOUT).unwrap(), [file]); - let _ = fs::remove_dir_all(dir); } #[test] fn a_stale_endpoint_file_is_ignored_and_replaced() { - let (path, dir, file) = folder("stale"); + let (path, _dir, file) = folder("stale"); // The recorded app is gone: whatever holds the port closes without a greeting. (A freed // port can be taken by another test's listener meanwhile, which would then accept this // connection in place of its own client's.) @@ -357,18 +363,16 @@ mod tests { let (_primary, rx) = primary(&path); forward(&path, std::slice::from_ref(&file)).unwrap(); assert_eq!(rx.recv_timeout(CLIENT_TIMEOUT).unwrap(), [file]); - let _ = fs::remove_dir_all(dir); } #[test] fn a_replaced_endpoint_file_stays_when_the_earlier_app_ends() { - let (path, dir, _) = folder("replaced"); + let (path, _dir, _) = folder("replaced"); let (first, _rx1) = primary(&path); let (_second, _rx2) = primary(&path); let second_token = read_endpoint(&path).unwrap().token; drop(first); assert_eq!(read_endpoint(&path).map(|e| e.token), Some(second_token)); - let _ = fs::remove_dir_all(dir); } #[test] @@ -383,9 +387,8 @@ mod tests { #[test] fn the_endpoint_file_is_the_users_alone() { use std::os::unix::fs::PermissionsExt as _; - let (path, dir, _) = folder("mode"); + let (path, _dir, _) = folder("mode"); let _primary = primary(&path); assert_eq!(fs::metadata(&path).unwrap().permissions().mode() & 0o777, 0o600); - let _ = fs::remove_dir_all(dir); } } diff --git a/apps/vectorcraft/src/system_fonts.rs b/apps/vectorcraft/src/system_fonts.rs index 67bbf7843..fe9df48ca 100644 --- a/apps/vectorcraft/src/system_fonts.rs +++ b/apps/vectorcraft/src/system_fonts.rs @@ -284,8 +284,8 @@ mod tests { #[test] fn fonts_only_gdi_has_loaded_are_listed_by_their_files() { use windows::Win32::Graphics::Gdi::{AddFontResourceExW, FR_PRIVATE, RemoveFontResourceExW}; - let dir = std::env::temp_dir().join(format!("vc-gdi-fonts-{}", std::process::id())); - std::fs::create_dir_all(&dir).unwrap(); + let temp = tempfile::Builder::new().prefix("vc-gdi-fonts-").tempdir().unwrap(); + let dir = temp.path(); let file = dir.join("29457"); let source = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../assets/fonts/SourceSans3-Regular.ttf"); let mut data = std::fs::read(source).unwrap(); @@ -303,7 +303,6 @@ mod tests { assert_eq!(unsafe { AddFontResourceExW(&path, FR_PRIVATE, None) }, 1); let files = super::font_files(); let _ = unsafe { RemoveFontResourceExW(&path, FR_PRIVATE.0, None) }; - let _ = std::fs::remove_dir_all(&dir); let wanted = file.to_string_lossy().to_lowercase(); assert!(files.iter().any(|f| f.to_lowercase() == wanted), "{wanted} not in {} files", files.len()); } diff --git a/apps/vectorcraft/src/tests.rs b/apps/vectorcraft/src/tests.rs index e6096c54a..116651fc8 100644 --- a/apps/vectorcraft/src/tests.rs +++ b/apps/vectorcraft/src/tests.rs @@ -99,9 +99,8 @@ fn unreadable_saved_docking_keeps_preferences_and_every_workspace() { #[test] fn an_unreadable_ui_json_is_kept_beside_it() { - let stamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos(); - let dir = std::env::temp_dir().join(format!("vectorcraft-ui-prefs-{}-{stamp}", std::process::id())); - std::fs::create_dir(&dir).unwrap(); + let temp = tempfile::Builder::new().prefix("vectorcraft-ui-prefs-").tempdir().unwrap(); + let dir = temp.path(); let path = dir.join("ui.json"); super::keep_prefs_copy(&path, b"{\"docking\": {\"root\": {\"FutureNode\": {}}}}", "ui.unreadable"); super::keep_prefs_copy(&path, b"not json", "ui.unreadable"); @@ -109,7 +108,6 @@ fn an_unreadable_ui_json_is_kept_beside_it() { let first = std::fs::read(dir.join("ui.unreadable.json")).unwrap(); let second = std::fs::read(dir.join("ui.unreadable-2.json")).unwrap(); let before = std::fs::read(dir.join("ui.before-layout-migration.json")).unwrap(); - let _ = std::fs::remove_dir_all(&dir); assert!(first.starts_with(b"{\"docking\""), "the first copy is not replaced"); assert_eq!(second, b"not json"); assert_eq!(before, b"{}");