diff --git a/src/function.rs b/src/function.rs index 9cfc69f..4b4b1ec 100644 --- a/src/function.rs +++ b/src/function.rs @@ -1,9 +1,8 @@ - use std::path::{Path, PathBuf}; use std::str; +use nom::{Context, Err, ErrorKind, IResult}; use regex::Regex; -use nom::IResult; use super::Error; @@ -32,6 +31,12 @@ pub enum Function { const INVALID_PATH_CHARS: &str = "\":*?<>|\\"; // \ is treated as invalid to distinguish regex strings. const INVALID_REGEX_PATH_CHARS: &str = "\"<>"; +fn parse_regex(input: &str) -> IResult<&str, Regex> { + Regex::new(input) + .map(|r| ("", r)) + .map_err(|e| Err::Failure(Context::Code(input, ErrorKind::Custom(1)))) +} + impl Function { pub fn eval(&self) -> Result { // TODO: Handle all variants. @@ -44,15 +49,27 @@ impl Function { pub fn parse(input: &str) -> IResult<&str, Function> { // TODO: Handle all variants. - // TODO: Paths may not contain :*?"<>| do_parse!( input, - function: alt!( + function: + alt!( delimited!(tag!("file(\""), is_not!(INVALID_PATH_CHARS), tag!("\")")) => { |path| Function::FilePath(PathBuf::from(path)) } | + delimited!(tag!("file(\""), flat_map!(is_not!(INVALID_REGEX_PATH_CHARS), parse_regex), tag!("\"")) => { + |r| Function::FileRegex(r) + } | delimited!(tag!("active(\""), is_not!(INVALID_PATH_CHARS), tag!("\")")) => { |path| Function::ActivePath(PathBuf::from(path)) + } | + delimited!(tag!("active(\""), flat_map!(is_not!(INVALID_REGEX_PATH_CHARS), parse_regex), tag!("\"")) => { + |r| Function::ActiveRegex(r) + } | + delimited!(tag!("many(\""), flat_map!(is_not!(INVALID_REGEX_PATH_CHARS), parse_regex), tag!("\"")) => { + |r| Function::Many(r) + } | + delimited!(tag!("many_active(\""), flat_map!(is_not!(INVALID_REGEX_PATH_CHARS), parse_regex), tag!("\"")) => { + |r| Function::ManyActive(r) } ) >> (function) ) @@ -74,7 +91,19 @@ mod tests { } #[test] - fn function_parse_should_parse_an_active_function() { + fn function_parse_should_parse_a_file_regex_function() { + let result = Function::parse("file(\"Cargo.*\")").unwrap().1; + + match result { + Function::FileRegex(r) => { + assert_eq!(Regex::new("Cargo.*").unwrap().as_str(), r.as_str()) + } + _ => panic!("Expected a file regex function"), + } + } + + #[test] + fn function_parse_should_parse_an_active_path_function() { let result = Function::parse("active(\"Cargo.toml\")").unwrap().1; match result { @@ -83,6 +112,42 @@ mod tests { } } + #[test] + fn function_parse_should_parse_an_active_regex_function() { + let result = Function::parse("active(\"Cargo.*\")").unwrap().1; + + match result { + Function::ActiveRegex(r) => { + assert_eq!(Regex::new("Cargo.*").unwrap().as_str(), r.as_str()) + } + _ => panic!("Expected an active regex function"), + } + } + + #[test] + fn function_parse_should_parse_a_many_function() { + let result = Function::parse("many(\"Cargo.*\")").unwrap().1; + + match result { + Function::Many(r) => { + assert_eq!(Regex::new("Cargo.*").unwrap().as_str(), r.as_str()) + } + _ => panic!("Expected a many function"), + } + } + + #[test] + fn function_parse_should_parse_a_many_active_function() { + let result = Function::parse("many_active(\"Cargo.*\")").unwrap().1; + + match result { + Function::ManyActive(r) => { + assert_eq!(Regex::new("Cargo.*").unwrap().as_str(), r.as_str()) + } + _ => panic!("Expected a many active function"), + } + } + #[test] fn function_file_path_eval_should_return_true_if_the_file_exists_relative_to_the_data_path() { let function = Function::FilePath(PathBuf::from("Cargo.toml")); diff --git a/src/lib.rs b/src/lib.rs index 37f456d..6499d64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,8 +114,7 @@ mod tests { #[test] fn expression_parse_should_handle_a_single_compound_condition() { - let result = Expression::parse("file(\"Cargo.toml\")") - .unwrap().1; + let result = Expression::parse("file(\"Cargo.toml\")").unwrap().1; match result.0.as_slice() { [CompoundCondition(_)] => {} @@ -126,7 +125,8 @@ mod tests { #[test] fn expression_parse_should_handle_multiple_compound_conditions() { let result = Expression::parse("file(\"Cargo.toml\") or file(\"Cargo.toml\")") - .unwrap().1; + .unwrap() + .1; match result.0.as_slice() { [CompoundCondition(_), CompoundCondition(_)] => {} @@ -139,8 +139,7 @@ mod tests { #[test] fn compound_condition_parse_should_handle_a_single_condition() { - let result = CompoundCondition::parse("file(\"Cargo.toml\")") - .unwrap().1; + let result = CompoundCondition::parse("file(\"Cargo.toml\")").unwrap().1; match result.0.as_slice() { [Condition::Function(Function::FilePath(f))] => { @@ -156,7 +155,8 @@ mod tests { #[test] fn compound_condition_parse_should_handle_multiple_conditions() { let result = CompoundCondition::parse("file(\"Cargo.toml\") and file(\"README.md\")") - .unwrap().1; + .unwrap() + .1; match result.0.as_slice() { [Condition::Function(Function::FilePath(f1)), Condition::Function(Function::FilePath(f2))] => @@ -173,8 +173,7 @@ mod tests { #[test] fn condition_parse_should_handle_a_function() { - let result = Condition::parse("file(\"Cargo.toml\")") - .unwrap().1; + let result = Condition::parse("file(\"Cargo.toml\")").unwrap().1; match result { Condition::Function(Function::FilePath(f)) => { @@ -189,8 +188,7 @@ mod tests { #[test] fn condition_parse_should_handle_a_inverted_function() { - let result = Condition::parse("not file(\"Cargo.toml\")") - .unwrap().1; + let result = Condition::parse("not file(\"Cargo.toml\")").unwrap().1; match result { Condition::InvertedFunction(Function::FilePath(f)) => { @@ -205,8 +203,7 @@ mod tests { #[test] fn condition_parse_should_handle_an_expression_in_parentheses() { - let result = Condition::parse("(not file(\"Cargo.toml\"))") - .unwrap().1; + let result = Condition::parse("(not file(\"Cargo.toml\"))").unwrap().1; match result { Condition::Expression(_) => {}