1mod coercion;
6mod eval;
7mod prelude;
8mod value_handler;
9
10mod document;
11pub mod value;
12
13use std::collections::HashMap;
14use thiserror::Error;
15
16use crate::{
17 expression::{Expression, Symbol},
18 runtime::value::Value,
19 Location, Reference,
20};
21
22pub use value_handler::ValueHandler;
23
24#[derive(Error, Debug)]
25#[error("{kind}")]
26pub struct RuntimeError {
28 location: Location,
29 kind: RuntimeErrorKind,
30}
31
32impl RuntimeError {
33 pub fn new(location: Location, kind: RuntimeErrorKind) -> Self {
35 Self { location, kind }
36 }
37
38 pub fn kind(&self) -> &RuntimeErrorKind {
40 &self.kind
41 }
42
43 pub fn location(&self) -> Location {
45 self.location
46 }
47}
48
49#[derive(Error, Debug, Clone, Eq, PartialEq)]
51pub enum RuntimeErrorKind {
52 #[error("Unknown reference")]
54 UnknownReference,
55
56 #[error("Unknown symbol `{0}`")]
58 UnknownSymbol(String),
59
60 #[error("Type mismatch")]
62 TypeMismatch,
63
64 #[error("Not enough arguments")]
66 NotEnoughArguments,
67
68 #[error("Too many arguments")]
70 TooManyArguments,
71
72 #[error("Unsupported selection")]
74 UnsupportedSelection,
75
76 #[error("Unavailable random generator")]
78 UnavailableRandomGenerator,
79
80 #[error("Unavailable size")]
82 UnavailableSize,
83
84 #[error("Uncomparable types")]
86 UncomparableTypes,
87}
88
89pub enum Binding {
91 Available(Value),
93 Pending,
95 Unknown,
97}
98
99pub trait Context {
101 fn resolve(&self, symbol: &Symbol) -> Binding;
103
104 fn value_handler(&self, reference: Reference) -> Option<&dyn ValueHandler>;
106}
107
108type Prelude = HashMap<&'static str, Value>;
109
110impl Context for Prelude {
111 fn resolve(&self, symbol: &Symbol) -> Binding {
112 self.get(symbol.as_str())
113 .cloned()
114 .map(Binding::Available)
115 .unwrap_or(Binding::Unknown)
116 }
117
118 fn value_handler(&self, _reference: Reference) -> Option<&dyn ValueHandler> {
119 None
120 }
121}
122
123struct MergedContext<'a> {
124 root: &'a dyn Context,
125 current: &'a dyn Context,
126}
127
128struct EmptyContext;
129
130impl Context for EmptyContext {
131 fn resolve(&self, _: &Symbol) -> Binding {
132 Binding::Unknown
133 }
134
135 fn value_handler(&self, _reference: Reference) -> Option<&dyn ValueHandler> {
136 None
137 }
138}
139
140impl<'a> MergedContext<'a> {
141 fn new(root: &'a dyn Context, current: &'a dyn Context) -> Self {
142 Self { root, current }
143 }
144}
145
146impl Context for MergedContext<'_> {
147 fn resolve(&self, symbol: &Symbol) -> Binding {
148 match self.current.resolve(symbol) {
149 Binding::Unknown => self.root.resolve(symbol),
150 b => b,
151 }
152 }
153
154 fn value_handler(&self, reference: Reference) -> Option<&dyn ValueHandler> {
155 self.current
156 .value_handler(reference)
157 .or_else(|| self.root.value_handler(reference))
158 }
159}
160
161#[derive(Debug, PartialEq, Clone)]
162pub enum Evaluation {
164 Complete(Location, Value),
166 Partial(Expression),
169}
170
171impl Evaluation {
172 pub fn map<F: FnOnce(Value) -> Value>(self, op: F) -> Self {
173 match self {
174 Self::Complete(l, v) => Self::Complete(l, op(v)),
175 e => e,
176 }
177 }
178
179 pub fn map_unsafe<F: FnOnce(Value) -> Result<Value, RuntimeError>>(
180 self,
181 op: F,
182 ) -> Result<Self, RuntimeError> {
183 match self {
184 Self::Complete(l, v) => Ok(Self::Complete(l, op(v)?)),
185 e => Ok(e),
186 }
187 }
188
189 pub fn map_partial<F: FnOnce(Expression) -> Expression>(self, op: F) -> Self {
190 match self {
191 Self::Partial(e) => Self::Partial(op(e)),
192 e => e,
193 }
194 }
195
196 pub fn complete(self) -> Option<Value> {
197 match self {
198 Self::Complete(_, v) => Some(v),
199 _ => None,
200 }
201 }
202
203 pub fn partial(self) -> Option<Expression> {
204 match self {
205 Self::Partial(expression) => Some(expression),
206 _ => None,
207 }
208 }
209
210 pub fn is_complete(&self) -> bool {
211 matches!(self, Self::Complete(_, _))
212 }
213
214 pub fn into_expression(self) -> Expression {
215 match self {
216 Self::Complete(location, value) => Expression::new(location, value),
217 Self::Partial(expression) => expression,
218 }
219 }
220}
221
222pub trait Eval {
224 fn eval(&self, context: &dyn Context) -> Result<Evaluation, RuntimeError>;
226}
227
228pub struct Runtime<P = Prelude> {
230 prelude: P,
231}
232
233impl Runtime {
234 pub fn new() -> Self {
235 Self::with_prelude(prelude::prelude())
236 }
237}
238
239impl Default for Runtime {
240 fn default() -> Self {
241 Self::new()
242 }
243}
244
245impl<P: Context> Runtime<P> {
246 #[doc(hidden)]
247 pub fn with_prelude(prelude: P) -> Self {
249 Self { prelude }
250 }
251}
252
253impl Runtime {
254 pub fn eval_with_context(
256 &self,
257 e: &dyn Eval,
258 context: &dyn Context,
259 ) -> Result<Evaluation, RuntimeError> {
260 let context = MergedContext::new(&self.prelude, context);
261 e.eval(&context).map(|ev| {
262 ev.map(|v| {
263 v.to_value_handler(&context)
264 .and_then(|vh| vh.detach())
265 .unwrap_or_else(Value::null)
266 })
267 })
268 }
269
270 pub fn eval(&self, e: &dyn Eval) -> Result<Evaluation, RuntimeError> {
272 self.eval_with_context(e, &EmptyContext)
273 }
274}
275
276#[cfg(test)]
277mod tests {
278
279 use std::collections::HashMap;
280 use std::rc::Rc;
281
282 use super::value::{Object, QualifiedName, Value};
283 use crate::{
284 expression::Symbol,
285 parser::Parser,
286 runtime::{Binding, Context, RuntimeErrorKind, ValueHandler},
287 ContextId, Reference,
288 };
289
290 use super::{Prelude, Runtime, RuntimeError};
291 use crate::runtime::document::DocumentBuilder;
292 use test_case::test_case;
293
294 #[test]
295 fn inline_array() {
296 let json = r#"[":array", "0-17", [":str", "1-6", "one"], [":nbr", "8-9", "2"], [":bool", "11-16", "false"]]"#;
298
299 let expression = Parser::new().parse_str(json).unwrap();
300 let actual = Runtime::new()
301 .eval(&expression)
302 .unwrap()
303 .complete()
304 .unwrap();
305 let expected = &[
306 Value::string("one".to_string()),
307 Value::number(2.0),
308 Value::bool(false),
309 ];
310
311 assert_eq!(actual.as_slice().unwrap(), expected);
312 }
313
314 #[test]
315 fn unknown_symbol_fail() {
316 let pel = r#"[":ref", "0-7", "unknown"]"#;
318
319 let expression = Parser::new().parse_str(pel).unwrap();
320 let error = Runtime::new().eval(&expression).unwrap_err();
321
322 assert_eq!(
323 error.kind(),
324 &RuntimeErrorKind::UnknownSymbol("unknown".to_string())
325 );
326 }
327
328 #[test]
329 fn null_value() {
330 let pel = r#"[":null", "0-4"]"#;
332
333 let expression = Parser::new().parse_str(pel).unwrap();
334 let result = Runtime::new()
335 .eval(&expression)
336 .unwrap()
337 .complete()
338 .unwrap();
339
340 assert!(result.is_null());
341 }
342
343 #[test]
344 fn apply() {
345 let json = r#"[":apply", "5-7", [":ref", "5-7", "++"], [":str", "0-4", "hi"], [":str", "8-12", "by"]]"#;
347
348 let expression = Parser::new().parse_str(json).unwrap();
349 let result = Runtime::new()
350 .eval(&expression)
351 .unwrap()
352 .complete()
353 .unwrap();
354
355 assert_eq!("hiby", result.as_str().unwrap());
356 }
357
358 #[test]
359 fn if_else() {
360 let json = r#"[":if", "0-23", [":bool", "4-9", "false"], [":str", "11-14", "a"], [":str", "20-23", "b"]]"#;
362
363 let expression = Parser::new().parse_str(json).unwrap();
364 let result = Runtime::new()
365 .eval(&expression)
366 .unwrap()
367 .complete()
368 .unwrap();
369
370 assert_eq!("b", result.as_str().unwrap());
371 }
372
373 #[test]
374 fn default_left_null() {
375 let pel = r#"
377 [":default", "0-6",
378 [":null", "0-1"],
379 [":str", "5-6", "right"]
380 ]
381 "#;
382
383 let expression = Parser::new().parse_str(pel).unwrap();
384 let result = Runtime::new()
385 .eval(&expression)
386 .unwrap()
387 .complete()
388 .unwrap();
389
390 assert_eq!(result.as_str().unwrap(), "right");
391 }
392
393 #[test]
394 fn default_left_not_null() {
395 let pel = r#"
397 [":default", "0-6",
398 [":nbr", "0-1", "700"],
399 [":bool", "5-6", "true"]
400 ]
401 "#;
402
403 let expression = Parser::new().parse_str(pel).unwrap();
404 let result = Runtime::new()
405 .eval(&expression)
406 .unwrap()
407 .complete()
408 .unwrap();
409
410 assert_eq!(result.as_f64().unwrap(), 700.0);
411 }
412
413 #[test]
414 fn array_positive_index() {
415 let pel = r#"
417 [".", "0-45",
418 [":array", "0-41",
419 [":str", "1-9", "accept"],
420 [":str", "10-27", "accept-encoding"],
421 [":str", "28-40", "user-agent"]
422 ], [":nbr", "42-44", "2"]
423 ]"#;
424
425 let expression = Parser::new().parse_str(pel).unwrap();
426 let result = Runtime::new()
427 .eval(&expression)
428 .unwrap()
429 .complete()
430 .unwrap();
431
432 assert_eq!("user-agent", result.as_str().unwrap());
433 }
434
435 #[test]
436 fn array_negative_index() {
437 let pel = r#"
439 [".", "0-45",
440 [":array", "0-41",
441 [":str", "1-9", "accept"],
442 [":str", "10-27", "accept-encoding"],
443 [":str", "28-40", "user-agent"]
444 ], [":nbr", "42-44", "-2"]
445 ]"#;
446
447 let expression = Parser::new().parse_str(pel).unwrap();
448 let result = Runtime::new()
449 .eval(&expression)
450 .unwrap()
451 .complete()
452 .unwrap();
453
454 assert_eq!("accept-encoding", result.as_str().unwrap());
455 }
456
457 #[test]
458 fn array_out_of_bounds_index() {
459 let pel = r#"
461 [".", "0-45",
462 [":array", "0-41",
463 [":str", "1-9", "accept"],
464 [":str", "10-27", "accept-encoding"],
465 [":str", "28-40", "user-agent"]
466 ], [":nbr", "42-44", "5"]
467 ]"#;
468
469 let expression = Parser::new().parse_str(pel).unwrap();
470 let result = Runtime::new()
471 .eval(&expression)
472 .unwrap()
473 .complete()
474 .unwrap();
475
476 assert!(result.is_null());
477 }
478
479 #[test]
480 fn string_positive_index() {
481 let pel = r#"
483 [".", "0-45",
484 [":str", "0-41", "peregrine expression language"],
485 [":nbr", "42-44", "10"]
486 ]"#;
487
488 let expression = Parser::new().parse_str(pel).unwrap();
489 let result = Runtime::new()
490 .eval(&expression)
491 .unwrap()
492 .complete()
493 .unwrap();
494
495 assert_eq!("e", result.as_str().unwrap());
496 }
497
498 #[test]
499 fn string_negative_index() {
500 let pel = r#"
502 [".", "0-45",
503 [":str", "0-41", "peregrine expression language"],
504 [":nbr", "42-44", "-5"]
505 ]"#;
506
507 let expression = Parser::new().parse_str(pel).unwrap();
508 let result = Runtime::new()
509 .eval(&expression)
510 .unwrap()
511 .complete()
512 .unwrap();
513
514 assert_eq!("g", result.as_str().unwrap());
515 }
516
517 #[test]
518 fn string_out_of_bounds_index() {
519 let pel = r#"
521 [".", "0-45",
522 [":str", "0-41", "peregrine expression language"],
523 [":nbr", "42-44", "100"]
524 ]"#;
525
526 let expression = Parser::new().parse_str(pel).unwrap();
527 let result = Runtime::new()
528 .eval(&expression)
529 .unwrap()
530 .complete()
531 .unwrap();
532
533 assert!(result.is_null());
534 }
535
536 #[test]
537 fn selection_by_key() {
538 let mut b_object = Object::new();
540 b_object.insert("c".to_string(), Value::string("foo".to_string()));
541
542 let mut a_object = Object::new();
543 a_object.insert("b".to_string(), Value::object(b_object));
544
545 let a_object = Value::object(a_object);
546
547 let mut context = HashMap::new();
548 context.insert("a", a_object);
549
550 let json = r#"[".", "0-5", [".", "0-3", [":ref", "0-1", "a"], [":str", "2-3", "b"]], [":str", "4-5", "c"]]"#;
552
553 let expression = Parser::new().parse_str(json).unwrap();
554 let result = Runtime::new()
555 .eval_with_context(&expression, &context)
556 .unwrap()
557 .complete()
558 .unwrap();
559
560 assert_eq!("foo", result.as_str().unwrap());
561 }
562
563 #[test]
564 fn selection_by_key_in_array() {
565 let mut b_object = Object::new();
567 b_object.insert("c".to_string(), Value::string("foo".to_string()));
568
569 let mut a_object = Object::new();
570 a_object.insert("b".to_string(), Value::object(b_object));
571
572 let a_object = Value::object(a_object);
573
574 let array = Value::array(vec![a_object]);
575
576 let mut context = HashMap::new();
577 context.insert("array", array);
578
579 let pel = r#"
581 [".", "0-3",
582 [".", "0-5",
583 [":ref", "0-5", "array"],
584 [":str", "0-1", "b"]
585 ],
586 [":str", "2-3", "c"]
587 ]
588 "#;
589
590 let expression = Parser::new().parse_str(pel).unwrap();
591 let result = Runtime::new()
592 .eval_with_context(&expression, &context)
593 .unwrap()
594 .complete()
595 .unwrap();
596
597 assert_eq!(&[Value::string("foo")], result.as_slice().unwrap());
598 }
599
600 #[test]
601 fn select_by_key_inexistent_in_object() {
602 let b_object = Object::new();
604
605 let mut a_object = Object::new();
606 a_object.insert("b".to_string(), Value::object(b_object));
607
608 let a_object = Value::object(a_object);
609
610 let mut context = HashMap::new();
611 context.insert("a", a_object);
612
613 let pel = r#"
615 [".", "0-5",
616 [".", "0-3",
617 [":ref", "0-1", "a"],
618 [":str", "2-3", "b"]
619 ],
620 [":str", "4-5", "inexistent"]
621 ]
622 "#;
623
624 let expression = Parser::new().parse_str(pel).unwrap();
625 let result = Runtime::new()
626 .eval_with_context(&expression, &context)
627 .unwrap()
628 .complete()
629 .unwrap();
630
631 assert!(result.is_null());
632 }
633
634 #[test]
635 fn select_by_key_inexistent_in_reference() {
636 struct TestContext;
637 struct TestValueHandler;
638
639 const CONTEXT_ID: ContextId = ContextId::new("TestContext");
640 const REFERENCE: Reference = CONTEXT_ID.first_reference();
641
642 impl ValueHandler for TestValueHandler {
643 fn detach(&self) -> Option<Value> {
644 unimplemented!()
645 }
646
647 fn select_by_key(&self, _key: &str) -> Option<Value> {
648 None
649 }
650 }
651
652 impl Context for TestContext {
653 fn resolve(&self, symbol: &Symbol) -> Binding {
654 match symbol.as_str() {
655 "a" => Binding::Available(Value::reference(REFERENCE)),
656 _ => Binding::Unknown,
657 }
658 }
659
660 fn value_handler(&self, reference: Reference) -> Option<&dyn ValueHandler> {
661 match reference {
662 REFERENCE => Some(&TestValueHandler),
663 _ => None,
664 }
665 }
666 }
667
668 let pel = r#"
670 [".", "0-5",
671 [":ref", "0-1", "a"],
672 [":str", "2-3", "inexistent"]
673 ]
674 "#;
675
676 let expression = Parser::new().parse_str(pel).unwrap();
677 let result = Runtime::new()
678 .eval_with_context(&expression, &TestContext)
679 .unwrap()
680 .complete()
681 .unwrap();
682
683 assert!(result.is_null());
684 }
685
686 #[test]
687 fn operation_eq() {
688 let json = r#"["==", "0-6", [":nbr", "0-1", "10"], [":nbr", "5-6", "10.0"]]"#;
690
691 let expression = Parser::new().parse_str(json).unwrap();
692 let result = Runtime::new()
693 .eval(&expression)
694 .unwrap()
695 .complete()
696 .unwrap();
697
698 assert!(result.as_bool().unwrap());
699 }
700
701 #[test]
702 fn operation_eq_mismatch() {
703 let json = r#"["==", "0-6", [":nbr", "0-1", "10"], [":str", "5-6", "10.0"]]"#;
705
706 let expression = Parser::new().parse_str(json).unwrap();
707 let result = Runtime::new()
708 .eval(&expression)
709 .unwrap()
710 .complete()
711 .unwrap();
712
713 assert!(!result.as_bool().unwrap());
714 }
715
716 #[test]
717 fn operation_neq() {
718 let json = r#"["!=", "0-6", [":nbr", "0-1", "10"], [":nbr", "5-6", "10.0"]]"#;
720
721 let expression = Parser::new().parse_str(json).unwrap();
722 let result = Runtime::new()
723 .eval(&expression)
724 .unwrap()
725 .complete()
726 .unwrap();
727
728 assert!(!result.as_bool().unwrap());
729 }
730
731 #[test]
732 fn operation_neq_mismatch() {
733 let json = r#"["!=", "0-6", [":nbr", "0-1", "10"], [":str", "5-6", "10"]]"#;
735
736 let expression = Parser::new().parse_str(json).unwrap();
737 let result = Runtime::new()
738 .eval(&expression)
739 .unwrap()
740 .complete()
741 .unwrap();
742
743 assert!(result.as_bool().unwrap());
744 }
745
746 #[test]
747 fn operation_gt() {
748 let json = r#"[">", "0-6", [":nbr", "0-1", "10"], [":nbr", "5-6", "100.0"]]"#;
750
751 let expression = Parser::new().parse_str(json).unwrap();
752 let result = Runtime::new()
753 .eval(&expression)
754 .unwrap()
755 .complete()
756 .unwrap();
757
758 assert!(!result.as_bool().unwrap());
759 }
760
761 #[test]
762 fn operation_get() {
763 let json = r#"[">=", "0-6", [":str", "0-1", "left"], [":str", "5-6", "left"]]"#;
765
766 let expression = Parser::new().parse_str(json).unwrap();
767 let result = Runtime::new()
768 .eval(&expression)
769 .unwrap()
770 .complete()
771 .unwrap();
772
773 assert!(result.as_bool().unwrap());
774 }
775
776 #[test]
777 fn operation_lt() {
778 let json = r#"["<", "0-6", [":str", "0-1", "2.0"], [":nbr", "5-6", "10"]]"#;
780
781 let expression = Parser::new().parse_str(json).unwrap();
782 let result = Runtime::new()
783 .eval(&expression)
784 .unwrap()
785 .complete()
786 .unwrap();
787
788 assert!(result.as_bool().unwrap());
789 }
790
791 #[test]
792 fn operation_let() {
793 let json = r#"["<=", "0-6", [":bool", "0-1", "true"], [":str", "5-6", "true"]]"#;
795
796 let expression = Parser::new().parse_str(json).unwrap();
797 let result = Runtime::new()
798 .eval(&expression)
799 .unwrap()
800 .complete()
801 .unwrap();
802
803 assert!(result.as_bool().unwrap());
804 }
805
806 #[test]
807 fn operation_type_mismatch_fail() {
808 let json = r#"["<=", "0-14", [":str", "0-6", "11.0"], [":bool", "9-13", "true"]]"#;
810
811 let expression = Parser::new().parse_str(json).unwrap();
812 let error = Runtime::new().eval(&expression).err().unwrap();
813
814 assert_eq!(error.kind(), &RuntimeErrorKind::TypeMismatch);
815 assert_eq!(error.location().start, 0);
816 assert_eq!(error.location().end, 14);
817 }
818
819 #[test]
820 fn operation_and() {
821 let json = r#"["&&", "0-6", [":bool", "0-1", "false"], [":bool", "5-6", "true"]]"#;
823
824 let expression = Parser::new().parse_str(json).unwrap();
825 let result = Runtime::new()
826 .eval(&expression)
827 .unwrap()
828 .complete()
829 .unwrap();
830
831 assert!(!result.as_bool().unwrap());
832 }
833
834 #[test]
835 fn operation_or() {
836 let json = r#"["||", "0-6", [":bool", "0-1", "false"], [":bool", "5-6", "true"]]"#;
838
839 let expression = Parser::new().parse_str(json).unwrap();
840 let result = Runtime::new()
841 .eval(&expression)
842 .unwrap()
843 .complete()
844 .unwrap();
845
846 assert!(result.as_bool().unwrap());
847 }
848
849 #[test]
850 fn operation_not() {
851 let json = r#"["!", "0-6", [":bool", "0-1", "false"]]"#;
853
854 let expression = Parser::new().parse_str(json).unwrap();
855 let result = Runtime::new()
856 .eval(&expression)
857 .unwrap()
858 .complete()
859 .unwrap();
860
861 assert!(result.as_bool().unwrap());
862 }
863
864 #[test]
865 fn lower_null() {
866 let pel = r#"
868 [":apply", "5-7",
869 [":ref", "5-7", "lower"],
870 [":null", "0-4"]
871 ]
872 "#;
873
874 let expression = Parser::new().parse_str(pel).unwrap();
875 let result = Runtime::new()
876 .eval(&expression)
877 .unwrap()
878 .complete()
879 .unwrap();
880
881 assert!(result.is_null());
882 }
883
884 #[test]
885 fn lower_string() {
886 let pel = r#"
888 [":apply", "5-7",
889 [":ref", "5-7", "lower"],
890 [":str", "0-4", "Peregrine Expression Language"]
891 ]
892 "#;
893
894 let expression = Parser::new().parse_str(pel).unwrap();
895 let result = Runtime::new()
896 .eval(&expression)
897 .unwrap()
898 .complete()
899 .unwrap();
900
901 assert_eq!("peregrine expression language", result.as_str().unwrap());
902 }
903
904 #[test]
905 fn lower_boolean() {
906 let pel = r#"
908 [":apply", "5-7",
909 [":ref", "5-7", "lower"],
910 [":bool", "0-4", "true"]
911 ]
912 "#;
913
914 let expression = Parser::new().parse_str(pel).unwrap();
915 let result = Runtime::new()
916 .eval(&expression)
917 .unwrap()
918 .complete()
919 .unwrap();
920
921 assert_eq!("true", result.as_str().unwrap());
922 }
923
924 #[test]
925 fn lower_number() {
926 let pel = r#"
928 [":apply", "5-7",
929 [":ref", "5-7", "lower"],
930 [":nbr", "0-4", "1944.07"]
931 ]
932 "#;
933
934 let expression = Parser::new().parse_str(pel).unwrap();
935 let result = Runtime::new()
936 .eval(&expression)
937 .unwrap()
938 .complete()
939 .unwrap();
940
941 assert_eq!("1944.07", result.as_str().unwrap());
942 }
943
944 #[test]
945 fn lower_array_fail() {
946 let pel = r#"
948 [":apply", "0-50",
949 [":ref", "0-5", "lower"],
950 [":array", "6-49",
951 [":str", "7-15", "accept"],
952 [":str", "17-34", "accept-encoding"],
953 [":str", "36-48", "user-agent"]
954 ]
955 ]
956 "#;
957
958 let expression = Parser::new().parse_str(pel).unwrap();
959 let error = Runtime::new().eval(&expression).unwrap_err();
960
961 assert_eq!(error.kind(), &RuntimeErrorKind::TypeMismatch);
962 assert_eq!(error.location().start, 0);
963 assert_eq!(error.location().end, 50);
964 }
965
966 #[test]
967 fn selection_by_key_in_lookup_context() {
968 struct LookupValueHandler(fn(&str) -> Option<Value>);
969 struct LookupContext;
970
971 const CONTEXT_ID: ContextId = ContextId::new("lookup_context");
972 const A_REFERENCE: Reference = CONTEXT_ID.first_reference();
973 const B_REFERENCE: Reference = A_REFERENCE.next();
974
975 static A_VALUE_HANDLER: LookupValueHandler =
976 LookupValueHandler(|key| (key == "d").then(|| Value::reference(B_REFERENCE)));
977 static B_VALUE_HANDLER: LookupValueHandler =
978 LookupValueHandler(|key| (key == "c").then(|| Value::number(111.0)));
979
980 impl ValueHandler for LookupValueHandler {
981 fn select_by_key(&self, key: &str) -> Option<Value> {
982 self.0(key)
983 }
984
985 fn detach(&self) -> Option<Value> {
986 None
987 }
988 }
989
990 impl Context for LookupContext {
991 fn resolve(&self, symbol: &Symbol) -> Binding {
992 match symbol.as_str() {
993 "a" => Binding::Available(Value::reference(A_REFERENCE)),
994 _ => Binding::Unknown,
995 }
996 }
997
998 fn value_handler(
999 &self,
1000 reference: Reference,
1001 ) -> Option<&dyn crate::runtime::ValueHandler> {
1002 match reference {
1003 A_REFERENCE => Some(&A_VALUE_HANDLER),
1004 B_REFERENCE => Some(&B_VALUE_HANDLER),
1005 _ => None,
1006 }
1007 }
1008 }
1009
1010 let json = r#"[".", "0-5", [".", "0-3", [":ref", "0-1", "a"], [":str", "2-3", "d"]], [":str", "4-5", "c"]]"#;
1012
1013 let expression = Parser::new().parse_str(json).unwrap();
1014 let result = Runtime::new()
1015 .eval_with_context(&expression, &LookupContext)
1016 .unwrap()
1017 .complete()
1018 .unwrap();
1019
1020 assert_eq!(111, result.as_f64().unwrap() as i32);
1021 }
1022
1023 #[test]
1024 fn contains_string_string_is_true() {
1025 let pel = r#"
1027 [":apply", "5-7",
1028 [":ref", "5-8", "contains"],
1029 [":str", "5-7", "Peregrine expression language"],
1030 [":str", "0-4", "lang"]
1031 ]
1032 "#;
1033
1034 let expression = Parser::new().parse_str(pel).unwrap();
1035 let result = Runtime::new()
1036 .eval(&expression)
1037 .unwrap()
1038 .complete()
1039 .unwrap();
1040
1041 assert!(result.as_bool().unwrap());
1042 }
1043
1044 #[test]
1045 fn contains_string_number_is_true() {
1046 let pel = r#"
1048 [":apply", "5-7",
1049 [":ref", "5-8", "contains"],
1050 [":str", "5-7", "Peregrine expression language 1.0"],
1051 [":nbr", "0-4", "1.0"]
1052 ]
1053 "#;
1054
1055 let expression = Parser::new().parse_str(pel).unwrap();
1056 let result = Runtime::new()
1057 .eval(&expression)
1058 .unwrap()
1059 .complete()
1060 .unwrap();
1061
1062 assert!(result.as_bool().unwrap());
1063 }
1064
1065 #[test]
1066 fn contains_string_string_is_false() {
1067 let pel = r#"
1069 [":apply", "5-7",
1070 [":ref", "5-8", "contains"],
1071 [":str", "5-7", "Peregrine expression language"],
1072 [":str", "0-4", "PEREGRINE"]
1073 ]
1074 "#;
1075
1076 let expression = Parser::new().parse_str(pel).unwrap();
1077 let result = Runtime::new()
1078 .eval(&expression)
1079 .unwrap()
1080 .complete()
1081 .unwrap();
1082
1083 assert!(!result.as_bool().unwrap());
1084 }
1085
1086 #[test]
1087 fn contains_boolean_string_is_true() {
1088 let pel = r#"
1090 [":apply", "5-7",
1091 [":ref", "5-8", "contains"],
1092 [":bool", "5-7", "true"],
1093 [":str", "0-4", "ru"]
1094 ]
1095 "#;
1096
1097 let expression = Parser::new().parse_str(pel).unwrap();
1098 let result = Runtime::new()
1099 .eval(&expression)
1100 .unwrap()
1101 .complete()
1102 .unwrap();
1103
1104 assert!(result.as_bool().unwrap());
1105 }
1106
1107 #[test]
1108 fn contains_boolean_string_is_false() {
1109 let pel = r#"
1111 [":apply", "5-7",
1112 [":ref", "5-8", "contains"],
1113 [":bool", "5-7", "true"],
1114 [":str", "0-4", "fal"]
1115 ]
1116 "#;
1117
1118 let expression = Parser::new().parse_str(pel).unwrap();
1119 let result = Runtime::new()
1120 .eval(&expression)
1121 .unwrap()
1122 .complete()
1123 .unwrap();
1124
1125 assert!(!result.as_bool().unwrap());
1126 }
1127
1128 #[test]
1129 fn contains_number_string_is_true() {
1130 let pel = r#"
1132 [":apply", "5-7",
1133 [":ref", "5-8", "contains"],
1134 [":nbr", "5-7", "3.141516"],
1135 [":str", "0-4", ".141"]
1136 ]
1137 "#;
1138
1139 let expression = Parser::new().parse_str(pel).unwrap();
1140 let result = Runtime::new()
1141 .eval(&expression)
1142 .unwrap()
1143 .complete()
1144 .unwrap();
1145
1146 assert!(result.as_bool().unwrap());
1147 }
1148
1149 #[test]
1150 fn contains_number_number_is_false() {
1151 let pel = r#"
1153 [":apply", "5-7",
1154 [":ref", "5-8", "contains"],
1155 [":nbr", "5-7", "3.141516"],
1156 [":nbr", "0-4", "9"]
1157 ]
1158 "#;
1159
1160 let expression = Parser::new().parse_str(pel).unwrap();
1161 let result = Runtime::new()
1162 .eval(&expression)
1163 .unwrap()
1164 .complete()
1165 .unwrap();
1166
1167 assert!(!result.as_bool().unwrap());
1168 }
1169
1170 #[test]
1171 fn contains_array_is_true() {
1172 let pel = r#"
1174 [":apply", "5-7",
1175 [":ref", "5-8", "contains"],
1176 [":array", "5-7",
1177 [":str", "5-7", "a"],
1178 [":nbr", "5-7", "10"]
1179 ],
1180 [":nbr", "0-4", "10"]
1181 ]
1182 "#;
1183
1184 let expression = Parser::new().parse_str(pel).unwrap();
1185 let result = Runtime::new()
1186 .eval(&expression)
1187 .unwrap()
1188 .complete()
1189 .unwrap();
1190
1191 assert!(result.as_bool().unwrap());
1192 }
1193
1194 #[test]
1195 fn contains_array_is_false() {
1196 let pel = r#"
1198 [":apply", "5-7",
1199 [":ref", "5-8", "contains"],
1200 [":array", "5-7",
1201 [":str", "5-7", "a"],
1202 [":bool", "5-7", "false"]
1203 ],
1204 [":nbr", "0-4", "10"]
1205 ]
1206 "#;
1207
1208 let expression = Parser::new().parse_str(pel).unwrap();
1209 let result = Runtime::new()
1210 .eval(&expression)
1211 .unwrap()
1212 .complete()
1213 .unwrap();
1214
1215 assert!(!result.as_bool().unwrap());
1216 }
1217
1218 #[test]
1219 fn trim_array() {
1220 let pel = r#"
1222 [":apply", "5-7",
1223 [":ref", "5-7", "trim"],
1224 [":array", "0-17",
1225 [":str", "1-6", "one"],
1226 [":nbr", "8-9", "2"],
1227 [":bool", "11-16", "false"]
1228 ]
1229 ]
1230 "#;
1231
1232 let expression = Parser::new().parse_str(pel).unwrap();
1233 let error = Runtime::new().eval(&expression).unwrap_err();
1234
1235 assert_eq!(error.kind, RuntimeErrorKind::TypeMismatch);
1236 }
1237
1238 #[test]
1239 fn trim_boolean() {
1240 let json = r#"
1242 [":apply", "5-7",
1243 [":ref", "5-7", "trim"],
1244 [":bool", "0-4", "true"]
1245 ]
1246 "#;
1247
1248 let expression = Parser::new().parse_str(json).unwrap();
1249 let result = Runtime::new()
1250 .eval(&expression)
1251 .unwrap()
1252 .complete()
1253 .unwrap();
1254
1255 assert_eq!("true", result.as_str().unwrap());
1256 }
1257
1258 #[test]
1259 fn trim_number() {
1260 let json = r#"
1262 [":apply", "5-7",
1263 [":ref", "5-7", "trim"],
1264 [":nbr", "0-4", "1000.0"]
1265 ]
1266 "#;
1267
1268 let expression = Parser::new().parse_str(json).unwrap();
1269 let result = Runtime::new()
1270 .eval(&expression)
1271 .unwrap()
1272 .complete()
1273 .unwrap();
1274
1275 assert_eq!("1000.0", result.as_str().unwrap());
1277 }
1278
1279 #[test]
1280 fn trim_string() {
1281 let json = r#"
1283 [":apply", "5-7",
1284 [":ref", "5-7", "trim"],
1285 [":str", "0-4", " hello world "]
1286 ]
1287 "#;
1288
1289 let expression = Parser::new().parse_str(json).unwrap();
1290 let result = Runtime::new()
1291 .eval(&expression)
1292 .unwrap()
1293 .complete()
1294 .unwrap();
1295
1296 assert_eq!("hello world", result.as_str().unwrap());
1297 }
1298
1299 #[test]
1300 fn generate_uuid() {
1301 let pel = r#"
1303 [":apply", "5-7",
1304 [":ref", "5-7", "uuid"]
1305 ]
1306 "#;
1307
1308 let expression = Parser::new().parse_str(pel).unwrap();
1309 let result = Runtime::new()
1310 .eval(&expression)
1311 .unwrap()
1312 .complete()
1313 .unwrap();
1314
1315 let uuid = result.as_str().unwrap();
1316
1317 assert!(uuid::Uuid::parse_str(uuid).is_ok());
1318 }
1319
1320 #[test]
1321 fn size_of_string() {
1322 let pel = r#"
1324 [":apply", "0-45",
1325 [":ref", "0-10", "sizeOf"],
1326 [":str", "0-41", "hello world"]
1327 ]"#;
1328
1329 let expression = Parser::new().parse_str(pel).unwrap();
1330 let result = Runtime::new()
1331 .eval(&expression)
1332 .unwrap()
1333 .complete()
1334 .unwrap();
1335
1336 assert_eq!(11, result.as_f64().unwrap() as usize);
1337 }
1338
1339 #[test]
1340 fn size_of_array() {
1341 let pel = r#"
1343 [":apply", "0-45",
1344 [":ref", "0-10", "sizeOf"],
1345 [":array", "0-41",
1346 [":str", "1-9", "accept"],
1347 [":str", "10-27", "accept-encoding"],
1348 [":str", "28-40", "user-agent"]
1349 ]
1350 ]"#;
1351
1352 let expression = Parser::new().parse_str(pel).unwrap();
1353 let result = Runtime::new()
1354 .eval(&expression)
1355 .unwrap()
1356 .complete()
1357 .unwrap();
1358
1359 assert_eq!(3, result.as_f64().unwrap() as usize);
1360 }
1361
1362 #[test]
1363 fn size_of_object() {
1364 let object = Value::object(Object::from([("foo".to_string(), Value::bool(true))]));
1365
1366 let context = HashMap::from([("object", object)]);
1367
1368 let pel = r#"
1370 [":apply", "0-45",
1371 [":ref", "0-10", "sizeOf"],
1372 [":ref", "0-41", "object"]
1373 ]"#;
1374
1375 let expression = Parser::new().parse_str(pel).unwrap();
1376 let result = Runtime::new()
1377 .eval_with_context(&expression, &context)
1378 .unwrap()
1379 .complete()
1380 .unwrap();
1381
1382 assert_eq!(1, result.as_f64().unwrap() as usize);
1383 }
1384
1385 #[test_case(r#"[":apply", "0-45", [":ref", "0-10", "isEmpty"],[":str", "0-41", ""]]"#,
1386 true;
1387 r#"DW isEmpty('') should be true 1"#
1388 )]
1389 #[test_case(r#"[":apply", "0-45", [":ref", "0-10", "isEmpty"],[":str", "0-41", "peregrine"]]"#,
1390 false;
1391 r#"DW isEmpty('peregrine') should be false"#
1392 )]
1393 #[test_case(r#"[":apply", "0-45", [":ref", "0-10", "isEmpty"],[":array", "0-2"]]"#,
1394 true;
1395 r#"DW isEmpty([]) should be true 2"#
1396 )]
1397 #[test_case(r#"[":apply", "0-45", [":ref", "0-10", "isEmpty"],[":array", "0-41", [":str", "1-9", "accept"]]]"#,
1398 false;
1399 r#"DW isEmpty(['accept']) should be false"#
1400 )]
1401 #[test_case(r#"[":apply", "0-45", [":ref", "0-10", "isEmpty"],[":ref", "0-41", "empty_object"]]"#,
1402 true;
1403 r#"DW isEmpty({}) should be true 3"#
1404 )]
1405 #[test_case(r#"[":apply", "0-45", [":ref", "0-10", "isEmpty"],[":ref", "0-41", "object"]]"#,
1406 false;
1407 r#"DW isEmpty({'foo': true}) should be false"#
1408 )]
1409 fn is_empty(pel: &str, expected: bool) {
1410 let object = Value::object(Object::from([("foo".to_string(), Value::bool(true))]));
1411 let empty_object = Value::object(Object::from([]));
1412 let context = HashMap::from([("object", object), ("empty_object", empty_object)]);
1413
1414 let expression = Parser::new().parse_str(pel).unwrap();
1415 let result = Runtime::new()
1416 .eval_with_context(&expression, &context)
1417 .unwrap()
1418 .complete()
1419 .unwrap();
1420
1421 assert_eq!(expected, result.as_bool().unwrap());
1422 }
1423
1424 #[test_case(r#"[":apply", "0-78", [":ref", "0-29", "toString"], [":apply", "30-69", [":ref", "30-60", "fromBase64"], [":str", "61-68", "SGk=="]], [":str", "70-77", "UTF-8"]]"#;
1425 r#"Double padded expression should return 'Hi'"#
1426 )]
1427 #[test_case(r#"[":apply", "0-77", [":ref", "0-29", "toString"], [":apply", "30-68", [":ref", "30-60", "fromBase64"], [":str", "61-67", "SGk="]], [":str", "69-76", "UTF-8"]]"#;
1428 r#"Padded expression should return 'Hi'"#
1429 )]
1430 #[test_case(r#"[":apply", "0-76", [":ref", "0-29", "toString"], [":apply", "30-68", [":ref", "30-60", "fromBase64"], [":str", "61-66", "SGk"]], [":str", "68-75", "UTF-8"]]"#;
1431 r#"Unpadded expression should return 'Hi'"#
1432 )]
1433 fn base64_is_decoded_padded_or_unpadded(pel: &str) {
1434 let headers = Value::object(HashMap::new());
1435 let context: Prelude = HashMap::from([("payload", headers)]);
1436
1437 let value = Runtime::new()
1438 .eval_with_context(&Parser::new().parse_str(pel).unwrap(), &context)
1439 .unwrap()
1440 .complete()
1441 .unwrap();
1442
1443 assert_eq!(value.as_str().unwrap(), "Hi");
1444 }
1445
1446 #[test]
1447 fn split_by_string_string() {
1448 let pel = r#"
1450 [":apply", "5-7",
1451 [":ref", "5-7", "splitBy"],
1452 [":str", "0-4", "Peregrine Expression Language"],
1453 [":str", "8-12", "re"]
1454 ]
1455 "#;
1456
1457 let expression = Parser::new().parse_str(pel).unwrap();
1458 let result = Runtime::new()
1459 .eval(&expression)
1460 .unwrap()
1461 .complete()
1462 .unwrap();
1463
1464 let expected = [
1465 Value::string("Pe".to_string()),
1466 Value::string("grine Exp".to_string()),
1467 Value::string("ssion Language".to_string()),
1468 ];
1469
1470 assert_eq!(&expected, result.as_slice().unwrap());
1471 }
1472
1473 #[test]
1474 fn split_by_string_empty_string() {
1475 let pel = r#"
1477 [":apply", "5-7",
1478 [":ref", "5-7", "splitBy"],
1479 [":str", "0-4", "2022"],
1480 [":str", "8-12", ""]
1481 ]
1482 "#;
1483
1484 let expression = Parser::new().parse_str(pel).unwrap();
1485 let result = Runtime::new()
1486 .eval(&expression)
1487 .unwrap()
1488 .complete()
1489 .unwrap();
1490
1491 let expected = [
1492 Value::string("2".to_string()),
1493 Value::string("0".to_string()),
1494 Value::string("2".to_string()),
1495 Value::string("2".to_string()),
1496 ];
1497
1498 assert_eq!(&expected, result.as_slice().unwrap());
1499 }
1500
1501 #[ignore = "bug W-11098754"]
1502 #[test]
1503 fn split_by_string_string_2() {
1504 let pel = r#"
1506 [":apply", "5-7",
1507 [":ref", "5-7", "splitBy"],
1508 [":str", "0-4", "2022"],
1509 [":str", "8-12", "2"]
1510 ]
1511 "#;
1512
1513 let expression = Parser::new().parse_str(pel).unwrap();
1514 let result = Runtime::new()
1515 .eval(&expression)
1516 .unwrap()
1517 .complete()
1518 .unwrap();
1519
1520 let expected = [
1521 Value::string("".to_string()),
1522 Value::string("0".to_string()),
1523 ];
1524
1525 assert_eq!(&expected, result.as_slice().unwrap());
1526 }
1527
1528 #[test]
1529 fn split_by_number_string() {
1530 let pel = r#"
1532 [":apply", "5-7",
1533 [":ref", "5-7", "splitBy"],
1534 [":nbr", "0-4", "1946.03"],
1535 [":str", "8-12", "."]
1536 ]
1537 "#;
1538
1539 let expression = Parser::new().parse_str(pel).unwrap();
1540 let result = Runtime::new()
1541 .eval(&expression)
1542 .unwrap()
1543 .complete()
1544 .unwrap();
1545
1546 let expected = [
1547 Value::string("1946".to_string()),
1548 Value::string("03".to_string()),
1549 ];
1550
1551 assert_eq!(&expected, result.as_slice().unwrap());
1552 }
1553
1554 #[test]
1555 fn split_by_boolean_string() {
1556 let pel = r#"
1558 [":apply", "5-7",
1559 [":ref", "5-7", "splitBy"],
1560 [":bool", "0-4", "true"],
1561 [":str", "8-12", "r"]
1562 ]
1563 "#;
1564
1565 let expression = Parser::new().parse_str(pel).unwrap();
1566 let result = Runtime::new()
1567 .eval(&expression)
1568 .unwrap()
1569 .complete()
1570 .unwrap();
1571
1572 let expected = [
1573 Value::string("t".to_string()),
1574 Value::string("ue".to_string()),
1575 ];
1576
1577 assert_eq!(&expected, result.as_slice().unwrap());
1578 }
1579
1580 #[test]
1581 fn split_by_null_string() {
1582 let pel = r#"
1584 [":apply", "5-7",
1585 [":ref", "5-7", "splitBy"],
1586 [":null", "0-41"],
1587 [":str", "8-12", "r"]
1588 ]
1589 "#;
1590
1591 let expression = Parser::new().parse_str(pel).unwrap();
1592 let result = Runtime::new()
1593 .eval(&expression)
1594 .unwrap()
1595 .complete()
1596 .unwrap();
1597
1598 assert!(result.is_null());
1599 }
1600
1601 #[test]
1602 fn split_by_string_null_faiil() {
1603 let pel = r#"
1605 [":apply", "5-7",
1606 [":ref", "5-7", "splitBy"],
1607 [":str", "0-41", "Peregrine"],
1608 [":null", "8-12"]
1609 ]
1610 "#;
1611
1612 let expression = Parser::new().parse_str(pel).unwrap();
1613 let error = Runtime::new().eval(&expression).unwrap_err();
1614
1615 assert_eq!(error.kind, RuntimeErrorKind::TypeMismatch);
1616 }
1617
1618 #[test]
1619 fn split_by_array_fail() {
1620 let pel = r#"
1622 [":apply", "5-7",
1623 [":ref", "5-7", "splitBy"],
1624 [":array", "0-41",
1625 [":str", "1-9", "accept"],
1626 [":str", "10-27", "accept-encoding"],
1627 [":str", "28-40", "user-agent"]
1628 ],
1629 [":str", "8-12", "r"]
1630 ]
1631 "#;
1632
1633 let expression = Parser::new().parse_str(pel).unwrap();
1634 let error = Runtime::new().eval(&expression).unwrap_err();
1635
1636 assert_eq!(error.kind, RuntimeErrorKind::TypeMismatch);
1637 }
1638
1639 #[test]
1640 fn substring_after_null_string() {
1641 let pel = r#"
1643 [":apply", "5-7",
1644 [":ref", "5-7", "substringAfter"],
1645 [":null", "0-4"],
1646 [":str", "8-12", "peregrine"]
1647 ]"#;
1648
1649 let expression = Parser::new().parse_str(pel).unwrap();
1650 let result = Runtime::new()
1651 .eval(&expression)
1652 .unwrap()
1653 .complete()
1654 .unwrap();
1655
1656 assert!(result.is_null());
1657 }
1658
1659 #[test]
1660 fn substring_after_string_string() {
1661 let pel = r#"
1663 [":apply", "5-7",
1664 [":ref", "5-7", "substringAfter"],
1665 [":str", "0-4", "peregrine"],
1666 [":str", "8-12", "gr"]
1667 ]"#;
1668
1669 let expression = Parser::new().parse_str(pel).unwrap();
1670 let result = Runtime::new()
1671 .eval(&expression)
1672 .unwrap()
1673 .complete()
1674 .unwrap();
1675
1676 assert_eq!(result.as_str().unwrap(), "ine");
1677 }
1678
1679 #[test]
1680 fn substring_after_string_null_fail() {
1681 let pel = r#"
1683 [":apply", "5-7",
1684 [":ref", "5-7", "substringAfter"],
1685 [":str", "0-4", "peregrine"],
1686 [":null", "8-12"]
1687 ]"#;
1688
1689 let expression = Parser::new().parse_str(pel).unwrap();
1690 let error = Runtime::new().eval(&expression).unwrap_err();
1691
1692 assert_eq!(error.kind, RuntimeErrorKind::TypeMismatch);
1693 }
1694
1695 #[test]
1696 fn substring_after_boolean_string() {
1697 let pel = r#"
1699 [":apply", "5-7",
1700 [":ref", "5-7", "substringAfter"],
1701 [":bool", "0-4", "true"],
1702 [":str", "8-12", "r"]
1703 ]"#;
1704
1705 let expression = Parser::new().parse_str(pel).unwrap();
1706 let result = Runtime::new()
1707 .eval(&expression)
1708 .unwrap()
1709 .complete()
1710 .unwrap();
1711
1712 assert_eq!(result.as_str().unwrap(), "ue");
1713 }
1714
1715 #[test]
1716 fn substring_after_number_number() {
1717 let pel = r#"
1719 [":apply", "5-7",
1720 [":ref", "5-7", "substringAfter"],
1721 [":nbr", "0-4", "1234.567"],
1722 [":nbr", "8-12", "4.5"]
1723 ]"#;
1724
1725 let expression = Parser::new().parse_str(pel).unwrap();
1726 let result = Runtime::new()
1727 .eval(&expression)
1728 .unwrap()
1729 .complete()
1730 .unwrap();
1731
1732 assert_eq!(result.as_str().unwrap(), "67");
1733 }
1734
1735 #[test]
1736 fn substring_after_array_fail() {
1737 let pel = r#"
1739 [":apply", "5-7",
1740 [":ref", "5-7", "substringAfter"],
1741 [":array", "0-41",
1742 [":str", "1-9", "accept"],
1743 [":str", "10-27", "accept-encoding"],
1744 [":str", "28-40", "user-agent"]
1745 ],
1746 [":str", "1-10", "re"]
1747 ]
1748 "#;
1749
1750 let expression = Parser::new().parse_str(pel).unwrap();
1751 let result = Runtime::new().eval(&expression).unwrap_err();
1752
1753 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
1754 }
1755
1756 #[test]
1757 fn substring_after_not_found() {
1758 let pel = r#"
1760 [":apply", "5-7",
1761 [":ref", "5-7", "substringAfter"],
1762 [":str", "0-4", "peregrine"],
1763 [":str", "8-12", "XX"]
1764 ]"#;
1765
1766 let expression = Parser::new().parse_str(pel).unwrap();
1767 let result = Runtime::new()
1768 .eval(&expression)
1769 .unwrap()
1770 .complete()
1771 .unwrap();
1772
1773 assert_eq!(result.as_str().unwrap(), "");
1774 }
1775
1776 #[test]
1777 fn substring_after_empty_string() {
1778 let pel = r#"
1780 [":apply", "5-7",
1781 [":ref", "5-7", "substringAfter"],
1782 [":str", "0-4", "peregrine"],
1783 [":str", "8-10", ""]
1784 ]"#;
1785
1786 let expression = Parser::new().parse_str(pel).unwrap();
1787 let result = Runtime::new()
1788 .eval(&expression)
1789 .unwrap()
1790 .complete()
1791 .unwrap();
1792
1793 assert_eq!(result.as_str().unwrap(), "peregrine");
1794 }
1795
1796 #[test]
1797 fn substring_after_last_null_string() {
1798 let pel = r#"
1800 [":apply", "5-7",
1801 [":ref", "5-7", "substringAfterLast"],
1802 [":null", "0-4"],
1803 [":str", "8-12", "peregrine"]
1804 ]"#;
1805
1806 let expression = Parser::new().parse_str(pel).unwrap();
1807 let result = Runtime::new()
1808 .eval(&expression)
1809 .unwrap()
1810 .complete()
1811 .unwrap();
1812
1813 assert!(result.is_null());
1814 }
1815
1816 #[test]
1817 fn substring_after_last_string_string() {
1818 let pel = r#"
1820 [":apply", "5-7",
1821 [":ref", "5-7", "substringAfterLast"],
1822 [":str", "0-4", "Peregrine Expression Language"],
1823 [":str", "8-12", "re"]
1824 ]"#;
1825
1826 let expression = Parser::new().parse_str(pel).unwrap();
1827 let result = Runtime::new()
1828 .eval(&expression)
1829 .unwrap()
1830 .complete()
1831 .unwrap();
1832
1833 assert_eq!(result.as_str().unwrap(), "ssion Language");
1834 }
1835
1836 #[test]
1837 fn substring_after_last_string_null_fail() {
1838 let pel = r#"
1840 [":apply", "5-7",
1841 [":ref", "5-7", "substringAfterLast"],
1842 [":str", "0-4", "peregrine"],
1843 [":null", "8-12"]
1844 ]"#;
1845
1846 let expression = Parser::new().parse_str(pel).unwrap();
1847 let error = Runtime::new().eval(&expression).unwrap_err();
1848
1849 assert_eq!(error.kind, RuntimeErrorKind::TypeMismatch);
1850 }
1851
1852 #[test]
1853 fn substring_after_last_boolean_string() {
1854 let pel = r#"
1856 [":apply", "5-7",
1857 [":ref", "5-7", "substringAfterLast"],
1858 [":bool", "0-4", "true"],
1859 [":str", "8-12", "r"]
1860 ]"#;
1861
1862 let expression = Parser::new().parse_str(pel).unwrap();
1863 let result = Runtime::new()
1864 .eval(&expression)
1865 .unwrap()
1866 .complete()
1867 .unwrap();
1868
1869 assert_eq!(result.as_str().unwrap(), "ue");
1870 }
1871
1872 #[test]
1873 fn substring_after_last_number_number() {
1874 let pel = r#"
1876 [":apply", "5-7",
1877 [":ref", "5-7", "substringAfterLast"],
1878 [":nbr", "0-4", "12123512.3512"],
1879 [":nbr", "8-12", "35"]
1880 ]"#;
1881
1882 let expression = Parser::new().parse_str(pel).unwrap();
1883 let result = Runtime::new()
1884 .eval(&expression)
1885 .unwrap()
1886 .complete()
1887 .unwrap();
1888
1889 assert_eq!(result.as_str().unwrap(), "12");
1890 }
1891
1892 #[test]
1893 fn substring_after_last_array_fail() {
1894 let pel = r#"
1896 [":apply", "5-7",
1897 [":ref", "5-7", "substringAfterLast"],
1898 [":array", "0-41",
1899 [":str", "1-9", "accept"],
1900 [":str", "10-27", "accept-encoding"],
1901 [":str", "28-40", "user-agent"]
1902 ],
1903 [":str", "1-10", "re"]
1904 ]
1905 "#;
1906
1907 let expression = Parser::new().parse_str(pel).unwrap();
1908 let result = Runtime::new().eval(&expression).unwrap_err();
1909
1910 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
1911 }
1912
1913 #[test]
1914 fn substring_after_last_not_found() {
1915 let pel = r#"
1917 [":apply", "5-7",
1918 [":ref", "5-7", "substringAfterLast"],
1919 [":str", "0-4", "peregrine"],
1920 [":str", "8-12", "XX"]
1921 ]"#;
1922
1923 let expression = Parser::new().parse_str(pel).unwrap();
1924 let result = Runtime::new()
1925 .eval(&expression)
1926 .unwrap()
1927 .complete()
1928 .unwrap();
1929
1930 assert_eq!(result.as_str().unwrap(), "");
1931 }
1932
1933 #[test]
1934 fn substring_after_last_empty_string() {
1935 let pel = r#"
1937 [":apply", "5-7",
1938 [":ref", "5-7", "substringAfterLast"],
1939 [":str", "0-4", "peregrine"],
1940 [":str", "8-10", ""]
1941 ]"#;
1942
1943 let expression = Parser::new().parse_str(pel).unwrap();
1944 let result = Runtime::new()
1945 .eval(&expression)
1946 .unwrap()
1947 .complete()
1948 .unwrap();
1949
1950 assert_eq!(result.as_str().unwrap(), "");
1951 }
1952
1953 #[test]
1954 fn substring_before_null_string() {
1955 let pel = r#"
1957 [":apply", "5-7",
1958 [":ref", "5-7", "substringBefore"],
1959 [":null", "0-4"],
1960 [":str", "8-12", "peregrine"]
1961 ]"#;
1962
1963 let expression = Parser::new().parse_str(pel).unwrap();
1964 let result = Runtime::new()
1965 .eval(&expression)
1966 .unwrap()
1967 .complete()
1968 .unwrap();
1969
1970 assert!(result.is_null());
1971 }
1972
1973 #[test]
1974 fn substring_before_string_string() {
1975 let pel = r#"
1977 [":apply", "5-7",
1978 [":ref", "5-7", "substringBefore"],
1979 [":str", "0-4", "peregrine"],
1980 [":str", "8-12", "gr"]
1981 ]"#;
1982
1983 let expression = Parser::new().parse_str(pel).unwrap();
1984 let result = Runtime::new()
1985 .eval(&expression)
1986 .unwrap()
1987 .complete()
1988 .unwrap();
1989
1990 assert_eq!(result.as_str().unwrap(), "pere");
1991 }
1992
1993 #[test]
1994 fn substring_before_string_null_fail() {
1995 let pel = r#"
1997 [":apply", "5-7",
1998 [":ref", "5-7", "substringBefore"],
1999 [":str", "0-4", "peregrine"],
2000 [":null", "8-12"]
2001 ]"#;
2002
2003 let expression = Parser::new().parse_str(pel).unwrap();
2004 let result = Runtime::new().eval(&expression).unwrap_err();
2005
2006 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
2007 }
2008
2009 #[test]
2010 fn substring_before_boolean_string() {
2011 let pel = r#"
2013 [":apply", "5-7",
2014 [":ref", "5-7", "substringBefore"],
2015 [":bool", "0-4", "true"],
2016 [":str", "8-12", "ue"]
2017 ]"#;
2018
2019 let expression = Parser::new().parse_str(pel).unwrap();
2020 let result = Runtime::new()
2021 .eval(&expression)
2022 .unwrap()
2023 .complete()
2024 .unwrap();
2025
2026 assert_eq!(result.as_str().unwrap(), "tr");
2027 }
2028
2029 #[test]
2030 fn substring_before_number_number() {
2031 let pel = r#"
2033 [":apply", "5-7",
2034 [":ref", "5-7", "substringBefore"],
2035 [":nbr", "0-4", "1234.56"],
2036 [":nbr", "8-12", "4.5"]
2037 ]"#;
2038
2039 let expression = Parser::new().parse_str(pel).unwrap();
2040 let result = Runtime::new()
2041 .eval(&expression)
2042 .unwrap()
2043 .complete()
2044 .unwrap();
2045
2046 assert_eq!(result.as_str().unwrap(), "123");
2047 }
2048
2049 #[test]
2050 fn substring_before_array_fail() {
2051 let pel = r#"
2053 [":apply", "5-7",
2054 [":ref", "5-7", "substringBefore"],
2055 [":array", "0-41",
2056 [":str", "1-9", "accept"],
2057 [":str", "10-27", "accept-encoding"],
2058 [":str", "28-40", "user-agent"]
2059 ],
2060 [":str", "1-10", "re"]
2061 ]
2062 "#;
2063
2064 let expression = Parser::new().parse_str(pel).unwrap();
2065 let result = Runtime::new().eval(&expression).unwrap_err();
2066
2067 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
2068 }
2069
2070 #[test]
2071 fn substring_before_not_found() {
2072 let pel = r#"
2074 [":apply", "5-7",
2075 [":ref", "5-7", "substringBefore"],
2076 [":str", "0-4", "peregrine"],
2077 [":str", "8-12", "XX"]
2078 ]"#;
2079
2080 let expression = Parser::new().parse_str(pel).unwrap();
2081 let result = Runtime::new()
2082 .eval(&expression)
2083 .unwrap()
2084 .complete()
2085 .unwrap();
2086
2087 assert_eq!(result.as_str().unwrap(), "");
2088 }
2089
2090 #[test]
2091 fn substring_before_empty_string() {
2092 let pel = r#"
2094 [":apply", "0-55",
2095 [":ref", "0-38", "substringBefore"],
2096 [":str", "39-50", "peregrine"],
2097 [":str", "52-54", ""]
2098 ]"#;
2099
2100 let expression = Parser::new().parse_str(pel).unwrap();
2101 let result = Runtime::new()
2102 .eval(&expression)
2103 .unwrap()
2104 .complete()
2105 .unwrap();
2106
2107 assert_eq!(result.as_str().unwrap(), "");
2108 }
2109
2110 #[test]
2111 fn substring_before_last_null_string() {
2112 let pel = r#"
2114 [":apply", "5-7",
2115 [":ref", "5-7", "substringBeforeLast"],
2116 [":null", "0-4"],
2117 [":str", "8-12", "peregrine"]
2118 ]"#;
2119
2120 let expression = Parser::new().parse_str(pel).unwrap();
2121 let result = Runtime::new()
2122 .eval(&expression)
2123 .unwrap()
2124 .complete()
2125 .unwrap();
2126
2127 assert!(result.is_null());
2128 }
2129
2130 #[test]
2131 fn substring_before_last_string_string() {
2132 let pel = r#"
2134 [":apply", "5-7",
2135 [":ref", "5-7", "substringBeforeLast"],
2136 [":str", "0-4", "Peregrine Expression Language"],
2137 [":str", "8-12", "re"]
2138 ]"#;
2139
2140 let expression = Parser::new().parse_str(pel).unwrap();
2141 let result = Runtime::new()
2142 .eval(&expression)
2143 .unwrap()
2144 .complete()
2145 .unwrap();
2146
2147 assert_eq!(result.as_str().unwrap(), "Peregrine Exp");
2148 }
2149
2150 #[test]
2151 fn substring_before_last_string_null_fail() {
2152 let pel = r#"
2154 [":apply", "5-7",
2155 [":ref", "5-7", "substringBeforeLast"],
2156 [":str", "0-4", "peregrine"],
2157 [":null", "8-12"]
2158 ]"#;
2159
2160 let expression = Parser::new().parse_str(pel).unwrap();
2161 let result = Runtime::new().eval(&expression).unwrap_err();
2162
2163 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
2164 }
2165
2166 #[test]
2167 fn substring_before_last_boolean_string() {
2168 let pel = r#"
2170 [":apply", "5-7",
2171 [":ref", "5-7", "substringBeforeLast"],
2172 [":bool", "0-4", "true"],
2173 [":str", "8-12", "ue"]
2174 ]"#;
2175
2176 let expression = Parser::new().parse_str(pel).unwrap();
2177 let result = Runtime::new()
2178 .eval(&expression)
2179 .unwrap()
2180 .complete()
2181 .unwrap();
2182
2183 assert_eq!(result.as_str().unwrap(), "tr");
2184 }
2185
2186 #[test]
2187 fn substring_before_last_number_number() {
2188 let pel = r#"
2190 [":apply", "5-7",
2191 [":ref", "5-7", "substringBeforeLast"],
2192 [":nbr", "0-4", "121235.123512"],
2193 [":nbr", "8-12", "12"]
2194 ]"#;
2195
2196 let expression = Parser::new().parse_str(pel).unwrap();
2197 let result = Runtime::new()
2198 .eval(&expression)
2199 .unwrap()
2200 .complete()
2201 .unwrap();
2202
2203 assert_eq!(result.as_str().unwrap(), "121235.1235");
2204 }
2205
2206 #[test]
2207 fn substring_before_last_array_fail() {
2208 let pel = r#"
2210 [":apply", "5-7",
2211 [":ref", "5-7", "substringBeforeLast"],
2212 [":array", "0-41",
2213 [":str", "1-9", "accept"],
2214 [":str", "10-27", "accept-encoding"],
2215 [":str", "28-40", "user-agent"]
2216 ],
2217 [":str", "1-10", "re"]
2218 ]
2219 "#;
2220
2221 let expression = Parser::new().parse_str(pel).unwrap();
2222 let result = Runtime::new().eval(&expression).unwrap_err();
2223
2224 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
2225 }
2226
2227 #[test]
2228 fn substring_before_last_not_found() {
2229 let pel = r#"
2231 [":apply", "5-7",
2232 [":ref", "5-7", "substringBeforeLast"],
2233 [":str", "0-4", "peregrine"],
2234 [":str", "8-12", "XX"]
2235 ]"#;
2236
2237 let expression = Parser::new().parse_str(pel).unwrap();
2238 let result = Runtime::new()
2239 .eval(&expression)
2240 .unwrap()
2241 .complete()
2242 .unwrap();
2243
2244 assert_eq!(result.as_str().unwrap(), "");
2245 }
2246
2247 #[test]
2248 fn substring_before_last_empty_string() {
2249 let pel = r#"
2251 [":apply", "0-55",
2252 [":ref", "0-38", "substringBeforeLast"],
2253 [":str", "39-50", "peregrine"],
2254 [":str", "52-54", ""]
2255 ]"#;
2256
2257 let expression = Parser::new().parse_str(pel).unwrap();
2258 let result = Runtime::new()
2259 .eval(&expression)
2260 .unwrap()
2261 .complete()
2262 .unwrap();
2263
2264 assert_eq!(result.as_str().unwrap(), "peregrin");
2265 }
2266
2267 #[test]
2268 fn upper_null() {
2269 let pel = r#"
2271 [":apply", "5-7",
2272 [":ref", "5-7", "upper"],
2273 [":null", "0-4"]
2274 ]
2275 "#;
2276
2277 let expression = Parser::new().parse_str(pel).unwrap();
2278 let result = Runtime::new()
2279 .eval(&expression)
2280 .unwrap()
2281 .complete()
2282 .unwrap();
2283
2284 assert!(result.is_null());
2285 }
2286
2287 #[test]
2288 fn upper_string() {
2289 let pel = r#"
2291 [":apply", "5-7",
2292 [":ref", "5-7", "upper"],
2293 [":str", "0-4", "Peregrine Expression Language"]
2294 ]
2295 "#;
2296
2297 let expression = Parser::new().parse_str(pel).unwrap();
2298 let result = Runtime::new()
2299 .eval(&expression)
2300 .unwrap()
2301 .complete()
2302 .unwrap();
2303
2304 assert_eq!("PEREGRINE EXPRESSION LANGUAGE", result.as_str().unwrap());
2305 }
2306
2307 #[test]
2308 fn upper_boolean() {
2309 let pel = r#"
2311 [":apply", "5-7",
2312 [":ref", "5-7", "upper"],
2313 [":bool", "0-4", "true"]
2314 ]
2315 "#;
2316
2317 let expression = Parser::new().parse_str(pel).unwrap();
2318 let result = Runtime::new()
2319 .eval(&expression)
2320 .unwrap()
2321 .complete()
2322 .unwrap();
2323
2324 assert_eq!("TRUE", result.as_str().unwrap());
2325 }
2326
2327 #[test]
2328 fn upper_number() {
2329 let pel = r#"
2331 [":apply", "5-7",
2332 [":ref", "5-7", "upper"],
2333 [":nbr", "0-4", "123.4"]
2334 ]
2335 "#;
2336
2337 let expression = Parser::new().parse_str(pel).unwrap();
2338 let result = Runtime::new()
2339 .eval(&expression)
2340 .unwrap()
2341 .complete()
2342 .unwrap();
2343
2344 assert_eq!("123.4", result.as_str().unwrap());
2345 }
2346
2347 #[test]
2348 fn upper_array_fail() {
2349 let pel = r#"
2351 [":apply", "5-7",
2352 [":ref", "5-7", "upper"],
2353 [":array", "0-41",
2354 [":str", "1-9", "accept"],
2355 [":str", "10-27", "accept-encoding"],
2356 [":str", "28-40", "user-agent"]
2357 ]
2358 ]
2359 "#;
2360
2361 let expression = Parser::new().parse_str(pel).unwrap();
2362 let error = Runtime::new().eval(&expression).unwrap_err();
2363
2364 assert_eq!(error.kind, RuntimeErrorKind::TypeMismatch);
2365 }
2366
2367 #[test]
2368 fn to_binary() {
2369 let pel = r#"[":apply", "0-46", [":ref", "0-29", "toBinary"], [":str", "30-36", "some"], [":str", "38-45", "UTF-8"]]"#;
2371
2372 let expression = Parser::new().parse_str(pel).unwrap();
2373 let result = Runtime::new()
2374 .eval(&expression)
2375 .unwrap()
2376 .complete()
2377 .unwrap();
2378
2379 assert_eq!(result.as_binary().unwrap(), "some".as_bytes());
2380 }
2381
2382 #[test]
2383 fn to_binary_not_enough_args() {
2384 let pel = r#"[":apply", "0-46", [":ref", "0-29", "toBinary"], [":str", "30-36", "some"]]"#;
2386
2387 let expression = Parser::new().parse_str(pel).unwrap();
2388 let result = Runtime::new().eval(&expression).unwrap_err();
2389
2390 assert_eq!(result.kind, RuntimeErrorKind::NotEnoughArguments);
2391 }
2392
2393 #[test]
2394 fn to_binary_to_many_args() {
2395 let pel = r#"[":apply", "0-46", [":ref", "0-29", "toBinary"], [":str", "30-36", "some"], [":str", "38-45", "UTF-8"], [":str", "38-45", "UTF-8"]]"#;
2397
2398 let expression = Parser::new().parse_str(pel).unwrap();
2399 let result = Runtime::new().eval(&expression).unwrap_err();
2400
2401 assert_eq!(result.kind, RuntimeErrorKind::TooManyArguments);
2402 }
2403
2404 #[test]
2405 fn to_binary_invalid_argument() {
2406 let pel = r#"[":apply", "0-46", [":ref", "0-29", "toBinary"], [":str", "30-36", "some"], [":str", "38-45", "UTF-32"]]"#;
2408
2409 let expression = Parser::new().parse_str(pel).unwrap();
2410 let result = Runtime::new().eval(&expression).unwrap_err();
2411
2412 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
2413 }
2414
2415 #[test]
2416 fn from_binary() {
2417 let pel = r#"[":apply", "0-86", [":ref", "0-29", "toString"], [":apply", "30-76", [":ref", "30-59", "toBinary"], [":str", "60-66", "some"], [":str", "68-75", "UTF-8"]], [":str", "78-85", "UTF-8"]]"#;
2419
2420 let expression = Parser::new().parse_str(pel).unwrap();
2421 let result = Runtime::new()
2422 .eval(&expression)
2423 .unwrap()
2424 .complete()
2425 .unwrap();
2426
2427 assert_eq!(result.as_str(), Some("some"));
2428 }
2429
2430 #[test]
2431 fn from_binary_not_enough_args() {
2432 let pel = r#"[":apply", "0-86", [":ref", "0-29", "toString"], [":apply", "30-76", [":ref", "30-59", "toBinary"], [":str", "60-66", "some"], [":str", "68-75", "UTF-8"]]]"#;
2434
2435 let expression = Parser::new().parse_str(pel).unwrap();
2436 let result = Runtime::new().eval(&expression).unwrap_err();
2437
2438 assert_eq!(result.kind, RuntimeErrorKind::NotEnoughArguments);
2439 }
2440
2441 #[test]
2442 fn from_binary_to_many_args() {
2443 let pel = r#"[":apply", "0-86", [":ref", "0-29", "toString"], [":apply", "30-76", [":ref", "30-59", "toBinary"], [":str", "60-66", "some"], [":str", "68-75", "UTF-8"]], [":str", "78-85", "UTF-8"], [":str", "78-85", "UTF-8"]]"#;
2445
2446 let expression = Parser::new().parse_str(pel).unwrap();
2447 let result = Runtime::new().eval(&expression).unwrap_err();
2448
2449 assert_eq!(result.kind, RuntimeErrorKind::TooManyArguments);
2450 }
2451
2452 #[test]
2453 fn from_binary_invalid_argument() {
2454 let pel = r#"[":apply", "0-86", [":ref", "0-29", "toString"], [":apply", "30-76", [":ref", "30-59", "toBinary"], [":str", "60-66", "some"], [":str", "68-75", "UTF-8"]], [":str", "78-85", "UTF-32"]]"#;
2456
2457 let expression = Parser::new().parse_str(pel).unwrap();
2458 let result = Runtime::new().eval(&expression).unwrap_err();
2459
2460 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
2461 }
2462
2463 #[test]
2464 fn from_base64() {
2465 let pel =
2467 r#"[":apply", "0-46", [":ref", "0-29", "fromBase64"], [":str", "30-36", "c29tZQ=="]]"#;
2468
2469 let expression = Parser::new().parse_str(pel).unwrap();
2470 let result = Runtime::new()
2471 .eval(&expression)
2472 .unwrap()
2473 .complete()
2474 .unwrap();
2475
2476 assert_eq!(result.as_binary().unwrap(), "some".as_bytes());
2477 }
2478
2479 #[test]
2480 fn from_base64_not_enough_args() {
2481 let pel = r#"[":apply", "0-46", [":ref", "0-29", "fromBase64"]]"#;
2483
2484 let expression = Parser::new().parse_str(pel).unwrap();
2485 let result = Runtime::new().eval(&expression).unwrap_err();
2486
2487 assert_eq!(result.kind, RuntimeErrorKind::NotEnoughArguments);
2488 }
2489
2490 #[test]
2491 fn from_base64_to_many_args() {
2492 let pel = r#"[":apply", "0-46", [":ref", "0-29", "fromBase64"], [":str", "30-36", "AA"], [":str", "38-45", "UTF-8"]]"#;
2494
2495 let expression = Parser::new().parse_str(pel).unwrap();
2496 let result = Runtime::new().eval(&expression).unwrap_err();
2497
2498 assert_eq!(result.kind, RuntimeErrorKind::TooManyArguments);
2499 }
2500
2501 #[test]
2502 fn from_base64_invalid_argument() {
2503 let pel = r#"[":apply", "0-46", [":ref", "0-29", "fromBase64"], [":str", "30-36", "0"]]"#;
2505
2506 let expression = Parser::new().parse_str(pel).unwrap();
2507 let result = Runtime::new().eval(&expression).unwrap_err();
2508
2509 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
2510 }
2511
2512 #[test]
2513 fn to_base64() {
2514 let pel = r#"[":apply", "0-86", [":ref", "0-29", "toBase64"], [":apply", "30-76", [":ref", "30-59", "fromBase64"], [":str", "60-66", "AAAA"]]]"#;
2516
2517 let expression = Parser::new().parse_str(pel).unwrap();
2518 let result = Runtime::new()
2519 .eval(&expression)
2520 .unwrap()
2521 .complete()
2522 .unwrap();
2523
2524 assert_eq!(result.as_str(), Some("AAAA"));
2525 }
2526
2527 #[test]
2528 fn to_base64_not_enough_args() {
2529 let pel = r#"[":apply", "0-86", [":ref", "0-29", "toBase64"]]"#;
2531
2532 let expression = Parser::new().parse_str(pel).unwrap();
2533 let result = Runtime::new().eval(&expression).unwrap_err();
2534
2535 assert_eq!(result.kind, RuntimeErrorKind::NotEnoughArguments);
2536 }
2537
2538 #[test]
2539 fn to_base64_to_many_args() {
2540 let pel = r#"[":apply", "0-86", [":ref", "0-29", "toBase64"], [":apply", "30-76", [":ref", "30-59", "fromBase64"], [":str", "60-66", "AAAA"]], [":str", "78-85", "UTF-8"]]"#;
2542
2543 let expression = Parser::new().parse_str(pel).unwrap();
2544 let result = Runtime::new().eval(&expression).unwrap_err();
2545
2546 assert_eq!(result.kind, RuntimeErrorKind::TooManyArguments);
2547 }
2548
2549 #[test]
2550 fn decode_basic_auth() {
2551 let pel = r#"[":apply", "0-143", [":ref", "0-29", "toString"], [":apply", "30-133", [":ref", "30-60", "fromBase64"], [":apply", "61-132", [":ref", "61-94", "substringAfter"], [":str", "95-120", "bearer c29tZTpvdGhlcg=="], [":str", "122-131", "bearer "]]], [":str", "135-142", "UTF-8"]]"#;
2553
2554 let expression = Parser::new().parse_str(pel).unwrap();
2555 let result = Runtime::new()
2556 .eval(&expression)
2557 .unwrap()
2558 .complete()
2559 .unwrap();
2560
2561 assert_eq!(result.as_str().unwrap(), "some:other");
2562 }
2563
2564 #[test]
2565 fn decode_basic_auth_auto_coerce() {
2566 let pel = r#"[":apply", "0-90", [":ref", "0-33", "substringAfter"], [":apply", "34-84", [":ref", "34-64", "fromBase64"], [":str", "65-83", "c29tZTpvdGhlcg=="]], [":str", "86-89", ":"]]"#;
2568
2569 let expression = Parser::new().parse_str(pel).unwrap();
2570 let result = Runtime::new()
2571 .eval(&expression)
2572 .unwrap()
2573 .complete()
2574 .unwrap();
2575
2576 assert_eq!(result.as_str().unwrap(), "other");
2577 }
2578
2579 #[test]
2580 fn encode_basic_auth() {
2581 let pel = r#"[":apply", "0-82", [":ref", "0-28", "toBase64"], [":apply", "29-81", [":ref", "29-58", "toBinary"], [":str", "59-71", "some:other"], [":str", "73-80", "utf-8"]]]"#;
2583
2584 let expression = Parser::new().parse_str(pel).unwrap();
2585 let result = Runtime::new()
2586 .eval(&expression)
2587 .unwrap()
2588 .complete()
2589 .unwrap();
2590
2591 assert_eq!(result.as_str().unwrap(), "c29tZTpvdGhlcg==");
2592 }
2593
2594 #[test]
2595 fn encode_basic_auth_auto_coerce() {
2596 let pel =
2598 r#"[":apply", "0-0", [":ref", "0-28", "toBase64"], [":str", "0-0", "some:other"]]"#;
2599
2600 let expression = Parser::new().parse_str(pel).unwrap();
2601 let result = Runtime::new()
2602 .eval(&expression)
2603 .unwrap()
2604 .complete()
2605 .unwrap();
2606
2607 assert_eq!(result.as_str().unwrap(), "c29tZTpvdGhlcg==");
2608 }
2609
2610 #[test]
2611 fn multimap_return_full() {
2612 let origin = "<envelope><some>b</some></envelope>";
2613 let value = DocumentBuilder::root(
2614 QualifiedName::new("", "envelope"),
2615 Rc::new(origin.to_string()),
2616 0..origin.len(),
2617 )
2618 .with_element(QualifiedName::new("", "some"), 10..24)
2619 .with_text("b")
2620 .finish_element()
2621 .finish_element()
2622 .build();
2623
2624 let pel = r#"[":ref", "0-0", "payload"]"#;
2626
2627 assert_eq!(
2628 evaluate(pel, value).as_doc_node().unwrap().content(),
2629 Some(origin.to_string())
2630 )
2631 }
2632
2633 #[test]
2634 fn multimap_return_obj() {
2635 let origin = "<envelope><some>b</some></envelope>";
2636 let value = DocumentBuilder::root(
2637 QualifiedName::new("", "envelope"),
2638 Rc::new(origin.to_string()),
2639 0..origin.len(),
2640 )
2641 .with_element(QualifiedName::new("", "some"), 10..24)
2642 .with_text("b")
2643 .finish_element()
2644 .finish_element()
2645 .build();
2646
2647 let pel = r#"
2649 [".", "0-0",
2650 [":ref", "0-0", "payload"],
2651 [":str", "0-0", "envelope"]
2652 ]
2653 "#;
2654
2655 assert_eq!(
2656 evaluate(pel, value).as_doc_node().unwrap().content(),
2657 Some("<?xml version='1.0' encoding='UTF-8'?>\n<some>\n b\n</some>".to_string())
2658 )
2659 }
2660
2661 #[test]
2662 fn access_multimap_by_name() {
2663 let origin = "<envelope>b</envelope>";
2664 let value = DocumentBuilder::root(
2665 QualifiedName::new("", "envelope"),
2666 Rc::new(origin.to_string()),
2667 0..origin.len(),
2668 )
2669 .with_text("b")
2670 .finish_element()
2671 .build();
2672
2673 let pel = r#"
2675 ["==", "0-0",
2676 [":str", "0-0", "b"],
2677 [".", "0-0",
2678 [":ref", "0-0", "payload"],
2679 [":str", "0-0", "envelope"]
2680 ]
2681 ]
2682 "#;
2683
2684 evaluate_and_assert(pel, value, Value::bool(true))
2685 }
2686
2687 #[test]
2688 fn multimap_content() {
2689 let value = DocumentBuilder::root(
2690 QualifiedName::new("", "envelope"),
2691 Rc::new(Default::default()),
2692 0..0,
2693 )
2694 .with_element(QualifiedName::prefixed("s", "some-uri", "some"), 0..0)
2695 .with_attribute(
2696 QualifiedName::prefixed("s", "some-uri", "qualified"),
2697 "qualified",
2698 )
2699 .with_attribute(
2700 QualifiedName::prefixed("", "some-uri", "unqualified"),
2701 "unqualified",
2702 )
2703 .with_element(QualifiedName::prefixed("s", "some-uri", "first"), 0..0)
2704 .finish_element()
2705 .with_element(QualifiedName::prefixed("s", "some-uri", "second"), 0..0)
2706 .with_text("b")
2707 .finish_element()
2708 .finish_element()
2709 .finish_element()
2710 .build();
2711
2712 let pel = r#"
2714 [".", "0-0",
2715 [":ref", "0-0", "payload"],
2716 [":str", "0-0", "envelope"]
2717 ]
2718 "#;
2719
2720 assert_eq!(
2721 evaluate(pel, value.clone())
2722 .as_doc_node()
2723 .unwrap()
2724 .content(),
2725 Some(
2726 r#"<?xml version='1.0' encoding='UTF-8'?>
2727<s:some xmlns:s="some-uri" s:qualified="qualified" xmlns="some-uri" unqualified="unqualified">
2728 <s:first/>
2729 <s:second>
2730 b
2731 </s:second>
2732</s:some>"#
2733 .to_string()
2734 )
2735 );
2736
2737 let pel = r#"
2739 [".", "0-0",
2740 [".", "0-0",
2741 [":ref", "0-0", "payload"],
2742 [":str", "0-0", "envelope"]
2743 ],
2744 [":str", "0-0", "some"]
2745 ]
2746 "#;
2747
2748 assert_eq!(evaluate(pel, value).as_doc_node().unwrap().content(), None)
2749 }
2750
2751 #[test]
2752 fn access_multimap_by_qname() {
2753 let value = DocumentBuilder::root(
2755 QualifiedName::new("http://test.com", "envelope"),
2756 Rc::new("".to_string()),
2757 0..0,
2758 )
2759 .with_text("b")
2760 .finish_element()
2761 .build();
2762
2763 let pel = r#"
2765 ["==", "0-0",
2766 [":str", "0-0", "b"],
2767 [".", "0-0", [":ref", "0-0", "payload"], [":name", "0-0", [":ns", "0-0", "http://test.com"], [":str", "0-0", "envelope"]]]
2768 ]
2769 "#;
2770
2771 evaluate_and_assert(pel, value, Value::bool(true))
2772 }
2773
2774 #[test]
2775 fn access_multimap_attribute_by_name() {
2776 let value = DocumentBuilder::root(
2778 QualifiedName::new("http://test.com", "envelope"),
2779 Rc::new("".to_string()),
2780 0..0,
2781 )
2782 .with_attribute(QualifiedName::new("http://another.com", "attr"), "another")
2783 .with_attribute(QualifiedName::new("http://test.com", "attr"), "JJ")
2784 .with_text("b")
2785 .finish_element()
2786 .build();
2787
2788 let pel = r#"
2790 ["==", "0-0",
2791 [":str", "0-0", "another"],
2792 ["@", "0-0", [".", "0-0", [":ref", "0-0", "payload"], [":str", "0-0", "envelope"]], [":str", "0-0", "attr"]]
2793 ]
2794 "#;
2795
2796 evaluate_and_assert(pel, value, Value::bool(true))
2797 }
2798
2799 #[test]
2800 fn access_multimap_attribute_by_qname() {
2801 let value = DocumentBuilder::root(
2803 QualifiedName::new("http://test.com", "envelope"),
2804 Rc::new("".to_string()),
2805 0..0,
2806 )
2807 .with_attribute(QualifiedName::new("http://another.com", "attr"), "another")
2808 .with_attribute(QualifiedName::new("http://test.com", "attr"), "JJ")
2809 .with_text("b")
2810 .finish_element()
2811 .build();
2812
2813 let pel = r#"
2815 ["==", "0-0",
2816 [":str", "0-0", "JJ"],
2817 ["@", "0-0", [".", "0-0", [":ref", "0-0", "payload"], [":str", "0-0", "envelope"]], [":name", "0-0", [":ns", "0-0", "http://test.com"], [":str", "0-0", "attr"]]]
2818 ]
2819 "#;
2820
2821 evaluate_and_assert(pel, value, Value::bool(true))
2822 }
2823
2824 #[test]
2825 fn access_multimap_by_non_existing_key() {
2826 let value = DocumentBuilder::root(
2828 QualifiedName::new("", "envelope"),
2829 Rc::new("".to_string()),
2830 0..0,
2831 )
2832 .with_text("b")
2833 .finish_element()
2834 .build();
2835
2836 let pel = r#"
2838 ["==", "0-0",
2839 [".", "0-0",
2840 [":ref", "0-0", "payload"],
2841 [":str", "0-0", "env"]
2842 ],
2843 [":null", "0-0"]
2844 ]
2845 "#;
2846 evaluate_and_assert(pel, value, Value::bool(true))
2847 }
2848
2849 #[test]
2850 fn access_multimap_by_repeated_key() {
2851 let value = DocumentBuilder::root(
2856 QualifiedName::new("", "envelope"),
2857 Rc::new("".to_string()),
2858 0..0,
2859 )
2860 .with_element(QualifiedName::new("", "a"), 0..0)
2861 .with_text("a1")
2862 .finish_element()
2863 .with_element(QualifiedName::new("", "a"), 0..0)
2864 .with_text("a2")
2865 .finish_element()
2866 .finish_element()
2867 .build();
2868
2869 let pel = r#"
2871 ["==", "0-0",
2872 [".", "0-0",
2873 [".", "0-0",
2874 [":ref", "0-0", "payload"],
2875 [":str", "0-0", "envelope"]
2876 ],
2877 [":str", "0-0", "a"]
2878 ],
2879 [":str", "0-0", "a1"]
2880 ]
2881 "#;
2882 evaluate_and_assert(pel, value, Value::bool(true))
2883 }
2884
2885 #[test]
2886 fn compare_multimaps() {
2887 let value = DocumentBuilder::root(
2892 QualifiedName::new("", "envelope"),
2893 Rc::new("".to_string()),
2894 0..0,
2895 )
2896 .with_element(QualifiedName::new("", "a1"), 0..0)
2897 .with_text("a")
2898 .with_element(QualifiedName::new("", "b"), 0..0)
2899 .finish_element()
2900 .finish_element()
2901 .with_element(QualifiedName::new("", "a2"), 0..0)
2902 .with_text("a")
2903 .with_element(QualifiedName::new("", "b"), 0..0)
2904 .finish_element()
2905 .finish_element()
2906 .finish_element()
2907 .build();
2908
2909 let pel = r#"
2911 ["==", "0-0",
2912 [".", "0-0",
2913 [".", "0-0",
2914 [":ref", "0-0", "payload"],
2915 [":str", "0-0", "envelope"]
2916 ],
2917 [":str", "0-0", "a1"]
2918 ],
2919 [".", "0-0",
2920 [".", "0-0",
2921 [":ref", "0-0", "payload"],
2922 [":str", "0-0", "envelope"]
2923 ],
2924 [":str", "0-0", "a2"]
2925 ]
2926 ]
2927 "#;
2928 evaluate_and_assert(pel, value, Value::bool(true))
2929 }
2930
2931 #[test]
2932 fn access_multimap_by_index() {
2933 let value = DocumentBuilder::root(
2935 QualifiedName::new("", "envelope"),
2936 Rc::new("".to_string()),
2937 0..0,
2938 )
2939 .with_text("b")
2940 .finish_element()
2941 .build();
2942
2943 let pel = r#"
2945 ["==", "0-0",
2946 [".", "0-0",
2947 [":ref", "0-0", "payload"],
2948 [":nbr", "0-0", "0"]
2949 ],
2950 [":str", "0-0", "b"]
2951 ]
2952 "#;
2953 evaluate_and_assert(pel, value, Value::bool(true))
2954 }
2955
2956 #[test]
2957 fn access_multimap_by_non_existing_index() {
2958 let value = DocumentBuilder::root(
2960 QualifiedName::new("", "envelope"),
2961 Rc::new("".to_string()),
2962 0..0,
2963 )
2964 .with_text("b")
2965 .finish_element()
2966 .build();
2967
2968 let pel = r#"
2970 ["==", "0-0",
2971 [".", "0-0",
2972 [":ref", "0-0", "payload"],
2973 [":nbr", "0-0", "1"]
2974 ],
2975 [":null", "0-0"]
2976 ]
2977 "#;
2978 evaluate_and_assert(pel, value, Value::bool(true))
2979 }
2980
2981 #[test]
2982 fn access_multimap_multivalue_by_name() {
2983 let value = DocumentBuilder::root(
2985 QualifiedName::new("http://test.com", "envelope"),
2986 Rc::new("".to_string()),
2987 0..0,
2988 )
2989 .with_element(QualifiedName::new("http://test.com", "b"), 0..0)
2990 .with_text("1")
2991 .finish_element()
2992 .with_element(QualifiedName::new("http://test.com", "b"), 0..0)
2993 .with_text("2")
2994 .finish_element()
2995 .finish_element()
2996 .build();
2997
2998 let pel = r#"
2999 ["*", "0-0", [".", "0-0", [":ref", "0-0", "payload"], [":str", "0-0", "envelope"]], [":str", "0-0", "b"]]
3000 "#;
3001
3002 let expected = Value::array(vec![Value::string("1"), Value::string("2")]);
3003 evaluate_and_assert(pel, value, expected)
3004 }
3005
3006 #[test]
3007 fn access_multimap_multivalue_by_qname() {
3008 let value = DocumentBuilder::root(
3010 QualifiedName::new("http://test.com", "envelope"),
3011 Rc::new("".to_string()),
3012 0..0,
3013 )
3014 .with_element(QualifiedName::new("http://test.com", "b"), 0..0)
3015 .with_text("1")
3016 .finish_element()
3017 .with_element(QualifiedName::new("http://other.com", "b"), 0..0)
3018 .with_text("2")
3019 .finish_element()
3020 .with_element(QualifiedName::new("http://test.com", "b"), 0..0)
3021 .with_text("3")
3022 .finish_element()
3023 .finish_element()
3024 .build();
3025
3026 let pel = r#"
3027 ["*", "0-0", [".", "0-0", [":ref", "0-0", "payload"], [":str", "0-0", "envelope"]], [":name", "0-0", [":ns", "0-0", "http://test.com"], [":str", "0-0", "b"]]]
3028 "#;
3029
3030 let expected = Value::array(vec![Value::string("1"), Value::string("3")]);
3031 evaluate_and_assert(pel, value, expected)
3032 }
3033
3034 #[cfg(feature = "experimental_coerced_type")]
3035 #[test]
3036 fn multimap_root_coerced() {
3037 let origin = "<envelope><some>b</some></envelope>";
3038 let value = DocumentBuilder::root(
3039 QualifiedName::new("", "envelope"),
3040 Rc::new(origin.to_string()),
3041 0..origin.len(),
3042 )
3043 .with_element(QualifiedName::new("", "some"), 10..24)
3044 .with_text("b")
3045 .finish_element()
3046 .finish_element()
3047 .build();
3048
3049 let pel = r#"[":apply", "0-0", [":ref", "0-0", "++"], [":ref", "0-0", "payload"], [":str", "0-0", "envelope"]]"#;
3051
3052 assert_eq!(
3053 evaluate(pel, value.clone()).as_str().unwrap(),
3054 origin.to_string() + "envelope"
3055 );
3056
3057 let pel = r#"[":apply", "0-0", [":ref", "0-0", "++"], [":str", "0-0", "envelope"], [":ref", "0-0", "payload"]]"#;
3059 assert_eq!(
3060 evaluate(pel, value.clone()).as_str().unwrap(),
3061 "envelope".to_string() + origin
3062 );
3063
3064 let pel = r#"
3066 ["==", "0-0",
3067 [":ref", "0-0", "payload"],
3068 [":str", "0-0", "<envelope><some>b</some></envelope>"]
3069 ]
3070 "#;
3071 assert!(evaluate(pel, value).as_bool().unwrap());
3072 }
3073
3074 #[test]
3075 fn multimap_not_coerced() {
3076 let origin = "<envelope><some>b</some></envelope>";
3077 let value = DocumentBuilder::root(
3078 QualifiedName::new("", "envelope"),
3079 Rc::new(origin.to_string()),
3080 0..origin.len(),
3081 )
3082 .with_element(QualifiedName::new("", "some"), 10..24)
3083 .with_text("b")
3084 .finish_element()
3085 .finish_element()
3086 .build();
3087
3088 let pel = r#"[":apply", "0-0",
3090 [":ref", "0-0", "++"],
3091 [".", "0-0",
3092 [":ref", "0-0", "payload"],
3093 [":str", "0-0", "envelope"]
3094 ],
3095 [":str", "0-0", "envelope"]
3096 ]"#;
3097
3098 assert_eq!(
3099 &RuntimeErrorKind::TypeMismatch,
3100 evaluate_error(pel, value.clone()).kind(),
3101 );
3102
3103 let pel = r#"
3105 ["==", "0-0",
3106 [".", "0-0",
3107 [":ref", "0-0", "payload"],
3108 [":str", "0-0", "envelope"]
3109 ],
3110 [":str", "0-0", "<some>b</some>"]
3111 ]
3112 "#;
3113 assert!(!evaluate(pel, value).as_bool().unwrap());
3114 }
3115
3116 #[cfg(feature = "experimental_coerced_type")]
3117 #[test]
3118 fn object_root_coerced() {
3119 let origin = r#"{"envelope":{"some":"value"}}"#;
3120 let value = Value::coerced_object(
3121 HashMap::from([(
3122 "envelope".to_string(),
3123 Value::object(HashMap::from([(
3124 "some".to_string(),
3125 Value::string("value"),
3126 )])),
3127 )]),
3128 Rc::new(origin.to_string()),
3129 );
3130
3131 let pel = r#"[":apply", "0-0", [":ref", "0-0", "++"], [":ref", "0-0", "payload"], [":str", "0-0", "envelope"]]"#;
3133
3134 assert_eq!(
3135 evaluate(pel, value.clone()).as_str().unwrap(),
3136 origin.to_string() + "envelope"
3137 );
3138
3139 let pel = r#"[":apply", "0-0", [":ref", "0-0", "++"], [":str", "0-0", "envelope"], [":ref", "0-0", "payload"]]"#;
3141 assert_eq!(
3142 evaluate(pel, value.clone()).as_str().unwrap(),
3143 "envelope".to_string() + origin
3144 );
3145
3146 let pel = r#"
3148 ["==", "0-0",
3149 [":ref", "0-0", "payload"],
3150 [":str", "0-0", "{\"envelope\":{\"some\":\"value\"}}"]
3151 ]
3152 "#;
3153 assert!(evaluate(pel, value).as_bool().unwrap());
3154 }
3155
3156 #[test]
3157 fn object_not_coerced() {
3158 #[cfg(feature = "experimental_coerced_type")]
3159 let origin = r#"{"envelope":{"some":"value"}}"#;
3160
3161 let map = HashMap::from([(
3162 "envelope".to_string(),
3163 Value::object(HashMap::from([(
3164 "some".to_string(),
3165 Value::string("value"),
3166 )])),
3167 )]);
3168
3169 #[cfg(feature = "experimental_coerced_type")]
3170 let value = Value::coerced_object(map, Rc::new(origin.to_string()));
3171
3172 #[cfg(not(feature = "experimental_coerced_type"))]
3173 let value = Value::object(map);
3174
3175 let pel = r#"[":apply", "0-0",
3177 [":ref", "0-0", "++"],
3178 [".", "0-0",
3179 [":ref", "0-0", "payload"],
3180 [":str", "0-0", "envelope"]
3181 ],
3182 [":str", "0-0", "envelope"]
3183 ]"#;
3184
3185 assert_eq!(
3186 &RuntimeErrorKind::TypeMismatch,
3187 evaluate_error(pel, value.clone()).kind(),
3188 );
3189
3190 let pel = r#"
3192 ["==", "0-0",
3193 [".", "0-0",
3194 [":ref", "0-0", "payload"],
3195 [":str", "0-0", "envelope"]
3196 ],
3197 [":str", "0-0", "{\"some\":\"value\"}"]
3198 ]
3199 "#;
3200 assert!(!evaluate(pel, value).as_bool().unwrap());
3201 }
3202
3203 fn evaluate_error(pel: &str, payload: Value) -> RuntimeError {
3204 let context: Prelude = HashMap::from([("payload", payload)]);
3205
3206 let expression = Parser::new().parse_str(pel).unwrap();
3207 Runtime::new()
3208 .eval_with_context(&expression, &context)
3209 .err()
3210 .unwrap()
3211 }
3212
3213 fn evaluate(pel: &str, payload: Value) -> Value {
3214 let context: Prelude = HashMap::from([("payload", payload)]);
3215
3216 let expression = Parser::new().parse_str(pel).unwrap();
3217 Runtime::new()
3218 .eval_with_context(&expression, &context)
3219 .unwrap()
3220 .complete()
3221 .unwrap()
3222 }
3223
3224 fn evaluate_and_assert(pel: &str, payload: Value, expected: Value) {
3225 assert_eq!(evaluate(pel, payload), expected)
3226 }
3227
3228 mod partial_evaluation {
3229 use std::collections::HashMap;
3230
3231 use crate::{
3232 expression::Symbol,
3233 parser::Parser,
3234 runtime::{value::Value, Binding, Context, Runtime, ValueHandler},
3235 Reference,
3236 };
3237
3238 struct TestContextChain {
3239 contexts: Vec<HashMap<String, Value>>,
3240 }
3241
3242 impl TestContextChain {
3243 fn new<const N: usize>(entries: [(&str, Value); N]) -> Self {
3244 Self { contexts: vec![] }.then(entries)
3245 }
3246
3247 fn then<const N: usize>(mut self, entries: [(&str, Value); N]) -> Self {
3248 self.contexts
3249 .push(entries.map(|(k, v)| (k.to_string(), v)).into());
3250 self
3251 }
3252
3253 fn next(mut self) -> Self {
3254 self.contexts.remove(0);
3255 self
3256 }
3257 }
3258
3259 impl Context for TestContextChain {
3260 fn resolve(&self, symbol: &Symbol) -> Binding {
3261 let s = symbol.as_str();
3262 match self.contexts.first().expect("Empty context").get(s) {
3263 Some(value) => Binding::Available(value.clone()),
3264 None => {
3265 if self.contexts.iter().any(|c| c.contains_key(s)) {
3266 Binding::Pending
3267 } else {
3268 Binding::Unknown
3269 }
3270 }
3271 }
3272 }
3273
3274 fn value_handler(&self, _reference: Reference) -> Option<&dyn ValueHandler> {
3275 None
3276 }
3277 }
3278
3279 #[test]
3280 fn if_else_pending_condition() {
3281 let runtime = Runtime::new();
3282 let parser = Parser::new();
3283
3284 let context_1 = TestContextChain::new([("a", Value::string("ctx1".to_string()))])
3285 .then([("condition", Value::bool(true))])
3286 .then([("b", Value::string("ctx3".to_string()))]);
3287
3288 let pel_1 = r#"[":if", "0-23", [":ref", "4-9", "condition"], [":ref", "11-14", "a"], [":ref", "20-23", "b"]]"#;
3290
3291 let expression_1 = parser.parse_str(pel_1).unwrap();
3292 let expression_2 = runtime
3293 .eval_with_context(&expression_1, &context_1)
3294 .unwrap()
3295 .partial()
3296 .unwrap();
3297
3298 let pel_2 = r#"[":if", "0-23", [":ref", "4-9", "condition"], [":str", "11-14", "ctx1"], [":ref", "20-23", "b"]]"#;
3300
3301 assert_eq!(expression_2, parser.parse_str(pel_2).unwrap());
3302
3303 let context_2 = context_1.next();
3304 let result = runtime
3305 .eval_with_context(&expression_2, &context_2)
3306 .unwrap()
3307 .complete()
3308 .unwrap();
3309
3310 assert_eq!(result.as_str().unwrap(), "ctx1");
3311 }
3312
3313 #[test]
3314 fn if_else_pending_true_branch() {
3315 let runtime = Runtime::new();
3316 let parser = Parser::new();
3317
3318 let context_1 = TestContextChain::new([("a", Value::string("ctx1".to_string()))])
3319 .then([("b", Value::string("ctx2".to_string()))]);
3320
3321 let pel_1 = r#"[":if", "0-23", [":bool", "4-9", "true"], [":ref", "11-14", "b"], [":ref", "20-23", "a"]]"#;
3323
3324 let expression_1 = parser.parse_str(pel_1).unwrap();
3325 let expression_2 = runtime
3326 .eval_with_context(&expression_1, &context_1)
3327 .unwrap()
3328 .partial()
3329 .unwrap();
3330
3331 let pel_2 = r#"[":ref", "11-14", "b"]"#;
3332
3333 assert_eq!(expression_2, parser.parse_str(pel_2).unwrap());
3334
3335 let context_2 = context_1.next();
3336 let result = runtime
3337 .eval_with_context(&expression_2, &context_2)
3338 .unwrap()
3339 .complete()
3340 .unwrap();
3341
3342 assert_eq!(result.as_str().unwrap(), "ctx2");
3343 }
3344
3345 #[test]
3346 fn if_else_pending_false_branch() {
3347 let runtime = Runtime::new();
3348 let parser = Parser::new();
3349
3350 let context_1 = TestContextChain::new([("a", Value::string("ctx1".to_string()))])
3351 .then([("b", Value::string("ctx2".to_string()))]);
3352
3353 let pel_1 = r#"[":if", "0-23", [":bool", "4-9", "false"], [":ref", "11-14", "a"], [":ref", "20-23", "b"]]"#;
3355
3356 let expression_1 = parser.parse_str(pel_1).unwrap();
3357 let expression_2 = runtime
3358 .eval_with_context(&expression_1, &context_1)
3359 .unwrap()
3360 .partial()
3361 .unwrap();
3362
3363 let pel_2 = r#"[":ref", "20-23", "b"]"#;
3364
3365 assert_eq!(expression_2, parser.parse_str(pel_2).unwrap());
3366
3367 let context_2 = context_1.next();
3368 let result = runtime
3369 .eval_with_context(&expression_2, &context_2)
3370 .unwrap()
3371 .complete()
3372 .unwrap();
3373
3374 assert_eq!(result.as_str().unwrap(), "ctx2");
3375 }
3376
3377 #[test]
3378 fn default_left_unavailable() {
3379 let runtime = Runtime::new();
3380 let parser = Parser::new();
3381
3382 let context_1 = TestContextChain::new([("right", Value::string("ctx1".to_string()))])
3383 .then([("left", Value::null())]);
3384
3385 let pel_1 = r#"
3387 [":default", "0-6",
3388 [":ref", "0-1", "left"],
3389 [":ref", "5-6", "right"]
3390 ]
3391 "#;
3392
3393 let expression_1 = parser.parse_str(pel_1).unwrap();
3394 let expression_2 = runtime
3395 .eval_with_context(&expression_1, &context_1)
3396 .unwrap()
3397 .partial()
3398 .unwrap();
3399
3400 let pel_2 = r#"
3402 [":default", "0-6",
3403 [":ref", "0-1", "left"],
3404 [":str", "5-6", "ctx1"]
3405 ]
3406 "#;
3407
3408 assert_eq!(expression_2, parser.parse_str(pel_2).unwrap());
3409
3410 let context_2 = context_1.next();
3411 let result = runtime
3412 .eval_with_context(&expression_2, &context_2)
3413 .unwrap()
3414 .complete()
3415 .unwrap();
3416
3417 assert_eq!(result.as_str().unwrap(), "ctx1");
3418 }
3419
3420 #[test]
3421 fn default_right_unavailable() {
3422 let runtime = Runtime::new();
3423 let parser = Parser::new();
3424
3425 let context_1 = TestContextChain::new([("left", Value::null())])
3426 .then([("right", Value::string("ctx1".to_string()))]);
3427
3428 let pel_1 = r#"
3430 [":default", "0-6",
3431 [":ref", "0-1", "left"],
3432 [":ref", "5-6", "right"]
3433 ]
3434 "#;
3435
3436 let expression_1 = parser.parse_str(pel_1).unwrap();
3437 let expression_2 = runtime
3438 .eval_with_context(&expression_1, &context_1)
3439 .unwrap()
3440 .partial()
3441 .unwrap();
3442
3443 let pel_2 = r#"
3445 [":ref", "5-6", "right"]
3446 "#;
3447
3448 assert_eq!(expression_2, parser.parse_str(pel_2).unwrap());
3449
3450 let context_2 = context_1.next();
3451 let result = runtime
3452 .eval_with_context(&expression_2, &context_2)
3453 .unwrap()
3454 .complete()
3455 .unwrap();
3456
3457 assert_eq!(result.as_str().unwrap(), "ctx1");
3458 }
3459 }
3460}