summaryrefslogtreecommitdiff
path: root/dhall/src
diff options
context:
space:
mode:
Diffstat (limited to 'dhall/src')
-rw-r--r--dhall/src/semantics/resolve/cache.rs133
1 files changed, 121 insertions, 12 deletions
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