mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-09-11 05:35:53 +03:00
add daysAfterNow/DaysBeforeNow filters
This commit is contained in:
parent
88f4173d06
commit
b85bdc29e1
@ -418,6 +418,8 @@ variable-name: [A-Za-z] [A-Za-z_-0-9]*
|
||||
|
||||
filter:
|
||||
count-filter
|
||||
| days-after-now
|
||||
| days-before-now
|
||||
| format-filter
|
||||
| html-escape-filter
|
||||
| html-unescape-filter
|
||||
@ -432,6 +434,10 @@ filter:
|
||||
|
||||
count-filter: "count"
|
||||
|
||||
days-after-now: "daysAfterNow"
|
||||
|
||||
days-before-now: "daysBeforeNow"
|
||||
|
||||
format-filter: "format"
|
||||
|
||||
html-escape-filter: "htmlEscape"
|
||||
|
@ -1,2 +1,7 @@
|
||||
GET https://hurl.dev
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
certificate "Subject" == "CN=hurl.dev"
|
||||
certificate "Issuer" == "C=US, O=Let's Encrypt, CN=R3"
|
||||
certificate "Expire-Date" daysAfterNow > 30
|
||||
certificate "Serial-Number" == "03:db:c4:f3:c8:5e:13:66:cc:52:a3:69:2c:fa:04:a0:7b:b1"
|
||||
|
@ -11,6 +11,7 @@
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"ETag"</span> <span class="predicate-type">==</span> <span class="string">"\"33a64df551425fcc55e4d42a148795d9f25f89d4\""</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Expires"</span> <span class="predicate-type">==</span> <span class="string">"Wed, 21 Oct 2015 07:28:00 GMT"</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Expires"</span> <span class="filter-type">toDate</span> <span class="string">"%a, %d %b %Y %H:%M:%S GMT"</span> <span class="filter-type">format</span> <span class="string">"%Y"</span> <span class="predicate-type">==</span> <span class="string">"2015"</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Expires"</span> <span class="filter-type">toDate</span> <span class="string">"%a, %d %b %Y %H:%M:%S GMT"</span> <span class="filter-type">daysBeforeNow</span> <span class="predicate-type">></span> <span class="number">1000</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Set-Cookie"</span> <span class="predicate-type">exists</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Set-Cookie"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">3</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Set-Cookie"</span> <span class="predicate-type">includes</span> <span class="string">"cookie1=value1; Path=/"</span></span>
|
||||
|
@ -11,6 +11,7 @@ header "Header1" == "value1"
|
||||
header "ETag" == "\"33a64df551425fcc55e4d42a148795d9f25f89d4\""
|
||||
header "Expires" == "Wed, 21 Oct 2015 07:28:00 GMT"
|
||||
header "Expires" toDate "%a, %d %b %Y %H:%M:%S GMT" format "%Y" == "2015"
|
||||
header "Expires" toDate "%a, %d %b %Y %H:%M:%S GMT" daysBeforeNow > 1000
|
||||
header "Set-Cookie" exists
|
||||
header "Set-Cookie" count == 3
|
||||
header "Set-Cookie" includes "cookie1=value1; Path=/"
|
||||
|
@ -1 +1 @@
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/assert-header"},"response":{"status":200,"headers":[{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Set-Cookie","value":"cookie1=value1; Path=/"},{"name":"Set-Cookie","value":"cookie2=value2; Path=/"}],"asserts":[{"query":{"type":"header","name":"Custom"},"predicate":{"not":true,"type":"exist"}},{"query":{"type":"header","name":"Content-Type"},"predicate":{"type":"exist"}},{"query":{"type":"header","name":"Header1"},"predicate":{"type":"equal","value":"value1"}},{"query":{"type":"header","name":"ETag"},"predicate":{"type":"equal","value":"\"33a64df551425fcc55e4d42a148795d9f25f89d4\""}},{"query":{"type":"header","name":"Expires"},"predicate":{"type":"equal","value":"Wed, 21 Oct 2015 07:28:00 GMT"}},{"query":{"type":"header","name":"Expires"},"filters":[{"type":"toDate","fmt":"%a, %d %b %Y %H:%M:%S GMT"},{"type":"format","fmt":"%Y"}],"predicate":{"type":"equal","value":"2015"}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"type":"exist"}},{"query":{"type":"header","name":"Set-Cookie"},"filters":[{"type":"count"}],"predicate":{"type":"equal","value":3}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"type":"include","value":"cookie1=value1; Path=/"}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"not":true,"type":"include","value":"cookie4=value4; Path=/"}}]}}]}
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/assert-header"},"response":{"status":200,"headers":[{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Set-Cookie","value":"cookie1=value1; Path=/"},{"name":"Set-Cookie","value":"cookie2=value2; Path=/"}],"asserts":[{"query":{"type":"header","name":"Custom"},"predicate":{"not":true,"type":"exist"}},{"query":{"type":"header","name":"Content-Type"},"predicate":{"type":"exist"}},{"query":{"type":"header","name":"Header1"},"predicate":{"type":"equal","value":"value1"}},{"query":{"type":"header","name":"ETag"},"predicate":{"type":"equal","value":"\"33a64df551425fcc55e4d42a148795d9f25f89d4\""}},{"query":{"type":"header","name":"Expires"},"predicate":{"type":"equal","value":"Wed, 21 Oct 2015 07:28:00 GMT"}},{"query":{"type":"header","name":"Expires"},"filters":[{"type":"toDate","fmt":"%a, %d %b %Y %H:%M:%S GMT"},{"type":"format","fmt":"%Y"}],"predicate":{"type":"equal","value":"2015"}},{"query":{"type":"header","name":"Expires"},"filters":[{"type":"toDate","fmt":"%a, %d %b %Y %H:%M:%S GMT"},{"type":"daysBeforeNow"}],"predicate":{"type":"greater","value":1000}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"type":"exist"}},{"query":{"type":"header","name":"Set-Cookie"},"filters":[{"type":"count"}],"predicate":{"type":"equal","value":3}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"type":"include","value":"cookie1=value1; Path=/"}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"not":true,"type":"include","value":"cookie4=value4; Path=/"}}]}}]}
|
||||
|
@ -1 +1 @@
|
||||
{"cookies":[{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie1","path":"/","value":"value1"},{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie2","path":"/","value":"value2"},{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie3","path":"/","value":"value3"}],"entries":[{"asserts":[{"line":3,"success":true},{"line":3,"success":true},{"line":4,"success":true},{"line":5,"success":true},{"line":6,"success":true},{"line":8,"success":true},{"line":9,"success":true},{"line":10,"success":true},{"line":11,"success":true},{"line":12,"success":true},{"line":13,"success":true},{"line":14,"success":true},{"line":15,"success":true},{"line":16,"success":true},{"line":17,"success":true}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/assert-header"},"response":{"cookies":[{"name":"cookie1","path":"/","value":"value1"},{"name":"cookie2","path":"/","value":"value2"},{"name":"cookie3","path":"/","value":"value3"}],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Header1","value":"value1"},{"name":"ETag","value":"\"33a64df551425fcc55e4d42a148795d9f25f89d4\""},{"name":"Expires","value":"~~~"},{"name":"Set-Cookie","value":"cookie1=value1; Path=/"},{"name":"Set-Cookie","value":"cookie2=value2; Path=/"},{"name":"Set-Cookie","value":"cookie3=value3; Path=/"},{"name":"Server","value":"Flask Server"},{"name":"Content-Length","value":"0"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":200},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfert":~~~,"start_transfert":~~~,"total":~~~}}],"captures":[],"index":1,"time":~~~}],"filename":"tests_ok/assert_header.hurl","success":true,"time":~~~}
|
||||
{"cookies":[{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie1","path":"/","value":"value1"},{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie2","path":"/","value":"value2"},{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie3","path":"/","value":"value3"}],"entries":[{"asserts":[{"line":3,"success":true},{"line":3,"success":true},{"line":4,"success":true},{"line":5,"success":true},{"line":6,"success":true},{"line":8,"success":true},{"line":9,"success":true},{"line":10,"success":true},{"line":11,"success":true},{"line":12,"success":true},{"line":13,"success":true},{"line":14,"success":true},{"line":15,"success":true},{"line":16,"success":true},{"line":17,"success":true},{"line":18,"success":true}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/assert-header"},"response":{"cookies":[{"name":"cookie1","path":"/","value":"value1"},{"name":"cookie2","path":"/","value":"value2"},{"name":"cookie3","path":"/","value":"value3"}],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Header1","value":"value1"},{"name":"ETag","value":"\"33a64df551425fcc55e4d42a148795d9f25f89d4\""},{"name":"Expires","value":"~~~"},{"name":"Set-Cookie","value":"cookie1=value1; Path=/"},{"name":"Set-Cookie","value":"cookie2=value2; Path=/"},{"name":"Set-Cookie","value":"cookie3=value3; Path=/"},{"name":"Server","value":"Flask Server"},{"name":"Content-Length","value":"0"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":200},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfert":~~~,"start_transfert":~~~,"total":~~~}}],"captures":[],"index":1,"time":~~~}],"filename":"tests_ok/assert_header.hurl","success":true,"time":~~~}
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
use std::collections::HashMap;
|
||||
|
||||
use chrono::NaiveDateTime;
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use hurl_core::ast::{Filter, FilterValue, RegexValue, SourceInfo, Template};
|
||||
use percent_encoding::AsciiSet;
|
||||
|
||||
@ -49,6 +49,8 @@ fn eval_filter(
|
||||
) -> Result<Value, Error> {
|
||||
match &filter.value {
|
||||
FilterValue::Count => eval_count(value, &filter.source_info, in_assert),
|
||||
FilterValue::DaysAfterNow => eval_days_after_now(value, &filter.source_info, in_assert),
|
||||
FilterValue::DaysBeforeNow => eval_days_before_now(value, &filter.source_info, in_assert),
|
||||
FilterValue::Format { fmt, .. } => {
|
||||
eval_format(value, fmt, variables, &filter.source_info, in_assert)
|
||||
}
|
||||
@ -133,6 +135,42 @@ fn eval_count(value: &Value, source_info: &SourceInfo, assert: bool) -> Result<V
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_days_after_now(
|
||||
value: &Value,
|
||||
source_info: &SourceInfo,
|
||||
assert: bool,
|
||||
) -> Result<Value, Error> {
|
||||
match value {
|
||||
Value::Date(value) => {
|
||||
let diff = value.signed_duration_since(Utc::now());
|
||||
Ok(Value::Integer(diff.num_days()))
|
||||
}
|
||||
v => Err(Error {
|
||||
source_info: source_info.clone(),
|
||||
inner: RunnerError::FilterInvalidInput(v._type()),
|
||||
assert,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_days_before_now(
|
||||
value: &Value,
|
||||
source_info: &SourceInfo,
|
||||
assert: bool,
|
||||
) -> Result<Value, Error> {
|
||||
match value {
|
||||
Value::Date(value) => {
|
||||
let diff = Utc::now().signed_duration_since(*value);
|
||||
Ok(Value::Integer(diff.num_days()))
|
||||
}
|
||||
v => Err(Error {
|
||||
source_info: source_info.clone(),
|
||||
inner: RunnerError::FilterInvalidInput(v._type()),
|
||||
assert,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_format(
|
||||
value: &Value,
|
||||
fmt: &Template,
|
||||
@ -347,6 +385,7 @@ fn eval_to_int(value: &Value, source_info: &SourceInfo, assert: bool) -> Result<
|
||||
pub mod tests {
|
||||
use chrono::offset::Utc;
|
||||
use chrono::prelude::*;
|
||||
use chrono::Duration;
|
||||
use hurl_core::ast::{FilterValue, SourceInfo, Template, TemplateElement, Whitespace};
|
||||
|
||||
use super::*;
|
||||
@ -407,6 +446,54 @@ pub mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn eval_filter_days_after_before_now() {
|
||||
let variables = HashMap::new();
|
||||
|
||||
let now = Utc::now();
|
||||
assert_eq!(
|
||||
eval_filter(
|
||||
&Filter {
|
||||
source_info: SourceInfo::new(1, 1, 1, 1),
|
||||
value: FilterValue::DaysAfterNow,
|
||||
},
|
||||
&Value::Date(now),
|
||||
&variables,
|
||||
false,
|
||||
)
|
||||
.unwrap(),
|
||||
Value::Integer(0)
|
||||
);
|
||||
|
||||
let now_plus_30hours = now + Duration::hours(30);
|
||||
assert_eq!(
|
||||
eval_filter(
|
||||
&Filter {
|
||||
source_info: SourceInfo::new(1, 1, 1, 1),
|
||||
value: FilterValue::DaysAfterNow,
|
||||
},
|
||||
&Value::Date(now_plus_30hours),
|
||||
&variables,
|
||||
false,
|
||||
)
|
||||
.unwrap(),
|
||||
Value::Integer(1)
|
||||
);
|
||||
assert_eq!(
|
||||
eval_filter(
|
||||
&Filter {
|
||||
source_info: SourceInfo::new(1, 1, 1, 1),
|
||||
value: FilterValue::DaysBeforeNow,
|
||||
},
|
||||
&Value::Date(now_plus_30hours),
|
||||
&variables,
|
||||
false,
|
||||
)
|
||||
.unwrap(),
|
||||
Value::Integer(-1)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn eval_filter_format() {
|
||||
// let naivedatetime_utc = NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(2, 0, 0).unwrap();
|
||||
|
@ -887,6 +887,8 @@ pub struct Filter {
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum FilterValue {
|
||||
Count,
|
||||
DaysAfterNow,
|
||||
DaysBeforeNow,
|
||||
Format {
|
||||
space0: Whitespace,
|
||||
fmt: Template,
|
||||
|
@ -1148,6 +1148,12 @@ impl Htmlable for FilterValue {
|
||||
fn to_html(&self) -> String {
|
||||
match self {
|
||||
FilterValue::Count => "<span class=\"filter-type\">count</span>".to_string(),
|
||||
FilterValue::DaysAfterNow => {
|
||||
"<span class=\"filter-type\">daysAfterNow</span>".to_string()
|
||||
}
|
||||
FilterValue::DaysBeforeNow => {
|
||||
"<span class=\"filter-type\">daysBeforeNow</span>".to_string()
|
||||
}
|
||||
FilterValue::Format { space0, fmt } => {
|
||||
let mut buffer = "<span class=\"filter-type\">format</span>".to_string();
|
||||
buffer.push_str(space0.to_html().as_str());
|
||||
|
@ -52,6 +52,8 @@ pub fn filter(reader: &mut Reader) -> ParseResult<'static, Filter> {
|
||||
let value = choice(
|
||||
&[
|
||||
count_filter,
|
||||
days_after_now_filter,
|
||||
days_before_now_filter,
|
||||
format_filter,
|
||||
html_decode_filter,
|
||||
html_encode_filter,
|
||||
@ -89,6 +91,16 @@ fn count_filter(reader: &mut Reader) -> ParseResult<'static, FilterValue> {
|
||||
Ok(FilterValue::Count)
|
||||
}
|
||||
|
||||
fn days_after_now_filter(reader: &mut Reader) -> ParseResult<'static, FilterValue> {
|
||||
try_literal("daysAfterNow", reader)?;
|
||||
Ok(FilterValue::DaysAfterNow)
|
||||
}
|
||||
|
||||
fn days_before_now_filter(reader: &mut Reader) -> ParseResult<'static, FilterValue> {
|
||||
try_literal("daysBeforeNow", reader)?;
|
||||
Ok(FilterValue::DaysBeforeNow)
|
||||
}
|
||||
|
||||
fn format_filter(reader: &mut Reader) -> ParseResult<'static, FilterValue> {
|
||||
try_literal("format", reader)?;
|
||||
let space0 = one_or_more_spaces(reader)?;
|
||||
|
@ -553,6 +553,18 @@ impl ToJson for FilterValue {
|
||||
FilterValue::Count => {
|
||||
attributes.push(("type".to_string(), JValue::String("count".to_string())));
|
||||
}
|
||||
FilterValue::DaysAfterNow => {
|
||||
attributes.push((
|
||||
"type".to_string(),
|
||||
JValue::String("daysAfterNow".to_string()),
|
||||
));
|
||||
}
|
||||
FilterValue::DaysBeforeNow => {
|
||||
attributes.push((
|
||||
"type".to_string(),
|
||||
JValue::String("daysBeforeNow".to_string()),
|
||||
));
|
||||
}
|
||||
FilterValue::Format { fmt, .. } => {
|
||||
attributes.push(("type".to_string(), JValue::String("format".to_string())));
|
||||
attributes.push(("fmt".to_string(), JValue::String(fmt.to_string())));
|
||||
|
@ -1167,6 +1167,8 @@ impl Tokenizable for Filter {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
match self.value.clone() {
|
||||
FilterValue::Count => vec![Token::FilterType(String::from("count"))],
|
||||
FilterValue::DaysAfterNow => vec![Token::FilterType(String::from("daysAfterNow"))],
|
||||
FilterValue::DaysBeforeNow => vec![Token::FilterType(String::from("daysBeforeNow"))],
|
||||
FilterValue::Format { space0, fmt } => {
|
||||
let mut tokens: Vec<Token> = vec![Token::FilterType(String::from("format"))];
|
||||
tokens.append(&mut space0.tokenize());
|
||||
|
Loading…
Reference in New Issue
Block a user