#[cfg(feature = "string")]
use jmespath::{Runtime, Variable};
#[cfg(feature = "string")]
use jmespath_extensions::registry::{Category, FunctionRegistry};
#[cfg(feature = "string")]
use std::rc::Rc;
#[cfg(feature = "string")]
fn create_runtime_with_registry(registry: &FunctionRegistry) -> Runtime {
let mut runtime = Runtime::new();
runtime.register_builtin_functions();
registry.apply(&mut runtime);
runtime
}
#[test]
#[cfg(feature = "string")]
fn test_disable_function_prevents_execution() {
let mut registry = FunctionRegistry::new();
registry.register_category(Category::String);
registry.disable_function("upper");
let runtime = create_runtime_with_registry(®istry);
let expr = runtime.compile("upper('hello')");
match expr {
Ok(compiled) => {
let result = compiled.search(Rc::new(Variable::Null));
assert!(
result.is_err(),
"Expected 'upper' to fail at runtime when disabled, but it succeeded"
);
}
Err(_) => {
}
}
let expr = runtime
.compile("lower('HELLO')")
.expect("lower should compile");
let result = expr
.search(Rc::new(Variable::Null))
.expect("lower should execute");
let result_str = result.as_string().expect("lower should return string");
assert_eq!(result_str, "hello");
}
#[test]
#[cfg(feature = "string")]
fn test_disable_multiple_functions() {
let mut registry = FunctionRegistry::new();
registry.register_category(Category::String);
registry.disable_function("upper");
registry.disable_function("lower");
registry.disable_function("trim");
let runtime = create_runtime_with_registry(®istry);
for func_name in &["upper", "lower", "trim"] {
let expr_str = format!("{}('test')", func_name);
let expr = runtime.compile(&expr_str);
match expr {
Ok(compiled) => {
let result = compiled.search(Rc::new(Variable::Null));
assert!(
result.is_err(),
"Expected '{}' to fail at runtime when disabled",
func_name
);
}
Err(_) => {
}
}
}
let expr = runtime
.compile("pad_left('hi', `5`, ' ')")
.expect("pad_left should compile");
let result = expr
.search(Rc::new(Variable::Null))
.expect("pad_left should execute");
let result_str = result.as_string().expect("pad_left should return string");
assert_eq!(result_str, " hi");
}
#[test]
#[cfg(feature = "string")]
fn test_enable_function_restores_access() {
let mut registry = FunctionRegistry::new();
registry.register_category(Category::String);
registry.disable_function("upper");
assert!(!registry.is_enabled("upper"));
registry.enable_function("upper");
assert!(registry.is_enabled("upper"));
let runtime = create_runtime_with_registry(®istry);
let expr = runtime
.compile("upper('hello')")
.expect("upper should compile after re-enabling");
let result = expr
.search(Rc::new(Variable::Null))
.expect("upper should execute after re-enabling");
let result_str = result.as_string().expect("upper should return string");
assert_eq!(result_str, "HELLO");
}
#[test]
#[cfg(feature = "string")]
fn test_is_enabled_reflects_state() {
let mut registry = FunctionRegistry::new();
registry.register_category(Category::String);
assert!(registry.is_enabled("upper"));
assert!(registry.is_enabled("lower"));
registry.disable_function("upper");
assert!(!registry.is_enabled("upper"));
assert!(registry.is_enabled("lower"));
registry.enable_function("upper");
assert!(registry.is_enabled("upper"));
}
#[test]
#[cfg(feature = "string")]
fn test_get_function_returns_none_for_disabled() {
let mut registry = FunctionRegistry::new();
registry.register_category(Category::String);
assert!(registry.get_function("upper").is_some());
registry.disable_function("upper");
assert!(registry.get_function("upper").is_none());
}
#[test]
#[cfg(feature = "string")]
fn test_functions_iterator_excludes_disabled() {
let mut registry = FunctionRegistry::new();
registry.register_category(Category::String);
let initial_count = registry.functions().count();
registry.disable_function("upper");
registry.disable_function("lower");
let after_disable_count = registry.functions().count();
assert_eq!(after_disable_count, initial_count - 2);
let names: Vec<_> = registry.functions().map(|f| f.name).collect();
assert!(!names.contains(&"upper"));
assert!(!names.contains(&"lower"));
}
#[test]
#[cfg(all(feature = "string", feature = "math"))]
fn test_disable_across_categories() {
let mut registry = FunctionRegistry::new();
registry.register_category(Category::String);
registry.register_category(Category::Math);
registry.disable_function("upper"); registry.disable_function("add");
let runtime = create_runtime_with_registry(®istry);
for (func_name, expr_str) in &[("upper", "upper('test')"), ("add", "add(`1`, `2`)")] {
let expr = runtime.compile(expr_str);
match expr {
Ok(compiled) => {
let result = compiled.search(Rc::new(Variable::Null));
assert!(
result.is_err(),
"Expected '{}' to fail at runtime when disabled",
func_name
);
}
Err(_) => {
}
}
}
let expr = runtime
.compile("lower('TEST')")
.expect("lower should compile");
let result = expr
.search(Rc::new(Variable::Null))
.expect("lower should execute");
assert_eq!(result.as_string().unwrap(), "test");
let expr = runtime
.compile("subtract(`5`, `3`)")
.expect("subtract should compile");
let result = expr
.search(Rc::new(Variable::Null))
.expect("subtract should execute");
assert_eq!(result.as_number().unwrap(), 2.0);
}
#[test]
#[cfg(feature = "string")]
fn test_len_accounts_for_disabled() {
let mut registry = FunctionRegistry::new();
registry.register_category(Category::String);
let initial_len = registry.len();
registry.disable_function("upper");
registry.disable_function("lower");
assert_eq!(registry.len(), initial_len - 2);
}
#[test]
#[cfg(feature = "string")]
fn test_disable_nonexistent_function() {
let mut registry = FunctionRegistry::new();
registry.register_category(Category::String);
let initial_count = registry.functions().count();
registry.disable_function("nonexistent_function_xyz");
assert_eq!(registry.functions().count(), initial_count);
}