diff options
Diffstat (limited to '')
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | dhall/Cargo.toml | 1 | ||||
-rw-r--r-- | dhall/src/semantics/resolve/cache.rs | 133 |
3 files changed, 123 insertions, 12 deletions
@@ -150,6 +150,7 @@ dependencies = [ "pest_generator 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_cbor 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/dhall/Cargo.toml b/dhall/Cargo.toml index fca96d0..376506f 100644 --- a/dhall/Cargo.toml +++ b/dhall/Cargo.toml @@ -29,6 +29,7 @@ url = "2.1" [dev-dependencies] pretty_assertions = "0.6.1" version-sync = "0.8" +rand = "0.7" [build-dependencies] walkdir = "2" diff --git a/dhall/src/semantics/resolve/cache.rs b/dhall/src/semantics/resolve/cache.rs index e616038..8ac523b 100644 --- a/dhall/src/semantics/resolve/cache.rs +++ b/dhall/src/semantics/resolve/cache.rs @@ -9,6 +9,7 @@ use crate::syntax::Hash; use crate::syntax::{binary, Expr}; use crate::Parsed; use std::fs::File; +use std::env::VarError; #[cfg(unix)] const ALTERNATE_ENV_VAR: &str = "HOME"; @@ -16,42 +17,51 @@ const ALTERNATE_ENV_VAR: &str = "HOME"; #[cfg(windows)] const ALTERNATE_ENV_VAR: &str = "LOCALAPPDATA"; -fn alternate_env_var_cache_dir() -> Option<PathBuf> { - env::var(ALTERNATE_ENV_VAR) +fn alternate_env_var_cache_dir(provider: impl Fn(&str) -> Result<String, VarError>) -> Option<PathBuf> { + provider(ALTERNATE_ENV_VAR) .map(PathBuf::from) .map(|env_dir| env_dir.join(".cache").join("dhall")) .ok() } -fn env_var_cache_dir() -> Option<PathBuf> { - env::var("XDG_CACHE_HOME") +fn env_var_cache_dir(provider: impl Fn(&str) -> Result<String, VarError>) -> Option<PathBuf> { + provider("XDG_CACHE_HOME") .map(PathBuf::from) .map(|cache_home| cache_home.join("dhall")) .ok() } -fn load_cache_dir() -> Result<PathBuf, CacheError> { - env_var_cache_dir() - .or_else(alternate_env_var_cache_dir) +fn load_cache_dir(provider: impl Fn(&str) -> Result<String, VarError> + Copy) -> Result<PathBuf, CacheError> { + env_var_cache_dir(provider) + .or_else(|| alternate_env_var_cache_dir(provider)) .ok_or(CacheError::MissingConfiguration) } +#[derive(Debug, PartialEq)] pub struct Cache { cache_dir: Option<PathBuf>, } impl Cache { - pub fn new() -> Cache { + fn new_with_provider(provider: impl Fn(&str) -> Result<String, VarError> + Copy) -> Cache { // Should warn that we can't initialize cache on error - let cache_dir = load_cache_dir().and_then(|path| { - std::fs::create_dir_all(path.as_path()) - .map(|_| path) - .map_err(|e| CacheError::InitialisationError { cause: e }) + let cache_dir = load_cache_dir(provider).and_then(|path| { + if !path.exists() { + std::fs::create_dir_all(path.as_path()) + .map(|_| path) + .map_err(|e| CacheError::InitialisationError { cause: e }) + } else { + Ok(path) + } }); Cache { cache_dir: cache_dir.ok(), } } + + pub fn new() -> Cache { + Cache::new_with_provider(|name| env::var(name)) + } } impl Cache { @@ -153,3 +163,102 @@ impl AsRef<[u8]> for Hash { } } } + + +#[cfg(test)] +mod test { + use super::*; + use std::env::temp_dir; + use rand::Rng; + use rand::distributions::Alphanumeric; + + #[cfg(unix)] + #[test] + fn alternate_env_var_cache_dir_should_result_unix_folder_path() { + let actual = alternate_env_var_cache_dir(|_| Ok("/home/user".to_string())); + assert_eq!(actual, Some(PathBuf::from("/home/user/.cache/dhall"))); + } + + #[test] + fn alternate_env_var_cache_dir_should_result_none_on_missing_var() { + let actual = alternate_env_var_cache_dir(|_| Err(VarError::NotPresent)); + assert_eq!(actual, None); + } + + #[test] + fn env_var_cache_dir_should_result_xdg_cache_home() { + let actual = env_var_cache_dir(|_| Ok("/home/user/custom/path/for/cache".to_string())); + assert_eq!(actual, Some(PathBuf::from("/home/user/custom/path/for/cache/dhall"))); + } + + #[test] + fn env_var_cache_dir_should_result_none_on_missing_var() { + let actual = env_var_cache_dir(|_| Err(VarError::NotPresent)); + assert_eq!(actual, None); + } + + #[test] + fn load_cache_dir_should_result_xdg_cache_first() { + let actual = load_cache_dir( + |var| match var { + "XDG_CACHE_HOME" => Ok("/home/user/custom".to_string()), + _ => Err(VarError::NotPresent) + } + ); + assert_eq!(actual.unwrap(), PathBuf::from("/home/user/custom/dhall")); + } + + #[cfg(unix)] + #[test] + fn load_cache_dir_should_result_alternate() { + let actual = load_cache_dir(|var| + match var { + ALTERNATE_ENV_VAR => Ok("/home/user".to_string()), + _ => Err(VarError::NotPresent) + } + ); + assert_eq!(actual.unwrap(), PathBuf::from("/home/user/.cache/dhall")); + } + + #[test] + fn load_cache_dir_should_result_none() { + let actual = load_cache_dir(|_| Err(VarError::NotPresent)); + assert!(matches!(actual.unwrap_err(), CacheError::MissingConfiguration)); + } + + #[test] + fn new_with_provider_should_create_cache_folder() { + let test_id = rand::thread_rng() + .sample_iter(Alphanumeric) + .take(36) + .collect::<String>(); + let dir = temp_dir().join(test_id); + + std::fs::create_dir_all(dir.as_path()).unwrap(); + + let actual = Cache::new_with_provider(|_| Ok(dir.clone().to_str().map(String::from).unwrap())); + assert_eq!(actual, Cache{ cache_dir: Some(dir.join("dhall"))}); + assert!(dir.join("dhall").exists()); + std::fs::remove_dir_all(dir.as_path()).unwrap(); + } + + #[test] + fn new_with_provider_should_return_cache_for_existing_folder() { + let test_id = rand::thread_rng() + .sample_iter(Alphanumeric) + .take(36) + .collect::<String>(); + let dir = temp_dir().join(test_id); + + std::fs::create_dir_all(dir.as_path()).unwrap(); + File::create(dir.join("dhall")).unwrap(); + + assert!(dir.join("dhall").exists()); + + let actual = Cache::new_with_provider(|_| Ok(dir.clone().to_str().map(String::from).unwrap())); + assert_eq!(actual, Cache{ cache_dir: Some(dir.join("dhall"))}); + std::fs::remove_dir_all(dir.as_path()).unwrap(); + } + + +}
\ No newline at end of file |