mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-13 06:54:54 +03:00
Add bytes query and equals predicate for bytearray
This commit is contained in:
parent
45a3ab480e
commit
93c2fede66
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -365,6 +365,7 @@ name = "hurlfmt"
|
||||
version = "1.3.0"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"base64",
|
||||
"clap",
|
||||
"colored",
|
||||
"hurl_core",
|
||||
|
@ -1 +1 @@
|
||||
<div class="hurl-file"><div class="hurl-entry"><div class="request"><span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/bytes</span></span></div><div class="response"><span class="line"><span class="version">HTTP/1.0</span> <span class="status">200</span></span><span class="line"><span class="string">Content-Type</span><span>:</span> <span class="string">application/octet-stream</span></span><span class="line section-header">[Asserts]</span></span></div></div><span class="line"><span class="comment">#TODO create a bytes query to get e byte array</span></span><span class="line"><span class="comment">#body countEquals 1</span></span><span class="line"></span><span class="line"></span><span class="line"></span></div>
|
||||
<div class="hurl-file"><div class="hurl-entry"><div class="request"><span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/bytes</span></span></div><div class="response"><span class="line"><span class="version">HTTP/1.0</span> <span class="status">200</span></span><span class="line"><span class="string">Content-Type</span><span>:</span> <span class="string">application/octet-stream</span></span><span class="line section-header">[Asserts]</span></span><span class="line"><span class="query-type">bytes</span> <span class="predicate-type">equals</span> <span class="hex">hex,ff;</span></span><span class="line"><span class="query-type">bytes</span> <span class="predicate-type">equals</span> <span class="number">1</span></span></div></div><span class="line"></span></div>
|
@ -2,8 +2,6 @@ GET http://localhost:8000/bytes
|
||||
HTTP/1.0 200
|
||||
Content-Type: application/octet-stream
|
||||
[Asserts]
|
||||
#TODO create a bytes query to get e byte array
|
||||
#body countEquals 1
|
||||
|
||||
|
||||
bytes equals hex,ff;
|
||||
bytes countEquals 1
|
||||
|
||||
|
@ -1 +1 @@
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/bytes"},"response":{"version":"HTTP/1.0","status":200,"headers":[{"name":"Content-Type","value":"application/octet-stream"}]}}]}
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/bytes"},"response":{"version":"HTTP/1.0","status":200,"headers":[{"name":"Content-Type","value":"application/octet-stream"}],"asserts":[{"query":{"type":"bytes"},"predicate":{"type":"equal","value":{"value":"/w==","encoding":"base64"}}},{"query":{"type":"bytes"},"predicate":{"type":"count","value":1}}]}}]}
|
@ -164,6 +164,9 @@ fn expected(
|
||||
let expected = eval_template(expected, variables)?;
|
||||
Ok(format!("string <{}>", expected))
|
||||
}
|
||||
PredicateFuncValue::EqualHex {
|
||||
value: expected, ..
|
||||
} => Ok(format!("bytearray <{}>", expected.to_string())),
|
||||
PredicateFuncValue::EqualExpression {
|
||||
value: expected, ..
|
||||
} => {
|
||||
@ -326,6 +329,14 @@ fn eval_something(
|
||||
Ok(assert_values_equal(value, Value::String(expected)))
|
||||
}
|
||||
|
||||
// equals hex
|
||||
PredicateFuncValue::EqualHex {
|
||||
value: Hex {
|
||||
value: expected, ..
|
||||
},
|
||||
..
|
||||
} => Ok(assert_values_equal(value, Value::Bytes(expected))),
|
||||
|
||||
// equals expression
|
||||
PredicateFuncValue::EqualExpression {
|
||||
value: expected, ..
|
||||
@ -392,6 +403,12 @@ fn eval_something(
|
||||
expected: expected_value.to_string(),
|
||||
type_mismatch: false,
|
||||
}),
|
||||
Value::Bytes(data) => Ok(AssertResult {
|
||||
success: data.len() as u64 == expected_value,
|
||||
actual: data.len().to_string(),
|
||||
expected: expected_value.to_string(),
|
||||
type_mismatch: false,
|
||||
}),
|
||||
_ => Ok(AssertResult {
|
||||
success: false,
|
||||
actual: value.clone().display(),
|
||||
|
@ -203,6 +203,7 @@ pub fn eval_query(
|
||||
QueryValue::Duration {} => Ok(Some(Value::Integer(
|
||||
http_response.duration.as_millis() as i64
|
||||
))),
|
||||
QueryValue::Bytes {} => Ok(Some(Value::Bytes(http_response.body))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1006,4 +1007,22 @@ pub mod tests {
|
||||
assert_eq!(error.source_info, SourceInfo::init(1, 7, 1, 10));
|
||||
assert_eq!(error.inner, RunnerError::InvalidRegex());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_bytes() {
|
||||
let variables = HashMap::new();
|
||||
assert_eq!(
|
||||
eval_query(
|
||||
Query {
|
||||
source_info: SourceInfo::init(0, 0, 0, 0),
|
||||
value: QueryValue::Bytes {},
|
||||
},
|
||||
&variables,
|
||||
http::hello_http_response(),
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
Value::Bytes(String::into_bytes(String::from("Hello World!")))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -323,6 +323,7 @@ pub enum QueryValue {
|
||||
name: Template,
|
||||
},
|
||||
Duration {},
|
||||
Bytes {},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@ -403,6 +404,7 @@ pub enum PredicateFuncValue {
|
||||
EqualFloat { space0: Whitespace, value: Float },
|
||||
EqualBool { space0: Whitespace, value: bool },
|
||||
EqualNull { space0: Whitespace },
|
||||
EqualHex { space0: Whitespace, value: Hex },
|
||||
EqualExpression { space0: Whitespace, value: Expr },
|
||||
GreaterThanInt { space0: Whitespace, value: i64 },
|
||||
GreaterThanFloat { space0: Whitespace, value: Float },
|
||||
@ -528,6 +530,14 @@ pub enum Bytes {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Hex {
|
||||
pub space0: Whitespace,
|
||||
pub value: Vec<u8>,
|
||||
pub encoded: String,
|
||||
pub space1: Whitespace,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Pos {
|
||||
pub line: usize,
|
||||
|
@ -131,6 +131,16 @@ impl fmt::Display for CookieAttribute {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Hex {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"hex,{}{}{};",
|
||||
self.space0.value, self.encoded, self.space1.value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -375,6 +375,9 @@ impl Htmlable for QueryValue {
|
||||
QueryValue::Duration {} => {
|
||||
buffer.push_str("<span class=\"query-type\">duration</span>");
|
||||
}
|
||||
QueryValue::Bytes {} => {
|
||||
buffer.push_str("<span class=\"query-type\">bytes</span>");
|
||||
}
|
||||
}
|
||||
buffer
|
||||
}
|
||||
@ -463,6 +466,12 @@ impl Htmlable for PredicateFuncValue {
|
||||
format!("<span class=\"number\">{}</span>", value.to_string()).as_str(),
|
||||
);
|
||||
}
|
||||
PredicateFuncValue::EqualHex { space0, value } => {
|
||||
buffer.push_str("<span class=\"predicate-type\">equals</span>");
|
||||
buffer.push_str(space0.to_html().as_str());
|
||||
buffer
|
||||
.push_str(format!("<span class=\"hex\">{}</span>", value.to_string()).as_str());
|
||||
}
|
||||
PredicateFuncValue::GreaterThanInt { space0, value } => {
|
||||
buffer.push_str("<span class=\"predicate-type\">greaterThan</span>");
|
||||
buffer.push_str(space0.to_html().as_str());
|
||||
|
@ -103,6 +103,7 @@ fn equal_predicate(reader: &mut Reader) -> ParseResult<'static, PredicateFuncVal
|
||||
Ok(PredicateValue::Bool { value }) => Ok(PredicateFuncValue::EqualBool { space0, value }),
|
||||
Ok(PredicateValue::Int { value }) => Ok(PredicateFuncValue::EqualInt { space0, value }),
|
||||
Ok(PredicateValue::Float { value }) => Ok(PredicateFuncValue::EqualFloat { space0, value }),
|
||||
Ok(PredicateValue::Hex { value }) => Ok(PredicateFuncValue::EqualHex { space0, value }),
|
||||
Ok(PredicateValue::Expression { value }) => {
|
||||
Ok(PredicateFuncValue::EqualExpression { space0, value })
|
||||
}
|
||||
@ -273,6 +274,9 @@ fn include_predicate(reader: &mut Reader) -> ParseResult<'static, PredicateFuncV
|
||||
Ok(PredicateValue::Template { value }) => {
|
||||
Ok(PredicateFuncValue::IncludeString { space0, value })
|
||||
}
|
||||
Ok(PredicateValue::Hex { value: _ }) => {
|
||||
todo!()
|
||||
}
|
||||
Ok(PredicateValue::Expression { value }) => {
|
||||
Ok(PredicateFuncValue::IncludeExpression { space0, value })
|
||||
}
|
||||
@ -332,6 +336,7 @@ enum PredicateValue {
|
||||
Float { value: Float },
|
||||
Bool { value: bool },
|
||||
Template { value: Template },
|
||||
Hex { value: Hex },
|
||||
Expression { value: Expr },
|
||||
}
|
||||
|
||||
@ -354,6 +359,10 @@ fn predicate_value(reader: &mut Reader) -> ParseResult<'static, PredicateValue>
|
||||
Ok(value) => Ok(PredicateValue::Int { value }),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
|p1| match hex(p1) {
|
||||
Ok(value) => Ok(PredicateValue::Hex { value }),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
|p1| match expr::parse(p1) {
|
||||
Ok(value) => Ok(PredicateValue::Expression { value }),
|
||||
Err(e) => Err(e),
|
||||
|
@ -263,6 +263,42 @@ pub fn key_value(reader: &mut Reader) -> ParseResult<'static, KeyValue> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn hex(reader: &mut Reader) -> ParseResult<'static, Hex> {
|
||||
try_literal("hex", reader)?;
|
||||
literal(",", reader)?;
|
||||
let space0 = zero_or_more_spaces(reader)?;
|
||||
let mut value: Vec<u8> = vec![];
|
||||
let start = reader.state.cursor;
|
||||
let mut current: i32 = -1;
|
||||
loop {
|
||||
let s = reader.state.clone();
|
||||
match hex_digit(reader) {
|
||||
Ok(d) => {
|
||||
if current != -1 {
|
||||
value.push((current * 16 + d as i32) as u8);
|
||||
current = -1;
|
||||
} else {
|
||||
current = d as i32;
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
reader.state = s;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
let encoded = reader.from(start);
|
||||
let space1 = zero_or_more_spaces(reader)?;
|
||||
literal(";", reader)?;
|
||||
|
||||
Ok(Hex {
|
||||
space0,
|
||||
value,
|
||||
encoded,
|
||||
space1,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn filename(reader: &mut Reader) -> ParseResult<'static, Filename> {
|
||||
// this is an absolure file
|
||||
// that you have to write with a relative name
|
||||
@ -882,7 +918,7 @@ mod tests {
|
||||
Float {
|
||||
int: 1,
|
||||
decimal: 0,
|
||||
decimal_digits: 1
|
||||
decimal_digits: 1,
|
||||
}
|
||||
);
|
||||
assert_eq!(reader.state.cursor, 3);
|
||||
@ -893,7 +929,7 @@ mod tests {
|
||||
Float {
|
||||
int: -1,
|
||||
decimal: 0,
|
||||
decimal_digits: 1
|
||||
decimal_digits: 1,
|
||||
}
|
||||
);
|
||||
assert_eq!(reader.state.cursor, 4);
|
||||
@ -904,7 +940,7 @@ mod tests {
|
||||
Float {
|
||||
int: 1,
|
||||
decimal: 100_000_000_000_000_000,
|
||||
decimal_digits: 1
|
||||
decimal_digits: 1,
|
||||
}
|
||||
);
|
||||
assert_eq!(reader.state.cursor, 3);
|
||||
@ -915,7 +951,7 @@ mod tests {
|
||||
Float {
|
||||
int: 1,
|
||||
decimal: 100_000_000_000_000_000,
|
||||
decimal_digits: 3
|
||||
decimal_digits: 3,
|
||||
}
|
||||
);
|
||||
assert_eq!(reader.state.cursor, 5);
|
||||
@ -926,7 +962,7 @@ mod tests {
|
||||
Float {
|
||||
int: 1,
|
||||
decimal: 10_000_000_000_000_000,
|
||||
decimal_digits: 2
|
||||
decimal_digits: 2,
|
||||
}
|
||||
);
|
||||
assert_eq!(reader.state.cursor, 4);
|
||||
@ -937,7 +973,7 @@ mod tests {
|
||||
Float {
|
||||
int: 1,
|
||||
decimal: 10_000_000_000_000_000,
|
||||
decimal_digits: 3
|
||||
decimal_digits: 3,
|
||||
}
|
||||
);
|
||||
assert_eq!(reader.state.cursor, 5);
|
||||
@ -948,7 +984,7 @@ mod tests {
|
||||
Float {
|
||||
int: 0,
|
||||
decimal: 333_333_333_333_333_333,
|
||||
decimal_digits: 18
|
||||
decimal_digits: 18,
|
||||
}
|
||||
);
|
||||
assert_eq!(reader.state.cursor, 21);
|
||||
@ -1254,4 +1290,41 @@ mod tests {
|
||||
assert_eq!(error.inner, ParseError::HexDigit {});
|
||||
assert_eq!(error.recoverable, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hex() {
|
||||
let mut reader = Reader::init("hex, ff;");
|
||||
assert_eq!(
|
||||
hex(&mut reader).unwrap(),
|
||||
Hex {
|
||||
space0: Whitespace {
|
||||
value: " ".to_string(),
|
||||
source_info: SourceInfo::init(1, 5, 1, 6)
|
||||
},
|
||||
value: vec![255],
|
||||
encoded: "ff".to_string(),
|
||||
space1: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo::init(1, 8, 1, 8)
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let mut reader = Reader::init("hex,010203 ;");
|
||||
assert_eq!(
|
||||
hex(&mut reader).unwrap(),
|
||||
Hex {
|
||||
space0: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo::init(1, 5, 1, 5)
|
||||
},
|
||||
value: vec![1, 2, 3],
|
||||
encoded: "010203".to_string(),
|
||||
space1: Whitespace {
|
||||
value: " ".to_string(),
|
||||
source_info: SourceInfo::init(1, 11, 1, 12)
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ fn query_value(reader: &mut Reader) -> ParseResult<'static, QueryValue> {
|
||||
regex_query,
|
||||
variable_query,
|
||||
duration_query,
|
||||
bytes_query,
|
||||
],
|
||||
reader,
|
||||
)
|
||||
@ -154,6 +155,11 @@ fn duration_query(reader: &mut Reader) -> ParseResult<'static, QueryValue> {
|
||||
Ok(QueryValue::Duration {})
|
||||
}
|
||||
|
||||
fn bytes_query(reader: &mut Reader) -> ParseResult<'static, QueryValue> {
|
||||
try_literal("bytes", reader)?;
|
||||
Ok(QueryValue::Bytes {})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -15,6 +15,7 @@ strict = []
|
||||
|
||||
[dependencies]
|
||||
atty = "0.2.13"
|
||||
base64 = "0.11.0"
|
||||
clap = "2.33.0"
|
||||
colored = "2"
|
||||
hurl_core = { version = "1.1.0", path = "../hurl_core" }
|
||||
|
@ -293,6 +293,9 @@ impl ToJson for QueryValue {
|
||||
QueryValue::Duration {} => {
|
||||
attributes.push(("type".to_string(), JValue::String("duration".to_string())));
|
||||
}
|
||||
QueryValue::Bytes {} => {
|
||||
attributes.push(("type".to_string(), JValue::String("bytes".to_string())));
|
||||
}
|
||||
};
|
||||
JValue::Object(attributes)
|
||||
}
|
||||
@ -344,6 +347,17 @@ impl ToJson for Predicate {
|
||||
attributes.push(("type".to_string(), JValue::String("equal".to_string())));
|
||||
attributes.push(("value".to_string(), JValue::Null));
|
||||
}
|
||||
PredicateFuncValue::EqualHex { value, .. } => {
|
||||
attributes.push(("type".to_string(), JValue::String("equal".to_string())));
|
||||
let value = JValue::Object(vec![
|
||||
(
|
||||
"value".to_string(),
|
||||
JValue::String(base64::encode(&value.value)),
|
||||
),
|
||||
("encoding".to_string(), JValue::String("base64".to_string())),
|
||||
]);
|
||||
attributes.push(("value".to_string(), value));
|
||||
}
|
||||
PredicateFuncValue::EqualExpression { value, .. } => {
|
||||
attributes.push(("type".to_string(), JValue::String("equal".to_string())));
|
||||
attributes.push(("value".to_string(), JValue::String(value.to_string())));
|
||||
|
@ -463,6 +463,7 @@ impl Tokenizable for Query {
|
||||
add_tokens(&mut tokens, name.tokenize());
|
||||
}
|
||||
QueryValue::Duration {} => tokens.push(Token::QueryType(String::from("duration"))),
|
||||
QueryValue::Bytes {} => tokens.push(Token::QueryType(String::from("bytes"))),
|
||||
}
|
||||
tokens
|
||||
}
|
||||
@ -551,6 +552,11 @@ impl Tokenizable for PredicateFuncValue {
|
||||
add_tokens(&mut tokens, space0.tokenize());
|
||||
tokens.push(Token::Number(value.to_string()));
|
||||
}
|
||||
PredicateFuncValue::EqualHex { space0, value } => {
|
||||
tokens.push(Token::PredicateType(String::from("equals")));
|
||||
add_tokens(&mut tokens, space0.tokenize());
|
||||
tokens.push(Token::String(value.to_string()));
|
||||
}
|
||||
PredicateFuncValue::EqualExpression { space0, value } => {
|
||||
tokens.push(Token::PredicateType(String::from("equals")));
|
||||
add_tokens(&mut tokens, space0.tokenize());
|
||||
|
@ -296,6 +296,7 @@ impl Lintable<QueryValue> for QueryValue {
|
||||
space0: one_whitespace(),
|
||||
},
|
||||
QueryValue::Duration {} => QueryValue::Duration {},
|
||||
QueryValue::Bytes {} => QueryValue::Bytes {},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -403,6 +404,10 @@ impl Lintable<PredicateFuncValue> for PredicateFuncValue {
|
||||
space0: one_whitespace(),
|
||||
value: value.clone(),
|
||||
},
|
||||
PredicateFuncValue::EqualHex { value, .. } => PredicateFuncValue::EqualHex {
|
||||
space0: one_whitespace(),
|
||||
value: value.lint(),
|
||||
},
|
||||
PredicateFuncValue::EqualExpression { value, .. } => {
|
||||
PredicateFuncValue::EqualExpression {
|
||||
space0: one_whitespace(),
|
||||
@ -664,6 +669,20 @@ fn one_whitespace() -> Whitespace {
|
||||
source_info: SourceInfo::init(0, 0, 0, 0),
|
||||
}
|
||||
}
|
||||
impl Lintable<Hex> for Hex {
|
||||
fn errors(&self) -> Vec<Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn lint(&self) -> Hex {
|
||||
Hex {
|
||||
space0: one_whitespace(),
|
||||
value: self.value.clone(),
|
||||
encoded: self.encoded.clone(),
|
||||
space1: empty_whitespace(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Lintable<LineTerminator> for LineTerminator {
|
||||
fn errors(&self) -> Vec<Error> {
|
||||
|
Loading…
Reference in New Issue
Block a user