use super::DirectoryFinder;
use crate::env::Env;
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct WindowsDirectoryFinder {
app_name: String,
company_name: String,
}
impl WindowsDirectoryFinder {
pub fn new(app_name: impl Into<String>, company_name: impl Into<String>) -> Self {
Self {
app_name: app_name.into(),
company_name: company_name.into(),
}
}
fn appdata_roaming(&self, env: &dyn Env) -> PathBuf {
env.get("APPDATA")
.map(PathBuf::from)
.unwrap_or_else(|| {
env.home_dir()
.map(|h| h.join("AppData").join("Roaming"))
.unwrap_or_else(|| PathBuf::from("C:\\"))
})
.join(&self.company_name)
.join(&self.app_name)
}
fn appdata_local(&self, env: &dyn Env) -> PathBuf {
env.get("LOCALAPPDATA")
.map(PathBuf::from)
.unwrap_or_else(|| {
env.home_dir()
.map(|h| h.join("AppData").join("Local"))
.unwrap_or_else(|| PathBuf::from("C:\\"))
})
.join(&self.company_name)
.join(&self.app_name)
}
fn program_data(&self, env: &dyn Env) -> PathBuf {
env.get("PROGRAMDATA")
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("C:\\ProgramData"))
.join(&self.company_name)
.join(&self.app_name)
}
}
impl DirectoryFinder for WindowsDirectoryFinder {
fn user_dirs(&self, env: &dyn Env) -> Vec<PathBuf> {
vec![
self.appdata_roaming(env),
self.appdata_local(env),
]
}
fn local_dirs(&self, _env: &dyn Env) -> Vec<PathBuf> {
Vec::new()
}
fn system_dirs(&self, env: &dyn Env) -> Vec<PathBuf> {
vec![
self.program_data(env),
PathBuf::from("C:\\Program Files\\Common Files")
.join(&self.company_name)
.join(&self.app_name),
]
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestEnv {
vars: std::collections::HashMap<String, String>,
home: PathBuf,
}
impl TestEnv {
fn new() -> Self {
Self {
vars: std::collections::HashMap::new(),
home: PathBuf::from("C:\\Users\\TestUser"),
}
}
fn with_var(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.vars.insert(key.into(), value.into());
self
}
}
impl Env for TestEnv {
fn get(&self, key: &str) -> Option<String> {
self.vars.get(key).cloned()
}
fn home_dir(&self) -> Option<PathBuf> {
Some(self.home.clone())
}
}
#[test]
fn test_user_dirs_with_appdata() {
let env = TestEnv::new().with_var("APPDATA", "C:\\Users\\TestUser\\AppData\\Roaming");
let finder = WindowsDirectoryFinder::new("MyApp", "MyCompany");
let dirs = finder.user_dirs(&env);
assert_eq!(
dirs[0],
PathBuf::from("C:\\Users\\TestUser\\AppData\\Roaming\\MyCompany\\MyApp")
);
}
#[test]
fn test_system_dirs() {
let env = TestEnv::new().with_var("PROGRAMDATA", "C:\\ProgramData");
let finder = WindowsDirectoryFinder::new("MyApp", "MyCompany");
let dirs = finder.system_dirs(&env);
assert_eq!(dirs[0], PathBuf::from("C:\\ProgramData\\MyCompany\\MyApp"));
}
}