mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-24 04:31:37 +03:00
Merge pull request #235 from Orange-OpenSource/feature/support-predicates-with-bytearray
Support startsWith and contains predicates with bytes
This commit is contained in:
commit
d3f3c18d2d
@ -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 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>base64,/w==;</span></span><span class="line"><span class="query-type">bytes</span> <span class="query-type">count</span> <span class="predicate-type">==</span> <span class="number">1</span></span><span class="line"><span class="query-type">sha256</span> <span class="predicate-type">equals</span> <span class="hex">hex,a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89;</span></span></div></div></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 class="line"><span class="query-type">bytes</span> <span class="predicate-type">equals</span> <span class="hex">hex,010203;</span></span><span class="line"><span class="query-type">bytes</span> <span class="predicate-type">equals</span> <span>base64,AQID;</span></span><span class="line"><span class="query-type">bytes</span> <span class="query-type">count</span> <span class="predicate-type">==</span> <span class="number">3</span></span><span class="line"><span class="query-type">bytes</span> <span class="predicate-type">startsWith</span> <span class="hex">hex,01;</span></span><span class="line"><span class="query-type">bytes</span> <span class="predicate-type">contains</span> <span class="hex">hex,02;</span></span><span class="line"><span class="query-type">sha256</span> <span class="predicate-type">equals</span> <span class="hex">hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;</span></span></div></div></div>
|
@ -2,7 +2,9 @@ GET http://localhost:8000/bytes
|
||||
HTTP/1.0 200
|
||||
Content-Type: application/octet-stream
|
||||
[Asserts]
|
||||
bytes equals hex,ff;
|
||||
bytes equals base64,/w==;
|
||||
bytes count == 1
|
||||
sha256 equals hex,a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89;
|
||||
bytes equals hex,010203;
|
||||
bytes equals base64,AQID;
|
||||
bytes count == 3
|
||||
bytes startsWith hex,01;
|
||||
bytes contains hex,02;
|
||||
sha256 equals hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
|
||||
|
@ -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"}],"asserts":[{"query":{"type":"bytes"},"predicate":{"type":"equal","value":"/w==","encoding":"base64"}},{"query":{"type":"bytes"},"predicate":{"type":"equal","value":"/w==","encoding":"base64"}},{"query":{"type":"bytes","subquery":{"type":"count"}},"predicate":{"type":"equal","value":1}},{"query":{"type":"sha256"},"predicate":{"type":"equal","value":"qBAK5qoZQNC2Y7sxzUZhQuu9vVGHExuS2TgYmHgy64k=","encoding":"base64"}}]}}]}
|
||||
{"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":"AQID","encoding":"base64"}},{"query":{"type":"bytes"},"predicate":{"type":"equal","value":"AQID","encoding":"base64"}},{"query":{"type":"bytes","subquery":{"type":"count"}},"predicate":{"type":"equal","value":3}},{"query":{"type":"bytes"},"predicate":{"type":"start-with","value":"AQ==","encoding":"base64"}},{"query":{"type":"bytes"},"predicate":{"type":"contain","value":"Ag==","encoding":"base64"}},{"query":{"type":"sha256"},"predicate":{"type":"equal","value":"A5BYxvLAy0ksUzsKTRTvd8wPeKvMztUofYShogEc+4E=","encoding":"base64"}}]}}]}
|
@ -1 +1 @@
|
||||
<EFBFBD>
|
||||
|
@ -6,7 +6,7 @@ from io import BytesIO
|
||||
@app.route('/bytes')
|
||||
def bytes():
|
||||
result = BytesIO()
|
||||
result.write(b'\xff')
|
||||
result.write(b'\x01\x02\x03')
|
||||
data = result.getvalue()
|
||||
resp = make_response(data)
|
||||
resp.content_type = 'application/octet-stream'
|
||||
|
@ -55,3 +55,11 @@ error: Assert Failure
|
||||
| expected: float
|
||||
|
|
||||
|
||||
error: Assert Failure
|
||||
--> tests/error_assert_value_error.hurl:11:0
|
||||
|
|
||||
11 | bytes contains hex,00;
|
||||
| actual: byte array <7b202276616c756573223a205b312c322c335d2c2022636f756e74223a20327d>
|
||||
| expected: contains byte array <00>
|
||||
|
|
||||
|
||||
|
@ -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/error-assert-value</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 section-header">[Asserts]</span><span class="line"><span class="query-type">header</span> <span class="string">"content-type"</span> <span class="predicate-type">equals</span> <span class="string">"XXX"</span></span><span class="line"><span class="query-type">header</span> <span class="string">"content-type"</span> <span class="predicate-type">notEquals</span> <span class="string">"text/html; charset=utf-8"</span></span><span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.id"</span> <span class="predicate-type">equals</span> <span class="string">"000001"</span></span><span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.values"</span> <span class="predicate-type">includes</span> <span class="number">100</span></span><span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.values"</span> not <span class="predicate-type">contains</span> <span class="string">"Hello"</span></span><span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.count"</span> <span class="predicate-type">greaterThan</span> <span class="number">5</span></span><span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.count"</span> <span class="predicate-type">isFloat</span></span></div></div></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/error-assert-value</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 section-header">[Asserts]</span><span class="line"><span class="query-type">header</span> <span class="string">"content-type"</span> <span class="predicate-type">equals</span> <span class="string">"XXX"</span></span><span class="line"><span class="query-type">header</span> <span class="string">"content-type"</span> <span class="predicate-type">notEquals</span> <span class="string">"text/html; charset=utf-8"</span></span><span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.id"</span> <span class="predicate-type">equals</span> <span class="string">"000001"</span></span><span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.values"</span> <span class="predicate-type">includes</span> <span class="number">100</span></span><span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.values"</span> not <span class="predicate-type">contains</span> <span class="string">"Hello"</span></span><span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.count"</span> <span class="predicate-type">greaterThan</span> <span class="number">5</span></span><span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.count"</span> <span class="predicate-type">isFloat</span></span><span class="line"><span class="query-type">bytes</span> <span class="predicate-type">contains</span> <span class="hex">hex,00;</span></span></div></div></div>
|
@ -8,3 +8,4 @@ jsonpath "$.values" includes 100
|
||||
jsonpath "$.values" not contains "Hello"
|
||||
jsonpath "$.count" greaterThan 5
|
||||
jsonpath "$.count" isFloat
|
||||
bytes contains hex,00;
|
@ -1 +1 @@
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/error-assert-value"},"response":{"version":"HTTP/1.0","status":200,"asserts":[{"query":{"type":"header","name":"content-type"},"predicate":{"type":"equal","value":"XXX"}},{"query":{"type":"header","name":"content-type"},"predicate":{"type":"not-equal","value":"text/html; charset=utf-8"}},{"query":{"type":"jsonpath","expr":"$.id"},"predicate":{"type":"equal","value":"000001"}},{"query":{"type":"jsonpath","expr":"$.values"},"predicate":{"type":"include","value":100}},{"query":{"type":"jsonpath","expr":"$.values"},"predicate":{"not":true,"type":"contain","value":"Hello"}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"greater","value":5}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"isFloat"}}]}}]}
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/error-assert-value"},"response":{"version":"HTTP/1.0","status":200,"asserts":[{"query":{"type":"header","name":"content-type"},"predicate":{"type":"equal","value":"XXX"}},{"query":{"type":"header","name":"content-type"},"predicate":{"type":"not-equal","value":"text/html; charset=utf-8"}},{"query":{"type":"jsonpath","expr":"$.id"},"predicate":{"type":"equal","value":"000001"}},{"query":{"type":"jsonpath","expr":"$.values"},"predicate":{"type":"include","value":100}},{"query":{"type":"jsonpath","expr":"$.values"},"predicate":{"not":true,"type":"contain","value":"Hello"}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"greater","value":5}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"isFloat"}},{"query":{"type":"bytes"},"predicate":{"type":"contain","value":"AA==","encoding":"base64"}}]}}]}
|
@ -302,27 +302,29 @@ fn eval_something(
|
||||
}),
|
||||
},
|
||||
|
||||
// starts with string
|
||||
// starts with string or bytes
|
||||
PredicateFuncValue::StartWith {
|
||||
value: expected, ..
|
||||
} => {
|
||||
let template = if let PredicateValue::String(template) = expected {
|
||||
template
|
||||
} else {
|
||||
panic!("expect a string predicate value")
|
||||
};
|
||||
let expected = eval_template(template, variables)?;
|
||||
match value.clone() {
|
||||
Value::String(actual) => Ok(AssertResult {
|
||||
success: actual.as_str().starts_with(expected.as_str()),
|
||||
let expected_value = eval_predicate_value(expected, variables)?;
|
||||
let expected = format!("starts with {}", expected_value.clone().display());
|
||||
match (expected_value, value.clone()) {
|
||||
(Value::String(s), Value::String(actual)) => Ok(AssertResult {
|
||||
success: actual.as_str().starts_with(s.as_str()),
|
||||
actual: value.display(),
|
||||
expected: format!("starts with string <{}>", expected),
|
||||
expected,
|
||||
type_mismatch: false,
|
||||
}),
|
||||
(Value::Bytes(bytes), Value::Bytes(actual)) => Ok(AssertResult {
|
||||
success: actual.starts_with(&bytes),
|
||||
actual: value.display(),
|
||||
expected,
|
||||
type_mismatch: false,
|
||||
}),
|
||||
_ => Ok(AssertResult {
|
||||
success: false,
|
||||
actual: value.display(),
|
||||
expected: format!("starts with string <{}>", expected),
|
||||
expected,
|
||||
type_mismatch: true,
|
||||
}),
|
||||
}
|
||||
@ -332,23 +334,25 @@ fn eval_something(
|
||||
PredicateFuncValue::Contain {
|
||||
value: expected, ..
|
||||
} => {
|
||||
let template = if let PredicateValue::String(template) = expected {
|
||||
template
|
||||
} else {
|
||||
panic!("expect a string predicate value")
|
||||
};
|
||||
let expected = eval_template(template, variables)?;
|
||||
match value.clone() {
|
||||
Value::String(actual) => Ok(AssertResult {
|
||||
success: actual.as_str().contains(expected.as_str()),
|
||||
let expected_value = eval_predicate_value(expected, variables)?;
|
||||
let expected = format!("contains {}", expected_value.clone().display());
|
||||
match (expected_value, value.clone()) {
|
||||
(Value::String(s), Value::String(actual)) => Ok(AssertResult {
|
||||
success: actual.as_str().contains(s.as_str()),
|
||||
actual: value.display(),
|
||||
expected: format!("contains string <{}>", expected),
|
||||
expected,
|
||||
type_mismatch: false,
|
||||
}),
|
||||
(Value::Bytes(bytes), Value::Bytes(actual)) => Ok(AssertResult {
|
||||
success: contains(actual.as_slice(), bytes.as_slice()),
|
||||
actual: value.display(),
|
||||
expected,
|
||||
type_mismatch: false,
|
||||
}),
|
||||
_ => Ok(AssertResult {
|
||||
success: false,
|
||||
actual: value.display(),
|
||||
expected: format!("contains string <{}>", expected),
|
||||
expected,
|
||||
type_mismatch: true,
|
||||
}),
|
||||
}
|
||||
@ -750,6 +754,12 @@ fn assert_include(value: Value, element: Value) -> AssertResult {
|
||||
}
|
||||
}
|
||||
|
||||
fn contains(haystack: &[u8], needle: &[u8]) -> bool {
|
||||
haystack
|
||||
.windows(needle.len())
|
||||
.any(|window| window == needle)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::AssertResult;
|
||||
@ -762,6 +772,14 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_contains() {
|
||||
let haystack = [1 as u8, 2 as u8, 3 as u8];
|
||||
assert!(contains(&haystack, &[1 as u8]));
|
||||
assert!(contains(&haystack, &[1 as u8, 2 as u8]));
|
||||
assert!(!contains(&haystack, &[1 as u8, 3 as u8]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_xpath() {}
|
||||
|
||||
|
@ -110,6 +110,10 @@ impl PredicateValue {
|
||||
pub fn is_string(&self) -> bool {
|
||||
matches!(self, PredicateValue::String(_))
|
||||
}
|
||||
|
||||
pub fn is_bytearray(&self) -> bool {
|
||||
matches!(self, PredicateValue::Hex(_)) | matches!(self, PredicateValue::Base64(_))
|
||||
}
|
||||
}
|
||||
|
||||
fn equal_predicate(reader: &mut Reader) -> ParseResult<'static, PredicateFuncValue> {
|
||||
@ -254,7 +258,7 @@ fn start_with_predicate(reader: &mut Reader) -> ParseResult<'static, PredicateFu
|
||||
let space0 = one_or_more_spaces(reader)?;
|
||||
let save = reader.state.clone();
|
||||
let value = predicate_value(reader)?;
|
||||
if !value.is_string() {
|
||||
if !value.is_string() && !value.is_bytearray() {
|
||||
return Err(Error {
|
||||
pos: save.pos,
|
||||
recoverable: false,
|
||||
@ -269,7 +273,7 @@ fn contain_predicate(reader: &mut Reader) -> ParseResult<'static, PredicateFuncV
|
||||
let space0 = one_or_more_spaces(reader)?;
|
||||
let save = reader.state.clone();
|
||||
let value = predicate_value(reader)?;
|
||||
if !value.is_string() {
|
||||
if !value.is_string() && !value.is_bytearray() {
|
||||
return Err(Error {
|
||||
pos: save.pos,
|
||||
recoverable: false,
|
||||
|
Loading…
Reference in New Issue
Block a user