Add isNumber predicate

This commit is contained in:
jcamiel 2024-03-28 11:12:30 +01:00
parent f1ece5c9ef
commit bc1303552a
No known key found for this signature in database
GPG Key ID: 07FF11CFD55356CC
16 changed files with 63 additions and 2 deletions

View File

@ -431,3 +431,13 @@ error: Assert failure
| expected: not string with format YYYY-MM-DDTHH:mm:ss.sssZ
|
error: Assert failure
--> tests_failed/predicate.hurl:47:0
|
| GET http://localhost:8000/predicate/error/type
| ...
47 | jsonpath "$.not_a_date" isNumber
| actual: string <2018>
| expected: number
|

View File

@ -44,3 +44,4 @@ jsonpath "$.not-exist" exists
jsonpath "$.not-exist" isEmpty
jsonpath "$.not_a_date" isIsoDate
jsonpath "$.is_a_date" not isIsoDate
jsonpath "$.not_a_date" isNumber

View File

@ -50,6 +50,7 @@ jsonpath "$.duration" <= 2.0
jsonpath "$.duration" < 2
jsonpath "$.duration" < {{two}}
jsonpath "$.duration" isFloat
jsonpath "$.duration" isNumber
jsonpath "$.duration" not isInteger
jsonpath "$.nullable" == null
jsonpath "$.tags[0]" == "test"
@ -67,6 +68,7 @@ jsonpath "$..id" count == 3
jsonpath "$.dates[0]" isIsoDate
jsonpath "$.dates[1]" isIsoDate
jsonpath "$.tags[0]" not isIsoDate
jsonpath "$.tags[0]" not isNumber
# FIXME do we accept count filter on object?

View File

@ -26,4 +26,5 @@
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.release"</span> <span class="predicate-type">matches</span> <span class="regex">/\d{4}/</span></span> <span class="comment"># matches</span>
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.movie"</span> <span class="predicate-type">startsWith</span> <span class="string">"The"</span></span> <span class="comment"># startsWith</span>
<span class="line"><span class="query-type">bytes</span> <span class="predicate-type">startsWith</span> hex,<span class="hex">efbbbf</span>;</span> <span class="comment"># startsWith</span>
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.count"</span> <span class="predicate-type">isNumber</span></span> <span class="comment"># isNumber</span>
</span></span></code></pre>

View File

@ -26,3 +26,4 @@ jsonpath "$.release" matches "\\d{4}" # matches
jsonpath "$.release" matches /\d{4}/ # matches
jsonpath "$.movie" startsWith "The" # startsWith
bytes startsWith hex,efbbbf; # startsWith
jsonpath "$.count" isNumber # isNumber

View File

@ -1 +1 @@
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/dummy"},"response":{"status":200,"asserts":[{"query":{"type":"jsonpath","expr":"$.book"},"predicate":{"not":true,"type":"equal","value":"Dune"}},{"query":{"type":"jsonpath","expr":"$.book"},"predicate":{"type":"equal","value":"Dune"}},{"query":{"type":"jsonpath","expr":"$.color"},"predicate":{"type":"not-equal","value":"red"}},{"query":{"type":"jsonpath","expr":"$.year"},"predicate":{"type":"greater","value":1978}},{"query":{"type":"jsonpath","expr":"$.year"},"predicate":{"type":"greater-or-equal","value":1978}},{"query":{"type":"jsonpath","expr":"$.year"},"predicate":{"type":"less","value":1978}},{"query":{"type":"jsonpath","expr":"$.year"},"predicate":{"type":"less-or-equal","value":1978}},{"query":{"type":"jsonpath","expr":"$.movie"},"predicate":{"type":"contain","value":"Empire"}},{"query":{"type":"bytes"},"predicate":{"type":"contain","value":"vu8=","encoding":"base64"}},{"query":{"type":"jsonpath","expr":"$.movie"},"predicate":{"type":"end-with","value":"Back"}},{"query":{"type":"bytes"},"predicate":{"type":"end-with","value":"qxI0Vg==","encoding":"base64"}},{"query":{"type":"jsonpath","expr":"$.book"},"predicate":{"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.nooks"},"predicate":{"type":"include","value":"Dune"}},{"query":{"type":"jsonpath","expr":"$.succeeded"},"predicate":{"type":"isBoolean"}},{"query":{"type":"jsonpath","expr":"$.books"},"predicate":{"type":"isCollection"}},{"query":{"type":"certificate","expr":"Expire-Date"},"predicate":{"type":"isDate"}},{"query":{"type":"jsonpath","expr":"$.publication_date"},"predicate":{"type":"isIsoDate"}},{"query":{"type":"jsonpath","expr":"$.movies"},"predicate":{"type":"isEmpty"}},{"query":{"type":"jsonpath","expr":"$.height"},"predicate":{"type":"isFloat"}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"isInteger"}},{"query":{"type":"jsonpath","expr":"$.name"},"predicate":{"type":"isString"}},{"query":{"type":"jsonpath","expr":"$.release"},"predicate":{"type":"match","value":"\\d{4}"}},{"query":{"type":"jsonpath","expr":"$.release"},"predicate":{"type":"match","value":"\\d{4}","encoding":"regex"}},{"query":{"type":"jsonpath","expr":"$.movie"},"predicate":{"type":"start-with","value":"The"}},{"query":{"type":"bytes"},"predicate":{"type":"start-with","value":"77u/","encoding":"base64"}}]}}]}
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/dummy"},"response":{"status":200,"asserts":[{"query":{"type":"jsonpath","expr":"$.book"},"predicate":{"not":true,"type":"equal","value":"Dune"}},{"query":{"type":"jsonpath","expr":"$.book"},"predicate":{"type":"equal","value":"Dune"}},{"query":{"type":"jsonpath","expr":"$.color"},"predicate":{"type":"not-equal","value":"red"}},{"query":{"type":"jsonpath","expr":"$.year"},"predicate":{"type":"greater","value":1978}},{"query":{"type":"jsonpath","expr":"$.year"},"predicate":{"type":"greater-or-equal","value":1978}},{"query":{"type":"jsonpath","expr":"$.year"},"predicate":{"type":"less","value":1978}},{"query":{"type":"jsonpath","expr":"$.year"},"predicate":{"type":"less-or-equal","value":1978}},{"query":{"type":"jsonpath","expr":"$.movie"},"predicate":{"type":"contain","value":"Empire"}},{"query":{"type":"bytes"},"predicate":{"type":"contain","value":"vu8=","encoding":"base64"}},{"query":{"type":"jsonpath","expr":"$.movie"},"predicate":{"type":"end-with","value":"Back"}},{"query":{"type":"bytes"},"predicate":{"type":"end-with","value":"qxI0Vg==","encoding":"base64"}},{"query":{"type":"jsonpath","expr":"$.book"},"predicate":{"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.nooks"},"predicate":{"type":"include","value":"Dune"}},{"query":{"type":"jsonpath","expr":"$.succeeded"},"predicate":{"type":"isBoolean"}},{"query":{"type":"jsonpath","expr":"$.books"},"predicate":{"type":"isCollection"}},{"query":{"type":"certificate","expr":"Expire-Date"},"predicate":{"type":"isDate"}},{"query":{"type":"jsonpath","expr":"$.publication_date"},"predicate":{"type":"isIsoDate"}},{"query":{"type":"jsonpath","expr":"$.movies"},"predicate":{"type":"isEmpty"}},{"query":{"type":"jsonpath","expr":"$.height"},"predicate":{"type":"isFloat"}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"isInteger"}},{"query":{"type":"jsonpath","expr":"$.name"},"predicate":{"type":"isString"}},{"query":{"type":"jsonpath","expr":"$.release"},"predicate":{"type":"match","value":"\\d{4}"}},{"query":{"type":"jsonpath","expr":"$.release"},"predicate":{"type":"match","value":"\\d{4}","encoding":"regex"}},{"query":{"type":"jsonpath","expr":"$.movie"},"predicate":{"type":"start-with","value":"The"}},{"query":{"type":"bytes"},"predicate":{"type":"start-with","value":"77u/","encoding":"base64"}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"isNumber"}}]}}]}

View File

@ -26,3 +26,4 @@ jsonpath "$.release" matches "\\d{4}" # matches
jsonpath "$.release" matches /\d{4}/ # matches
jsonpath "$.movie" startsWith "The" # startsWith
bytes startsWith hex,efbbbf; # startsWith
jsonpath "$.count" isNumber # isNumber

View File

@ -238,6 +238,7 @@ fn expected_no_value(
PredicateFuncValue::IsIsoDate => Ok("date".to_string()),
PredicateFuncValue::Exist => Ok("something".to_string()),
PredicateFuncValue::IsEmpty => Ok("empty".to_string()),
PredicateFuncValue::IsNumber => Ok("number".to_string()),
}
}
@ -306,6 +307,7 @@ fn eval_predicate_func(
PredicateFuncValue::IsIsoDate => eval_is_iso_date(value),
PredicateFuncValue::Exist => eval_exist(value),
PredicateFuncValue::IsEmpty => eval_is_empty(value),
PredicateFuncValue::IsNumber => eval_is_number(value),
}
}
@ -670,6 +672,16 @@ fn eval_is_empty(actual: &Value) -> Result<AssertResult, Error> {
}
}
/// Evaluates if an `actual` value is a number.
fn eval_is_number(actual: &Value) -> Result<AssertResult, Error> {
Ok(AssertResult {
success: matches!(actual, Value::Number(_)),
actual: actual.display(),
expected: "number".to_string(),
type_mismatch: false,
})
}
fn assert_values_equal(actual: &Value, expected: &Value) -> AssertResult {
let actual_display = actual.display();
let expected_display = expected.display();
@ -1590,4 +1602,21 @@ mod tests {
assert_eq!(res.actual, "bool <true>");
assert_eq!(res.expected, "string");
}
#[test]
fn test_predicate_is_number() {
let value = Value::Number(Number::Integer(1));
let res = eval_is_number(&value).unwrap();
assert!(res.success);
assert!(!res.type_mismatch);
assert_eq!(res.actual, "int <1>");
assert_eq!(res.expected, "number");
let value = Value::Number(Number::Float(1.0));
let res = eval_is_number(&value).unwrap();
assert!(res.success);
assert!(!res.type_mismatch);
assert_eq!(res.actual, "float <1.0>");
assert_eq!(res.expected, "number");
}
}

View File

@ -493,6 +493,7 @@ pub enum PredicateFuncValue {
IsIsoDate,
Exist,
IsEmpty,
IsNumber,
}
//

View File

@ -273,6 +273,7 @@ impl PredicateFuncValue {
PredicateFuncValue::IsIsoDate => "isIsoDate".to_string(),
PredicateFuncValue::Exist => "exists".to_string(),
PredicateFuncValue::IsEmpty => "isEmpty".to_string(),
PredicateFuncValue::IsNumber => "isNumber".to_string(),
}
}
}

View File

@ -533,6 +533,7 @@ impl HtmlFormatter {
PredicateFuncValue::IsIsoDate => {}
PredicateFuncValue::Exist => {}
PredicateFuncValue::IsEmpty => {}
PredicateFuncValue::IsNumber => {}
}
}

View File

@ -137,7 +137,7 @@ fn version(reader: &mut Reader) -> ParseResult<Version> {
let next_c = reader.peek();
match next_c {
Some('/') => {
let available_version = vec![
let available_version = [
("/1.0", VersionValue::Version1),
("/1.1", VersionValue::Version11),
("/2", VersionValue::Version2),

View File

@ -90,6 +90,7 @@ fn predicate_func_value(reader: &mut Reader) -> ParseResult<PredicateFuncValue>
iso_date_predicate,
exist_predicate,
is_empty_predicate,
is_number_predicate,
],
reader,
) {
@ -341,6 +342,11 @@ fn is_empty_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
Ok(PredicateFuncValue::IsEmpty)
}
fn is_number_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
try_literal("isNumber", reader)?;
Ok(PredicateFuncValue::IsNumber)
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -572,6 +572,9 @@ impl ToJson for Predicate {
PredicateFuncValue::IsEmpty => {
attributes.push(("type".to_string(), JValue::String("isEmpty".to_string())));
}
PredicateFuncValue::IsNumber => {
attributes.push(("type".to_string(), JValue::String("isNumber".to_string())));
}
}
JValue::Object(attributes)
}

View File

@ -608,6 +608,9 @@ impl Tokenizable for PredicateFuncValue {
PredicateFuncValue::IsEmpty => {
tokens.push(Token::PredicateType(self.name()));
}
PredicateFuncValue::IsNumber => {
tokens.push(Token::PredicateType(self.name()));
}
}
tokens
}

View File

@ -399,6 +399,7 @@ fn lint_predicate_func_value(predicate_func_value: &PredicateFuncValue) -> Predi
PredicateFuncValue::IsIsoDate => PredicateFuncValue::IsIsoDate,
PredicateFuncValue::Exist => PredicateFuncValue::Exist,
PredicateFuncValue::IsEmpty => PredicateFuncValue::IsEmpty,
PredicateFuncValue::IsNumber => PredicateFuncValue::IsNumber,
}
}