Pass whether filters are applied in assert or not

This commit is contained in:
Fabrice Reix 2023-01-18 07:48:05 +01:00 committed by jcamiel
parent e0d3e4aab6
commit 748a2084c5
No known key found for this signature in database
GPG Key ID: 07FF11CFD55356CC
7 changed files with 149 additions and 52 deletions

View File

@ -0,0 +1,7 @@
error: Filter Error
--> tests_failed/filter_in_capture.hurl:4:21
|
4 | id: jsonpath "$.id" toInt
| ^^^^^ invalid filter input: string <123x>
|

View File

@ -0,0 +1 @@
3

View File

@ -0,0 +1,6 @@
GET http://localhost:8000/error-filter-in-capture
HTTP 200
[Captures]
id: jsonpath "$.id" toInt
[Asserts]
jsonpath "$.id" toInt == 1

View File

@ -0,0 +1,15 @@
from app import app
from flask import Response
@app.route("/error-filter-in-capture")
def error_filter_in_capture():
return Response(
"""{
"id":"123x",
"status": true,
"list": [1,2,3]
}
""",
mimetype="application/json",
)

View File

@ -154,7 +154,7 @@ pub fn eval_assert(
}), }),
Some(value) => { Some(value) => {
let filters = assert.filters.iter().map(|(_, f)| f.clone()).collect(); let filters = assert.filters.iter().map(|(_, f)| f.clone()).collect();
match eval_filters(&filters, &value, variables) { match eval_filters(&filters, &value, variables, true) {
Ok(value) => Ok(Some(value)), Ok(value) => Ok(Some(value)),
Err(e) => Err(e), Err(e) => Err(e),
} }

View File

@ -46,7 +46,7 @@ pub fn eval_capture(
} }
Some(value) => { Some(value) => {
let filters = capture.filters.iter().map(|(_, f)| f.clone()).collect(); let filters = capture.filters.iter().map(|(_, f)| f.clone()).collect();
eval_filters(&filters, &value, variables)? eval_filters(&filters, &value, variables, false)?
} }
}; };
Ok(CaptureResult { Ok(CaptureResult {

View File

@ -26,15 +26,17 @@ use crate::runner::regex::eval_regex_value;
use crate::runner::template::eval_template; use crate::runner::template::eval_template;
use crate::runner::{Error, RunnerError, Value}; use crate::runner::{Error, RunnerError, Value};
// TODO: indicated whether you running the filter in an assert / this produce an "assert" error /// Apply successive `filters` to an input `value`.
/// Specify whether they are executed `in_assert` or not.
pub fn eval_filters( pub fn eval_filters(
filters: &Vec<Filter>, filters: &Vec<Filter>,
value: &Value, value: &Value,
variables: &HashMap<String, Value>, variables: &HashMap<String, Value>,
in_assert: bool,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
let mut value = value.clone(); let mut value = value.clone();
for filter in filters { for filter in filters {
value = eval_filter(filter, &value, variables)?; value = eval_filter(filter, &value, variables, in_assert)?;
} }
Ok(value) Ok(value)
} }
@ -43,24 +45,40 @@ fn eval_filter(
filter: &Filter, filter: &Filter,
value: &Value, value: &Value,
variables: &HashMap<String, Value>, variables: &HashMap<String, Value>,
in_assert: bool,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match &filter.value { match &filter.value {
FilterValue::Count => eval_count(value, &filter.source_info), FilterValue::Count => eval_count(value, &filter.source_info, in_assert),
FilterValue::HtmlEscape => eval_html_escape(value, &filter.source_info), FilterValue::HtmlEscape => eval_html_escape(value, &filter.source_info, in_assert),
FilterValue::HtmlUnescape => eval_html_unescape(value, &filter.source_info), FilterValue::HtmlUnescape => eval_html_unescape(value, &filter.source_info, in_assert),
FilterValue::Regex { FilterValue::Regex {
value: regex_value, .. value: regex_value, ..
} => eval_regex(value, regex_value, variables, &filter.source_info), } => eval_regex(
FilterValue::Nth { n, .. } => eval_nth(value, &filter.source_info, *n), value,
regex_value,
variables,
&filter.source_info,
in_assert,
),
FilterValue::Nth { n, .. } => eval_nth(value, &filter.source_info, in_assert, *n),
FilterValue::Replace { FilterValue::Replace {
old_value, old_value,
new_value, new_value,
.. ..
} => eval_replace(value, variables, &filter.source_info, old_value, new_value), } => eval_replace(
FilterValue::Split { sep, .. } => eval_split(value, variables, &filter.source_info, sep), value,
FilterValue::ToInt => eval_to_int(value, &filter.source_info), variables,
FilterValue::UrlDecode => eval_url_decode(value, &filter.source_info), &filter.source_info,
FilterValue::UrlEncode => eval_url_encode(value, &filter.source_info), in_assert,
old_value,
new_value,
),
FilterValue::Split { sep, .. } => {
eval_split(value, variables, &filter.source_info, in_assert, sep)
}
FilterValue::ToInt => eval_to_int(value, &filter.source_info, in_assert),
FilterValue::UrlDecode => eval_url_decode(value, &filter.source_info, in_assert),
FilterValue::UrlEncode => eval_url_encode(value, &filter.source_info, in_assert),
} }
} }
@ -69,6 +87,7 @@ fn eval_regex(
regex_value: &RegexValue, regex_value: &RegexValue,
variables: &HashMap<String, Value>, variables: &HashMap<String, Value>,
source_info: &SourceInfo, source_info: &SourceInfo,
assert: bool,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
let re = eval_regex_value(regex_value, variables)?; let re = eval_regex_value(regex_value, variables)?;
match value { match value {
@ -78,24 +97,24 @@ fn eval_regex(
None => Err(Error { None => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterRegexNoCapture {}, inner: RunnerError::FilterRegexNoCapture {},
assert: false, assert,
}), }),
}, },
None => Err(Error { None => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterRegexNoCapture {}, inner: RunnerError::FilterRegexNoCapture {},
assert: false, assert,
}), }),
}, },
v => Err(Error { v => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput(v._type()), inner: RunnerError::FilterInvalidInput(v._type()),
assert: false, assert,
}), }),
} }
} }
fn eval_count(value: &Value, source_info: &SourceInfo) -> Result<Value, Error> { fn eval_count(value: &Value, source_info: &SourceInfo, assert: bool) -> Result<Value, Error> {
match value { match value {
Value::List(values) => Ok(Value::Integer(values.len() as i64)), Value::List(values) => Ok(Value::Integer(values.len() as i64)),
Value::Bytes(values) => Ok(Value::Integer(values.len() as i64)), Value::Bytes(values) => Ok(Value::Integer(values.len() as i64)),
@ -103,14 +122,14 @@ fn eval_count(value: &Value, source_info: &SourceInfo) -> Result<Value, Error> {
v => Err(Error { v => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput(v._type()), inner: RunnerError::FilterInvalidInput(v._type()),
assert: false, assert,
}), }),
} }
} }
// does not encopde "/" // does not encode "/"
// like Jinja template (https://jinja.palletsprojects.com/en/3.1.x/templates/#jinja-filters.urlencode) // like Jinja template (https://jinja.palletsprojects.com/en/3.1.x/templates/#jinja-filters.urlencode)
fn eval_url_encode(value: &Value, source_info: &SourceInfo) -> Result<Value, Error> { fn eval_url_encode(value: &Value, source_info: &SourceInfo, assert: bool) -> Result<Value, Error> {
match value { match value {
Value::String(value) => { Value::String(value) => {
const FRAGMENT: &AsciiSet = &percent_encoding::NON_ALPHANUMERIC const FRAGMENT: &AsciiSet = &percent_encoding::NON_ALPHANUMERIC
@ -125,12 +144,12 @@ fn eval_url_encode(value: &Value, source_info: &SourceInfo) -> Result<Value, Err
v => Err(Error { v => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput(v._type()), inner: RunnerError::FilterInvalidInput(v._type()),
assert: false, assert,
}), }),
} }
} }
fn eval_url_decode(value: &Value, source_info: &SourceInfo) -> Result<Value, Error> { fn eval_url_decode(value: &Value, source_info: &SourceInfo, assert: bool) -> Result<Value, Error> {
match value { match value {
Value::String(value) => { Value::String(value) => {
match percent_encoding::percent_decode(value.as_bytes()).decode_utf8() { match percent_encoding::percent_decode(value.as_bytes()).decode_utf8() {
@ -138,19 +157,19 @@ fn eval_url_decode(value: &Value, source_info: &SourceInfo) -> Result<Value, Err
Err(_) => Err(Error { Err(_) => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput("Invalid UTF8 stream".to_string()), inner: RunnerError::FilterInvalidInput("Invalid UTF8 stream".to_string()),
assert: false, assert,
}), }),
} }
} }
v => Err(Error { v => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput(v._type()), inner: RunnerError::FilterInvalidInput(v._type()),
assert: false, assert,
}), }),
} }
} }
fn eval_nth(value: &Value, source_info: &SourceInfo, n: u64) -> Result<Value, Error> { fn eval_nth(value: &Value, source_info: &SourceInfo, assert: bool, n: u64) -> Result<Value, Error> {
match value { match value {
Value::List(values) => match values.get(n as usize) { Value::List(values) => match values.get(n as usize) {
None => Err(Error { None => Err(Error {
@ -159,19 +178,19 @@ fn eval_nth(value: &Value, source_info: &SourceInfo, n: u64) -> Result<Value, Er
"Out of bound - size is {}", "Out of bound - size is {}",
values.len() values.len()
)), )),
assert: false, assert,
}), }),
Some(value) => Ok(value.clone()), Some(value) => Ok(value.clone()),
}, },
v => Err(Error { v => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput(v.display()), inner: RunnerError::FilterInvalidInput(v.display()),
assert: false, assert,
}), }),
} }
} }
fn eval_html_escape(value: &Value, source_info: &SourceInfo) -> Result<Value, Error> { fn eval_html_escape(value: &Value, source_info: &SourceInfo, assert: bool) -> Result<Value, Error> {
match value { match value {
Value::String(value) => { Value::String(value) => {
let encoded = html::html_escape(value); let encoded = html::html_escape(value);
@ -180,12 +199,16 @@ fn eval_html_escape(value: &Value, source_info: &SourceInfo) -> Result<Value, Er
v => Err(Error { v => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput(v._type()), inner: RunnerError::FilterInvalidInput(v._type()),
assert: false, assert,
}), }),
} }
} }
fn eval_html_unescape(value: &Value, source_info: &SourceInfo) -> Result<Value, Error> { fn eval_html_unescape(
value: &Value,
source_info: &SourceInfo,
assert: bool,
) -> Result<Value, Error> {
match value { match value {
Value::String(value) => { Value::String(value) => {
let decoded = html::html_unescape(value); let decoded = html::html_unescape(value);
@ -194,7 +217,7 @@ fn eval_html_unescape(value: &Value, source_info: &SourceInfo) -> Result<Value,
v => Err(Error { v => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput(v._type()), inner: RunnerError::FilterInvalidInput(v._type()),
assert: false, assert,
}), }),
} }
} }
@ -203,6 +226,7 @@ fn eval_replace(
value: &Value, value: &Value,
variables: &HashMap<String, Value>, variables: &HashMap<String, Value>,
source_info: &SourceInfo, source_info: &SourceInfo,
assert: bool,
old_value: &RegexValue, old_value: &RegexValue,
new_value: &Template, new_value: &Template,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
@ -216,7 +240,7 @@ fn eval_replace(
v => Err(Error { v => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput(v.display()), inner: RunnerError::FilterInvalidInput(v.display()),
assert: false, assert,
}), }),
} }
} }
@ -225,6 +249,7 @@ fn eval_split(
value: &Value, value: &Value,
variables: &HashMap<String, Value>, variables: &HashMap<String, Value>,
source_info: &SourceInfo, source_info: &SourceInfo,
assert: bool,
sep: &Template, sep: &Template,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match value { match value {
@ -239,12 +264,12 @@ fn eval_split(
v => Err(Error { v => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput(v.display()), inner: RunnerError::FilterInvalidInput(v.display()),
assert: false, assert,
}), }),
} }
} }
fn eval_to_int(value: &Value, source_info: &SourceInfo) -> Result<Value, Error> { fn eval_to_int(value: &Value, source_info: &SourceInfo, assert: bool) -> Result<Value, Error> {
match value { match value {
Value::Integer(v) => Ok(Value::Integer(*v)), Value::Integer(v) => Ok(Value::Integer(*v)),
Value::Float(v) => Ok(Value::Integer(*v as i64)), Value::Float(v) => Ok(Value::Integer(*v as i64)),
@ -253,13 +278,13 @@ fn eval_to_int(value: &Value, source_info: &SourceInfo) -> Result<Value, Error>
Err(_) => Err(Error { Err(_) => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput(value.display()), inner: RunnerError::FilterInvalidInput(value.display()),
assert: false, assert,
}), }),
}, },
v => Err(Error { v => Err(Error {
source_info: source_info.clone(), source_info: source_info.clone(),
inner: RunnerError::FilterInvalidInput(v.display()), inner: RunnerError::FilterInvalidInput(v.display()),
assert: false, assert,
}), }),
} }
} }
@ -290,6 +315,7 @@ pub mod tests {
Value::Integer(2), Value::Integer(2),
]), ]),
&variables, &variables,
false,
) )
.unwrap(), .unwrap(),
Value::Integer(3) Value::Integer(3)
@ -309,12 +335,13 @@ pub mod tests {
Value::Integer(2), Value::Integer(2),
]), ]),
&variables, &variables,
false,
) )
.unwrap(), .unwrap(),
Value::Integer(3) Value::Integer(3)
); );
let error = eval_filter(&filter_count(), &Value::Bool(true), &variables) let error = eval_filter(&filter_count(), &Value::Bool(true), &variables, false)
.err() .err()
.unwrap(); .unwrap();
assert_eq!(error.source_info, SourceInfo::new(1, 1, 1, 6)); assert_eq!(error.source_info, SourceInfo::new(1, 1, 1, 6));
@ -351,12 +378,13 @@ pub mod tests {
&filter, &filter,
&Value::String("Hello Bob!".to_string()), &Value::String("Hello Bob!".to_string()),
&variables, &variables,
false,
) )
.unwrap(), .unwrap(),
Value::String("Bob".to_string()) Value::String("Bob".to_string())
); );
let error = eval_filter(&filter, &Value::Bool(true), &variables) let error = eval_filter(&filter, &Value::Bool(true), &variables, false)
.err() .err()
.unwrap(); .unwrap();
assert_eq!(error.source_info, SourceInfo::new(1, 1, 1, 20)); assert_eq!(error.source_info, SourceInfo::new(1, 1, 1, 20));
@ -391,6 +419,7 @@ pub mod tests {
&filter, &filter,
&Value::String("Hello Bob!".to_string()), &Value::String("Hello Bob!".to_string()),
&variables, &variables,
false,
) )
.err() .err()
.unwrap(); .unwrap();
@ -410,6 +439,7 @@ pub mod tests {
&filter, &filter,
&Value::String("https://mozilla.org/?x=шеллы".to_string()), &Value::String("https://mozilla.org/?x=шеллы".to_string()),
&variables, &variables,
false,
) )
.unwrap(), .unwrap(),
Value::String( Value::String(
@ -430,6 +460,7 @@ pub mod tests {
&filter, &filter,
&Value::String("https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B".to_string()), &Value::String("https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B".to_string()),
&variables, &variables,
false,
) )
.unwrap(), .unwrap(),
Value::String("https://mozilla.org/?x=шеллы".to_string()) Value::String("https://mozilla.org/?x=шеллы".to_string())
@ -444,15 +475,21 @@ pub mod tests {
value: FilterValue::ToInt, value: FilterValue::ToInt,
}; };
assert_eq!( assert_eq!(
eval_filter(&filter, &Value::String("123".to_string()), &variables).unwrap(), eval_filter(
&filter,
&Value::String("123".to_string()),
&variables,
false
)
.unwrap(),
Value::Integer(123) Value::Integer(123)
); );
assert_eq!( assert_eq!(
eval_filter(&filter, &Value::Integer(123), &variables).unwrap(), eval_filter(&filter, &Value::Integer(123), &variables, false).unwrap(),
Value::Integer(123) Value::Integer(123)
); );
assert_eq!( assert_eq!(
eval_filter(&filter, &Value::Float(1.6), &variables).unwrap(), eval_filter(&filter, &Value::Float(1.6), &variables, false).unwrap(),
Value::Integer(1) Value::Integer(1)
); );
} }
@ -464,14 +501,19 @@ pub mod tests {
source_info: SourceInfo::new(1, 1, 1, 1), source_info: SourceInfo::new(1, 1, 1, 1),
value: FilterValue::ToInt, value: FilterValue::ToInt,
}; };
let err = eval_filter(&filter, &Value::String("123x".to_string()), &variables) let err = eval_filter(
.err() &filter,
.unwrap(); &Value::String("123x".to_string()),
&variables,
false,
)
.err()
.unwrap();
assert_eq!( assert_eq!(
err.inner, err.inner,
RunnerError::FilterInvalidInput("string <123x>".to_string()) RunnerError::FilterInvalidInput("string <123x>".to_string())
); );
let err = eval_filter(&filter, &Value::Bool(true), &variables) let err = eval_filter(&filter, &Value::Bool(true), &variables, false)
.err() .err()
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
@ -499,7 +541,13 @@ pub mod tests {
]; ];
for (input, output) in tests.iter() { for (input, output) in tests.iter() {
assert_eq!( assert_eq!(
eval_filter(&filter, &Value::String(input.to_string()), &variables).unwrap(), eval_filter(
&filter,
&Value::String(input.to_string()),
&variables,
false
)
.unwrap(),
Value::String(output.to_string()) Value::String(output.to_string())
); );
} }
@ -524,7 +572,13 @@ pub mod tests {
]; ];
for (input, output) in tests.iter() { for (input, output) in tests.iter() {
assert_eq!( assert_eq!(
eval_filter(&filter, &Value::String(input.to_string()), &variables).unwrap(), eval_filter(
&filter,
&Value::String(input.to_string()),
&variables,
false
)
.unwrap(),
Value::String(output.to_string()) Value::String(output.to_string())
); );
} }
@ -553,7 +607,8 @@ pub mod tests {
Value::Integer(2), Value::Integer(2),
Value::Integer(3) Value::Integer(3)
]), ]),
&variables &variables,
false
) )
.unwrap(), .unwrap(),
Value::Integer(2) Value::Integer(2)
@ -562,7 +617,8 @@ pub mod tests {
eval_filter( eval_filter(
&filter, &filter,
&Value::List(vec![Value::Integer(0), Value::Integer(1)]), &Value::List(vec![Value::Integer(0), Value::Integer(1)]),
&variables &variables,
false
) )
.err() .err()
.unwrap(), .unwrap(),
@ -608,7 +664,13 @@ pub mod tests {
}; };
assert_eq!( assert_eq!(
eval_filter(&filter, &Value::String("1 2\t3 4".to_string()), &variables).unwrap(), eval_filter(
&filter,
&Value::String("1 2\t3 4".to_string()),
&variables,
false
)
.unwrap(),
Value::String("1,2,3,4".to_string()) Value::String("1,2,3,4".to_string())
); );
} }
@ -635,7 +697,13 @@ pub mod tests {
}; };
assert_eq!( assert_eq!(
eval_filter(&filter, &Value::String("1,2,3".to_string()), &variables).unwrap(), eval_filter(
&filter,
&Value::String("1,2,3".to_string()),
&variables,
false
)
.unwrap(),
Value::List(vec![ Value::List(vec![
Value::String("1".to_string()), Value::String("1".to_string()),
Value::String("2".to_string()), Value::String("2".to_string()),