diff options
Diffstat (limited to 'src/bindings.rs')
-rw-r--r-- | src/bindings.rs | 131 |
1 files changed, 102 insertions, 29 deletions
diff --git a/src/bindings.rs b/src/bindings.rs index 40ef0b4..9d80394 100644 --- a/src/bindings.rs +++ b/src/bindings.rs @@ -5,12 +5,13 @@ use super::StepKind; use crate::{Result, SubplotError}; use serde::Deserialize; +use serde_aux::prelude::*; use std::fs::File; use std::io::Read; use std::path::Path; -use regex::{escape, Regex}; +use regex::{escape, Regex, RegexBuilder}; /// A binding of a scenario step to its implementation. /// @@ -33,11 +34,15 @@ impl Binding { pattern: &str, function: &str, cleanup: Option<&str>, + case_sensitive: bool, ) -> Result<Binding> { + let regex = RegexBuilder::new(&format!("^{}$", pattern)) + .case_insensitive(!case_sensitive) + .build()?; Ok(Binding { kind, pattern: pattern.to_owned(), - regex: Regex::new(&format!("^{}$", pattern))?, + regex, function: function.to_string(), cleanup: cleanup.map(String::from), }) @@ -149,7 +154,7 @@ mod test_binding { #[test] fn creates_new_without_cleanup() { - let b = Binding::new(StepKind::Given, "I am Tomjon", "set_name", None).unwrap(); + let b = Binding::new(StepKind::Given, "I am Tomjon", "set_name", None, false).unwrap(); assert_eq!(b.kind(), StepKind::Given); assert!(b.regex().is_match("I am Tomjon")); assert!(!b.regex().is_match("I am Tomjon of Lancre")); @@ -165,6 +170,7 @@ mod test_binding { "I am Tomjon", "set_name", Some("unset_name"), + false, ) .unwrap(); assert_eq!(b.kind(), StepKind::Given); @@ -177,36 +183,57 @@ mod test_binding { #[test] fn equal() { - let a = Binding::new(StepKind::Given, "I am Tomjon", "set_name", Some("unset")).unwrap(); - let b = Binding::new(StepKind::Given, "I am Tomjon", "set_name", Some("unset")).unwrap(); + let a = Binding::new( + StepKind::Given, + "I am Tomjon", + "set_name", + Some("unset"), + false, + ) + .unwrap(); + let b = Binding::new( + StepKind::Given, + "I am Tomjon", + "set_name", + Some("unset"), + false, + ) + .unwrap(); assert_eq!(a, b); } #[test] fn not_equal() { - let a = Binding::new(StepKind::Given, "I am Tomjon", "set_name", None).unwrap(); - let b = Binding::new(StepKind::Given, "I am Tomjon of Lancre", "set_name", None).unwrap(); + let a = Binding::new(StepKind::Given, "I am Tomjon", "set_name", None, false).unwrap(); + let b = Binding::new( + StepKind::Given, + "I am Tomjon of Lancre", + "set_name", + None, + false, + ) + .unwrap(); assert_ne!(a, b); } #[test] fn does_not_match_with_wrong_kind() { let step = ScenarioStep::new(StepKind::Given, "given", "yo"); - let b = Binding::new(StepKind::When, "yo", "do_yo", None).unwrap(); + let b = Binding::new(StepKind::When, "yo", "do_yo", None, false).unwrap(); assert!(b.match_with_step(&step).is_none()); } #[test] fn does_not_match_with_wrong_text() { let step = ScenarioStep::new(StepKind::Given, "given", "foo"); - let b = Binding::new(StepKind::Given, "bar", "yo", None).unwrap(); + let b = Binding::new(StepKind::Given, "bar", "yo", None, false).unwrap(); assert!(b.match_with_step(&step).is_none()); } #[test] fn match_with_fixed_pattern() { let step = ScenarioStep::new(StepKind::Given, "given", "foo"); - let b = Binding::new(StepKind::Given, "foo", "do_foo", None).unwrap(); + let b = Binding::new(StepKind::Given, "foo", "do_foo", None, false).unwrap(); let m = b.match_with_step(&step).unwrap(); assert_eq!(m.kind(), StepKind::Given); let mut parts = m.parts(); @@ -223,6 +250,7 @@ mod test_binding { r"I am (?P<who>\S+), I am", "set_name", None, + false, ) .unwrap(); let m = b.match_with_step(&step).unwrap(); @@ -233,6 +261,15 @@ mod test_binding { assert_eq!(parts.next().unwrap(), &PartialStep::uncaptured(", I am")); assert_eq!(parts.next(), None); } + + #[test] + fn case_sensitive_mismatch() { + let step = ScenarioStep::new(StepKind::Given, "given", "I am Tomjon"); + let b = Binding::new(StepKind::Given, r"i am tomjon", "set_name", None, false).unwrap(); + assert!(b.match_with_step(&step).is_some()); + let b = Binding::new(StepKind::Given, r"i am tomjon", "set_name", None, true).unwrap(); + assert!(b.match_with_step(&step).is_none()); + } } /// Set of all known bindings. @@ -255,6 +292,15 @@ struct ParsedBinding { function: String, cleanup: Option<String>, regex: Option<bool>, + #[serde(default)] + case_sensitive: bool, +} + +#[derive(Debug, Deserialize)] +#[serde(transparent)] +struct ParsedBindingWrapper { + #[serde(deserialize_with = "deserialize_struct_case_insensitive")] + binding: ParsedBinding, } impl Bindings { @@ -280,9 +326,9 @@ impl Bindings { /// Add bindings from a YAML string pub fn add_from_yaml(&mut self, yaml: &str) -> Result<()> { - let bindings: Vec<ParsedBinding> = serde_yaml::from_str(yaml)?; - for b in bindings { - self.add(from_hashmap(&b)?); + let bindings: Vec<ParsedBindingWrapper> = serde_yaml::from_str(yaml)?; + for wrapper in bindings { + self.add(from_hashmap(&wrapper.binding)?); } Ok(()) } @@ -372,6 +418,7 @@ fn from_hashmap(parsed: &ParsedBinding) -> Result<Binding> { None => None, Some(ref s) => Some(s), }, + parsed.case_sensitive, )?) } @@ -392,8 +439,14 @@ mod test_bindings { #[test] fn adds_binding() { - let binding = - Binding::new(StepKind::Given, r"I am (?P<name>\S+)", "set_name", None).unwrap(); + let binding = Binding::new( + StepKind::Given, + r"I am (?P<name>\S+)", + "set_name", + None, + false, + ) + .unwrap(); let mut bindings = Bindings::new(); bindings.add(binding.clone()); assert_eq!(bindings.bindings(), &[binding]); @@ -402,12 +455,15 @@ mod test_bindings { #[test] fn adds_from_yaml() { let yaml = " -- given: I am Tomjon +- GIVEN: I am Tomjon function: set_name - when: I declare myself king - function: declare_king -- then: there is applause + Function: declare_king +- tHEn: there is applause function: check_for_applause +- given: you are alice + function: other_name + case_sensitive: true "; let mut bindings = Bindings::new(); bindings.add_from_yaml(&yaml).unwrap(); @@ -415,15 +471,17 @@ mod test_bindings { assert!(bindings.has(StepKind::Given, "I am Tomjon")); assert!(bindings.has(StepKind::When, "I declare myself king")); assert!(bindings.has(StepKind::Then, "there is applause")); - assert_eq!(bindings.len(), 3); + assert!(bindings.has(StepKind::Given, "you are alice")); + assert!(!bindings.has(StepKind::Given, "you are Alice")); + assert_eq!(bindings.len(), 4); } #[test] fn add_from_yaml_notices_multiple_keywords() { let yaml = " -- given: I am Tomjon - when: I am indeed Tomjon - function: set_name +- Given: I am Tomjon + wheN: I am indeed Tomjon + FUNCTION: set_name "; match Bindings::new().add_from_yaml(&yaml) { Ok(_) => unreachable!(), @@ -435,7 +493,7 @@ mod test_bindings { #[test] fn does_not_find_match_for_unmatching_kind() { let step = ScenarioStep::new(StepKind::Given, "given", "I am Tomjon"); - let binding = Binding::new(StepKind::When, r"I am Tomjon", "set_foo", None).unwrap(); + let binding = Binding::new(StepKind::When, r"I am Tomjon", "set_foo", None, false).unwrap(); let mut bindings = Bindings::new(); bindings.add(binding); assert!(match bindings.find(&step) { @@ -447,8 +505,14 @@ mod test_bindings { #[test] fn does_not_find_match_for_unmatching_pattern() { let step = ScenarioStep::new(StepKind::Given, "given", "I am Tomjon"); - let binding = - Binding::new(StepKind::Given, r"I am Tomjon of Lancre", "set_foo", None).unwrap(); + let binding = Binding::new( + StepKind::Given, + r"I am Tomjon of Lancre", + "set_foo", + None, + false, + ) + .unwrap(); let mut bindings = Bindings::new(); bindings.add(binding); assert!(match bindings.find(&step) { @@ -461,13 +525,15 @@ mod test_bindings { fn two_matching_bindings() { let step = ScenarioStep::new(StepKind::Given, "given", "I am Tomjon"); let mut bindings = Bindings::default(); - bindings.add(Binding::new(StepKind::Given, r"I am Tomjon", "set_foo", None).unwrap()); + bindings + .add(Binding::new(StepKind::Given, r"I am Tomjon", "set_foo", None, false).unwrap()); bindings.add( Binding::new( StepKind::Given, &super::regex_from_simple_pattern(r"I am {name}", false).unwrap(), "set_foo", None, + false, ) .unwrap(), ); @@ -480,7 +546,8 @@ mod test_bindings { #[test] fn finds_match_for_fixed_string_pattern() { let step = ScenarioStep::new(StepKind::Given, "given", "I am Tomjon"); - let binding = Binding::new(StepKind::Given, r"I am Tomjon", "set_name", None).unwrap(); + let binding = + Binding::new(StepKind::Given, r"I am Tomjon", "set_name", None, false).unwrap(); let mut bindings = Bindings::new(); bindings.add(binding); let m = bindings.find(&step).unwrap(); @@ -497,8 +564,14 @@ mod test_bindings { #[test] fn finds_match_for_regexp_pattern() { let step = ScenarioStep::new(StepKind::Given, "given", "I am Tomjon"); - let binding = - Binding::new(StepKind::Given, r"I am (?P<name>\S+)", "set_name", None).unwrap(); + let binding = Binding::new( + StepKind::Given, + r"I am (?P<name>\S+)", + "set_name", + None, + false, + ) + .unwrap(); let mut bindings = Bindings::new(); bindings.add(binding); let m = bindings.find(&step).unwrap(); |