A cross-platform Rust library for resolving XDG and platform-specific directories with proper fallbacks.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add `temp-env` as a dev dependency and refactor tests (#4)

## Summary

- Introduce `temp-env` crate (v0.3) to simplify environment variable
handling in tests.
- Replace custom `env::set_var`/`env::remove_var` calls with `temp_env`
utility methods.
- Eliminate unsafe code in test cases by leveraging `temp_env`'s scoped
modification functions.
- Update `Cargo.toml` and `Cargo.lock` to reflect the new development
dependency.

## Type of Change

<!-- Mark with an `x` all that apply -->

- [ ] 🐛 Bug fix (non-breaking change that fixes an issue)
- [ ] ✨ New feature (non-breaking change that adds functionality)
- [ ] 💥 Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] 📚 Documentation update
- [x] 🧹 Code cleanup or refactoring
- [x] 🔧 Build system or dependency changes
- [x] 🧪 Test improvements

## What Changed?

This refactors tests to use temp-env instead of using unsafe code

## How Has This Been Tested?

<!-- Describe the tests you ran to verify your changes -->

- [x] Existing tests pass (`mise test`)
- [x] New tests added for new functionality
- [x] Manual testing performed
- [x] Code follows style guidelines (`mise lint`)

authored by aaronmallen.dev and committed by

GitHub 004dcc5d 1f0db9ba

+252 -130
+154
Cargo.lock
··· 3 3 version = 4 4 4 5 5 [[package]] 6 + name = "autocfg" 7 + version = "1.5.0" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 10 + 11 + [[package]] 12 + name = "bitflags" 13 + version = "2.9.3" 14 + source = "registry+https://github.com/rust-lang/crates.io-index" 15 + checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" 16 + 17 + [[package]] 18 + name = "cfg-if" 19 + version = "1.0.3" 20 + source = "registry+https://github.com/rust-lang/crates.io-index" 21 + checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" 22 + 23 + [[package]] 6 24 name = "dir_spec" 7 25 version = "0.2.0" 26 + dependencies = [ 27 + "temp-env", 28 + ] 29 + 30 + [[package]] 31 + name = "libc" 32 + version = "0.2.175" 33 + source = "registry+https://github.com/rust-lang/crates.io-index" 34 + checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" 35 + 36 + [[package]] 37 + name = "lock_api" 38 + version = "0.4.13" 39 + source = "registry+https://github.com/rust-lang/crates.io-index" 40 + checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" 41 + dependencies = [ 42 + "autocfg", 43 + "scopeguard", 44 + ] 45 + 46 + [[package]] 47 + name = "parking_lot" 48 + version = "0.12.4" 49 + source = "registry+https://github.com/rust-lang/crates.io-index" 50 + checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" 51 + dependencies = [ 52 + "lock_api", 53 + "parking_lot_core", 54 + ] 55 + 56 + [[package]] 57 + name = "parking_lot_core" 58 + version = "0.9.11" 59 + source = "registry+https://github.com/rust-lang/crates.io-index" 60 + checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" 61 + dependencies = [ 62 + "cfg-if", 63 + "libc", 64 + "redox_syscall", 65 + "smallvec", 66 + "windows-targets", 67 + ] 68 + 69 + [[package]] 70 + name = "redox_syscall" 71 + version = "0.5.17" 72 + source = "registry+https://github.com/rust-lang/crates.io-index" 73 + checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" 74 + dependencies = [ 75 + "bitflags", 76 + ] 77 + 78 + [[package]] 79 + name = "scopeguard" 80 + version = "1.2.0" 81 + source = "registry+https://github.com/rust-lang/crates.io-index" 82 + checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 83 + 84 + [[package]] 85 + name = "smallvec" 86 + version = "1.15.1" 87 + source = "registry+https://github.com/rust-lang/crates.io-index" 88 + checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 89 + 90 + [[package]] 91 + name = "temp-env" 92 + version = "0.3.6" 93 + source = "registry+https://github.com/rust-lang/crates.io-index" 94 + checksum = "96374855068f47402c3121c6eed88d29cb1de8f3ab27090e273e420bdabcf050" 95 + dependencies = [ 96 + "parking_lot", 97 + ] 98 + 99 + [[package]] 100 + name = "windows-targets" 101 + version = "0.52.6" 102 + source = "registry+https://github.com/rust-lang/crates.io-index" 103 + checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 104 + dependencies = [ 105 + "windows_aarch64_gnullvm", 106 + "windows_aarch64_msvc", 107 + "windows_i686_gnu", 108 + "windows_i686_gnullvm", 109 + "windows_i686_msvc", 110 + "windows_x86_64_gnu", 111 + "windows_x86_64_gnullvm", 112 + "windows_x86_64_msvc", 113 + ] 114 + 115 + [[package]] 116 + name = "windows_aarch64_gnullvm" 117 + version = "0.52.6" 118 + source = "registry+https://github.com/rust-lang/crates.io-index" 119 + checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 120 + 121 + [[package]] 122 + name = "windows_aarch64_msvc" 123 + version = "0.52.6" 124 + source = "registry+https://github.com/rust-lang/crates.io-index" 125 + checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 126 + 127 + [[package]] 128 + name = "windows_i686_gnu" 129 + version = "0.52.6" 130 + source = "registry+https://github.com/rust-lang/crates.io-index" 131 + checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 132 + 133 + [[package]] 134 + name = "windows_i686_gnullvm" 135 + version = "0.52.6" 136 + source = "registry+https://github.com/rust-lang/crates.io-index" 137 + checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 138 + 139 + [[package]] 140 + name = "windows_i686_msvc" 141 + version = "0.52.6" 142 + source = "registry+https://github.com/rust-lang/crates.io-index" 143 + checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 144 + 145 + [[package]] 146 + name = "windows_x86_64_gnu" 147 + version = "0.52.6" 148 + source = "registry+https://github.com/rust-lang/crates.io-index" 149 + checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 150 + 151 + [[package]] 152 + name = "windows_x86_64_gnullvm" 153 + version = "0.52.6" 154 + source = "registry+https://github.com/rust-lang/crates.io-index" 155 + checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 156 + 157 + [[package]] 158 + name = "windows_x86_64_msvc" 159 + version = "0.52.6" 160 + source = "registry+https://github.com/rust-lang/crates.io-index" 161 + checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+3
Cargo.toml
··· 11 11 keywords = ["xdg", "directories", "cross-platform", "filesystem", "config"] 12 12 categories = ["filesystem", "os", "config"] 13 13 14 + [dev-dependencies] 15 + temp-env = "0.3" 16 + 14 17 [lints.clippy] 15 18 complexity = { level = "warn", priority = -1 } 16 19 correctness = { level = "warn", priority = -1 }
+95 -130
src/lib.rs
··· 425 425 426 426 #[cfg(test)] 427 427 mod tests { 428 - use std::env; 429 - 430 428 use super::*; 431 429 432 430 #[test] 433 - #[allow(unsafe_code)] 434 431 fn test_resolve_xdg_path_absolute() { 435 - unsafe { 436 - env::set_var("TEST_XDG_VAR", "/absolute/path"); 437 - } 438 - let result = Dir::resolve_xdg_path("TEST_XDG_VAR"); 439 - assert_eq!(result, Some(PathBuf::from("/absolute/path"))); 440 - unsafe { 441 - env::remove_var("TEST_XDG_VAR"); 442 - } 432 + temp_env::with_var("TEST_XDG_VAR", Some("/absolute/path"), || { 433 + let result = Dir::resolve_xdg_path("TEST_XDG_VAR"); 434 + assert_eq!(result, Some(PathBuf::from("/absolute/path"))); 435 + }); 443 436 } 444 437 445 438 #[test] 446 - #[allow(unsafe_code)] 447 439 fn test_resolve_xdg_path_relative_ignored() { 448 - unsafe { 449 - env::set_var("TEST_XDG_VAR", "relative/path"); 450 - } 451 - let result = Dir::resolve_xdg_path("TEST_XDG_VAR"); 452 - assert_eq!(result, None); 453 - unsafe { 454 - env::remove_var("TEST_XDG_VAR"); 455 - } 440 + temp_env::with_var("TEST_XDG_VAR", Some("relative/path"), || { 441 + let result = Dir::resolve_xdg_path("TEST_XDG_VAR"); 442 + assert_eq!(result, None); 443 + }); 456 444 } 457 445 458 446 #[test] 459 - #[allow(unsafe_code)] 460 447 fn test_resolve_xdg_path_unset() { 461 - unsafe { 462 - env::remove_var("TEST_XDG_VAR"); 463 - } 464 - let result = Dir::resolve_xdg_path("TEST_XDG_VAR"); 465 - assert_eq!(result, None); 448 + temp_env::with_var_unset("TEST_XDG_VAR", || { 449 + let result = Dir::resolve_xdg_path("TEST_XDG_VAR"); 450 + assert_eq!(result, None); 451 + }); 466 452 } 467 453 468 454 #[test] ··· 474 460 } 475 461 476 462 #[test] 477 - #[allow(unsafe_code)] 478 463 fn test_config_home_default() { 479 - unsafe { 480 - env::remove_var("XDG_CONFIG_HOME"); 481 - } 482 - let config = Dir::config_home(); 483 - if let Some(config_path) = config { 484 - assert!(config_path.is_absolute()); 464 + temp_env::with_var_unset("XDG_CONFIG_HOME", || { 465 + let config = Dir::config_home(); 466 + if let Some(config_path) = config { 467 + assert!(config_path.is_absolute()); 485 468 486 - #[cfg(target_os = "linux")] 487 - assert!(config_path.to_string_lossy().ends_with(".config")); 469 + #[cfg(target_os = "linux")] 470 + assert!(config_path.to_string_lossy().ends_with(".config")); 488 471 489 - #[cfg(target_os = "macos")] 490 - assert!(config_path.to_string_lossy().contains("Library/Application Support")); 491 - } 472 + #[cfg(target_os = "macos")] 473 + assert!(config_path.to_string_lossy().contains("Library/Application Support")); 474 + } 475 + }); 492 476 } 493 477 494 478 #[test] 495 - #[allow(unsafe_code)] 496 479 fn test_config_home_xdg_override() { 497 480 let test_path = if cfg!(windows) { "C:\\test\\config" } else { "/test/config" }; 498 - unsafe { 499 - env::set_var("XDG_CONFIG_HOME", test_path); 500 - } 501 - let config = Dir::config_home(); 502 - assert_eq!(config, Some(PathBuf::from(test_path))); 503 - unsafe { 504 - env::remove_var("XDG_CONFIG_HOME"); 505 - } 481 + temp_env::with_var("XDG_CONFIG_HOME", Some(test_path), || { 482 + let config = Dir::config_home(); 483 + assert_eq!(config, Some(PathBuf::from(test_path))); 484 + }); 506 485 } 507 486 508 487 #[test] 509 - #[allow(unsafe_code)] 510 488 fn test_cache_home_default() { 511 - unsafe { 512 - env::remove_var("XDG_CACHE_HOME"); 513 - } 514 - let cache = Dir::cache_home(); 515 - if let Some(cache_path) = cache { 516 - assert!(cache_path.is_absolute()); 489 + temp_env::with_var_unset("XDG_CACHE_HOME", || { 490 + let cache = Dir::cache_home(); 491 + if let Some(cache_path) = cache { 492 + assert!(cache_path.is_absolute()); 517 493 518 - #[cfg(target_os = "linux")] 519 - assert!(cache_path.to_string_lossy().ends_with(".cache")); 494 + #[cfg(target_os = "linux")] 495 + assert!(cache_path.to_string_lossy().ends_with(".cache")); 520 496 521 - #[cfg(target_os = "macos")] 522 - assert!(cache_path.to_string_lossy().contains("Library/Caches")); 523 - } 497 + #[cfg(target_os = "macos")] 498 + assert!(cache_path.to_string_lossy().contains("Library/Caches")); 499 + } 500 + }); 524 501 } 525 502 526 503 #[test] 527 - #[allow(unsafe_code)] 528 504 fn test_data_home_default() { 529 - unsafe { 530 - env::remove_var("XDG_DATA_HOME"); 531 - } 532 - let data = Dir::data_home(); 533 - if let Some(data_path) = data { 534 - assert!(data_path.is_absolute()); 505 + temp_env::with_var_unset("XDG_DATA_HOME", || { 506 + let data = Dir::data_home(); 507 + if let Some(data_path) = data { 508 + assert!(data_path.is_absolute()); 535 509 536 - #[cfg(target_os = "linux")] 537 - assert!(data_path.to_string_lossy().ends_with(".local/share")); 510 + #[cfg(target_os = "linux")] 511 + assert!(data_path.to_string_lossy().ends_with(".local/share")); 538 512 539 - #[cfg(target_os = "macos")] 540 - assert!(data_path.to_string_lossy().contains("Library/Application Support")); 541 - } 513 + #[cfg(target_os = "macos")] 514 + assert!(data_path.to_string_lossy().contains("Library/Application Support")); 515 + } 516 + }); 542 517 } 543 518 544 519 #[test] 545 - #[allow(unsafe_code)] 546 520 fn test_bin_home_default() { 547 - unsafe { 548 - env::remove_var("XDG_BIN_HOME"); 549 - } 550 - let bin = Dir::bin_home(); 551 - if let Some(bin_path) = bin { 552 - assert!(bin_path.is_absolute()); 521 + temp_env::with_var_unset("XDG_BIN_HOME", || { 522 + let bin = Dir::bin_home(); 523 + if let Some(bin_path) = bin { 524 + assert!(bin_path.is_absolute()); 553 525 554 - #[cfg(any(target_os = "linux", target_os = "macos"))] 555 - assert!(bin_path.to_string_lossy().ends_with(".local/bin")); 526 + #[cfg(any(target_os = "linux", target_os = "macos"))] 527 + assert!(bin_path.to_string_lossy().ends_with(".local/bin")); 556 528 557 - #[cfg(target_os = "windows")] 558 - assert!(bin_path.to_string_lossy().contains("Programs")); 559 - } 529 + #[cfg(target_os = "windows")] 530 + assert!(bin_path.to_string_lossy().contains("Programs")); 531 + } 532 + }); 560 533 } 561 534 562 535 #[test] 563 - #[allow(unsafe_code)] 564 536 fn test_runtime_default() { 565 - unsafe { 566 - env::remove_var("XDG_RUNTIME_DIR"); 567 - } 568 - let runtime = Dir::runtime(); 569 - if let Some(runtime_path) = runtime { 570 - assert!(runtime_path.is_absolute()); 537 + temp_env::with_var_unset("XDG_RUNTIME_DIR", || { 538 + let runtime = Dir::runtime(); 539 + if let Some(runtime_path) = runtime { 540 + assert!(runtime_path.is_absolute()); 571 541 572 - #[cfg(any(target_os = "linux", target_os = "macos"))] 573 - { 574 - let path_str = runtime_path.to_string_lossy(); 575 - assert!(path_str.contains("tmp") || path_str.starts_with("/var/folders")); 542 + #[cfg(any(target_os = "linux", target_os = "macos"))] 543 + { 544 + let path_str = runtime_path.to_string_lossy(); 545 + assert!(path_str.contains("tmp") || path_str.starts_with("/var/folders")); 546 + } 576 547 } 577 - } 548 + }); 578 549 } 579 550 580 551 #[test] 581 - #[allow(unsafe_code)] 582 552 fn test_desktop_default() { 583 - unsafe { 584 - env::remove_var("XDG_DESKTOP_DIR"); 585 - } 586 - let desktop = Dir::desktop(); 587 - if let Some(desktop_path) = desktop { 588 - assert!(desktop_path.is_absolute()); 589 - assert!(desktop_path.to_string_lossy().ends_with("Desktop")); 590 - } 553 + temp_env::with_var_unset("XDG_DESKTOP_DIR", || { 554 + let desktop = Dir::desktop(); 555 + if let Some(desktop_path) = desktop { 556 + assert!(desktop_path.is_absolute()); 557 + assert!(desktop_path.to_string_lossy().ends_with("Desktop")); 558 + } 559 + }); 591 560 } 592 561 593 562 #[test] 594 - #[allow(unsafe_code)] 595 563 fn test_videos_platform_differences() { 596 - unsafe { 597 - env::remove_var("XDG_VIDEOS_DIR"); 598 - } 599 - let videos = Dir::videos(); 600 - if let Some(videos_path) = videos { 601 - assert!(videos_path.is_absolute()); 564 + temp_env::with_var_unset("XDG_VIDEOS_DIR", || { 565 + let videos = Dir::videos(); 566 + if let Some(videos_path) = videos { 567 + assert!(videos_path.is_absolute()); 602 568 603 - #[cfg(target_os = "linux")] 604 - assert!(videos_path.to_string_lossy().ends_with("Videos")); 569 + #[cfg(target_os = "linux")] 570 + assert!(videos_path.to_string_lossy().ends_with("Videos")); 605 571 606 - #[cfg(target_os = "macos")] 607 - assert!(videos_path.to_string_lossy().ends_with("Movies")); 572 + #[cfg(target_os = "macos")] 573 + assert!(videos_path.to_string_lossy().ends_with("Movies")); 608 574 609 - #[cfg(target_os = "windows")] 610 - assert!(videos_path.to_string_lossy().ends_with("Videos")); 611 - } 575 + #[cfg(target_os = "windows")] 576 + assert!(videos_path.to_string_lossy().ends_with("Videos")); 577 + } 578 + }); 612 579 } 613 580 614 581 #[test] 615 - #[allow(unsafe_code)] 616 582 fn test_publicshare_windows_absolute() { 617 - unsafe { 618 - env::remove_var("XDG_PUBLICSHARE_DIR"); 619 - } 620 - let public = Dir::publicshare(); 621 - if let Some(public_path) = public { 622 - assert!(public_path.is_absolute()); 583 + temp_env::with_var_unset("XDG_PUBLICSHARE_DIR", || { 584 + let public = Dir::publicshare(); 585 + if let Some(public_path) = public { 586 + assert!(public_path.is_absolute()); 623 587 624 - #[cfg(target_os = "windows")] 625 - assert_eq!(public_path, PathBuf::from("C:\\Users\\Public")); 588 + #[cfg(target_os = "windows")] 589 + assert_eq!(public_path, PathBuf::from("C:\\Users\\Public")); 626 590 627 - #[cfg(any(target_os = "linux", target_os = "macos"))] 628 - assert!(public_path.to_string_lossy().ends_with("Public")); 629 - } 591 + #[cfg(any(target_os = "linux", target_os = "macos"))] 592 + assert!(public_path.to_string_lossy().ends_with("Public")); 593 + } 594 + }); 630 595 } 631 596 }