use serde::{Serialize, Deserialize};
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, Read};
mod include_administrative;
pub use include_administrative::IncludeAdministrative;
mod path;
pub use path::{Path, SyntaxSuggarPath, Paths};
#[derive(Default, Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub struct Config {
#[serde(default)]
pub base: bool,
#[serde(default)]
pub include_administrative: Option<IncludeAdministrative>,
#[serde(default)]
pub paths: Paths,
#[serde(default)]
pub env: HashMap<String, String>,
}
impl Config {
pub fn new() -> Config {
Default::default()
}
pub fn included() -> Config {
toml::from_str(include_str!("../config.toml")).unwrap()
}
pub fn from_file<P: AsRef<std::path::Path>>(path: P) -> io::Result<Config> {
let mut file = File::open(path)?;
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
Ok(toml::from_slice(&contents)?)
}
pub fn with_env(mut self) -> Config {
self.env = std::env::vars().collect();
self
}
pub fn merge(self, other: Config) -> Config {
Config {
base: self.base || other.base,
include_administrative: other.include_administrative
.or(self.include_administrative),
paths: self.paths.merge(other.paths),
env: self.env.into_iter().chain(other.env).collect()
}
}
}
#[cfg(test)]
mod tests {
use crate::config::{Config, IncludeAdministrative, Paths};
#[test]
fn test_new() {
assert_eq!(Config::new(), Default::default());
}
#[test]
fn test_from_file() {
let config = Config::from_file("src/config.toml");
let wanted = Config::included();
assert_eq!(config.unwrap(), wanted);
}
#[test]
fn test_with_env() {
use std::env;
env::set_var("FOO", "BAR");
let config = Config::new().with_env();
assert_eq!(config.env["FOO"], "BAR");
}
#[test]
fn test_merge() {
let config1 = Config {
base: true,
include_administrative: Some(IncludeAdministrative::Always),
paths: vec!["/foo/bar", "/bar/bazz"].into(),
env: vec![("FOO".to_string(), "BAR".to_string())].into_iter().collect()
};
let config2 = Config {
base: true,
include_administrative: Some(IncludeAdministrative::RootOnly),
paths: Paths(vec!["/fnort".into()]),
env: vec![("FOO".to_string(), "FNAFF".to_string())].into_iter().collect(),
};
let result = Config {
base: true,
include_administrative: Some(IncludeAdministrative::RootOnly),
paths: vec!["/fnort", "/foo/bar", "/bar/bazz"].into(),
env: vec![("FOO".to_string(), "FNAFF".to_string())].into_iter().collect()
};
assert_eq!(config1.merge(config2), result);
}
#[test]
fn test_included() {
Config::included();
}
}