use std::borrow::Cow;
#[cfg(feature = "secrecy")]
use secrecy::ExposeSecret;
use crate::FilterValue;
function! {
trim(string) {
match string.as_ref() {
FilterValue::String(Cow::Borrowed(s)) => {
Cow::Owned(FilterValue::String(Cow::Borrowed(s.trim())))
}
FilterValue::String(Cow::Owned(s)) => {
Cow::Owned(FilterValue::String(Cow::Owned(s.trim().to_string())))
}
#[cfg(feature = "secrecy")]
FilterValue::Secret(s) => Cow::Owned(FilterValue::secret(s.expose_secret().trim())),
_ => Cow::Owned(FilterValue::Null),
}
}
}
#[cfg(test)]
mod tests {
use std::borrow::Cow;
use crate::{FilterValue, functions::Function};
use super::trim;
#[test]
fn name_and_arity() {
assert_eq!(trim.name(), "trim");
assert_eq!(trim.arity(), 1);
}
#[test]
fn borrowed_strings_trim_to_a_borrowed_sub_slice() {
let result = trim.call(&[Cow::Owned(FilterValue::String(Cow::Borrowed(" hi ")))]);
let FilterValue::String(cow) = result.as_ref() else {
panic!("expected a string, got {:?}", result.as_ref());
};
assert!(
matches!(cow, Cow::Borrowed(_)),
"the trimmed string should stay borrowed"
);
assert_eq!(cow.as_ref(), "hi");
}
#[test]
fn owned_strings_are_trimmed() {
let result = trim.call(&[Cow::Owned(FilterValue::String(Cow::Owned(
" hi there ".to_string(),
)))]);
assert_eq!(result.as_ref(), &FilterValue::String("hi there".into()));
}
#[test]
fn non_strings_yield_null() {
let result = trim.call(&[Cow::Owned(FilterValue::Number(1.0))]);
assert_eq!(result.as_ref(), &FilterValue::Null);
}
#[cfg(feature = "secrecy")]
#[test]
fn secrets_stay_wrapped_and_redacted() {
let result = trim.call(&[Cow::Owned(FilterValue::secret(" hunter2 "))]);
let result = result.as_ref();
assert!(matches!(result, FilterValue::Secret(_)));
assert_eq!(result.to_string(), "[REDACTED]");
assert_eq!(result, &FilterValue::String("hunter2".into()));
}
}