1#![recursion_limit="200"]
94#![deny(missing_docs)]
95
96#![forbid(unsafe_code)]
97#[macro_use]
98extern crate quick_error;
99extern crate serde;
100extern crate serde_json;
101
102mod math;
103mod function;
104mod operator;
105mod node;
106mod tree;
107mod error;
108mod builtin;
109mod expr;
110
111pub use expr::ExecOptions;
112use function::ConstFunction;
113pub use serde_json::Value;
114pub use error::Error;
115pub use function::Function;
116pub use expr::Expr;
117
118use std::{collections::HashMap, rc::Rc, cell::RefCell};
119use serde_json::to_value as json_to_value;
120use serde::Serialize;
121
122pub fn to_value<S: Serialize>(v: S) -> Value {
124 json_to_value(v).unwrap()
125}
126
127pub type Context = HashMap<String, Value>;
129pub type Contexts = Vec<Context>;
131pub type Functions = HashMap<String, Function>;
133pub type ConstFunctions = HashMap<String, ConstFunction>;
135
136pub fn eval(expr: &str) -> Result<Value, Error> {
138 Expr::new(expr).compile()?.exec()
139}
140
141type Compiled = Box<dyn Fn(&[Context], &Functions, Rc<RefCell<ConstFunctions>>) -> Result<Value, Error>>;
142
143#[cfg(test)]
144mod tests {
145 use std::collections::HashMap;
146
147 use crate::to_value;
148 use crate::error::Error;
149 use crate::Expr;
150 use crate::tree::Tree;
151 use crate::Value;
152 use crate::eval;
153
154 #[test]
155 fn test_add() {
156 assert_eq!(eval("2 + 3"), Ok(to_value(5)));
157 }
158
159 #[test]
160 fn test_brackets_add() {
161 assert_eq!(eval("(2 + 3) + (3 + 5)"), Ok(to_value(13)));
162 }
163
164 #[test]
165 fn test_brackets_float_add() {
166 assert_eq!(eval("(2 + 3.2) + (3 + 5)"), Ok(to_value(13.2)));
167 }
168
169 #[test]
170 fn test_brackets_float_mul() {
171 assert_eq!(eval("(2 + 3.2) * 5"), Ok(to_value(26.0)));
172 }
173
174 #[test]
175 fn test_brackets_sub() {
176 assert_eq!(eval("(4 - 3) * 5"), Ok(to_value(5)));
177 }
178
179 #[test]
180 fn test_useless_brackets() {
181 assert_eq!(eval("2 + 3 + (5)"), Ok(to_value(10)));
182 }
183
184 #[test]
185 fn test_error_brackets_not_with_function() {
186 assert_eq!(eval("5 + ()"), Err(Error::BracketNotWithFunction));
187 }
188
189 #[test]
190 fn test_deep_brackets() {
191 assert_eq!(eval("(2 + (3 + 4) + (6 + (6 + 7)) + 5)"), Ok(to_value(33)));
192 }
193
194 #[test]
195 fn test_brackets_div() {
196 assert_eq!(eval("(4 / (2 + 2)) * 5"), Ok(to_value(5.0)));
197 }
198
199 #[test]
200 fn test_min() {
201 assert_eq!(eval("min(30, 5, 245, 20)"), Ok(to_value(5)));
202 }
203
204 #[test]
205 fn test_min_brackets() {
206 assert_eq!(
207 eval("(min(30, 5, 245, 20) * 10 + (5 + 5) * 5)"),
208 Ok(to_value(100))
209 );
210 }
211
212 #[test]
213 fn test_min_and_mul() {
214 assert_eq!(eval("min(30, 5, 245, 20) * 10"), Ok(to_value(50)));
215 }
216
217 #[test]
218 fn test_max() {
219 assert_eq!(eval("max(30, 5, 245, 20)"), Ok(to_value(245)));
220 }
221
222 #[test]
223 fn test_max_brackets() {
224 assert_eq!(
225 eval("(max(30, 5, 245, 20) * 10 + (5 + 5) * 5)"),
226 Ok(to_value(2500))
227 );
228 }
229
230 #[test]
231 fn test_max_and_mul() {
232 assert_eq!(eval("max(30, 5, 245, 20) * 10"), Ok(to_value(2450)));
233 }
234
235 #[test]
236 fn test_len_array() {
237 assert_eq!(eval("len(array(2, 3, 4, 5, 6))"), Ok(to_value(5)));
238 }
239
240 #[test]
241 fn test_null_and_number() {
242 assert_eq!(eval("hos != 0"), Ok(to_value(true)));
243 assert_eq!(eval("hos > 0"), Ok(to_value(false)));
244 }
245
246 #[test]
247 fn test_len_string() {
248 assert_eq!(eval("len('Hello world!')"), Ok(to_value(12)));
249 }
250
251 #[test]
252 fn test_len_object() {
253 let mut object = HashMap::new();
254 object.insert("field1", "value1");
255 object.insert("field2", "value2");
256 object.insert("field3", "value3");
257 assert_eq!(
258 Expr::new("len(object)").value("object", object).exec(),
259 Ok(to_value(3_i64))
260 );
261 }
262
263 #[test]
264 fn test_brackets_1() {
265 assert_eq!(eval("(5) + (min(3, 4, 5)) + 20"), Ok(to_value(28)));
266 }
267
268 #[test]
269 fn test_brackets_2() {
270 assert_eq!(eval("(((5) / 5))"), Ok(to_value(1.0)));
271 }
272
273 #[test]
274 fn test_string_add() {
275 assert_eq!(eval(r#""Hello"+", world!""#), Ok(to_value("Hello, world!")));
276 }
277
278 #[test]
279 fn test_equal() {
280 assert_eq!(eval("1 == 1"), Ok(to_value(true)));
281 }
282
283 #[test]
284 fn test_not_equal() {
285 assert_eq!(eval("1 != 2"), Ok(to_value(true)));
286 }
287
288 #[test]
289 fn test_multiple_equal() {
290 assert_eq!(eval("(1 == 2) == (2 == 3)"), Ok(to_value(true)));
291 }
292
293 #[test]
294 fn test_multiple_not_equal() {
295 assert_eq!(eval("(1 != 2) == (2 != 3)"), Ok(to_value(true)));
296 }
297
298 #[test]
299 fn test_greater_than() {
300 assert_eq!(eval("1 > 2"), Ok(to_value(false)));
301 assert_eq!(eval("2 > 1"), Ok(to_value(true)));
302 }
303
304 #[test]
305 fn test_less_than() {
306 assert_eq!(eval("2 < 1"), Ok(to_value(false)));
307 assert_eq!(eval("1 < 2"), Ok(to_value(true)));
308 }
309
310 #[test]
311 fn test_greater_and_less() {
312 assert_eq!(eval("(2 > 1) == (1 < 2)"), Ok(to_value(true)));
313 }
314
315 #[test]
316 fn test_ge() {
317 assert_eq!(eval("2 >= 1"), Ok(to_value(true)));
318 assert_eq!(eval("2 >= 2"), Ok(to_value(true)));
319 assert_eq!(eval("2 >= 3"), Ok(to_value(false)));
320 }
321
322 #[test]
323 fn test_le() {
324 assert_eq!(eval("2 <= 1"), Ok(to_value(false)));
325 assert_eq!(eval("2 <= 2"), Ok(to_value(true)));
326 assert_eq!(eval("2 <= 3"), Ok(to_value(true)));
327 }
328
329 #[test]
330 fn test_quotes() {
331 assert_eq!(eval(r#""1><2" + "3<>4""#), Ok(to_value("1><23<>4")));
332 assert_eq!(eval(r#""1==2" + "3--4""#), Ok(to_value("1==23--4")));
333 assert_eq!(eval(r#""1!=2" + "3>>4""#), Ok(to_value("1!=23>>4")));
334 assert_eq!(eval(r#""><1!=2" + "3>>4""#), Ok(to_value("><1!=23>>4")));
335 }
336
337 #[test]
338 fn test_single_quote() {
339 assert_eq!(eval(r#"'1><2' + '3<>4'"#), Ok(to_value("1><23<>4")));
340 assert_eq!(eval(r#"'1==2' + '3--4'"#), Ok(to_value("1==23--4")));
341 assert_eq!(eval(r#"'1!=2' + '3>>4'"#), Ok(to_value("1!=23>>4")));
342 assert_eq!(eval(r#"'!=1<>2' + '3>>4'"#), Ok(to_value("!=1<>23>>4")));
343 }
344
345 #[test]
346 fn test_single_and_double_quote() {
347 assert_eq!(
348 eval(r#"' """" ' + ' """" '"#),
349 Ok(to_value(r#" """" """" "#))
350 );
351 }
352
353 #[test]
354 fn test_double_and_single_quote() {
355 assert_eq!(
356 eval(r#"" '''' " + " '''' ""#),
357 Ok(to_value(r#" '''' '''' "#))
358 );
359 }
360
361 #[test]
362 fn test_array() {
363 assert_eq!(eval("array(1, 2, 3, 4)"), Ok(to_value(vec![1, 2, 3, 4])));
364 }
365
366 #[test]
367 fn test_range() {
368 assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4])));
369 }
370
371 #[test]
372 fn test_range_and_min() {
373 assert_eq!(eval("min(0..5)"), Ok(to_value(0)));
374 }
375
376 #[test]
377 fn test_rem_1() {
378 assert_eq!(eval("2 % 2"), Ok(to_value(0)));
379 }
380
381 #[test]
382 fn test_rem_2() {
383 assert_eq!(eval("5 % 56 % 5"), Ok(to_value(0)));
384 }
385
386 #[test]
387 fn test_rem_3() {
388 assert_eq!(eval("5.5 % 23"), Ok(to_value(5.5)));
389 }
390
391 #[test]
392 fn test_rem_4() {
393 assert_eq!(eval("23 % 5.5"), Ok(to_value(1.0)));
394 }
395
396 #[test]
397 fn test_and_1() {
398 assert_eq!(eval("3 > 2 && 2 > 1"), Ok(to_value(true)));
399 }
400
401 #[test]
402 fn test_and_2() {
403 assert_eq!(eval("3 == 2 && 2 == 1"), Ok(to_value(false)));
404 }
405
406 #[test]
407 fn test_and_3() {
408 assert_eq!(eval("3 > 2 && 2 == 1"), Ok(to_value(false)));
409 }
410
411 #[test]
412 fn test_or_1() {
413 assert_eq!(eval("3 > 2 || 2 > 1"), Ok(to_value(true)));
414 }
415
416 #[test]
417 fn test_or_2() {
418 assert_eq!(eval("3 < 2 || 2 < 1"), Ok(to_value(false)));
419 }
420
421 #[test]
422 fn test_or_3() {
423 assert_eq!(eval("3 > 2 || 2 < 1"), Ok(to_value(true)));
424 }
425
426 #[test]
427 fn test_or_4() {
428 assert_eq!(eval("3 < 2 || 2 > 1"), Ok(to_value(true)));
429 }
430
431 #[test]
432 fn test_not() {
433 assert_eq!(eval("!false"), Ok(to_value(true)));
434 assert_eq!(eval("!true"), Ok(to_value(false)));
435 assert_eq!(eval("!(1 != 2)"), Ok(to_value(false)));
436 assert_eq!(eval("!(1 == 2)"), Ok(to_value(true)));
437 assert_eq!(eval("!(1 == 2) == true"), Ok(to_value(true)));
438 }
439
440 #[test]
441 fn test_not_and_brackets() {
442 assert_eq!(eval("(!(1 == 2)) == true"), Ok(to_value(true)));
443 }
444
445 #[test]
446 fn test_object_access() {
447 let mut object = HashMap::new();
448 object.insert("foo", "Foo, hello world!");
449 object.insert("bar", "Bar, hello world!");
450 assert_eq!(
451 Expr::new("object.foo == 'Foo, hello world!'")
452 .value("object", object)
453 .exec(),
454 Ok(to_value(true))
455 );
456 }
457
458 #[test]
459 fn test_object_dynamic_access() {
460 let mut object = HashMap::new();
461 object.insert("foo", "Foo, hello world!");
462 object.insert("bar", "Bar, hello world!");
463 assert_eq!(
464 Expr::new("object['foo'] == 'Foo, hello world!'")
465 .value("object", object)
466 .exec(),
467 Ok(to_value(true))
468 );
469 }
470
471 #[test]
472 fn test_object_dynamic_access_2() {
473 let mut object = HashMap::new();
474 object.insert("foo", "Foo, hello world!");
475 object.insert("bar", "Bar, hello world!");
476 assert_eq!(
477 Expr::new("object[foo] == 'Foo, hello world!'")
478 .value("object", object)
479 .value("foo", "foo")
480 .exec(),
481 Ok(to_value(true))
482 );
483 }
484
485 #[test]
486 fn test_path() {
487 assert_eq!(Expr::new("array[2-2].foo[2-2]").exec(), Ok(Value::Null));
488 }
489
490 #[test]
491 fn test_array_access() {
492 let array = vec!["hello", "world", "!"];
493 assert_eq!(
494 Expr::new(
495 "array[1-1] == 'hello' && array[1] == 'world' && array[2] == '!'",
496 ).value("array", array)
497 .exec(),
498 Ok(to_value(true))
499 );
500 }
501
502 #[test]
503 fn test_builtin_is_empty() {
504 assert_eq!(
505 Expr::new("is_empty(array)")
506 .value("array", Vec::<String>::new())
507 .exec(),
508 Ok(to_value(true))
509 );
510 }
511
512 #[test]
513 fn test_builtin_min() {
514 assert_eq!(
515 Expr::new("min(array)")
516 .value("array", vec![23_i32, 34_i32, 45_i32, 2_i32])
517 .exec(),
518 Ok(to_value(2_i32))
519 );
520 }
521
522 #[test]
523 fn test_custom_function() {
524 assert_eq!(
525 Expr::new("output()")
526 .function(
527 "output",
528 |_| Ok(to_value("This is custom function's output")),
529 )
530 .exec(),
531 Ok(to_value("This is custom function's output"))
532 );
533 }
534
535 #[test]
536 fn test_error_start_with_non_value_operator() {
537 let mut tree = Tree {
538 raw: "+ + 5".to_owned(),
539 ..Default::default()
540 };
541
542 tree.parse_pos().unwrap();
543 tree.parse_operators().unwrap();
544
545 assert_eq!(tree.parse_node(), Err(Error::StartWithNonValueOperator));
546 }
547
548 #[test]
549 fn test_error_duplicate_operator() {
550 let mut tree = Tree {
551 raw: "5 + + 5".to_owned(),
552 ..Default::default()
553 };
554
555 tree.parse_pos().unwrap();
556 tree.parse_operators().unwrap();
557
558 assert_eq!(tree.parse_node(), Err(Error::DuplicateOperatorNode));
559 }
560
561 #[test]
562 fn test_error_duplicate_value() {
563 let mut tree = Tree {
564 raw: "2 + 6 5".to_owned(),
565 ..Default::default()
566 };
567
568 tree.parse_pos().unwrap();
569 tree.parse_operators().unwrap();
570
571 assert_eq!(tree.parse_node(), Err(Error::DuplicateValueNode));
572 }
573
574 #[test]
575 fn test_error_unpaired_brackets() {
576 let mut tree = Tree {
577 raw: "(2 + 3)) * 5".to_owned(),
578 ..Default::default()
579 };
580
581 tree.parse_pos().unwrap();
582
583 assert_eq!(tree.parse_operators(), Err(Error::UnpairedBrackets));
584 }
585
586 #[test]
587 fn test_error_comma() {
588 let mut tree = Tree {
589 raw: ", 2 + 5".to_owned(),
590 ..Default::default()
591 };
592
593 tree.parse_pos().unwrap();
594 tree.parse_operators().unwrap();
595
596 assert_eq!(tree.parse_node(), Err(Error::CommaNotWithFunction));
597 }
598
599 #[test]
600 fn test_eval_issue_2() {
601 assert_eq!(eval("2 * (4 + 0) + 4"), Ok(to_value(12)));
602 assert_eq!(eval("2 * (2 + 2) + (1 + 3)"), Ok(to_value(12)));
603 assert_eq!(eval("2 * (4) + (4)"), Ok(to_value(12)));
604 }
605
606 #[test]
607 fn test_eval_math_function(){
608 fn pow(v: Vec<Value>)->Result<Value, Error>{
609 let Some(base) = v.get(0) else {
610 return Err(Error::ArgumentsLess(2));
611 };
612 let Some(pow) = v.get(1) else {
613 return Err(Error::ArgumentsLess(2));
614 };
615 let Value::Number(base) = base else {
616 return Err(Error::ExpectedNumber);
617 };
618 let Value::Number(pow) = pow else {
619 return Err(Error::ExpectedNumber);
620 };
621 let Some(base) = base.as_i64() else {
622 return Err(Error::Custom("Must can into i64".into()));
623 };
624 let Some(pow) = pow.as_u64() else {
625 return Err(Error::Custom("Must can into u64".into()));
626 };
627 Ok(base.pow(pow as u32).into())
628 }
629 fn add2(v: Vec<Value>)->Result<Value, Error>{
630 let Some(base) = v.get(0) else {
631 return Err(Error::ArgumentsLess(1));
632 };
633 let Value::Number(base) = base else {
634 return Err(Error::ExpectedNumber);
635 };
636 let Some(base) = base.as_i64() else {
637 return Err(Error::Custom("Must can into i64".into()));
638 };
639 Ok((base + 2).into())
640 }
641 let e = Expr::new("add2(pow(2, 2) + pow(2, 2))").const_function("pow", pow).const_function("add2",add2);
642 assert_eq!(e.compile().unwrap().exec(), Ok(to_value(4 + 4 + 2)));
643 }
644
645 #[test]
646 fn test_div_by_zero() {
647 use crate::eval;
648 assert_eq!(eval("5 / 0"), Err(Error::DivisionByZero));
649 }
650
651 #[test]
652 fn test_rem_by_zero() {
653 use crate::eval;
654 assert_eq!(eval("5 % 0"), Err(Error::ModuloByZero));
655 }
656
657 #[test]
658 fn test_short_circuit_and() {
659 use crate::eval;
660 assert_eq!(eval("false && (1 / 0 > 0)"), Ok(to_value(false)));
662 }
663
664 #[test]
665 fn test_short_circuit_or() {
666 use crate::eval;
667 assert_eq!(eval("true || (1 / 0 > 0)"), Ok(to_value(true)));
669 }
670
671 #[test]
672 fn test_empty_string_double_quotes() {
673 use crate::eval;
674 assert_eq!(eval(r#""""#), Ok(to_value("")));
675 }
676
677 #[test]
678 fn test_empty_string_single_quotes() {
679 use crate::eval;
680 assert_eq!(eval("''"), Ok(to_value("")));
681 }
682
683 #[test]
684 fn test_not_non_boolean() {
685 use crate::eval;
686 assert_eq!(eval("!(2 + 3)"), Err(Error::ExpectedBoolean(to_value(5_u64))));
688 }
689
690 #[test]
691 fn test_len_boolean() {
692 assert!(Expr::new("len(v)").value("v", true).exec().is_err());
693 }
694
695 #[test]
696 fn test_string_gt() {
697 use crate::eval;
698 assert!(eval("'b' > 'a'").is_err());
699 }
700
701 #[test]
702 fn test_min_no_args() {
703 use crate::eval;
704 assert_eq!(eval("min()"), Err(Error::ArgumentsLess(1)));
705 }
706
707 #[test]
708 fn test_is_empty_null() {
709 use crate::eval;
710 assert_eq!(eval("is_empty(hos)"), Ok(to_value(true)));
712 }
713
714 #[test]
715 fn test_is_empty_number() {
716 assert_eq!(
717 Expr::new("is_empty(v)").value("v", 0_i32).exec(),
718 Ok(to_value(false))
719 );
720 }
721
722 #[test]
723 fn test_chained_dot_access() {
724 let mut inner = HashMap::new();
725 inner.insert("b", "deep");
726 let mut outer = HashMap::new();
727 outer.insert("a", to_value(inner));
728 assert_eq!(
729 Expr::new("obj.a.b").value("obj", outer).exec(),
730 Ok(to_value("deep"))
731 );
732 }
733
734 #[test]
735 fn test_and_non_boolean() {
736 use crate::eval;
737 assert!(eval("1 && true").is_err());
738 }
739
740 #[test]
741 fn test_or_non_boolean() {
742 use crate::eval;
743 assert!(eval("1 || false").is_err());
744 }
745
746 #[test]
747 fn test_null_arithmetic() {
748 use crate::eval;
749 assert!(eval("hos + 1").is_err());
750 }
751
752 #[test]
753 fn test_div_float_by_zero() {
754 use crate::eval;
755 assert_eq!(eval("5.0 / 0.0"), Err(Error::DivisionByZero));
756 }
757
758 #[test]
759 fn test_rem_float_by_zero() {
760 use crate::eval;
761 assert_eq!(eval("5.5 % 0.0"), Err(Error::ModuloByZero));
762 }
763
764 #[test]
767 fn test_unary_minus_literal() {
768 assert_eq!(eval("-5"), Ok(to_value(-5_i64)));
769 }
770
771 #[test]
772 fn test_unary_minus_float() {
773 assert_eq!(eval("-2.5"), Ok(to_value(-2.5_f64)));
774 }
775
776 #[test]
777 fn test_unary_minus_double() {
778 assert_eq!(eval("-(-3)"), Ok(to_value(3_i64)));
779 }
780
781 #[test]
782 fn test_unary_minus_variable() {
783 assert_eq!(Expr::new("-x").value("x", 5_i32).exec(), Ok(to_value(-5_i64)));
784 }
785
786 #[test]
787 fn test_unary_minus_in_add() {
788 assert_eq!(eval("10 + -3"), Ok(to_value(7_i64)));
789 }
790
791 #[test]
792 fn test_unary_minus_in_mul() {
793 assert_eq!(eval("10 * -2"), Ok(to_value(-20_i64)));
794 }
795
796 #[test]
797 fn test_unary_minus_pow_precedence() {
798 assert_eq!(eval("-2 ** 2"), Ok(to_value(-4.0_f64)));
800 }
801
802 #[test]
805 fn test_pow_operator_basic() {
806 assert_eq!(eval("2 ** 10"), Ok(to_value(1024.0_f64)));
807 }
808
809 #[test]
810 fn test_pow_operator_zero_exp() {
811 assert_eq!(eval("5 ** 0"), Ok(to_value(1.0_f64)));
812 }
813
814 #[test]
815 fn test_pow_operator_fractional() {
816 assert_eq!(eval("4 ** 0.5"), Ok(to_value(2.0_f64)));
817 }
818
819 #[test]
820 fn test_pow_operator_priority_add() {
821 assert_eq!(eval("2 + 3 ** 2"), Ok(to_value(11.0_f64)));
823 }
824
825 #[test]
826 fn test_pow_operator_priority_mul() {
827 assert_eq!(eval("2 * 3 ** 2"), Ok(to_value(18.0_f64)));
829 }
830
831 #[test]
832 fn test_pow_paren_base() {
833 assert_eq!(eval("(-2) ** 2"), Ok(to_value(4.0_f64)));
834 }
835
836 #[test]
839 fn test_null_coalesce_null_var() {
840 assert_eq!(
841 Expr::new("missing ?? 'default'").exec(),
842 Ok(to_value("default"))
843 );
844 }
845
846 #[test]
847 fn test_null_coalesce_present_var() {
848 assert_eq!(
849 Expr::new("v ?? 'default'").value("v", "hello").exec(),
850 Ok(to_value("hello"))
851 );
852 }
853
854 #[test]
855 fn test_null_coalesce_zero_not_null() {
856 assert_eq!(
857 Expr::new("v ?? 99").value("v", 0_i32).exec(),
858 Ok(to_value(0_i64))
859 );
860 }
861
862 #[test]
863 fn test_null_coalesce_false_not_null() {
864 assert_eq!(
865 Expr::new("v ?? true").value("v", false).exec(),
866 Ok(to_value(false))
867 );
868 }
869
870 #[test]
871 fn test_null_coalesce_chained() {
872 assert_eq!(eval("missing ?? another ?? 42"), Ok(to_value(42_i64)));
874 }
875
876 #[test]
879 fn test_in_array_found() {
880 assert_eq!(eval("1 in array(1, 2, 3)"), Ok(to_value(true)));
881 }
882
883 #[test]
884 fn test_in_array_not_found() {
885 assert_eq!(eval("5 in array(1, 2, 3)"), Ok(to_value(false)));
886 }
887
888 #[test]
889 fn test_in_array_variable() {
890 assert_eq!(
891 Expr::new("x in arr")
892 .value("x", 2_i32)
893 .value("arr", vec![1_i32, 2, 3])
894 .exec(),
895 Ok(to_value(true))
896 );
897 }
898
899 #[test]
900 fn test_in_object_key_found() {
901 let mut map = HashMap::new();
902 map.insert("foo", 1_i32);
903 map.insert("bar", 2_i32);
904 assert_eq!(
905 Expr::new("'foo' in obj").value("obj", map).exec(),
906 Ok(to_value(true))
907 );
908 }
909
910 #[test]
911 fn test_in_object_key_not_found() {
912 let mut map = HashMap::new();
913 map.insert("foo", 1_i32);
914 assert_eq!(
915 Expr::new("'baz' in obj").value("obj", map).exec(),
916 Ok(to_value(false))
917 );
918 }
919
920 #[test]
921 fn test_in_string_found() {
922 assert_eq!(eval("'lo' in 'hello'"), Ok(to_value(true)));
923 }
924
925 #[test]
926 fn test_in_string_not_found() {
927 assert_eq!(eval("'xyz' in 'hello'"), Ok(to_value(false)));
928 }
929
930 #[test]
931 fn test_in_with_and() {
932 assert_eq!(
933 eval("1 in array(1,2,3) && 2 in array(2,3,4)"),
934 Ok(to_value(true))
935 );
936 }
937
938 #[test]
941 fn test_abs_negative() {
942 assert_eq!(eval("abs(-7)"), Ok(to_value(7_i64)));
943 }
944
945 #[test]
946 fn test_abs_positive() {
947 assert_eq!(eval("abs(3)"), Ok(to_value(3_i64)));
948 }
949
950 #[test]
951 fn test_abs_float() {
952 assert_eq!(eval("abs(-3.5)"), Ok(to_value(3.5_f64)));
953 }
954
955 #[test]
956 fn test_floor() {
957 assert_eq!(eval("floor(3.9)"), Ok(to_value(3.0_f64)));
958 assert_eq!(eval("floor(-3.1)"), Ok(to_value(-4.0_f64)));
959 }
960
961 #[test]
962 fn test_ceil() {
963 assert_eq!(eval("ceil(3.1)"), Ok(to_value(4.0_f64)));
964 assert_eq!(eval("ceil(-3.9)"), Ok(to_value(-3.0_f64)));
965 }
966
967 #[test]
968 fn test_round() {
969 assert_eq!(eval("round(3.5)"), Ok(to_value(4.0_f64)));
970 assert_eq!(eval("round(3.4)"), Ok(to_value(3.0_f64)));
971 }
972
973 #[test]
974 fn test_sqrt() {
975 assert_eq!(eval("sqrt(16.0)"), Ok(to_value(4.0_f64)));
976 assert_eq!(eval("sqrt(2.0)"), Ok(to_value(2.0_f64.sqrt())));
977 }
978
979 #[test]
980 fn test_pow_builtin() {
981 assert_eq!(eval("pow(2, 8)"), Ok(to_value(256.0_f64)));
982 assert_eq!(eval("pow(3, 0)"), Ok(to_value(1.0_f64)));
983 }
984
985 #[test]
988 fn test_contains_string_found() {
989 assert_eq!(eval("contains('hello world', 'world')"), Ok(to_value(true)));
990 }
991
992 #[test]
993 fn test_contains_string_not_found() {
994 assert_eq!(eval("contains('hello', 'xyz')"), Ok(to_value(false)));
995 }
996
997 #[test]
998 fn test_contains_array_found() {
999 assert_eq!(eval("contains(array(1,2,3), 2)"), Ok(to_value(true)));
1000 }
1001
1002 #[test]
1003 fn test_contains_array_not_found() {
1004 assert_eq!(eval("contains(array(1,2,3), 9)"), Ok(to_value(false)));
1005 }
1006
1007 #[test]
1008 fn test_starts_with_true() {
1009 assert_eq!(eval("starts_with('hello', 'hel')"), Ok(to_value(true)));
1010 }
1011
1012 #[test]
1013 fn test_starts_with_false() {
1014 assert_eq!(eval("starts_with('hello', 'llo')"), Ok(to_value(false)));
1015 }
1016
1017 #[test]
1018 fn test_ends_with_true() {
1019 assert_eq!(eval("ends_with('hello', 'llo')"), Ok(to_value(true)));
1020 }
1021
1022 #[test]
1023 fn test_ends_with_false() {
1024 assert_eq!(eval("ends_with('hello', 'hel')"), Ok(to_value(false)));
1025 }
1026
1027 #[test]
1028 fn test_upper() {
1029 assert_eq!(eval("upper('hello')"), Ok(to_value("HELLO")));
1030 }
1031
1032 #[test]
1033 fn test_lower() {
1034 assert_eq!(eval("lower('HELLO')"), Ok(to_value("hello")));
1035 }
1036
1037 #[test]
1038 fn test_trim() {
1039 assert_eq!(eval("trim(' hello ')"), Ok(to_value("hello")));
1040 assert_eq!(eval("trim('no-spaces')"), Ok(to_value("no-spaces")));
1041 }
1042
1043 #[test]
1046 fn test_is_null_of_null_value() {
1047 assert_eq!(
1048 Expr::new("is_null(v)").value("v", Value::Null).exec(),
1049 Ok(to_value(true))
1050 );
1051 }
1052
1053 #[test]
1054 fn test_is_null_unset_var() {
1055 assert_eq!(eval("is_null(missing)"), Ok(to_value(true)));
1056 }
1057
1058 #[test]
1059 fn test_is_null_false() {
1060 assert_eq!(eval("is_null(5)"), Ok(to_value(false)));
1061 }
1062
1063 #[test]
1064 fn test_is_number_int() {
1065 assert_eq!(eval("is_number(42)"), Ok(to_value(true)));
1066 }
1067
1068 #[test]
1069 fn test_is_number_float() {
1070 assert_eq!(eval("is_number(3.14)"), Ok(to_value(true)));
1071 }
1072
1073 #[test]
1074 fn test_is_number_false() {
1075 assert_eq!(eval("is_number('hello')"), Ok(to_value(false)));
1076 }
1077
1078 #[test]
1079 fn test_is_string_true() {
1080 assert_eq!(eval("is_string('hello')"), Ok(to_value(true)));
1081 }
1082
1083 #[test]
1084 fn test_is_string_false() {
1085 assert_eq!(eval("is_string(42)"), Ok(to_value(false)));
1086 }
1087
1088 #[test]
1089 fn test_is_array_true() {
1090 assert_eq!(eval("is_array(array(1,2,3))"), Ok(to_value(true)));
1091 }
1092
1093 #[test]
1094 fn test_is_array_false() {
1095 assert_eq!(eval("is_array(42)"), Ok(to_value(false)));
1096 }
1097
1098 #[test]
1101 fn test_int_from_string() {
1102 assert_eq!(eval("int('42')"), Ok(to_value(42_i64)));
1103 }
1104
1105 #[test]
1106 fn test_int_from_float_string() {
1107 assert_eq!(eval("int('3.9')"), Ok(to_value(3_i64)));
1108 }
1109
1110 #[test]
1111 fn test_int_from_number() {
1112 assert_eq!(eval("int(7)"), Ok(to_value(7_i64)));
1113 }
1114
1115 #[test]
1116 fn test_int_from_bool() {
1117 assert_eq!(eval("int(true)"), Ok(to_value(1_i64)));
1118 assert_eq!(eval("int(false)"), Ok(to_value(0_i64)));
1119 }
1120
1121 #[test]
1122 fn test_float_from_string() {
1123 assert_eq!(eval("float('3.14')"), Ok(to_value(3.14_f64)));
1124 }
1125
1126 #[test]
1127 fn test_float_from_number() {
1128 assert_eq!(eval("float(5)"), Ok(to_value(5.0_f64)));
1129 }
1130
1131 #[test]
1132 fn test_str_from_number() {
1133 assert_eq!(eval("str(42)"), Ok(to_value("42")));
1134 }
1135
1136 #[test]
1137 fn test_str_from_bool() {
1138 assert_eq!(eval("str(true)"), Ok(to_value("true")));
1139 }
1140
1141 #[test]
1142 fn test_str_from_null() {
1143 assert_eq!(eval("str(missing)"), Ok(to_value("null")));
1144 }
1145
1146 #[test]
1147 fn test_str_already_string() {
1148 assert_eq!(eval("str('hello')"), Ok(to_value("hello")));
1149 }
1150
1151 #[test]
1154 fn test_and_or_precedence() {
1155 assert_eq!(eval("false || true && false"), Ok(to_value(false)));
1157 }
1158
1159 #[test]
1160 fn test_and_or_precedence_2() {
1161 assert_eq!(eval("true || false && false"), Ok(to_value(true)));
1163 }
1164
1165 #[test]
1166 fn test_in_with_or() {
1167 assert_eq!(
1168 eval("5 in array(1,2,3) || 2 in array(2,3,4)"),
1169 Ok(to_value(true))
1170 );
1171 }
1172
1173 #[test]
1174 fn test_null_coalesce_with_and() {
1175 assert_eq!(
1177 Expr::new("missing ?? true && false").exec(),
1178 Ok(to_value(false))
1179 );
1180 }
1181
1182 #[test]
1183 fn test_null_coalesce_null_literal() {
1184 assert_eq!(eval("missing ?? another"), Ok(Value::Null));
1186 }
1187
1188 #[test]
1191 fn test_pow_zero_zero() {
1192 assert_eq!(eval("0 ** 0"), Ok(to_value(1.0_f64)));
1194 }
1195
1196 #[test]
1197 fn test_pow_negative_exponent() {
1198 assert_eq!(eval("2 ** -1"), Ok(to_value(0.5_f64)));
1200 }
1201
1202 #[test]
1203 fn test_pow_chained_left_assoc() {
1204 assert_eq!(eval("2 ** 3 ** 2"), Ok(to_value(64.0_f64)));
1206 }
1207
1208 #[test]
1211 fn test_null_equals_null() {
1212 assert_eq!(eval("missing == another"), Ok(to_value(true)));
1214 }
1215
1216 #[test]
1217 fn test_cross_type_equality() {
1218 assert_eq!(eval("1 == '1'"), Ok(to_value(false)));
1220 }
1221
1222 #[test]
1223 fn test_null_not_equal_to_zero() {
1224 assert_eq!(eval("missing != 0"), Ok(to_value(true)));
1225 }
1226
1227 #[test]
1230 fn test_in_unsupported_rhs_type() {
1231 assert!(eval("1 in 42").is_err());
1233 }
1234
1235 #[test]
1236 fn test_in_object_non_string_key() {
1237 let mut map = HashMap::new();
1239 map.insert("foo", 1_i32);
1240 assert!(Expr::new("42 in obj").value("obj", map).exec().is_err());
1241 }
1242
1243 #[test]
1246 fn test_array_out_of_bounds() {
1247 let arr = vec![1_i32, 2, 3];
1249 assert_eq!(
1250 Expr::new("arr[10]").value("arr", arr).exec(),
1251 Ok(Value::Null)
1252 );
1253 }
1254
1255 #[test]
1256 fn test_array_negative_index() {
1257 let arr = vec![1_i32, 2, 3];
1259 assert!(Expr::new("arr[-1]").value("arr", arr).exec().is_err());
1260 }
1261
1262 #[test]
1263 fn test_len_empty_string() {
1264 assert_eq!(eval("len('')"), Ok(to_value(0_i64)));
1265 }
1266
1267 #[test]
1268 fn test_len_empty_array() {
1269 assert_eq!(eval("len(array())"), Ok(to_value(0_i64)));
1270 }
1271
1272 #[test]
1273 fn test_is_empty_empty_string() {
1274 assert_eq!(eval("is_empty('')"), Ok(to_value(true)));
1275 }
1276
1277 #[test]
1278 fn test_is_empty_nonempty_array() {
1279 assert_eq!(eval("is_empty(array(1))"), Ok(to_value(false)));
1280 }
1281
1282 #[test]
1283 fn test_is_empty_empty_array() {
1284 assert_eq!(eval("is_empty(array())"), Ok(to_value(true)));
1285 }
1286
1287 #[test]
1290 fn test_function_not_exists() {
1291 assert_eq!(eval("no_such_fn(1)"), Err(Error::FunctionNotExists("no_such_fn".into())));
1292 }
1293
1294 #[test]
1297 fn test_abs_zero() {
1298 assert_eq!(eval("abs(0)"), Ok(to_value(0_i64)));
1299 }
1300
1301 #[test]
1302 fn test_abs_non_number() {
1303 assert!(eval("abs('hello')").is_err());
1304 }
1305
1306 #[test]
1307 fn test_sqrt_zero() {
1308 assert_eq!(eval("sqrt(0)"), Ok(to_value(0.0_f64)));
1309 }
1310
1311 #[test]
1312 fn test_round_negative_half() {
1313 assert_eq!(eval("round(-0.5)"), Ok(to_value(-1.0_f64)));
1315 }
1316
1317 #[test]
1318 fn test_floor_integer_input() {
1319 assert_eq!(eval("floor(5)"), Ok(to_value(5.0_f64)));
1320 }
1321
1322 #[test]
1323 fn test_ceil_integer_input() {
1324 assert_eq!(eval("ceil(5)"), Ok(to_value(5.0_f64)));
1325 }
1326
1327 #[test]
1330 fn test_starts_with_empty_prefix() {
1331 assert_eq!(eval("starts_with('hello', '')"), Ok(to_value(true)));
1333 }
1334
1335 #[test]
1336 fn test_ends_with_empty_suffix() {
1337 assert_eq!(eval("ends_with('hello', '')"), Ok(to_value(true)));
1338 }
1339
1340 #[test]
1341 fn test_contains_empty_needle() {
1342 assert_eq!(eval("contains('hello', '')"), Ok(to_value(true)));
1343 }
1344
1345 #[test]
1346 fn test_upper_already_upper() {
1347 assert_eq!(eval("upper('HELLO')"), Ok(to_value("HELLO")));
1348 }
1349
1350 #[test]
1351 fn test_lower_already_lower() {
1352 assert_eq!(eval("lower('hello')"), Ok(to_value("hello")));
1353 }
1354
1355 #[test]
1356 fn test_trim_only_leading() {
1357 assert_eq!(eval("trim(' hi')"), Ok(to_value("hi")));
1358 }
1359
1360 #[test]
1361 fn test_trim_only_trailing() {
1362 assert_eq!(eval("trim('hi ')"), Ok(to_value("hi")));
1363 }
1364
1365 #[test]
1368 fn test_int_invalid_string() {
1369 assert!(eval("int('not-a-number')").is_err());
1370 }
1371
1372 #[test]
1373 fn test_float_invalid_string() {
1374 assert!(eval("float('not-a-number')").is_err());
1375 }
1376
1377 #[test]
1378 fn test_float_from_bool() {
1379 assert_eq!(eval("float(true)"), Ok(to_value(1.0_f64)));
1380 assert_eq!(eval("float(false)"), Ok(to_value(0.0_f64)));
1381 }
1382
1383 #[test]
1384 fn test_int_from_null() {
1385 assert!(eval("int(missing)").is_err());
1387 }
1388
1389 #[test]
1390 fn test_float_from_null() {
1391 assert!(eval("float(missing)").is_err());
1392 }
1393
1394 #[test]
1397 fn test_range_single_element() {
1398 assert_eq!(eval("3..4"), Ok(to_value(vec![3_i64])));
1399 }
1400
1401 #[test]
1402 fn test_range_empty() {
1403 assert_eq!(eval("5..5"), Ok(to_value(Vec::<i64>::new())));
1405 }
1406
1407 #[test]
1408 fn test_range_inverted_empty() {
1409 assert_eq!(eval("5..2"), Ok(to_value(Vec::<i64>::new())));
1411 }
1412
1413 #[test]
1416 fn test_if_true_branch() {
1417 assert_eq!(eval("if(true, 1, 2)"), Ok(to_value(1_u64)));
1418 }
1419
1420 #[test]
1421 fn test_if_false_branch() {
1422 assert_eq!(eval("if(false, 1, 2)"), Ok(to_value(2_u64)));
1423 }
1424
1425 #[test]
1426 fn test_if_with_expression_condition() {
1427 assert_eq!(eval("if(3 > 2, 'yes', 'no')"), Ok(to_value("yes")));
1428 assert_eq!(eval("if(1 > 2, 'yes', 'no')"), Ok(to_value("no")));
1429 }
1430
1431 #[test]
1432 fn test_if_short_circuits_true() {
1433 assert_eq!(eval("if(true, 42, 1 / 0)"), Ok(to_value(42_u64)));
1435 }
1436
1437 #[test]
1438 fn test_if_short_circuits_false() {
1439 assert_eq!(eval("if(false, 1 / 0, 99)"), Ok(to_value(99_u64)));
1440 }
1441
1442 #[test]
1443 fn test_if_nested() {
1444 assert_eq!(eval("if(true, if(false, 1, 2), 3)"), Ok(to_value(2_u64)));
1445 }
1446
1447 #[test]
1448 fn test_if_with_variable() {
1449 assert_eq!(
1450 Expr::new("if(x > 0, 'pos', 'non-pos')").value("x", 5_i32).exec(),
1451 Ok(to_value("pos"))
1452 );
1453 }
1454
1455 #[test]
1456 fn test_if_non_boolean_condition() {
1457 assert!(eval("if(1, 'a', 'b')").is_err());
1458 }
1459
1460 #[test]
1461 fn test_if_wrong_arg_count() {
1462 assert!(eval("if(true, 1)").is_err());
1463 assert!(eval("if(true, 1, 2, 3)").is_err());
1464 }
1465
1466 #[test]
1469 fn test_not_in_array_true() {
1470 assert_eq!(eval("5 not in array(1, 2, 3)"), Ok(to_value(true)));
1471 }
1472
1473 #[test]
1474 fn test_not_in_array_false() {
1475 assert_eq!(eval("2 not in array(1, 2, 3)"), Ok(to_value(false)));
1476 }
1477
1478 #[test]
1479 fn test_not_in_string() {
1480 assert_eq!(eval("'xyz' not in 'hello'"), Ok(to_value(true)));
1481 assert_eq!(eval("'lo' not in 'hello'"), Ok(to_value(false)));
1482 }
1483
1484 #[test]
1485 fn test_not_in_object() {
1486 let mut map = HashMap::new();
1487 map.insert("foo", 1_i32);
1488 assert_eq!(
1489 Expr::new("'bar' not in obj").value("obj", map).exec(),
1490 Ok(to_value(true))
1491 );
1492 }
1493
1494 #[test]
1495 fn test_not_in_with_and() {
1496 assert_eq!(
1497 eval("5 not in array(1,2,3) && 9 not in array(2,3,4)"),
1498 Ok(to_value(true))
1499 );
1500 }
1501
1502 #[test]
1505 fn test_bitwise_and() {
1506 assert_eq!(eval("12 & 10"), Ok(to_value(8_i64))); }
1508
1509 #[test]
1510 fn test_bitwise_or() {
1511 assert_eq!(eval("12 | 10"), Ok(to_value(14_i64))); }
1513
1514 #[test]
1515 fn test_bitwise_xor() {
1516 assert_eq!(eval("12 ^ 10"), Ok(to_value(6_i64))); }
1518
1519 #[test]
1520 fn test_bitwise_not() {
1521 assert_eq!(eval("~0"), Ok(to_value(-1_i64)));
1522 assert_eq!(eval("~(-1)"), Ok(to_value(0_i64)));
1523 }
1524
1525 #[test]
1526 fn test_shift_left() {
1527 assert_eq!(eval("1 << 4"), Ok(to_value(16_i64)));
1528 assert_eq!(eval("3 << 2"), Ok(to_value(12_i64)));
1529 }
1530
1531 #[test]
1532 fn test_shift_right() {
1533 assert_eq!(eval("16 >> 2"), Ok(to_value(4_i64)));
1534 assert_eq!(eval("8 >> 1"), Ok(to_value(4_i64)));
1535 }
1536
1537 #[test]
1538 fn test_bitwise_priority_vs_add() {
1539 assert_eq!(eval("1 + 2 & 3"), Ok(to_value(3_i64)));
1542 }
1543
1544 #[test]
1545 fn test_bitwise_and_vs_or_priority() {
1546 assert_eq!(eval("1 | 2 & 3"), Ok(to_value(3_i64)));
1548 }
1549
1550 #[test]
1551 fn test_shift_left_too_large() {
1552 assert!(eval("1 << 64").is_err());
1553 }
1554
1555 #[test]
1556 fn test_bitwise_on_non_integer() {
1557 assert!(eval("1.5 & 3").is_err());
1558 }
1559
1560 #[test]
1563 fn test_split_basic() {
1564 assert_eq!(
1565 eval("split('a,b,c', ',')"),
1566 Ok(to_value(vec!["a", "b", "c"]))
1567 );
1568 }
1569
1570 #[test]
1571 fn test_split_empty_string() {
1572 assert_eq!(
1573 eval("split('', ',')"),
1574 Ok(to_value(vec![""]))
1575 );
1576 }
1577
1578 #[test]
1579 fn test_split_no_delimiter() {
1580 assert_eq!(
1581 eval("split('hello', ',')"),
1582 Ok(to_value(vec!["hello"]))
1583 );
1584 }
1585
1586 #[test]
1587 fn test_join_basic() {
1588 assert_eq!(
1589 eval("join(array('a', 'b', 'c'), '-')"),
1590 Ok(to_value("a-b-c"))
1591 );
1592 }
1593
1594 #[test]
1595 fn test_join_empty_delimiter() {
1596 assert_eq!(
1597 eval("join(array('x', 'y'), '')"),
1598 Ok(to_value("xy"))
1599 );
1600 }
1601
1602 #[test]
1603 fn test_join_numbers() {
1604 assert_eq!(
1605 eval("join(array(1, 2, 3), ', ')"),
1606 Ok(to_value("1, 2, 3"))
1607 );
1608 }
1609
1610 #[test]
1611 fn test_split_then_join() {
1612 assert_eq!(
1613 eval("join(split('a,b,c', ','), '-')"),
1614 Ok(to_value("a-b-c"))
1615 );
1616 }
1617
1618 #[test]
1621 fn test_replace_basic() {
1622 assert_eq!(eval("replace('hello world', 'world', 'Rust')"), Ok(to_value("hello Rust")));
1623 }
1624
1625 #[test]
1626 fn test_replace_all_occurrences() {
1627 assert_eq!(eval("replace('aaa', 'a', 'b')"), Ok(to_value("bbb")));
1628 }
1629
1630 #[test]
1631 fn test_replace_not_found() {
1632 assert_eq!(eval("replace('hello', 'xyz', 'ABC')"), Ok(to_value("hello")));
1633 }
1634
1635 #[test]
1636 fn test_replace_empty_from() {
1637 assert_eq!(
1639 eval("replace('ab', '', '-')"),
1640 Ok(to_value("-a-b-"))
1641 );
1642 }
1643
1644 #[test]
1647 fn test_keys_basic() {
1648 let mut map = HashMap::new();
1649 map.insert("a", 1_i32);
1650 let result = Expr::new("keys(obj)").value("obj", map).exec().unwrap();
1651 let mut keys: Vec<String> = result.as_array().unwrap()
1652 .iter().map(|v| v.as_str().unwrap().to_owned()).collect();
1653 keys.sort();
1654 assert_eq!(keys, vec!["a"]);
1655 }
1656
1657 #[test]
1658 fn test_keys_non_object_error() {
1659 assert!(eval("keys(array(1,2))").is_err());
1660 }
1661
1662 #[test]
1663 fn test_values_basic() {
1664 let mut map = HashMap::new();
1665 map.insert("x", 42_i32);
1666 let result = Expr::new("values(obj)").value("obj", map).exec().unwrap();
1667 let vals: Vec<i64> = result.as_array().unwrap()
1668 .iter().map(|v| v.as_i64().unwrap()).collect();
1669 assert_eq!(vals, vec![42]);
1670 }
1671
1672 #[test]
1675 fn test_type_of_null() {
1676 assert_eq!(eval("type_of(missing)"), Ok(to_value("null")));
1677 }
1678
1679 #[test]
1680 fn test_type_of_number() {
1681 assert_eq!(eval("type_of(42)"), Ok(to_value("number")));
1682 assert_eq!(eval("type_of(3.14)"), Ok(to_value("number")));
1683 }
1684
1685 #[test]
1686 fn test_type_of_string() {
1687 assert_eq!(eval("type_of('hi')"), Ok(to_value("string")));
1688 }
1689
1690 #[test]
1691 fn test_type_of_bool() {
1692 assert_eq!(eval("type_of(true)"), Ok(to_value("bool")));
1693 assert_eq!(eval("type_of(false)"), Ok(to_value("bool")));
1694 }
1695
1696 #[test]
1697 fn test_type_of_array() {
1698 assert_eq!(eval("type_of(array(1,2))"), Ok(to_value("array")));
1699 }
1700
1701 #[test]
1704 fn test_clamp_in_range() {
1705 assert_eq!(eval("clamp(5, 1, 10)"), Ok(to_value(5.0_f64)));
1706 }
1707
1708 #[test]
1709 fn test_clamp_below_min() {
1710 assert_eq!(eval("clamp(-5, 0, 10)"), Ok(to_value(0.0_f64)));
1711 }
1712
1713 #[test]
1714 fn test_clamp_above_max() {
1715 assert_eq!(eval("clamp(15, 0, 10)"), Ok(to_value(10.0_f64)));
1716 }
1717
1718 #[test]
1719 fn test_clamp_at_boundary() {
1720 assert_eq!(eval("clamp(0, 0, 10)"), Ok(to_value(0.0_f64)));
1721 assert_eq!(eval("clamp(10, 0, 10)"), Ok(to_value(10.0_f64)));
1722 }
1723
1724 #[test]
1727 fn test_log_e() {
1728 let result = eval("log(2.718281828)").unwrap();
1729 let f = result.as_f64().unwrap();
1730 assert!((f - 1.0).abs() < 1e-6, "log(e) ≈ 1, got {f}");
1731 }
1732
1733 #[test]
1734 fn test_log2_basic() {
1735 assert_eq!(eval("log2(8)"), Ok(to_value(3.0_f64)));
1736 }
1737
1738 #[test]
1739 fn test_log10_basic() {
1740 assert_eq!(eval("log10(1000)"), Ok(to_value(3.0_f64)));
1741 }
1742
1743 #[test]
1744 fn test_log_one() {
1745 assert_eq!(eval("log(1)"), Ok(to_value(0.0_f64)));
1746 }
1747
1748 #[test]
1751 fn test_index_of_found() {
1752 assert_eq!(eval("index_of(array(10, 20, 30), 20)"), Ok(to_value(1_i64)));
1753 }
1754
1755 #[test]
1756 fn test_index_of_not_found() {
1757 assert_eq!(eval("index_of(array(1, 2, 3), 99)"), Ok(to_value(-1_i64)));
1758 }
1759
1760 #[test]
1761 fn test_index_of_first_occurrence() {
1762 assert_eq!(eval("index_of(array(1, 2, 1), 1)"), Ok(to_value(0_i64)));
1764 }
1765
1766 #[test]
1769 fn test_sort_numbers() {
1770 assert_eq!(
1771 eval("sort(array(3, 1, 2))"),
1772 Ok(to_value(vec![1_i64, 2, 3]))
1773 );
1774 }
1775
1776 #[test]
1777 fn test_sort_strings() {
1778 assert_eq!(
1779 eval("sort(array('banana', 'apple', 'cherry'))"),
1780 Ok(to_value(vec!["apple", "banana", "cherry"]))
1781 );
1782 }
1783
1784 #[test]
1785 fn test_sort_already_sorted() {
1786 assert_eq!(
1787 eval("sort(array(1, 2, 3))"),
1788 Ok(to_value(vec![1_i64, 2, 3]))
1789 );
1790 }
1791
1792 #[test]
1793 fn test_reverse_basic() {
1794 assert_eq!(
1795 eval("reverse(array(1, 2, 3))"),
1796 Ok(to_value(vec![3_i64, 2, 1]))
1797 );
1798 }
1799
1800 #[test]
1801 fn test_reverse_single() {
1802 assert_eq!(eval("reverse(array(42))"), Ok(to_value(vec![42_i64])));
1803 }
1804
1805 #[test]
1806 fn test_unique_basic() {
1807 assert_eq!(
1808 eval("unique(array(1, 2, 1, 3, 2))"),
1809 Ok(to_value(vec![1_i64, 2, 3]))
1810 );
1811 }
1812
1813 #[test]
1814 fn test_unique_no_duplicates() {
1815 assert_eq!(
1816 eval("unique(array(1, 2, 3))"),
1817 Ok(to_value(vec![1_i64, 2, 3]))
1818 );
1819 }
1820
1821 #[test]
1822 fn test_unique_all_same() {
1823 assert_eq!(eval("unique(array(5, 5, 5))"), Ok(to_value(vec![5_i64])));
1824 }
1825
1826 #[test]
1829 fn test_any_found() {
1830 assert_eq!(eval("any(array(1, 2, 3), 2)"), Ok(to_value(true)));
1831 }
1832
1833 #[test]
1834 fn test_any_not_found() {
1835 assert_eq!(eval("any(array(1, 2, 3), 9)"), Ok(to_value(false)));
1836 }
1837
1838 #[test]
1839 fn test_any_empty_array() {
1840 assert_eq!(eval("any(array(), 1)"), Ok(to_value(false)));
1841 }
1842
1843 #[test]
1844 fn test_all_match() {
1845 assert_eq!(eval("all(array(2, 2, 2), 2)"), Ok(to_value(true)));
1846 }
1847
1848 #[test]
1849 fn test_all_partial_match() {
1850 assert_eq!(eval("all(array(2, 2, 3), 2)"), Ok(to_value(false)));
1851 }
1852
1853 #[test]
1854 fn test_all_empty_array() {
1855 assert_eq!(eval("all(array(), 1)"), Ok(to_value(true)));
1857 }
1858
1859 #[test]
1862 fn test_format_basic() {
1863 assert_eq!(eval("format('Hello, {}!', 'world')"), Ok(to_value("Hello, world!")));
1864 }
1865
1866 #[test]
1867 fn test_format_multiple_args() {
1868 assert_eq!(
1869 eval("format('{} + {} = {}', 1, 2, 3)"),
1870 Ok(to_value("1 + 2 = 3"))
1871 );
1872 }
1873
1874 #[test]
1875 fn test_format_no_placeholders() {
1876 assert_eq!(eval("format('no placeholders')"), Ok(to_value("no placeholders")));
1877 }
1878
1879 #[test]
1880 fn test_format_with_variable() {
1881 assert_eq!(
1882 Expr::new("format('Hello, {}!', name)").value("name", "Alice").exec(),
1883 Ok(to_value("Hello, Alice!"))
1884 );
1885 }
1886
1887 #[test]
1888 fn test_format_number() {
1889 assert_eq!(eval("format('value: {}', 42)"), Ok(to_value("value: 42")));
1890 }
1891}