Add integration tests for utf8Encode/utf8Decode filters.

This commit is contained in:
Jean-Christophe Amiel 2025-09-17 17:41:17 +02:00
parent 11a36d7b83
commit b756e18468
No known key found for this signature in database
GPG Key ID: 07FF11CFD55356CC
9 changed files with 162 additions and 45 deletions

View File

@ -68,6 +68,7 @@ mod tests {
);
assert_eq!(ret.unwrap().unwrap(), Value::Bytes(bytes));
}
#[test]
fn eval_filter_base64_decode_ko_invalid_characters() {
let variables = VariableSet::new();

View File

@ -45,6 +45,8 @@ use crate::runner::filter::to_string::eval_to_string;
use crate::runner::filter::url_decode::eval_url_decode;
use crate::runner::filter::url_encode::eval_url_encode;
use crate::runner::filter::url_query_param::eval_url_query_param;
use crate::runner::filter::utf8_decode::eval_utf8_decode;
use crate::runner::filter::utf8_encode::eval_utf8_encode;
use crate::runner::filter::xpath::eval_xpath;
use crate::runner::{RunnerError, RunnerErrorKind, Value, VariableSet};
@ -78,39 +80,40 @@ pub fn eval_filter(
variables: &VariableSet,
in_assert: bool,
) -> Result<Option<Value>, RunnerError> {
let source_info = filter.source_info;
match &filter.value {
FilterValue::Base64Decode => eval_base64_decode(value, filter.source_info, in_assert),
FilterValue::Base64Encode => eval_base64_encode(value, filter.source_info, in_assert),
FilterValue::Base64Decode => eval_base64_decode(value, source_info, in_assert),
FilterValue::Base64Encode => eval_base64_encode(value, source_info, in_assert),
FilterValue::Base64UrlSafeDecode => {
eval_base64_url_safe_decode(value, filter.source_info, in_assert)
eval_base64_url_safe_decode(value, source_info, in_assert)
}
FilterValue::Base64UrlSafeEncode => {
eval_base64_url_safe_encode(value, filter.source_info, in_assert)
eval_base64_url_safe_encode(value, source_info, in_assert)
}
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::Count => eval_count(value, source_info, in_assert),
FilterValue::DaysAfterNow => eval_days_after_now(value, source_info, in_assert),
FilterValue::DaysBeforeNow => eval_days_before_now(value, source_info, in_assert),
FilterValue::Decode { encoding, .. } => {
eval_decode(value, encoding, variables, filter.source_info, in_assert)
eval_decode(value, encoding, variables, source_info, in_assert)
}
FilterValue::First => eval_first(value, filter.source_info, in_assert),
FilterValue::First => eval_first(value, source_info, in_assert),
FilterValue::Format { fmt, .. } => {
eval_date_format(value, fmt, variables, filter.source_info, in_assert)
eval_date_format(value, fmt, variables, source_info, in_assert)
}
FilterValue::DateFormat { fmt, .. } => {
eval_date_format(value, fmt, variables, filter.source_info, in_assert)
eval_date_format(value, fmt, variables, source_info, in_assert)
}
FilterValue::HtmlEscape => eval_html_escape(value, filter.source_info, in_assert),
FilterValue::HtmlUnescape => eval_html_unescape(value, filter.source_info, in_assert),
FilterValue::HtmlEscape => eval_html_escape(value, source_info, in_assert),
FilterValue::HtmlUnescape => eval_html_unescape(value, source_info, in_assert),
FilterValue::JsonPath { expr, .. } => {
eval_jsonpath(value, expr, variables, filter.source_info, in_assert)
eval_jsonpath(value, expr, variables, source_info, in_assert)
}
FilterValue::Last => eval_last(value, filter.source_info, in_assert),
FilterValue::Location => eval_location(value, filter.source_info, in_assert),
FilterValue::Last => eval_last(value, source_info, in_assert),
FilterValue::Location => eval_location(value, source_info, in_assert),
FilterValue::Regex {
value: regex_value, ..
} => eval_regex(value, regex_value, variables, filter.source_info, in_assert),
FilterValue::Nth { n, .. } => eval_nth(value, n, variables, filter.source_info, in_assert),
} => eval_regex(value, regex_value, variables, source_info, in_assert),
FilterValue::Nth { n, .. } => eval_nth(value, n, variables, source_info, in_assert),
FilterValue::Replace {
old_value,
new_value,
@ -118,38 +121,31 @@ pub fn eval_filter(
} => eval_replace(
value,
variables,
filter.source_info,
source_info,
in_assert,
old_value,
new_value,
),
FilterValue::ReplaceRegex {
pattern, new_value, ..
} => eval_replace_regex(
value,
variables,
filter.source_info,
in_assert,
pattern,
new_value,
),
FilterValue::Split { sep, .. } => {
eval_split(value, variables, filter.source_info, in_assert, sep)
}
} => eval_replace_regex(value, variables, source_info, in_assert, pattern, new_value),
FilterValue::Split { sep, .. } => eval_split(value, variables, source_info, in_assert, sep),
FilterValue::ToDate { fmt, .. } => {
eval_to_date(value, fmt, variables, filter.source_info, in_assert)
eval_to_date(value, fmt, variables, source_info, in_assert)
}
FilterValue::ToFloat => eval_to_float(value, filter.source_info, in_assert),
FilterValue::ToHex => eval_to_hex(value, filter.source_info, in_assert),
FilterValue::ToInt => eval_to_int(value, filter.source_info, in_assert),
FilterValue::ToString => eval_to_string(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),
FilterValue::ToFloat => eval_to_float(value, source_info, in_assert),
FilterValue::ToHex => eval_to_hex(value, source_info, in_assert),
FilterValue::ToInt => eval_to_int(value, source_info, in_assert),
FilterValue::ToString => eval_to_string(value, source_info, in_assert),
FilterValue::UrlDecode => eval_url_decode(value, source_info, in_assert),
FilterValue::UrlEncode => eval_url_encode(value, source_info, in_assert),
FilterValue::UrlQueryParam { param, .. } => {
eval_url_query_param(value, param, variables, filter.source_info, in_assert)
eval_url_query_param(value, param, variables, source_info, in_assert)
}
FilterValue::Utf8Decode => eval_utf8_decode(value, source_info, in_assert),
FilterValue::Utf8Encode => eval_utf8_encode(value, source_info, in_assert),
FilterValue::XPath { expr, .. } => {
eval_xpath(value, expr, variables, filter.source_info, in_assert)
eval_xpath(value, expr, variables, source_info, in_assert)
}
}
}

View File

@ -49,4 +49,6 @@ mod to_string;
mod url_decode;
mod url_encode;
mod url_query_param;
mod utf8_decode;
mod utf8_encode;
mod xpath;

View File

@ -0,0 +1,72 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2025 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
use crate::runner::{RunnerError, RunnerErrorKind, Value};
use hurl_core::ast::SourceInfo;
pub fn eval_utf8_decode(
value: &Value,
source_info: SourceInfo,
assert: bool,
) -> Result<Option<Value>, RunnerError> {
match value {
Value::Bytes(value) => {
let decoded = String::from_utf8_lossy(value);
Ok(Some(Value::String(decoded.to_string())))
}
v => {
let kind = RunnerErrorKind::FilterInvalidInput(v.kind().to_string());
Err(RunnerError::new(source_info, kind, assert))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::runner::Number;
use hurl_core::ast::SourceInfo;
use hurl_core::reader::Pos;
#[test]
fn eval_filter_utf8_decode_ok() {
let datas = [
(b"Hello World".to_vec(), "Hello World"),
// With some replacements for invalid UTF-8 bytes
(b"Hello \xF0\x90\x80World".to_vec(), "Hello <20>World"),
// With emojis
(
b"\xF0\x9F\x8D\x8E\xF0\x9F\x8D\x8C\xF0\x9F\x8D\x90\xF0\x9F\x8D\x8A".to_vec(),
"🍎🍌🍐🍊",
),
];
let source_info = SourceInfo::new(Pos::new(1, 1), Pos::new(1, 10));
for (bytes, expected) in datas {
let ret = eval_utf8_decode(&Value::Bytes(bytes), source_info, false);
assert_eq!(ret.unwrap().unwrap(), Value::String(expected.to_string()));
}
}
#[test]
fn eval_filter_utf8_decode_failed() {
let source_info = SourceInfo::new(Pos::new(1, 1), Pos::new(1, 10));
let ret = eval_utf8_decode(&Value::Number(Number::Integer(42)), source_info, false);
assert!(ret.is_err());
}
}

View File

@ -0,0 +1,36 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2025 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
use crate::runner::{RunnerError, RunnerErrorKind, Value};
use hurl_core::ast::SourceInfo;
pub fn eval_utf8_encode(
value: &Value,
source_info: SourceInfo,
assert: bool,
) -> Result<Option<Value>, RunnerError> {
match value {
Value::String(value) => {
let encoded = value.bytes().collect::<Vec<_>>();
Ok(Some(Value::Bytes(encoded)))
}
v => {
let kind = RunnerErrorKind::FilterInvalidInput(v.kind().to_string());
Err(RunnerError::new(source_info, kind, assert))
}
}
}

View File

@ -365,6 +365,8 @@ pub enum FilterValue {
space0: Whitespace,
param: Template,
},
Utf8Decode,
Utf8Encode,
XPath {
space0: Whitespace,
expr: Template,
@ -404,6 +406,8 @@ impl FilterValue {
FilterValue::UrlDecode => "urlDecode",
FilterValue::UrlEncode => "urlEncode",
FilterValue::UrlQueryParam { .. } => "urlQueryParam",
FilterValue::Utf8Decode => "utf8Decode",
FilterValue::Utf8Encode => "utf8Encode",
FilterValue::XPath { .. } => "xpath",
}
}

View File

@ -485,17 +485,19 @@ pub fn walk_filter<V: Visitor>(visitor: &mut V, filter: &Filter) {
FilterValue::ToFloat => {}
FilterValue::ToHex => {}
FilterValue::ToInt => {}
FilterValue::ToString => {}
FilterValue::UrlDecode => {}
FilterValue::UrlEncode => {}
FilterValue::XPath { space0, expr } => {
visitor.visit_whitespace(space0);
visitor.visit_template(expr);
}
FilterValue::ToString => {}
FilterValue::UrlQueryParam { space0, param } => {
visitor.visit_whitespace(space0);
visitor.visit_template(param);
}
FilterValue::Utf8Decode => {}
FilterValue::Utf8Encode => {}
FilterValue::XPath { space0, expr } => {
visitor.visit_whitespace(space0);
visitor.visit_template(expr);
}
}
}

View File

@ -82,6 +82,8 @@ pub fn filter(reader: &mut Reader) -> ParseResult<Filter> {
url_decode_filter,
url_encode_filter,
url_query_param_filter,
utf8_decode_filter,
utf8_encode_filter,
xpath_filter,
],
reader,

View File

@ -324,7 +324,9 @@ impl Lint for FilterValue {
| FilterValue::ToInt
| FilterValue::ToString
| FilterValue::UrlDecode
| FilterValue::UrlEncode => {}
| FilterValue::UrlEncode
| FilterValue::Utf8Decode
| FilterValue::Utf8Encode => {}
}
s
}