use async_trait::async_trait; use config::*; use std::{env, fs, path, str::FromStr}; use tokio::{fs::File, io::AsyncReadExt}; #[derive(Debug)] struct AsyncFile { path: String, format: FileFormat, } /// This is a test only implementation to be used in tests impl AsyncFile { pub fn new(path: String, format: FileFormat) -> Self { AsyncFile { path, format } } } #[async_trait] impl AsyncSource for AsyncFile { async fn collect(&self) -> Result, ConfigError> { let mut path = env::current_dir().unwrap(); let local = path::PathBuf::from_str(&self.path).unwrap(); path.extend(local.into_iter()); let path = match fs::canonicalize(path) { Ok(path) => path, Err(e) => return Err(ConfigError::Foreign(Box::new(e))), }; let text = match File::open(path).await { Ok(mut file) => { let mut buffer = String::default(); match file.read_to_string(&mut buffer).await { Ok(_read) => buffer, Err(e) => return Err(ConfigError::Foreign(Box::new(e))), } } Err(e) => return Err(ConfigError::Foreign(Box::new(e))), }; self.format .parse(Some(&self.path), &text) .map_err(|e| ConfigError::Foreign(e)) } } #[tokio::test] async fn test_single_async_file_source() { let config = Config::builder() .add_async_source(AsyncFile::new( "tests/Settings.json".to_owned(), FileFormat::Json, )) .build() .await .unwrap(); assert_eq!(true, config.get::("debug").unwrap()); } #[tokio::test] async fn test_two_async_file_sources() { let config = Config::builder() .add_async_source(AsyncFile::new( "tests/Settings.json".to_owned(), FileFormat::Json, )) .add_async_source(AsyncFile::new( "tests/Settings.toml".to_owned(), FileFormat::Toml, )) .build() .await .unwrap(); assert_eq!("Torre di Pisa", config.get::("place.name").unwrap()); assert_eq!(true, config.get::("debug_json").unwrap()); assert_eq!(1, config.get::("place.number").unwrap()); } #[tokio::test] async fn test_sync_to_async_file_sources() { let config = Config::builder() .add_source(config::File::new("tests/Settings", FileFormat::Json)) .add_async_source(AsyncFile::new( "tests/Settings.toml".to_owned(), FileFormat::Toml, )) .build() .await .unwrap(); assert_eq!("Torre di Pisa", config.get::("place.name").unwrap()); assert_eq!(1, config.get::("place.number").unwrap()); } #[tokio::test] async fn test_async_to_sync_file_sources() { let config = Config::builder() .add_async_source(AsyncFile::new( "tests/Settings.toml".to_owned(), FileFormat::Toml, )) .add_source(config::File::new("tests/Settings", FileFormat::Json)) .build() .await .unwrap(); assert_eq!("Torre di Pisa", config.get::("place.name").unwrap()); assert_eq!(1, config.get::("place.number").unwrap()); } #[tokio::test] async fn test_async_file_sources_with_defaults() { let config = Config::builder() .set_default("place.name", "Tower of London") .unwrap() .set_default("place.sky", "blue") .unwrap() .add_async_source(AsyncFile::new( "tests/Settings.toml".to_owned(), FileFormat::Toml, )) .build() .await .unwrap(); assert_eq!("Torre di Pisa", config.get::("place.name").unwrap()); assert_eq!("blue", config.get::("place.sky").unwrap()); assert_eq!(1, config.get::("place.number").unwrap()); } #[tokio::test] async fn test_async_file_sources_with_overrides() { let config = Config::builder() .set_override("place.name", "Tower of London") .unwrap() .add_async_source(AsyncFile::new( "tests/Settings.toml".to_owned(), FileFormat::Toml, )) .build() .await .unwrap(); assert_eq!( "Tower of London", config.get::("place.name").unwrap() ); assert_eq!(1, config.get::("place.number").unwrap()); }