diff --git a/Cargo.toml b/Cargo.toml index 8f7134ca..9f648269 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,6 +88,7 @@ streaming-stats = "0.2.3" humantime = "2.1" tempfile = "3.8" mock_instant = "0.3" +serde_test = "1.0.176" [[example]] name = "json_logger" diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 093dd2d1..ddb1c219 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -31,6 +31,7 @@ impl Deserializable for dyn Filter { } } +#[derive(PartialEq, Debug)] /// The response returned by a filter. pub enum Response { /// Accept the log event. @@ -78,3 +79,44 @@ impl<'de> de::Deserialize<'de> for FilterConfig { }) } } + +#[cfg(test)] +mod test { + #[cfg(feature = "config_parsing")] + use super::*; + #[cfg(feature = "config_parsing")] + use serde_test::{assert_de_tokens, assert_de_tokens_error, Token}; + + #[test] + #[cfg(feature = "config_parsing")] + fn test_cfg_deserializer() { + let filter = FilterConfig { + kind: "threshold".to_owned(), + config: Value::Map({ + let mut map = BTreeMap::new(); + map.insert( + Value::String("level".to_owned()), + Value::String("error".to_owned()), + ); + map + }), + }; + + let mut cfg = vec![ + Token::Struct { + name: "FilterConfig", + len: 2, + }, + Token::Str("kind"), + Token::Str("threshold"), + Token::Str("level"), + Token::Str("error"), + Token::StructEnd, + ]; + + assert_de_tokens(&filter, &cfg); + + cfg[1] = Token::Str("knd"); + assert_de_tokens_error::(&cfg, "missing field `kind`"); + } +} diff --git a/src/filter/threshold.rs b/src/filter/threshold.rs index 86c6e289..c62c5198 100644 --- a/src/filter/threshold.rs +++ b/src/filter/threshold.rs @@ -66,3 +66,98 @@ impl Deserialize for ThresholdFilterDeserializer { Ok(Box::new(ThresholdFilter::new(config.level))) } } + +#[cfg(test)] +mod test { + use log::{Level, LevelFilter, Record}; + + use super::*; + + #[cfg(feature = "config_parsing")] + use crate::config::Deserializers; + + #[cfg(feature = "config_parsing")] + use serde_test::{assert_de_tokens, assert_de_tokens_error, Token}; + + #[test] + #[cfg(feature = "config_parsing")] + fn test_cfg_deserialize() { + let filter_cfg = ThresholdFilterConfig { + level: LevelFilter::Off, + }; + + let mut cfg = vec![ + Token::Struct { + name: "ThresholdFilterConfig", + len: 1, + }, + Token::Str("level"), + Token::Enum { + name: "LevelFilter", + }, + Token::Str("Off"), + Token::Unit, + Token::StructEnd, + ]; + + assert_de_tokens(&filter_cfg, &cfg); + + cfg[1] = Token::Str("leel"); + assert_de_tokens_error::(&cfg, "missing field `level`"); + + cfg[1] = Token::Str("level"); + cfg[3] = Token::Str("On"); + cfg.remove(4); // No Unit on this one as the Option is invalid + assert_de_tokens_error::( + &cfg, + "unknown variant `On`, expected one of `OFF`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`", + ); + } + + #[test] + fn test_filter_new_vs_struct() { + assert_eq!( + ThresholdFilter::new(LevelFilter::Info), + ThresholdFilter { + level: LevelFilter::Info + } + ); + } + + #[test] + fn test_threshold_filter() { + let thres = ThresholdFilter::new(LevelFilter::Info); + let debug_record = Record::builder() + .level(Level::Debug) + .args(format_args!("the message")) + .module_path(Some("path")) + .file(Some("file")) + .line(Some(132)) + .build(); + + assert_eq!(thres.filter(&debug_record), Response::Reject); + + let error_record = Record::builder() + .level(Level::Error) + .args(format_args!("the message")) + .module_path(Some("path")) + .file(Some("file")) + .line(Some(132)) + .build(); + + assert_eq!(thres.filter(&error_record), Response::Neutral); + } + + #[test] + #[cfg(feature = "config_parsing")] + fn test_cfg_deserializer() { + let filter_cfg = ThresholdFilterConfig { + level: LevelFilter::Off, + }; + + let deserializer = ThresholdFilterDeserializer; + + let res = deserializer.deserialize(filter_cfg, &Deserializers::default()); + assert!(res.is_ok()); + } +}