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]
1425 fn split_by_string_string() {
1426 let pel = r#"
1428 [":apply", "5-7",
1429 [":ref", "5-7", "splitBy"],
1430 [":str", "0-4", "Peregrine Expression Language"],
1431 [":str", "8-12", "re"]
1432 ]
1433 "#;
1434
1435 let expression = Parser::new().parse_str(pel).unwrap();
1436 let result = Runtime::new()
1437 .eval(&expression)
1438 .unwrap()
1439 .complete()
1440 .unwrap();
1441
1442 let expected = [
1443 Value::string("Pe".to_string()),
1444 Value::string("grine Exp".to_string()),
1445 Value::string("ssion Language".to_string()),
1446 ];
1447
1448 assert_eq!(&expected, result.as_slice().unwrap());
1449 }
1450
1451 #[test]
1452 fn split_by_string_empty_string() {
1453 let pel = r#"
1455 [":apply", "5-7",
1456 [":ref", "5-7", "splitBy"],
1457 [":str", "0-4", "2022"],
1458 [":str", "8-12", ""]
1459 ]
1460 "#;
1461
1462 let expression = Parser::new().parse_str(pel).unwrap();
1463 let result = Runtime::new()
1464 .eval(&expression)
1465 .unwrap()
1466 .complete()
1467 .unwrap();
1468
1469 let expected = [
1470 Value::string("2".to_string()),
1471 Value::string("0".to_string()),
1472 Value::string("2".to_string()),
1473 Value::string("2".to_string()),
1474 ];
1475
1476 assert_eq!(&expected, result.as_slice().unwrap());
1477 }
1478
1479 #[ignore = "bug W-11098754"]
1480 #[test]
1481 fn split_by_string_string_2() {
1482 let pel = r#"
1484 [":apply", "5-7",
1485 [":ref", "5-7", "splitBy"],
1486 [":str", "0-4", "2022"],
1487 [":str", "8-12", "2"]
1488 ]
1489 "#;
1490
1491 let expression = Parser::new().parse_str(pel).unwrap();
1492 let result = Runtime::new()
1493 .eval(&expression)
1494 .unwrap()
1495 .complete()
1496 .unwrap();
1497
1498 let expected = [
1499 Value::string("".to_string()),
1500 Value::string("0".to_string()),
1501 ];
1502
1503 assert_eq!(&expected, result.as_slice().unwrap());
1504 }
1505
1506 #[test]
1507 fn split_by_number_string() {
1508 let pel = r#"
1510 [":apply", "5-7",
1511 [":ref", "5-7", "splitBy"],
1512 [":nbr", "0-4", "1946.03"],
1513 [":str", "8-12", "."]
1514 ]
1515 "#;
1516
1517 let expression = Parser::new().parse_str(pel).unwrap();
1518 let result = Runtime::new()
1519 .eval(&expression)
1520 .unwrap()
1521 .complete()
1522 .unwrap();
1523
1524 let expected = [
1525 Value::string("1946".to_string()),
1526 Value::string("03".to_string()),
1527 ];
1528
1529 assert_eq!(&expected, result.as_slice().unwrap());
1530 }
1531
1532 #[test]
1533 fn split_by_boolean_string() {
1534 let pel = r#"
1536 [":apply", "5-7",
1537 [":ref", "5-7", "splitBy"],
1538 [":bool", "0-4", "true"],
1539 [":str", "8-12", "r"]
1540 ]
1541 "#;
1542
1543 let expression = Parser::new().parse_str(pel).unwrap();
1544 let result = Runtime::new()
1545 .eval(&expression)
1546 .unwrap()
1547 .complete()
1548 .unwrap();
1549
1550 let expected = [
1551 Value::string("t".to_string()),
1552 Value::string("ue".to_string()),
1553 ];
1554
1555 assert_eq!(&expected, result.as_slice().unwrap());
1556 }
1557
1558 #[test]
1559 fn split_by_null_string() {
1560 let pel = r#"
1562 [":apply", "5-7",
1563 [":ref", "5-7", "splitBy"],
1564 [":null", "0-41"],
1565 [":str", "8-12", "r"]
1566 ]
1567 "#;
1568
1569 let expression = Parser::new().parse_str(pel).unwrap();
1570 let result = Runtime::new()
1571 .eval(&expression)
1572 .unwrap()
1573 .complete()
1574 .unwrap();
1575
1576 assert!(result.is_null());
1577 }
1578
1579 #[test]
1580 fn split_by_string_null_faiil() {
1581 let pel = r#"
1583 [":apply", "5-7",
1584 [":ref", "5-7", "splitBy"],
1585 [":str", "0-41", "Peregrine"],
1586 [":null", "8-12"]
1587 ]
1588 "#;
1589
1590 let expression = Parser::new().parse_str(pel).unwrap();
1591 let error = Runtime::new().eval(&expression).unwrap_err();
1592
1593 assert_eq!(error.kind, RuntimeErrorKind::TypeMismatch);
1594 }
1595
1596 #[test]
1597 fn split_by_array_fail() {
1598 let pel = r#"
1600 [":apply", "5-7",
1601 [":ref", "5-7", "splitBy"],
1602 [":array", "0-41",
1603 [":str", "1-9", "accept"],
1604 [":str", "10-27", "accept-encoding"],
1605 [":str", "28-40", "user-agent"]
1606 ],
1607 [":str", "8-12", "r"]
1608 ]
1609 "#;
1610
1611 let expression = Parser::new().parse_str(pel).unwrap();
1612 let error = Runtime::new().eval(&expression).unwrap_err();
1613
1614 assert_eq!(error.kind, RuntimeErrorKind::TypeMismatch);
1615 }
1616
1617 #[test]
1618 fn substring_after_null_string() {
1619 let pel = r#"
1621 [":apply", "5-7",
1622 [":ref", "5-7", "substringAfter"],
1623 [":null", "0-4"],
1624 [":str", "8-12", "peregrine"]
1625 ]"#;
1626
1627 let expression = Parser::new().parse_str(pel).unwrap();
1628 let result = Runtime::new()
1629 .eval(&expression)
1630 .unwrap()
1631 .complete()
1632 .unwrap();
1633
1634 assert!(result.is_null());
1635 }
1636
1637 #[test]
1638 fn substring_after_string_string() {
1639 let pel = r#"
1641 [":apply", "5-7",
1642 [":ref", "5-7", "substringAfter"],
1643 [":str", "0-4", "peregrine"],
1644 [":str", "8-12", "gr"]
1645 ]"#;
1646
1647 let expression = Parser::new().parse_str(pel).unwrap();
1648 let result = Runtime::new()
1649 .eval(&expression)
1650 .unwrap()
1651 .complete()
1652 .unwrap();
1653
1654 assert_eq!(result.as_str().unwrap(), "ine");
1655 }
1656
1657 #[test]
1658 fn substring_after_string_null_fail() {
1659 let pel = r#"
1661 [":apply", "5-7",
1662 [":ref", "5-7", "substringAfter"],
1663 [":str", "0-4", "peregrine"],
1664 [":null", "8-12"]
1665 ]"#;
1666
1667 let expression = Parser::new().parse_str(pel).unwrap();
1668 let error = Runtime::new().eval(&expression).unwrap_err();
1669
1670 assert_eq!(error.kind, RuntimeErrorKind::TypeMismatch);
1671 }
1672
1673 #[test]
1674 fn substring_after_boolean_string() {
1675 let pel = r#"
1677 [":apply", "5-7",
1678 [":ref", "5-7", "substringAfter"],
1679 [":bool", "0-4", "true"],
1680 [":str", "8-12", "r"]
1681 ]"#;
1682
1683 let expression = Parser::new().parse_str(pel).unwrap();
1684 let result = Runtime::new()
1685 .eval(&expression)
1686 .unwrap()
1687 .complete()
1688 .unwrap();
1689
1690 assert_eq!(result.as_str().unwrap(), "ue");
1691 }
1692
1693 #[test]
1694 fn substring_after_number_number() {
1695 let pel = r#"
1697 [":apply", "5-7",
1698 [":ref", "5-7", "substringAfter"],
1699 [":nbr", "0-4", "1234.567"],
1700 [":nbr", "8-12", "4.5"]
1701 ]"#;
1702
1703 let expression = Parser::new().parse_str(pel).unwrap();
1704 let result = Runtime::new()
1705 .eval(&expression)
1706 .unwrap()
1707 .complete()
1708 .unwrap();
1709
1710 assert_eq!(result.as_str().unwrap(), "67");
1711 }
1712
1713 #[test]
1714 fn substring_after_array_fail() {
1715 let pel = r#"
1717 [":apply", "5-7",
1718 [":ref", "5-7", "substringAfter"],
1719 [":array", "0-41",
1720 [":str", "1-9", "accept"],
1721 [":str", "10-27", "accept-encoding"],
1722 [":str", "28-40", "user-agent"]
1723 ],
1724 [":str", "1-10", "re"]
1725 ]
1726 "#;
1727
1728 let expression = Parser::new().parse_str(pel).unwrap();
1729 let result = Runtime::new().eval(&expression).unwrap_err();
1730
1731 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
1732 }
1733
1734 #[test]
1735 fn substring_after_not_found() {
1736 let pel = r#"
1738 [":apply", "5-7",
1739 [":ref", "5-7", "substringAfter"],
1740 [":str", "0-4", "peregrine"],
1741 [":str", "8-12", "XX"]
1742 ]"#;
1743
1744 let expression = Parser::new().parse_str(pel).unwrap();
1745 let result = Runtime::new()
1746 .eval(&expression)
1747 .unwrap()
1748 .complete()
1749 .unwrap();
1750
1751 assert_eq!(result.as_str().unwrap(), "");
1752 }
1753
1754 #[test]
1755 fn substring_after_empty_string() {
1756 let pel = r#"
1758 [":apply", "5-7",
1759 [":ref", "5-7", "substringAfter"],
1760 [":str", "0-4", "peregrine"],
1761 [":str", "8-10", ""]
1762 ]"#;
1763
1764 let expression = Parser::new().parse_str(pel).unwrap();
1765 let result = Runtime::new()
1766 .eval(&expression)
1767 .unwrap()
1768 .complete()
1769 .unwrap();
1770
1771 assert_eq!(result.as_str().unwrap(), "peregrine");
1772 }
1773
1774 #[test]
1775 fn substring_after_last_null_string() {
1776 let pel = r#"
1778 [":apply", "5-7",
1779 [":ref", "5-7", "substringAfterLast"],
1780 [":null", "0-4"],
1781 [":str", "8-12", "peregrine"]
1782 ]"#;
1783
1784 let expression = Parser::new().parse_str(pel).unwrap();
1785 let result = Runtime::new()
1786 .eval(&expression)
1787 .unwrap()
1788 .complete()
1789 .unwrap();
1790
1791 assert!(result.is_null());
1792 }
1793
1794 #[test]
1795 fn substring_after_last_string_string() {
1796 let pel = r#"
1798 [":apply", "5-7",
1799 [":ref", "5-7", "substringAfterLast"],
1800 [":str", "0-4", "Peregrine Expression Language"],
1801 [":str", "8-12", "re"]
1802 ]"#;
1803
1804 let expression = Parser::new().parse_str(pel).unwrap();
1805 let result = Runtime::new()
1806 .eval(&expression)
1807 .unwrap()
1808 .complete()
1809 .unwrap();
1810
1811 assert_eq!(result.as_str().unwrap(), "ssion Language");
1812 }
1813
1814 #[test]
1815 fn substring_after_last_string_null_fail() {
1816 let pel = r#"
1818 [":apply", "5-7",
1819 [":ref", "5-7", "substringAfterLast"],
1820 [":str", "0-4", "peregrine"],
1821 [":null", "8-12"]
1822 ]"#;
1823
1824 let expression = Parser::new().parse_str(pel).unwrap();
1825 let error = Runtime::new().eval(&expression).unwrap_err();
1826
1827 assert_eq!(error.kind, RuntimeErrorKind::TypeMismatch);
1828 }
1829
1830 #[test]
1831 fn substring_after_last_boolean_string() {
1832 let pel = r#"
1834 [":apply", "5-7",
1835 [":ref", "5-7", "substringAfterLast"],
1836 [":bool", "0-4", "true"],
1837 [":str", "8-12", "r"]
1838 ]"#;
1839
1840 let expression = Parser::new().parse_str(pel).unwrap();
1841 let result = Runtime::new()
1842 .eval(&expression)
1843 .unwrap()
1844 .complete()
1845 .unwrap();
1846
1847 assert_eq!(result.as_str().unwrap(), "ue");
1848 }
1849
1850 #[test]
1851 fn substring_after_last_number_number() {
1852 let pel = r#"
1854 [":apply", "5-7",
1855 [":ref", "5-7", "substringAfterLast"],
1856 [":nbr", "0-4", "12123512.3512"],
1857 [":nbr", "8-12", "35"]
1858 ]"#;
1859
1860 let expression = Parser::new().parse_str(pel).unwrap();
1861 let result = Runtime::new()
1862 .eval(&expression)
1863 .unwrap()
1864 .complete()
1865 .unwrap();
1866
1867 assert_eq!(result.as_str().unwrap(), "12");
1868 }
1869
1870 #[test]
1871 fn substring_after_last_array_fail() {
1872 let pel = r#"
1874 [":apply", "5-7",
1875 [":ref", "5-7", "substringAfterLast"],
1876 [":array", "0-41",
1877 [":str", "1-9", "accept"],
1878 [":str", "10-27", "accept-encoding"],
1879 [":str", "28-40", "user-agent"]
1880 ],
1881 [":str", "1-10", "re"]
1882 ]
1883 "#;
1884
1885 let expression = Parser::new().parse_str(pel).unwrap();
1886 let result = Runtime::new().eval(&expression).unwrap_err();
1887
1888 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
1889 }
1890
1891 #[test]
1892 fn substring_after_last_not_found() {
1893 let pel = r#"
1895 [":apply", "5-7",
1896 [":ref", "5-7", "substringAfterLast"],
1897 [":str", "0-4", "peregrine"],
1898 [":str", "8-12", "XX"]
1899 ]"#;
1900
1901 let expression = Parser::new().parse_str(pel).unwrap();
1902 let result = Runtime::new()
1903 .eval(&expression)
1904 .unwrap()
1905 .complete()
1906 .unwrap();
1907
1908 assert_eq!(result.as_str().unwrap(), "");
1909 }
1910
1911 #[test]
1912 fn substring_after_last_empty_string() {
1913 let pel = r#"
1915 [":apply", "5-7",
1916 [":ref", "5-7", "substringAfterLast"],
1917 [":str", "0-4", "peregrine"],
1918 [":str", "8-10", ""]
1919 ]"#;
1920
1921 let expression = Parser::new().parse_str(pel).unwrap();
1922 let result = Runtime::new()
1923 .eval(&expression)
1924 .unwrap()
1925 .complete()
1926 .unwrap();
1927
1928 assert_eq!(result.as_str().unwrap(), "");
1929 }
1930
1931 #[test]
1932 fn substring_before_null_string() {
1933 let pel = r#"
1935 [":apply", "5-7",
1936 [":ref", "5-7", "substringBefore"],
1937 [":null", "0-4"],
1938 [":str", "8-12", "peregrine"]
1939 ]"#;
1940
1941 let expression = Parser::new().parse_str(pel).unwrap();
1942 let result = Runtime::new()
1943 .eval(&expression)
1944 .unwrap()
1945 .complete()
1946 .unwrap();
1947
1948 assert!(result.is_null());
1949 }
1950
1951 #[test]
1952 fn substring_before_string_string() {
1953 let pel = r#"
1955 [":apply", "5-7",
1956 [":ref", "5-7", "substringBefore"],
1957 [":str", "0-4", "peregrine"],
1958 [":str", "8-12", "gr"]
1959 ]"#;
1960
1961 let expression = Parser::new().parse_str(pel).unwrap();
1962 let result = Runtime::new()
1963 .eval(&expression)
1964 .unwrap()
1965 .complete()
1966 .unwrap();
1967
1968 assert_eq!(result.as_str().unwrap(), "pere");
1969 }
1970
1971 #[test]
1972 fn substring_before_string_null_fail() {
1973 let pel = r#"
1975 [":apply", "5-7",
1976 [":ref", "5-7", "substringBefore"],
1977 [":str", "0-4", "peregrine"],
1978 [":null", "8-12"]
1979 ]"#;
1980
1981 let expression = Parser::new().parse_str(pel).unwrap();
1982 let result = Runtime::new().eval(&expression).unwrap_err();
1983
1984 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
1985 }
1986
1987 #[test]
1988 fn substring_before_boolean_string() {
1989 let pel = r#"
1991 [":apply", "5-7",
1992 [":ref", "5-7", "substringBefore"],
1993 [":bool", "0-4", "true"],
1994 [":str", "8-12", "ue"]
1995 ]"#;
1996
1997 let expression = Parser::new().parse_str(pel).unwrap();
1998 let result = Runtime::new()
1999 .eval(&expression)
2000 .unwrap()
2001 .complete()
2002 .unwrap();
2003
2004 assert_eq!(result.as_str().unwrap(), "tr");
2005 }
2006
2007 #[test]
2008 fn substring_before_number_number() {
2009 let pel = r#"
2011 [":apply", "5-7",
2012 [":ref", "5-7", "substringBefore"],
2013 [":nbr", "0-4", "1234.56"],
2014 [":nbr", "8-12", "4.5"]
2015 ]"#;
2016
2017 let expression = Parser::new().parse_str(pel).unwrap();
2018 let result = Runtime::new()
2019 .eval(&expression)
2020 .unwrap()
2021 .complete()
2022 .unwrap();
2023
2024 assert_eq!(result.as_str().unwrap(), "123");
2025 }
2026
2027 #[test]
2028 fn substring_before_array_fail() {
2029 let pel = r#"
2031 [":apply", "5-7",
2032 [":ref", "5-7", "substringBefore"],
2033 [":array", "0-41",
2034 [":str", "1-9", "accept"],
2035 [":str", "10-27", "accept-encoding"],
2036 [":str", "28-40", "user-agent"]
2037 ],
2038 [":str", "1-10", "re"]
2039 ]
2040 "#;
2041
2042 let expression = Parser::new().parse_str(pel).unwrap();
2043 let result = Runtime::new().eval(&expression).unwrap_err();
2044
2045 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
2046 }
2047
2048 #[test]
2049 fn substring_before_not_found() {
2050 let pel = r#"
2052 [":apply", "5-7",
2053 [":ref", "5-7", "substringBefore"],
2054 [":str", "0-4", "peregrine"],
2055 [":str", "8-12", "XX"]
2056 ]"#;
2057
2058 let expression = Parser::new().parse_str(pel).unwrap();
2059 let result = Runtime::new()
2060 .eval(&expression)
2061 .unwrap()
2062 .complete()
2063 .unwrap();
2064
2065 assert_eq!(result.as_str().unwrap(), "");
2066 }
2067
2068 #[test]
2069 fn substring_before_empty_string() {
2070 let pel = r#"
2072 [":apply", "0-55",
2073 [":ref", "0-38", "substringBefore"],
2074 [":str", "39-50", "peregrine"],
2075 [":str", "52-54", ""]
2076 ]"#;
2077
2078 let expression = Parser::new().parse_str(pel).unwrap();
2079 let result = Runtime::new()
2080 .eval(&expression)
2081 .unwrap()
2082 .complete()
2083 .unwrap();
2084
2085 assert_eq!(result.as_str().unwrap(), "");
2086 }
2087
2088 #[test]
2089 fn substring_before_last_null_string() {
2090 let pel = r#"
2092 [":apply", "5-7",
2093 [":ref", "5-7", "substringBeforeLast"],
2094 [":null", "0-4"],
2095 [":str", "8-12", "peregrine"]
2096 ]"#;
2097
2098 let expression = Parser::new().parse_str(pel).unwrap();
2099 let result = Runtime::new()
2100 .eval(&expression)
2101 .unwrap()
2102 .complete()
2103 .unwrap();
2104
2105 assert!(result.is_null());
2106 }
2107
2108 #[test]
2109 fn substring_before_last_string_string() {
2110 let pel = r#"
2112 [":apply", "5-7",
2113 [":ref", "5-7", "substringBeforeLast"],
2114 [":str", "0-4", "Peregrine Expression Language"],
2115 [":str", "8-12", "re"]
2116 ]"#;
2117
2118 let expression = Parser::new().parse_str(pel).unwrap();
2119 let result = Runtime::new()
2120 .eval(&expression)
2121 .unwrap()
2122 .complete()
2123 .unwrap();
2124
2125 assert_eq!(result.as_str().unwrap(), "Peregrine Exp");
2126 }
2127
2128 #[test]
2129 fn substring_before_last_string_null_fail() {
2130 let pel = r#"
2132 [":apply", "5-7",
2133 [":ref", "5-7", "substringBeforeLast"],
2134 [":str", "0-4", "peregrine"],
2135 [":null", "8-12"]
2136 ]"#;
2137
2138 let expression = Parser::new().parse_str(pel).unwrap();
2139 let result = Runtime::new().eval(&expression).unwrap_err();
2140
2141 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
2142 }
2143
2144 #[test]
2145 fn substring_before_last_boolean_string() {
2146 let pel = r#"
2148 [":apply", "5-7",
2149 [":ref", "5-7", "substringBeforeLast"],
2150 [":bool", "0-4", "true"],
2151 [":str", "8-12", "ue"]
2152 ]"#;
2153
2154 let expression = Parser::new().parse_str(pel).unwrap();
2155 let result = Runtime::new()
2156 .eval(&expression)
2157 .unwrap()
2158 .complete()
2159 .unwrap();
2160
2161 assert_eq!(result.as_str().unwrap(), "tr");
2162 }
2163
2164 #[test]
2165 fn substring_before_last_number_number() {
2166 let pel = r#"
2168 [":apply", "5-7",
2169 [":ref", "5-7", "substringBeforeLast"],
2170 [":nbr", "0-4", "121235.123512"],
2171 [":nbr", "8-12", "12"]
2172 ]"#;
2173
2174 let expression = Parser::new().parse_str(pel).unwrap();
2175 let result = Runtime::new()
2176 .eval(&expression)
2177 .unwrap()
2178 .complete()
2179 .unwrap();
2180
2181 assert_eq!(result.as_str().unwrap(), "121235.1235");
2182 }
2183
2184 #[test]
2185 fn substring_before_last_array_fail() {
2186 let pel = r#"
2188 [":apply", "5-7",
2189 [":ref", "5-7", "substringBeforeLast"],
2190 [":array", "0-41",
2191 [":str", "1-9", "accept"],
2192 [":str", "10-27", "accept-encoding"],
2193 [":str", "28-40", "user-agent"]
2194 ],
2195 [":str", "1-10", "re"]
2196 ]
2197 "#;
2198
2199 let expression = Parser::new().parse_str(pel).unwrap();
2200 let result = Runtime::new().eval(&expression).unwrap_err();
2201
2202 assert_eq!(result.kind, RuntimeErrorKind::TypeMismatch);
2203 }
2204
2205 #[test]
2206 fn substring_before_last_not_found() {
2207 let pel = r#"
2209 [":apply", "5-7",
2210 [":ref", "5-7", "substringBeforeLast"],
2211 [":str", "0-4", "peregrine"],
2212 [":str", "8-12", "XX"]
2213 ]"#;
2214
2215 let expression = Parser::new().parse_str(pel).unwrap();
2216 let result = Runtime::new()
2217 .eval(&expression)
2218 .unwrap()
2219 .complete()
2220 .unwrap();
2221
2222 assert_eq!(result.as_str().unwrap(), "");
2223 }
2224
2225 #[test]
2226 fn substring_before_last_empty_string() {
2227 let pel = r#"
2229 [":apply", "0-55",
2230 [":ref", "0-38", "substringBeforeLast"],
2231 [":str", "39-50", "peregrine"],
2232 [":str", "52-54", ""]
2233 ]"#;
2234
2235 let expression = Parser::new().parse_str(pel).unwrap();
2236 let result = Runtime::new()
2237 .eval(&expression)
2238 .unwrap()
2239 .complete()
2240 .unwrap();
2241
2242 assert_eq!(result.as_str().unwrap(), "peregrin");
2243 }
2244
2245 #[test]
2246 fn upper_null() {
2247 let pel = r#"
2249 [":apply", "5-7",
2250 [":ref", "5-7", "upper"],
2251 [":null", "0-4"]
2252 ]
2253 "#;
2254
2255 let expression = Parser::new().parse_str(pel).unwrap();
2256 let result = Runtime::new()
2257 .eval(&expression)
2258 .unwrap()
2259 .complete()
2260 .unwrap();
2261
2262 assert!(result.is_null());
2263 }
2264
2265 #[test]
2266 fn upper_string() {
2267 let pel = r#"
2269 [":apply", "5-7",
2270 [":ref", "5-7", "upper"],
2271 [":str", "0-4", "Peregrine Expression Language"]
2272 ]
2273 "#;
2274
2275 let expression = Parser::new().parse_str(pel).unwrap();
2276 let result = Runtime::new()
2277 .eval(&expression)
2278 .unwrap()
2279 .complete()
2280 .unwrap();
2281
2282 assert_eq!("PEREGRINE EXPRESSION LANGUAGE", result.as_str().unwrap());
2283 }
2284
2285 #[test]
2286 fn upper_boolean() {
2287 let pel = r#"
2289 [":apply", "5-7",
2290 [":ref", "5-7", "upper"],
2291 [":bool", "0-4", "true"]
2292 ]
2293 "#;
2294
2295 let expression = Parser::new().parse_str(pel).unwrap();
2296 let result = Runtime::new()
2297 .eval(&expression)
2298 .unwrap()
2299 .complete()
2300 .unwrap();
2301
2302 assert_eq!("TRUE", result.as_str().unwrap());
2303 }
2304
2305 #[test]
2306 fn upper_number() {
2307 let pel = r#"
2309 [":apply", "5-7",
2310 [":ref", "5-7", "upper"],
2311 [":nbr", "0-4", "123.4"]
2312 ]
2313 "#;
2314
2315 let expression = Parser::new().parse_str(pel).unwrap();
2316 let result = Runtime::new()
2317 .eval(&expression)
2318 .unwrap()
2319 .complete()
2320 .unwrap();
2321
2322 assert_eq!("123.4", result.as_str().unwrap());
2323 }
2324
2325 #[test]
2326 fn upper_array_fail() {
2327 let pel = r#"
2329 [":apply", "5-7",
2330 [":ref", "5-7", "upper"],
2331 [":array", "0-41",
2332 [":str", "1-9", "accept"],
2333 [":str", "10-27", "accept-encoding"],
2334 [":str", "28-40", "user-agent"]
2335 ]
2336 ]
2337 "#;
2338
2339 let expression = Parser::new().parse_str(pel).unwrap();
2340 let error = Runtime::new().eval(&expression).unwrap_err();
2341
2342 assert_eq!(error.kind, RuntimeErrorKind::TypeMismatch);
2343 }
2344
2345 #[test]
2346 fn to_binary() {
2347 let pel = r#"[":apply", "0-46", [":ref", "0-29", "toBinary"], [":str", "30-36", "some"], [":str", "38-45", "UTF-8"]]"#;
2349
2350 let expression = Parser::new().parse_str(pel).unwrap();
2351 let result = Runtime::new()
2352 .eval(&expression)
2353 .unwrap()
2354 .complete()
2355 .unwrap();
2356
2357 assert_eq!(result.as_binary().unwrap(), "some".as_bytes());
2358 }
2359
2360 #[test]
2361 fn to_binary_not_enough_args() {
2362 let pel = r#"[":apply", "0-46", [":ref", "0-29", "toBinary"], [":str", "30-36", "some"]]"#;
2364
2365 let expression = Parser::new().parse_str(pel).unwrap();
2366 let result = Runtime::new().eval(&expression).unwrap_err();
2367
2368 assert_eq!(result.kind, RuntimeErrorKind::NotEnoughArguments);
2369 }
2370
2371 #[test]
2372 fn to_binary_to_many_args() {
2373 let pel = r#"[":apply", "0-46", [":ref", "0-29", "toBinary"], [":str", "30-36", "some"], [":str", "38-45", "UTF-8"], [":str", "38-45", "UTF-8"]]"#;
2375
2376 let expression = Parser::new().parse_str(pel).unwrap();
2377 let result = Runtime::new().eval(&expression).unwrap_err();
2378
2379 assert_eq!(result.kind, RuntimeErrorKind::TooManyArguments);
2380 }
2381
2382 #[test]
2383 fn to_binary_invalid_argument() {
2384 let pel = r#"[":apply", "0-46", [":ref", "0-29", "toBinary"], [":str", "30-36", "some"], [":str", "38-45", "UTF-32"]]"#;
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::TypeMismatch);
2391 }
2392
2393 #[test]
2394 fn from_binary() {
2395 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"]]"#;
2397
2398 let expression = Parser::new().parse_str(pel).unwrap();
2399 let result = Runtime::new()
2400 .eval(&expression)
2401 .unwrap()
2402 .complete()
2403 .unwrap();
2404
2405 assert_eq!(result.as_str(), Some("some"));
2406 }
2407
2408 #[test]
2409 fn from_binary_not_enough_args() {
2410 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"]]]"#;
2412
2413 let expression = Parser::new().parse_str(pel).unwrap();
2414 let result = Runtime::new().eval(&expression).unwrap_err();
2415
2416 assert_eq!(result.kind, RuntimeErrorKind::NotEnoughArguments);
2417 }
2418
2419 #[test]
2420 fn from_binary_to_many_args() {
2421 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"]]"#;
2423
2424 let expression = Parser::new().parse_str(pel).unwrap();
2425 let result = Runtime::new().eval(&expression).unwrap_err();
2426
2427 assert_eq!(result.kind, RuntimeErrorKind::TooManyArguments);
2428 }
2429
2430 #[test]
2431 fn from_binary_invalid_argument() {
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"]], [":str", "78-85", "UTF-32"]]"#;
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::TypeMismatch);
2439 }
2440
2441 #[test]
2442 fn from_base64() {
2443 let pel =
2445 r#"[":apply", "0-46", [":ref", "0-29", "fromBase64"], [":str", "30-36", "c29tZQ=="]]"#;
2446
2447 let expression = Parser::new().parse_str(pel).unwrap();
2448 let result = Runtime::new()
2449 .eval(&expression)
2450 .unwrap()
2451 .complete()
2452 .unwrap();
2453
2454 assert_eq!(result.as_binary().unwrap(), "some".as_bytes());
2455 }
2456
2457 #[test]
2458 fn from_base64_not_enough_args() {
2459 let pel = r#"[":apply", "0-46", [":ref", "0-29", "fromBase64"]]"#;
2461
2462 let expression = Parser::new().parse_str(pel).unwrap();
2463 let result = Runtime::new().eval(&expression).unwrap_err();
2464
2465 assert_eq!(result.kind, RuntimeErrorKind::NotEnoughArguments);
2466 }
2467
2468 #[test]
2469 fn from_base64_to_many_args() {
2470 let pel = r#"[":apply", "0-46", [":ref", "0-29", "fromBase64"], [":str", "30-36", "AA"], [":str", "38-45", "UTF-8"]]"#;
2472
2473 let expression = Parser::new().parse_str(pel).unwrap();
2474 let result = Runtime::new().eval(&expression).unwrap_err();
2475
2476 assert_eq!(result.kind, RuntimeErrorKind::TooManyArguments);
2477 }
2478
2479 #[test]
2480 fn from_base64_invalid_argument() {
2481 let pel = r#"[":apply", "0-46", [":ref", "0-29", "fromBase64"], [":str", "30-36", "0"]]"#;
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::TypeMismatch);
2488 }
2489
2490 #[test]
2491 fn to_base64() {
2492 let pel = r#"[":apply", "0-86", [":ref", "0-29", "toBase64"], [":apply", "30-76", [":ref", "30-59", "fromBase64"], [":str", "60-66", "AAAA"]]]"#;
2494
2495 let expression = Parser::new().parse_str(pel).unwrap();
2496 let result = Runtime::new()
2497 .eval(&expression)
2498 .unwrap()
2499 .complete()
2500 .unwrap();
2501
2502 assert_eq!(result.as_str(), Some("AAAA"));
2503 }
2504
2505 #[test]
2506 fn to_base64_not_enough_args() {
2507 let pel = r#"[":apply", "0-86", [":ref", "0-29", "toBase64"]]"#;
2509
2510 let expression = Parser::new().parse_str(pel).unwrap();
2511 let result = Runtime::new().eval(&expression).unwrap_err();
2512
2513 assert_eq!(result.kind, RuntimeErrorKind::NotEnoughArguments);
2514 }
2515
2516 #[test]
2517 fn to_base64_to_many_args() {
2518 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"]]"#;
2520
2521 let expression = Parser::new().parse_str(pel).unwrap();
2522 let result = Runtime::new().eval(&expression).unwrap_err();
2523
2524 assert_eq!(result.kind, RuntimeErrorKind::TooManyArguments);
2525 }
2526
2527 #[test]
2528 fn decode_basic_auth() {
2529 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"]]"#;
2531
2532 let expression = Parser::new().parse_str(pel).unwrap();
2533 let result = Runtime::new()
2534 .eval(&expression)
2535 .unwrap()
2536 .complete()
2537 .unwrap();
2538
2539 assert_eq!(result.as_str().unwrap(), "some:other");
2540 }
2541
2542 #[test]
2543 fn decode_basic_auth_auto_coerce() {
2544 let pel = r#"[":apply", "0-90", [":ref", "0-33", "substringAfter"], [":apply", "34-84", [":ref", "34-64", "fromBase64"], [":str", "65-83", "c29tZTpvdGhlcg=="]], [":str", "86-89", ":"]]"#;
2546
2547 let expression = Parser::new().parse_str(pel).unwrap();
2548 let result = Runtime::new()
2549 .eval(&expression)
2550 .unwrap()
2551 .complete()
2552 .unwrap();
2553
2554 assert_eq!(result.as_str().unwrap(), "other");
2555 }
2556
2557 #[test]
2558 fn encode_basic_auth() {
2559 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"]]]"#;
2561
2562 let expression = Parser::new().parse_str(pel).unwrap();
2563 let result = Runtime::new()
2564 .eval(&expression)
2565 .unwrap()
2566 .complete()
2567 .unwrap();
2568
2569 assert_eq!(result.as_str().unwrap(), "c29tZTpvdGhlcg==");
2570 }
2571
2572 #[test]
2573 fn encode_basic_auth_auto_coerce() {
2574 let pel =
2576 r#"[":apply", "0-0", [":ref", "0-28", "toBase64"], [":str", "0-0", "some:other"]]"#;
2577
2578 let expression = Parser::new().parse_str(pel).unwrap();
2579 let result = Runtime::new()
2580 .eval(&expression)
2581 .unwrap()
2582 .complete()
2583 .unwrap();
2584
2585 assert_eq!(result.as_str().unwrap(), "c29tZTpvdGhlcg==");
2586 }
2587
2588 #[test]
2589 fn multimap_return_full() {
2590 let origin = "<envelope><some>b</some></envelope>";
2591 let value = DocumentBuilder::root(
2592 QualifiedName::new("", "envelope"),
2593 Rc::new(origin.to_string()),
2594 0..origin.len(),
2595 )
2596 .with_element(QualifiedName::new("", "some"), 10..24)
2597 .with_text("b")
2598 .finish_element()
2599 .finish_element()
2600 .build();
2601
2602 let pel = r#"[":ref", "0-0", "payload"]"#;
2604
2605 assert_eq!(
2606 evaluate(pel, value).as_doc_node().unwrap().content(),
2607 Some(origin.to_string())
2608 )
2609 }
2610
2611 #[test]
2612 fn multimap_return_obj() {
2613 let origin = "<envelope><some>b</some></envelope>";
2614 let value = DocumentBuilder::root(
2615 QualifiedName::new("", "envelope"),
2616 Rc::new(origin.to_string()),
2617 0..origin.len(),
2618 )
2619 .with_element(QualifiedName::new("", "some"), 10..24)
2620 .with_text("b")
2621 .finish_element()
2622 .finish_element()
2623 .build();
2624
2625 let pel = r#"
2627 [".", "0-0",
2628 [":ref", "0-0", "payload"],
2629 [":str", "0-0", "envelope"]
2630 ]
2631 "#;
2632
2633 assert_eq!(
2634 evaluate(pel, value).as_doc_node().unwrap().content(),
2635 Some("<?xml version='1.0' encoding='UTF-8'?>\n<some>\n b\n</some>".to_string())
2636 )
2637 }
2638
2639 #[test]
2640 fn access_multimap_by_name() {
2641 let origin = "<envelope>b</envelope>";
2642 let value = DocumentBuilder::root(
2643 QualifiedName::new("", "envelope"),
2644 Rc::new(origin.to_string()),
2645 0..origin.len(),
2646 )
2647 .with_text("b")
2648 .finish_element()
2649 .build();
2650
2651 let pel = r#"
2653 ["==", "0-0",
2654 [":str", "0-0", "b"],
2655 [".", "0-0",
2656 [":ref", "0-0", "payload"],
2657 [":str", "0-0", "envelope"]
2658 ]
2659 ]
2660 "#;
2661
2662 evaluate_and_assert(pel, value, Value::bool(true))
2663 }
2664
2665 #[test]
2666 fn multimap_content() {
2667 let value = DocumentBuilder::root(
2668 QualifiedName::new("", "envelope"),
2669 Rc::new(Default::default()),
2670 0..0,
2671 )
2672 .with_element(QualifiedName::prefixed("s", "some-uri", "some"), 0..0)
2673 .with_attribute(
2674 QualifiedName::prefixed("s", "some-uri", "qualified"),
2675 "qualified",
2676 )
2677 .with_attribute(
2678 QualifiedName::prefixed("", "some-uri", "unqualified"),
2679 "unqualified",
2680 )
2681 .with_element(QualifiedName::prefixed("s", "some-uri", "first"), 0..0)
2682 .finish_element()
2683 .with_element(QualifiedName::prefixed("s", "some-uri", "second"), 0..0)
2684 .with_text("b")
2685 .finish_element()
2686 .finish_element()
2687 .finish_element()
2688 .build();
2689
2690 let pel = r#"
2692 [".", "0-0",
2693 [":ref", "0-0", "payload"],
2694 [":str", "0-0", "envelope"]
2695 ]
2696 "#;
2697
2698 assert_eq!(
2699 evaluate(pel, value.clone())
2700 .as_doc_node()
2701 .unwrap()
2702 .content(),
2703 Some(
2704 r#"<?xml version='1.0' encoding='UTF-8'?>
2705<s:some xmlns:s="some-uri" s:qualified="qualified" xmlns="some-uri" unqualified="unqualified">
2706 <s:first/>
2707 <s:second>
2708 b
2709 </s:second>
2710</s:some>"#
2711 .to_string()
2712 )
2713 );
2714
2715 let pel = r#"
2717 [".", "0-0",
2718 [".", "0-0",
2719 [":ref", "0-0", "payload"],
2720 [":str", "0-0", "envelope"]
2721 ],
2722 [":str", "0-0", "some"]
2723 ]
2724 "#;
2725
2726 assert_eq!(evaluate(pel, value).as_doc_node().unwrap().content(), None)
2727 }
2728
2729 #[test]
2730 fn access_multimap_by_qname() {
2731 let value = DocumentBuilder::root(
2733 QualifiedName::new("http://test.com", "envelope"),
2734 Rc::new("".to_string()),
2735 0..0,
2736 )
2737 .with_text("b")
2738 .finish_element()
2739 .build();
2740
2741 let pel = r#"
2743 ["==", "0-0",
2744 [":str", "0-0", "b"],
2745 [".", "0-0", [":ref", "0-0", "payload"], [":name", "0-0", [":ns", "0-0", "http://test.com"], [":str", "0-0", "envelope"]]]
2746 ]
2747 "#;
2748
2749 evaluate_and_assert(pel, value, Value::bool(true))
2750 }
2751
2752 #[test]
2753 fn access_multimap_attribute_by_name() {
2754 let value = DocumentBuilder::root(
2756 QualifiedName::new("http://test.com", "envelope"),
2757 Rc::new("".to_string()),
2758 0..0,
2759 )
2760 .with_attribute(QualifiedName::new("http://another.com", "attr"), "another")
2761 .with_attribute(QualifiedName::new("http://test.com", "attr"), "JJ")
2762 .with_text("b")
2763 .finish_element()
2764 .build();
2765
2766 let pel = r#"
2768 ["==", "0-0",
2769 [":str", "0-0", "another"],
2770 ["@", "0-0", [".", "0-0", [":ref", "0-0", "payload"], [":str", "0-0", "envelope"]], [":str", "0-0", "attr"]]
2771 ]
2772 "#;
2773
2774 evaluate_and_assert(pel, value, Value::bool(true))
2775 }
2776
2777 #[test]
2778 fn access_multimap_attribute_by_qname() {
2779 let value = DocumentBuilder::root(
2781 QualifiedName::new("http://test.com", "envelope"),
2782 Rc::new("".to_string()),
2783 0..0,
2784 )
2785 .with_attribute(QualifiedName::new("http://another.com", "attr"), "another")
2786 .with_attribute(QualifiedName::new("http://test.com", "attr"), "JJ")
2787 .with_text("b")
2788 .finish_element()
2789 .build();
2790
2791 let pel = r#"
2793 ["==", "0-0",
2794 [":str", "0-0", "JJ"],
2795 ["@", "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"]]]
2796 ]
2797 "#;
2798
2799 evaluate_and_assert(pel, value, Value::bool(true))
2800 }
2801
2802 #[test]
2803 fn access_multimap_by_non_existing_key() {
2804 let value = DocumentBuilder::root(
2806 QualifiedName::new("", "envelope"),
2807 Rc::new("".to_string()),
2808 0..0,
2809 )
2810 .with_text("b")
2811 .finish_element()
2812 .build();
2813
2814 let pel = r#"
2816 ["==", "0-0",
2817 [".", "0-0",
2818 [":ref", "0-0", "payload"],
2819 [":str", "0-0", "env"]
2820 ],
2821 [":null", "0-0"]
2822 ]
2823 "#;
2824 evaluate_and_assert(pel, value, Value::bool(true))
2825 }
2826
2827 #[test]
2828 fn access_multimap_by_repeated_key() {
2829 let value = DocumentBuilder::root(
2834 QualifiedName::new("", "envelope"),
2835 Rc::new("".to_string()),
2836 0..0,
2837 )
2838 .with_element(QualifiedName::new("", "a"), 0..0)
2839 .with_text("a1")
2840 .finish_element()
2841 .with_element(QualifiedName::new("", "a"), 0..0)
2842 .with_text("a2")
2843 .finish_element()
2844 .finish_element()
2845 .build();
2846
2847 let pel = r#"
2849 ["==", "0-0",
2850 [".", "0-0",
2851 [".", "0-0",
2852 [":ref", "0-0", "payload"],
2853 [":str", "0-0", "envelope"]
2854 ],
2855 [":str", "0-0", "a"]
2856 ],
2857 [":str", "0-0", "a1"]
2858 ]
2859 "#;
2860 evaluate_and_assert(pel, value, Value::bool(true))
2861 }
2862
2863 #[test]
2864 fn compare_multimaps() {
2865 let value = DocumentBuilder::root(
2870 QualifiedName::new("", "envelope"),
2871 Rc::new("".to_string()),
2872 0..0,
2873 )
2874 .with_element(QualifiedName::new("", "a1"), 0..0)
2875 .with_text("a")
2876 .with_element(QualifiedName::new("", "b"), 0..0)
2877 .finish_element()
2878 .finish_element()
2879 .with_element(QualifiedName::new("", "a2"), 0..0)
2880 .with_text("a")
2881 .with_element(QualifiedName::new("", "b"), 0..0)
2882 .finish_element()
2883 .finish_element()
2884 .finish_element()
2885 .build();
2886
2887 let pel = r#"
2889 ["==", "0-0",
2890 [".", "0-0",
2891 [".", "0-0",
2892 [":ref", "0-0", "payload"],
2893 [":str", "0-0", "envelope"]
2894 ],
2895 [":str", "0-0", "a1"]
2896 ],
2897 [".", "0-0",
2898 [".", "0-0",
2899 [":ref", "0-0", "payload"],
2900 [":str", "0-0", "envelope"]
2901 ],
2902 [":str", "0-0", "a2"]
2903 ]
2904 ]
2905 "#;
2906 evaluate_and_assert(pel, value, Value::bool(true))
2907 }
2908
2909 #[test]
2910 fn access_multimap_by_index() {
2911 let value = DocumentBuilder::root(
2913 QualifiedName::new("", "envelope"),
2914 Rc::new("".to_string()),
2915 0..0,
2916 )
2917 .with_text("b")
2918 .finish_element()
2919 .build();
2920
2921 let pel = r#"
2923 ["==", "0-0",
2924 [".", "0-0",
2925 [":ref", "0-0", "payload"],
2926 [":nbr", "0-0", "0"]
2927 ],
2928 [":str", "0-0", "b"]
2929 ]
2930 "#;
2931 evaluate_and_assert(pel, value, Value::bool(true))
2932 }
2933
2934 #[test]
2935 fn access_multimap_by_non_existing_index() {
2936 let value = DocumentBuilder::root(
2938 QualifiedName::new("", "envelope"),
2939 Rc::new("".to_string()),
2940 0..0,
2941 )
2942 .with_text("b")
2943 .finish_element()
2944 .build();
2945
2946 let pel = r#"
2948 ["==", "0-0",
2949 [".", "0-0",
2950 [":ref", "0-0", "payload"],
2951 [":nbr", "0-0", "1"]
2952 ],
2953 [":null", "0-0"]
2954 ]
2955 "#;
2956 evaluate_and_assert(pel, value, Value::bool(true))
2957 }
2958
2959 #[test]
2960 fn access_multimap_multivalue_by_name() {
2961 let value = DocumentBuilder::root(
2963 QualifiedName::new("http://test.com", "envelope"),
2964 Rc::new("".to_string()),
2965 0..0,
2966 )
2967 .with_element(QualifiedName::new("http://test.com", "b"), 0..0)
2968 .with_text("1")
2969 .finish_element()
2970 .with_element(QualifiedName::new("http://test.com", "b"), 0..0)
2971 .with_text("2")
2972 .finish_element()
2973 .finish_element()
2974 .build();
2975
2976 let pel = r#"
2977 ["*", "0-0", [".", "0-0", [":ref", "0-0", "payload"], [":str", "0-0", "envelope"]], [":str", "0-0", "b"]]
2978 "#;
2979
2980 let expected = Value::array(vec![Value::string("1"), Value::string("2")]);
2981 evaluate_and_assert(pel, value, expected)
2982 }
2983
2984 #[test]
2985 fn access_multimap_multivalue_by_qname() {
2986 let value = DocumentBuilder::root(
2988 QualifiedName::new("http://test.com", "envelope"),
2989 Rc::new("".to_string()),
2990 0..0,
2991 )
2992 .with_element(QualifiedName::new("http://test.com", "b"), 0..0)
2993 .with_text("1")
2994 .finish_element()
2995 .with_element(QualifiedName::new("http://other.com", "b"), 0..0)
2996 .with_text("2")
2997 .finish_element()
2998 .with_element(QualifiedName::new("http://test.com", "b"), 0..0)
2999 .with_text("3")
3000 .finish_element()
3001 .finish_element()
3002 .build();
3003
3004 let pel = r#"
3005 ["*", "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"]]]
3006 "#;
3007
3008 let expected = Value::array(vec![Value::string("1"), Value::string("3")]);
3009 evaluate_and_assert(pel, value, expected)
3010 }
3011
3012 #[cfg(feature = "experimental_coerced_type")]
3013 #[test]
3014 fn multimap_root_coerced() {
3015 let origin = "<envelope><some>b</some></envelope>";
3016 let value = DocumentBuilder::root(
3017 QualifiedName::new("", "envelope"),
3018 Rc::new(origin.to_string()),
3019 0..origin.len(),
3020 )
3021 .with_element(QualifiedName::new("", "some"), 10..24)
3022 .with_text("b")
3023 .finish_element()
3024 .finish_element()
3025 .build();
3026
3027 let pel = r#"[":apply", "0-0", [":ref", "0-0", "++"], [":ref", "0-0", "payload"], [":str", "0-0", "envelope"]]"#;
3029
3030 assert_eq!(
3031 evaluate(pel, value.clone()).as_str().unwrap(),
3032 origin.to_string() + "envelope"
3033 );
3034
3035 let pel = r#"[":apply", "0-0", [":ref", "0-0", "++"], [":str", "0-0", "envelope"], [":ref", "0-0", "payload"]]"#;
3037 assert_eq!(
3038 evaluate(pel, value.clone()).as_str().unwrap(),
3039 "envelope".to_string() + origin
3040 );
3041
3042 let pel = r#"
3044 ["==", "0-0",
3045 [":ref", "0-0", "payload"],
3046 [":str", "0-0", "<envelope><some>b</some></envelope>"]
3047 ]
3048 "#;
3049 assert!(evaluate(pel, value).as_bool().unwrap());
3050 }
3051
3052 #[test]
3053 fn multimap_not_coerced() {
3054 let origin = "<envelope><some>b</some></envelope>";
3055 let value = DocumentBuilder::root(
3056 QualifiedName::new("", "envelope"),
3057 Rc::new(origin.to_string()),
3058 0..origin.len(),
3059 )
3060 .with_element(QualifiedName::new("", "some"), 10..24)
3061 .with_text("b")
3062 .finish_element()
3063 .finish_element()
3064 .build();
3065
3066 let pel = r#"[":apply", "0-0",
3068 [":ref", "0-0", "++"],
3069 [".", "0-0",
3070 [":ref", "0-0", "payload"],
3071 [":str", "0-0", "envelope"]
3072 ],
3073 [":str", "0-0", "envelope"]
3074 ]"#;
3075
3076 assert_eq!(
3077 &RuntimeErrorKind::TypeMismatch,
3078 evaluate_error(pel, value.clone()).kind(),
3079 );
3080
3081 let pel = r#"
3083 ["==", "0-0",
3084 [".", "0-0",
3085 [":ref", "0-0", "payload"],
3086 [":str", "0-0", "envelope"]
3087 ],
3088 [":str", "0-0", "<some>b</some>"]
3089 ]
3090 "#;
3091 assert!(!evaluate(pel, value).as_bool().unwrap());
3092 }
3093
3094 #[cfg(feature = "experimental_coerced_type")]
3095 #[test]
3096 fn object_root_coerced() {
3097 let origin = r#"{"envelope":{"some":"value"}}"#;
3098 let value = Value::coerced_object(
3099 HashMap::from([(
3100 "envelope".to_string(),
3101 Value::object(HashMap::from([(
3102 "some".to_string(),
3103 Value::string("value"),
3104 )])),
3105 )]),
3106 Rc::new(origin.to_string()),
3107 );
3108
3109 let pel = r#"[":apply", "0-0", [":ref", "0-0", "++"], [":ref", "0-0", "payload"], [":str", "0-0", "envelope"]]"#;
3111
3112 assert_eq!(
3113 evaluate(pel, value.clone()).as_str().unwrap(),
3114 origin.to_string() + "envelope"
3115 );
3116
3117 let pel = r#"[":apply", "0-0", [":ref", "0-0", "++"], [":str", "0-0", "envelope"], [":ref", "0-0", "payload"]]"#;
3119 assert_eq!(
3120 evaluate(pel, value.clone()).as_str().unwrap(),
3121 "envelope".to_string() + origin
3122 );
3123
3124 let pel = r#"
3126 ["==", "0-0",
3127 [":ref", "0-0", "payload"],
3128 [":str", "0-0", "{\"envelope\":{\"some\":\"value\"}}"]
3129 ]
3130 "#;
3131 assert!(evaluate(pel, value).as_bool().unwrap());
3132 }
3133
3134 #[test]
3135 fn object_not_coerced() {
3136 #[cfg(feature = "experimental_coerced_type")]
3137 let origin = r#"{"envelope":{"some":"value"}}"#;
3138
3139 let map = HashMap::from([(
3140 "envelope".to_string(),
3141 Value::object(HashMap::from([(
3142 "some".to_string(),
3143 Value::string("value"),
3144 )])),
3145 )]);
3146
3147 #[cfg(feature = "experimental_coerced_type")]
3148 let value = Value::coerced_object(map, Rc::new(origin.to_string()));
3149
3150 #[cfg(not(feature = "experimental_coerced_type"))]
3151 let value = Value::object(map);
3152
3153 let pel = r#"[":apply", "0-0",
3155 [":ref", "0-0", "++"],
3156 [".", "0-0",
3157 [":ref", "0-0", "payload"],
3158 [":str", "0-0", "envelope"]
3159 ],
3160 [":str", "0-0", "envelope"]
3161 ]"#;
3162
3163 assert_eq!(
3164 &RuntimeErrorKind::TypeMismatch,
3165 evaluate_error(pel, value.clone()).kind(),
3166 );
3167
3168 let pel = r#"
3170 ["==", "0-0",
3171 [".", "0-0",
3172 [":ref", "0-0", "payload"],
3173 [":str", "0-0", "envelope"]
3174 ],
3175 [":str", "0-0", "{\"some\":\"value\"}"]
3176 ]
3177 "#;
3178 assert!(!evaluate(pel, value).as_bool().unwrap());
3179 }
3180
3181 fn evaluate_error(pel: &str, payload: Value) -> RuntimeError {
3182 let context: Prelude = HashMap::from([("payload", payload)]);
3183
3184 let expression = Parser::new().parse_str(pel).unwrap();
3185 Runtime::new()
3186 .eval_with_context(&expression, &context)
3187 .err()
3188 .unwrap()
3189 }
3190
3191 fn evaluate(pel: &str, payload: Value) -> Value {
3192 let context: Prelude = HashMap::from([("payload", payload)]);
3193
3194 let expression = Parser::new().parse_str(pel).unwrap();
3195 Runtime::new()
3196 .eval_with_context(&expression, &context)
3197 .unwrap()
3198 .complete()
3199 .unwrap()
3200 }
3201
3202 fn evaluate_and_assert(pel: &str, payload: Value, expected: Value) {
3203 assert_eq!(evaluate(pel, payload), expected)
3204 }
3205
3206 mod partial_evaluation {
3207 use std::collections::HashMap;
3208
3209 use crate::{
3210 expression::Symbol,
3211 parser::Parser,
3212 runtime::{value::Value, Binding, Context, Runtime, ValueHandler},
3213 Reference,
3214 };
3215
3216 struct TestContextChain {
3217 contexts: Vec<HashMap<String, Value>>,
3218 }
3219
3220 impl TestContextChain {
3221 fn new<const N: usize>(entries: [(&str, Value); N]) -> Self {
3222 Self { contexts: vec![] }.then(entries)
3223 }
3224
3225 fn then<const N: usize>(mut self, entries: [(&str, Value); N]) -> Self {
3226 self.contexts
3227 .push(entries.map(|(k, v)| (k.to_string(), v)).into());
3228 self
3229 }
3230
3231 fn next(mut self) -> Self {
3232 self.contexts.remove(0);
3233 self
3234 }
3235 }
3236
3237 impl Context for TestContextChain {
3238 fn resolve(&self, symbol: &Symbol) -> Binding {
3239 let s = symbol.as_str();
3240 match self.contexts.first().expect("Empty context").get(s) {
3241 Some(value) => Binding::Available(value.clone()),
3242 None => {
3243 if self.contexts.iter().any(|c| c.contains_key(s)) {
3244 Binding::Pending
3245 } else {
3246 Binding::Unknown
3247 }
3248 }
3249 }
3250 }
3251
3252 fn value_handler(&self, _reference: Reference) -> Option<&dyn ValueHandler> {
3253 None
3254 }
3255 }
3256
3257 #[test]
3258 fn if_else_pending_condition() {
3259 let runtime = Runtime::new();
3260 let parser = Parser::new();
3261
3262 let context_1 = TestContextChain::new([("a", Value::string("ctx1".to_string()))])
3263 .then([("condition", Value::bool(true))])
3264 .then([("b", Value::string("ctx3".to_string()))]);
3265
3266 let pel_1 = r#"[":if", "0-23", [":ref", "4-9", "condition"], [":ref", "11-14", "a"], [":ref", "20-23", "b"]]"#;
3268
3269 let expression_1 = parser.parse_str(pel_1).unwrap();
3270 let expression_2 = runtime
3271 .eval_with_context(&expression_1, &context_1)
3272 .unwrap()
3273 .partial()
3274 .unwrap();
3275
3276 let pel_2 = r#"[":if", "0-23", [":ref", "4-9", "condition"], [":str", "11-14", "ctx1"], [":ref", "20-23", "b"]]"#;
3278
3279 assert_eq!(expression_2, parser.parse_str(pel_2).unwrap());
3280
3281 let context_2 = context_1.next();
3282 let result = runtime
3283 .eval_with_context(&expression_2, &context_2)
3284 .unwrap()
3285 .complete()
3286 .unwrap();
3287
3288 assert_eq!(result.as_str().unwrap(), "ctx1");
3289 }
3290
3291 #[test]
3292 fn if_else_pending_true_branch() {
3293 let runtime = Runtime::new();
3294 let parser = Parser::new();
3295
3296 let context_1 = TestContextChain::new([("a", Value::string("ctx1".to_string()))])
3297 .then([("b", Value::string("ctx2".to_string()))]);
3298
3299 let pel_1 = r#"[":if", "0-23", [":bool", "4-9", "true"], [":ref", "11-14", "b"], [":ref", "20-23", "a"]]"#;
3301
3302 let expression_1 = parser.parse_str(pel_1).unwrap();
3303 let expression_2 = runtime
3304 .eval_with_context(&expression_1, &context_1)
3305 .unwrap()
3306 .partial()
3307 .unwrap();
3308
3309 let pel_2 = r#"[":ref", "11-14", "b"]"#;
3310
3311 assert_eq!(expression_2, parser.parse_str(pel_2).unwrap());
3312
3313 let context_2 = context_1.next();
3314 let result = runtime
3315 .eval_with_context(&expression_2, &context_2)
3316 .unwrap()
3317 .complete()
3318 .unwrap();
3319
3320 assert_eq!(result.as_str().unwrap(), "ctx2");
3321 }
3322
3323 #[test]
3324 fn if_else_pending_false_branch() {
3325 let runtime = Runtime::new();
3326 let parser = Parser::new();
3327
3328 let context_1 = TestContextChain::new([("a", Value::string("ctx1".to_string()))])
3329 .then([("b", Value::string("ctx2".to_string()))]);
3330
3331 let pel_1 = r#"[":if", "0-23", [":bool", "4-9", "false"], [":ref", "11-14", "a"], [":ref", "20-23", "b"]]"#;
3333
3334 let expression_1 = parser.parse_str(pel_1).unwrap();
3335 let expression_2 = runtime
3336 .eval_with_context(&expression_1, &context_1)
3337 .unwrap()
3338 .partial()
3339 .unwrap();
3340
3341 let pel_2 = r#"[":ref", "20-23", "b"]"#;
3342
3343 assert_eq!(expression_2, parser.parse_str(pel_2).unwrap());
3344
3345 let context_2 = context_1.next();
3346 let result = runtime
3347 .eval_with_context(&expression_2, &context_2)
3348 .unwrap()
3349 .complete()
3350 .unwrap();
3351
3352 assert_eq!(result.as_str().unwrap(), "ctx2");
3353 }
3354
3355 #[test]
3356 fn default_left_unavailable() {
3357 let runtime = Runtime::new();
3358 let parser = Parser::new();
3359
3360 let context_1 = TestContextChain::new([("right", Value::string("ctx1".to_string()))])
3361 .then([("left", Value::null())]);
3362
3363 let pel_1 = r#"
3365 [":default", "0-6",
3366 [":ref", "0-1", "left"],
3367 [":ref", "5-6", "right"]
3368 ]
3369 "#;
3370
3371 let expression_1 = parser.parse_str(pel_1).unwrap();
3372 let expression_2 = runtime
3373 .eval_with_context(&expression_1, &context_1)
3374 .unwrap()
3375 .partial()
3376 .unwrap();
3377
3378 let pel_2 = r#"
3380 [":default", "0-6",
3381 [":ref", "0-1", "left"],
3382 [":str", "5-6", "ctx1"]
3383 ]
3384 "#;
3385
3386 assert_eq!(expression_2, parser.parse_str(pel_2).unwrap());
3387
3388 let context_2 = context_1.next();
3389 let result = runtime
3390 .eval_with_context(&expression_2, &context_2)
3391 .unwrap()
3392 .complete()
3393 .unwrap();
3394
3395 assert_eq!(result.as_str().unwrap(), "ctx1");
3396 }
3397
3398 #[test]
3399 fn default_right_unavailable() {
3400 let runtime = Runtime::new();
3401 let parser = Parser::new();
3402
3403 let context_1 = TestContextChain::new([("left", Value::null())])
3404 .then([("right", Value::string("ctx1".to_string()))]);
3405
3406 let pel_1 = r#"
3408 [":default", "0-6",
3409 [":ref", "0-1", "left"],
3410 [":ref", "5-6", "right"]
3411 ]
3412 "#;
3413
3414 let expression_1 = parser.parse_str(pel_1).unwrap();
3415 let expression_2 = runtime
3416 .eval_with_context(&expression_1, &context_1)
3417 .unwrap()
3418 .partial()
3419 .unwrap();
3420
3421 let pel_2 = r#"
3423 [":ref", "5-6", "right"]
3424 "#;
3425
3426 assert_eq!(expression_2, parser.parse_str(pel_2).unwrap());
3427
3428 let context_2 = context_1.next();
3429 let result = runtime
3430 .eval_with_context(&expression_2, &context_2)
3431 .unwrap()
3432 .complete()
3433 .unwrap();
3434
3435 assert_eq!(result.as_str().unwrap(), "ctx1");
3436 }
3437 }
3438}