1use crate::expr::Expr;
16use crate::ArmPattern;
17
18mod writer;
19
20use crate::text::writer::WriterError;
21
22pub fn from_string(input: impl AsRef<str>) -> Result<Expr, String> {
23 let trimmed = input.as_ref().trim();
24
25 if trimmed.starts_with("${") && trimmed.ends_with("}") {
29 let trimmed_open = trimmed.strip_prefix("${").unwrap();
30 let trimmed_closing = trimmed_open.strip_suffix('}').unwrap();
31 Expr::from_text(trimmed_closing)
32 } else {
33 Expr::from_text(input.as_ref())
34 }
35}
36
37pub fn to_string(expr: &Expr) -> Result<String, WriterError> {
38 writer::write_expr(expr)
39}
40
41pub fn to_string_arm_pattern(arm_pattern: &ArmPattern) -> Result<String, WriterError> {
42 writer::write_arm_pattern(arm_pattern)
43}
44
45#[cfg(test)]
46mod interpolation_tests {
47 use test_r::test;
48
49 use crate::{text, Expr};
50
51 #[test]
52 fn test_expr_wrapped_in_interpolation() {
53 let input = r#"${foo}"#;
54 let result = text::from_string(input);
55 assert_eq!(result, Ok(Expr::identifier_global("foo", None)));
56
57 let input = r#"${{foo}}"#;
58 let result = text::from_string(input);
59 assert_eq!(result, Ok(Expr::flags(vec!["foo".to_string()])));
60
61 let input = r#"${{foo: "bar"}}"#;
62 let result = text::from_string(input);
63 assert_eq!(
64 result,
65 Ok(Expr::record(vec![(
66 "foo".to_string(),
67 Expr::literal("bar")
68 )]))
69 );
70 }
71}
72
73#[cfg(test)]
74mod record_tests {
75 use bigdecimal::BigDecimal;
76 use test_r::test;
77
78 use crate::expr::*;
79 use crate::text::{from_string, to_string, Expr};
80 use crate::MatchArm;
81
82 #[test]
83 fn test_round_trip_simple_record_single() {
84 let input_expr = Expr::record(vec![(
85 "field".to_string(),
86 Expr::identifier_global("request", None),
87 )]);
88 let expr_str = to_string(&input_expr).unwrap();
89 let expected_str = "{field: request}".to_string();
90 let output_expr = from_string(expr_str.as_str()).unwrap();
91 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
92 }
93
94 #[test]
95 fn test_round_trip_read_write_record_multiple() {
96 let input_expr = Expr::record(vec![
97 (
98 "field1".to_string(),
99 Expr::identifier_global("request", None),
100 ),
101 (
102 "field2".to_string(),
103 Expr::identifier_global("request", None),
104 ),
105 ]);
106 let expr_str = to_string(&input_expr).unwrap();
107 let expected_str = "{field1: request, field2: request}".to_string();
108 let output_expr = from_string(expr_str.as_str()).unwrap();
109 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
110 }
111
112 #[test]
113 fn test_round_trip_read_write_record_of_literal() {
114 let input_expr = Expr::record(vec![
115 ("field1".to_string(), Expr::literal("hello")),
116 ("field2".to_string(), Expr::literal("world")),
117 ]);
118 let expr_str = to_string(&input_expr).unwrap();
119 let expected_str = r#"{field1: "hello", field2: "world"}"#.to_string();
120 let output_expr = from_string(expr_str.as_str()).unwrap();
121 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
122 }
123
124 #[test]
125 fn test_round_trip_read_write_record_of_number() {
126 let input_expr = Expr::record(vec![
127 ("field1".to_string(), Expr::number(BigDecimal::from(1))),
128 ("field2".to_string(), Expr::number(BigDecimal::from(2))),
129 ]);
130 let expr_str = to_string(&input_expr).unwrap();
131 let expected_str = "{field1: 1, field2: 2}".to_string();
132 let output_expr = from_string(expr_str.as_str()).unwrap();
133 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
134 }
135
136 #[test]
137 fn test_round_trip_read_write_record_of_select_field() {
138 let input_expr = Expr::record(vec![
139 (
140 "field1".to_string(),
141 Expr::select_field(Expr::identifier_global("request", None), "foo", None),
142 ),
143 (
144 "field2".to_string(),
145 Expr::select_field(Expr::identifier_global("request", None), "bar", None),
146 ),
147 ]);
148 let expr_str = to_string(&input_expr).unwrap();
149 let expected_str = "{field1: request.foo, field2: request.bar}".to_string();
150 let output_expr = from_string(expr_str.as_str()).unwrap();
151 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
152 }
153
154 #[test]
155 fn test_round_trip_read_write_record_of_select_index() {
156 let input_expr = Expr::record(vec![
157 (
158 "field1".to_string(),
159 Expr::select_index(
160 Expr::identifier_global("request", None),
161 Expr::number(BigDecimal::from(1)),
162 ),
163 ),
164 (
165 "field2".to_string(),
166 Expr::select_index(
167 Expr::identifier_global("request", None),
168 Expr::number(BigDecimal::from(2)),
169 ),
170 ),
171 ]);
172 let expr_str = to_string(&input_expr).unwrap();
173 let expected_str = "{field1: request[1], field2: request[2]}".to_string();
174 let output_expr = from_string(expr_str.as_str()).unwrap();
175 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
176 }
177
178 #[test]
179 fn test_round_trip_read_write_record_of_sequence() {
180 let input_expr = Expr::record(vec![
181 (
182 "field1".to_string(),
183 Expr::sequence(
184 vec![
185 Expr::identifier_global("request", None),
186 Expr::identifier_global("request", None),
187 ],
188 None,
189 ),
190 ),
191 (
192 "field2".to_string(),
193 Expr::sequence(
194 vec![
195 Expr::identifier_global("request", None),
196 Expr::identifier_global("request", None),
197 ],
198 None,
199 ),
200 ),
201 ]);
202 let expr_str = to_string(&input_expr).unwrap();
203 let expected_str = "{field1: [request, request], field2: [request, request]}".to_string();
204 let output_expr = from_string(expr_str.as_str()).unwrap();
205 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
206 }
207
208 #[test]
209 fn test_round_trip_read_write_record_of_record() {
210 let input_expr = Expr::record(vec![
211 (
212 "a".to_string(),
213 Expr::record(vec![
214 ("ab".to_string(), Expr::identifier_global("request", None)),
215 ("ac".to_string(), Expr::identifier_global("request", None)),
216 ]),
217 ),
218 (
219 "b".to_string(),
220 Expr::sequence(
221 vec![Expr::record(vec![
222 ("bc".to_string(), Expr::identifier_global("request", None)),
223 ("bd".to_string(), Expr::identifier_global("request", None)),
224 ])],
225 None,
226 ),
227 ),
228 ]);
229 let expr_str = to_string(&input_expr).unwrap();
230 let expected_record_str =
231 "{a: {ab: request, ac: request}, b: [{bc: request, bd: request}]}".to_string();
232 let output_expr = from_string(expr_str.as_str()).unwrap();
233 assert_eq!((expr_str, input_expr), (expected_record_str, output_expr));
234 }
235
236 #[test]
237 fn test_round_trip_read_write_record_of_tuple() {
238 let input_expr = Expr::record(vec![
239 (
240 "a".to_string(),
241 Expr::tuple(vec![
242 Expr::identifier_global("request", None),
243 Expr::identifier_global("worker", None),
244 ]),
245 ),
246 (
247 "b".to_string(),
248 Expr::tuple(vec![
249 Expr::identifier_global("request", None),
250 Expr::identifier_global("worker", None),
251 ]),
252 ),
253 ]);
254 let expr_str = to_string(&input_expr).unwrap();
255 let expected_record_str = "{a: (request, worker), b: (request, worker)}".to_string();
256 let output_expr = from_string(expr_str.as_str()).unwrap();
257 assert_eq!((expr_str, input_expr), (expected_record_str, output_expr));
258 }
259
260 #[test]
261 fn test_round_trip_read_write_record_of_flags() {
262 let input_expr = Expr::record(vec![
263 (
264 "a".to_string(),
265 Expr::flags(vec!["flag1".to_string(), "flag2".to_string()]),
266 ),
267 (
268 "b".to_string(),
269 Expr::flags(vec!["flag3".to_string(), "flag4".to_string()]),
270 ),
271 ]);
272 let expr_str = to_string(&input_expr).unwrap();
273 let expected_record_str = "{a: {flag1, flag2}, b: {flag3, flag4}}".to_string();
274 let output_expr = from_string(expr_str.as_str()).unwrap();
275 assert_eq!((expr_str, input_expr), (expected_record_str, output_expr));
276 }
277
278 #[test]
279 fn test_round_trip_read_write_record_of_boolean() {
280 let input_expr = Expr::record(vec![
281 ("a".to_string(), Expr::boolean(true)),
282 ("b".to_string(), Expr::boolean(false)),
283 ]);
284 let expr_str = to_string(&input_expr).unwrap();
285 let expected_record_str = "{a: true, b: false}".to_string();
286 let output_expr = from_string(expr_str.as_str()).unwrap();
287 assert_eq!((expr_str, input_expr), (expected_record_str, output_expr));
288 }
289
290 #[test]
291 fn test_round_trip_read_write_record_of_concatenation() {
292 let input_expr = Expr::record(vec![
293 (
294 "a".to_string(),
295 Expr::concat(vec![
296 Expr::literal("user-id-1-"),
297 Expr::select_field(Expr::identifier_global("request", None), "user-id-1", None),
298 ]),
299 ),
300 (
301 "b".to_string(),
302 Expr::concat(vec![
303 Expr::literal("user-id-2-"),
304 Expr::select_field(Expr::identifier_global("request", None), "user-id-2", None),
305 ]),
306 ),
307 ]);
308 let expr_str = to_string(&input_expr).unwrap();
309 let expected_record_str =
310 r#"{a: "user-id-1-${request.user-id-1}", b: "user-id-2-${request.user-id-2}"}"#
311 .to_string();
312 let output_expr = from_string(expr_str.as_str()).unwrap();
313 assert_eq!((expr_str, input_expr), (expected_record_str, output_expr));
314 }
315
316 #[test]
317 fn test_round_trip_read_write_record_of_math_op() {
318 let input_expr = Expr::record(vec![
319 (
320 "a".to_string(),
321 Expr::greater_than(
322 Expr::number(BigDecimal::from(1)),
323 Expr::number(BigDecimal::from(2)),
324 ),
325 ),
326 (
327 "b".to_string(),
328 Expr::less_than(
329 Expr::number(BigDecimal::from(1)),
330 Expr::number(BigDecimal::from(2)),
331 ),
332 ),
333 ]);
334 let expr_str = to_string(&input_expr).unwrap();
335 let expected_record_str = "{a: 1 > 2, b: 1 < 2}".to_string();
336 let output_expr = from_string(expr_str.as_str()).unwrap();
337 assert_eq!((expr_str, input_expr), (expected_record_str, output_expr));
338 }
339
340 #[test]
341 fn test_round_trip_read_write_record_of_if_condition() {
342 let input_expr = Expr::record(vec![
343 (
344 "a".to_string(),
345 Expr::cond(
346 Expr::equal_to(
347 Expr::select_field(Expr::identifier_global("request", None), "foo", None),
348 Expr::literal("bar"),
349 ),
350 Expr::literal("success"),
351 Expr::literal("failed"),
352 ),
353 ),
354 (
355 "b".to_string(),
356 Expr::cond(
357 Expr::equal_to(
358 Expr::select_field(Expr::identifier_global("request", None), "foo", None),
359 Expr::literal("bar"),
360 ),
361 Expr::literal("success"),
362 Expr::literal("failed"),
363 ),
364 ),
365 ]);
366 let expr_str = to_string(&input_expr).unwrap();
367 let expected_record_str = r#"{a: if request.foo == "bar" then "success" else "failed", b: if request.foo == "bar" then "success" else "failed"}"#.to_string();
368 let output_expr = from_string(expr_str.as_str()).unwrap();
369 assert_eq!((expr_str, input_expr), (expected_record_str, output_expr));
370 }
371
372 #[test]
373 fn test_round_trip_read_write_record_of_pattern_match() {
374 let input_expr = Expr::record(vec![
375 (
376 "a".to_string(),
377 Expr::pattern_match(
378 Expr::identifier_global("request", None),
379 vec![
380 MatchArm::new(
381 ArmPattern::constructor(
382 "ok",
383 vec![ArmPattern::literal(Expr::identifier_global("foo", None))],
384 ),
385 Expr::literal("success"),
386 ),
387 MatchArm::new(
388 ArmPattern::constructor(
389 "err",
390 vec![ArmPattern::literal(Expr::identifier_global("msg", None))],
391 ),
392 Expr::literal("failure"),
393 ),
394 ],
395 ),
396 ),
397 (
398 "b".to_string(),
399 Expr::pattern_match(
400 Expr::identifier_global("request", None),
401 vec![
402 MatchArm::new(
403 ArmPattern::constructor(
404 "ok",
405 vec![ArmPattern::literal(Expr::identifier_global("foo", None))],
406 ), Expr::literal("success"),
408 ),
409 MatchArm::new(
410 ArmPattern::constructor(
411 "err",
412 vec![ArmPattern::literal(Expr::identifier_global("msg", None))],
413 ),
414 Expr::pattern_match(
415 Expr::identifier_global("request", None),
416 vec![
417 MatchArm::new(
418 ArmPattern::constructor(
419 "ok",
420 vec![ArmPattern::literal(Expr::identifier_global(
421 "foo", None,
422 ))],
423 ),
424 Expr::literal("success"),
425 ),
426 MatchArm::new(
427 ArmPattern::constructor(
428 "err",
429 vec![ArmPattern::literal(Expr::identifier_global(
430 "msg", None,
431 ))],
432 ),
433 Expr::literal("failure"),
434 ),
435 ],
436 ),
437 ),
438 ],
439 ),
440 ),
441 ]);
442
443 let expr_str = to_string(&input_expr).unwrap();
444 let expected_record_str = r#"{a: match request { ok(foo) => "success", err(msg) => "failure" } , b: match request { ok(foo) => "success", err(msg) => match request { ok(foo) => "success", err(msg) => "failure" } } }"#.to_string();
445 let output_expr = from_string(expr_str.as_str()).unwrap();
446 assert_eq!((expr_str, input_expr), (expected_record_str, output_expr));
447 }
448
449 #[test]
450 fn test_round_trip_record_of_constructor() {
451 let input_expr = Expr::record(vec![
452 ("a".to_string(), Expr::ok(Expr::literal("foo"), None)),
453 ("b".to_string(), Expr::err(Expr::literal("msg"), None)),
454 ]);
455 let expr_str = to_string(&input_expr).unwrap();
456 let expected_record_str = r#"{a: ok("foo"), b: err("msg")}"#.to_string();
457 let output_expr = from_string(expr_str.as_str()).unwrap();
458 assert_eq!((expr_str, input_expr), (expected_record_str, output_expr));
459 }
460
461 #[test]
462 fn test_round_trip_record_literal_invalid() {
463 let expr_str = r#"
464 {body: golem:component/api.{get-character}(), headers: { x-test: 'foobar' } }
465 "#;
466
467 let result = from_string(expr_str);
468
469 assert!(result.is_err());
470
471 let expr_str = r#"
472 {body: golem:component/api.{get-character}(), headers: { x-test: "foobar" } }
473 "#;
474
475 let result = from_string(expr_str);
476
477 assert!(result.is_ok());
478 }
479}
480
481#[cfg(test)]
482mod sequence_tests {
483 use bigdecimal::BigDecimal;
484 use test_r::test;
485
486 use crate::expr::Expr;
487 use crate::text::{from_string, to_string};
488 use crate::{ArmPattern, MatchArm};
489
490 #[test]
491 fn test_round_trip_read_write_sequence_empty() {
492 let input_expr = Expr::sequence(vec![], None);
493 let expr_str = to_string(&input_expr).unwrap();
494 let expected_str = "[]".to_string();
495 let output_expr = from_string(expr_str.as_str()).unwrap();
496 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
497 }
498
499 #[test]
501 fn test_sequence_of_records_singleton() {
502 let expr_string = "[{bc: request}]";
503 let output_expr = from_string(expr_string).unwrap();
504 let expected_expr = Expr::sequence(
505 vec![Expr::record(vec![(
506 "bc".to_string(),
507 Expr::identifier_global("request", None),
508 )])],
509 None,
510 );
511 assert_eq!(output_expr, expected_expr);
512 }
513
514 #[test]
515 fn test_round_trip_read_write_sequence_of_request() {
516 let input_expr = Expr::sequence(
517 vec![
518 Expr::identifier_global("request", None),
519 Expr::identifier_global("request", None),
520 ],
521 None,
522 );
523 let expr_str = to_string(&input_expr).unwrap();
524 let expected_str = "[request, request]".to_string();
525 let output_expr = from_string(expr_str.as_str()).unwrap();
526 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
527 }
528
529 #[test]
530 fn test_round_trip_read_write_sequence_of_literal() {
531 let input_expr = Expr::sequence(vec![Expr::literal("hello"), Expr::literal("world")], None);
532 let expr_str = to_string(&input_expr).unwrap();
533 let expected_str = r#"["hello", "world"]"#.to_string();
534 let output_expr = from_string(expr_str.as_str()).unwrap();
535 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
536 }
537
538 #[test]
539 fn test_round_trip_read_write_sequence_of_select_field() {
540 let input_expr = Expr::sequence(
541 vec![
542 Expr::select_field(Expr::identifier_global("request", None), "field", None),
543 Expr::select_field(Expr::identifier_global("request", None), "field", None),
544 ],
545 None,
546 );
547 let expr_str = to_string(&input_expr).unwrap();
548 let expected_str = "[request.field, request.field]".to_string();
549 let output_expr = from_string(expr_str.as_str()).unwrap();
550 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
551 }
552
553 #[test]
554 fn test_round_trip_read_write_sequence_of_select_index() {
555 let input_expr = Expr::sequence(
556 vec![
557 Expr::select_index(
558 Expr::identifier_global("request", None),
559 Expr::number(BigDecimal::from(1)),
560 ),
561 Expr::select_index(
562 Expr::identifier_global("request", None),
563 Expr::number(BigDecimal::from(2)),
564 ),
565 ],
566 None,
567 );
568 let expr_str = to_string(&input_expr).unwrap();
569 let expected_str = "[request[1], request[2]]".to_string();
570 let output_expr = from_string(expr_str.as_str()).unwrap();
571 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
572 }
573
574 #[test]
575 fn test_round_trip_read_write_sequence_of_sequence() {
576 let input_expr = Expr::sequence(
577 vec![
578 Expr::sequence(
579 vec![
580 Expr::identifier_global("request", None),
581 Expr::identifier_global("request", None),
582 ],
583 None,
584 ),
585 Expr::sequence(
586 vec![
587 Expr::identifier_global("request", None),
588 Expr::identifier_global("request", None),
589 ],
590 None,
591 ),
592 ],
593 None,
594 );
595 let expr_str = to_string(&input_expr).unwrap();
596 let expected_str = "[[request, request], [request, request]]".to_string();
597 let output_expr = from_string(expr_str.as_str()).unwrap();
598 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
599 }
600
601 #[test]
602 fn test_round_trip_read_write_sequence_of_tuple() {
603 let input_expr = Expr::sequence(
604 vec![
605 Expr::tuple(vec![
606 Expr::identifier_global("request", None),
607 Expr::identifier_global("request", None),
608 ]),
609 Expr::tuple(vec![
610 Expr::identifier_global("request", None),
611 Expr::identifier_global("request", None),
612 ]),
613 ],
614 None,
615 );
616 let expr_str = to_string(&input_expr).unwrap();
617 let expected_str = "[(request, request), (request, request)]".to_string();
618 let output_expr = from_string(expr_str.as_str()).unwrap();
619 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
620 }
621
622 #[test]
623 fn test_round_trip_read_write_sequence_of_record() {
624 let input_expr = Expr::sequence(
625 vec![
626 Expr::record(vec![(
627 "field".to_string(),
628 Expr::identifier_global("request", None),
629 )]),
630 Expr::record(vec![(
631 "field".to_string(),
632 Expr::identifier_global("request", None),
633 )]),
634 ],
635 None,
636 );
637 let expr_str = to_string(&input_expr).unwrap();
638 let expected_str = "[{field: request}, {field: request}]".to_string();
639 let output_expr = from_string(expr_str.as_str()).unwrap();
640 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
641 }
642
643 #[test]
644 fn test_round_trip_read_write_sequence_of_flags() {
645 let input_expr = Expr::sequence(
646 vec![
647 Expr::flags(vec!["flag1".to_string(), "flag2".to_string()]),
648 Expr::flags(vec!["flag3".to_string(), "flag4".to_string()]),
649 ],
650 None,
651 );
652 let expr_str = to_string(&input_expr).unwrap();
653 let expected_str = "[{flag1, flag2}, {flag3, flag4}]".to_string();
654 let output_expr = from_string(expr_str.as_str()).unwrap();
655 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
656 }
657
658 #[test]
659 fn test_round_trip_read_write_sequence_of_concat() {
660 let input_expr = Expr::sequence(
661 vec![
662 Expr::concat(vec![
663 Expr::literal("user-id-1-"),
664 Expr::select_field(Expr::identifier_global("request", None), "user-id-1", None),
665 ]),
666 Expr::concat(vec![
667 Expr::literal("user-id-2-"),
668 Expr::select_field(Expr::identifier_global("request", None), "user-id-2", None),
669 ]),
670 ],
671 None,
672 );
673 let expr_str = to_string(&input_expr).unwrap();
674 let expected_str =
675 r#"["user-id-1-${request.user-id-1}", "user-id-2-${request.user-id-2}"]"#.to_string();
676 let output_expr = from_string(expr_str.as_str()).unwrap();
677 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
678 }
679
680 #[test]
681 fn test_round_trip_read_write_sequence_of_math_op() {
682 let input_expr = Expr::sequence(
683 vec![
684 Expr::greater_than(
685 Expr::number(BigDecimal::from(1)),
686 Expr::number(BigDecimal::from(2)),
687 ),
688 Expr::less_than(
689 Expr::number(BigDecimal::from(1)),
690 Expr::number(BigDecimal::from(2)),
691 ),
692 ],
693 None,
694 );
695 let expr_str = to_string(&input_expr).unwrap();
696 let expected_str = "[1 > 2, 1 < 2]".to_string();
697 let output_expr = from_string(expr_str.as_str()).unwrap();
698 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
699 }
700
701 #[test]
702 fn test_round_trip_read_write_sequence_of_if_condition() {
703 let input_expr = Expr::sequence(
704 vec![
705 Expr::cond(
706 Expr::equal_to(
707 Expr::select_field(Expr::identifier_global("request", None), "foo", None),
708 Expr::literal("bar"),
709 ),
710 Expr::literal("success"),
711 Expr::literal("failed"),
712 ),
713 Expr::cond(
714 Expr::equal_to(
715 Expr::select_field(Expr::identifier_global("request", None), "foo", None),
716 Expr::literal("bar"),
717 ),
718 Expr::literal("success"),
719 Expr::literal("failed"),
720 ),
721 ],
722 None,
723 );
724 let expr_str = to_string(&input_expr).unwrap();
725 let expected_str = r#"[if request.foo == "bar" then "success" else "failed", if request.foo == "bar" then "success" else "failed"]"#.to_string();
726 let output_expr = from_string(expr_str.as_str()).unwrap();
727 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
728 }
729
730 #[test]
731 fn test_round_trip_read_write_sequence_of_pattern_match() {
732 let input_expr = Expr::sequence(
733 vec![
734 Expr::pattern_match(
735 Expr::identifier_global("request", None),
736 vec![
737 MatchArm::new(
738 ArmPattern::Constructor(
739 "ok".to_string(),
740 vec![ArmPattern::literal(Expr::identifier_global("foo", None))],
741 ),
742 Expr::literal("success"),
743 ),
744 MatchArm::new(
745 ArmPattern::Constructor(
746 "err".to_string(),
747 vec![ArmPattern::literal(Expr::identifier_global("msg", None))],
748 ),
749 Expr::literal("failure"),
750 ),
751 ],
752 ),
753 Expr::pattern_match(
754 Expr::identifier_global("request", None),
755 vec![
756 MatchArm::new(
757 ArmPattern::Constructor(
758 "ok".to_string(),
759 vec![ArmPattern::literal(Expr::identifier_global("foo", None))],
760 ),
761 Expr::literal("success"),
762 ),
763 MatchArm::new(
764 ArmPattern::Constructor(
765 "err".to_string(),
766 vec![ArmPattern::literal(Expr::identifier_global("msg", None))],
767 ),
768 Expr::pattern_match(
769 Expr::identifier_global("request", None),
770 vec![
771 MatchArm::new(
772 ArmPattern::Constructor(
773 "ok".to_string(),
774 vec![ArmPattern::literal(Expr::identifier_global(
775 "foo", None,
776 ))],
777 ), Expr::literal("success"),
779 ),
780 MatchArm::new(
781 ArmPattern::Constructor(
782 "err".to_string(),
783 vec![ArmPattern::literal(Expr::identifier_global(
784 "msg", None,
785 ))],
786 ),
787 Expr::literal("failure"),
788 ),
789 ],
790 ),
791 ),
792 ],
793 ),
794 ],
795 None,
796 );
797
798 let expr_str = to_string(&input_expr).unwrap();
799 let expected_str = r#"[match request { ok(foo) => "success", err(msg) => "failure" } , match request { ok(foo) => "success", err(msg) => match request { ok(foo) => "success", err(msg) => "failure" } } ]"#.to_string();
800 let output_expr = from_string(expr_str.as_str()).unwrap();
801 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
802 }
803
804 #[test]
805 fn test_round_trip_read_write_sequence_of_constructor() {
806 let input_expr = Expr::sequence(
807 vec![
808 Expr::ok(Expr::literal("foo"), None),
809 Expr::err(Expr::literal("msg"), None),
810 ],
811 None,
812 );
813 let expr_str = to_string(&input_expr).unwrap();
814 let expected_str = "[ok(\"foo\"), err(\"msg\")]".to_string();
815 let output_expr = from_string(expr_str.as_str()).unwrap();
816 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
817 }
818}
819
820#[cfg(test)]
821mod tuple_tests {
822 use bigdecimal::BigDecimal;
823 use test_r::test;
824
825 use crate::expr::Expr;
826 use crate::text::{from_string, to_string};
827
828 #[test]
829 fn test_round_trip_read_write_tuple_empty() {
830 let input_expr = Expr::tuple(vec![]);
831 let expr_str = to_string(&input_expr).unwrap();
832 let expected_str = "()".to_string();
833 let output_expr = from_string(expr_str.as_str()).unwrap();
834 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
835 }
836
837 #[test]
838 fn test_round_trip_read_write_tuple_of_request() {
839 let input_expr = Expr::tuple(vec![
840 Expr::identifier_global("request", None),
841 Expr::identifier_global("request", None),
842 ]);
843 let expr_str = to_string(&input_expr).unwrap();
844 let expected_str = "(request, request)".to_string();
845 let output_expr = from_string(expr_str.as_str()).unwrap();
846 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
847 }
848
849 #[test]
850 fn test_round_trip_read_write_tuple_of_literal() {
851 let input_expr = Expr::tuple(vec![Expr::literal("hello"), Expr::literal("world")]);
852 let expr_str = to_string(&input_expr).unwrap();
853 let expected_str = r#"("hello", "world")"#.to_string();
854 let output_expr = from_string(expr_str.as_str()).unwrap();
855 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
856 }
857
858 #[test]
859 fn test_round_trip_read_write_tuple_of_select_field() {
860 let input_expr = Expr::tuple(vec![
861 Expr::select_field(Expr::identifier_global("request", None), "field", None),
862 Expr::select_field(Expr::identifier_global("request", None), "field", None),
863 ]);
864 let _expr_str = to_string(&input_expr).unwrap();
865 let _expected_str = "(request.field, request.field)".to_string();
866 }
867
868 #[test]
869 fn test_round_trip_read_write_tuple_of_select_index() {
870 let input_expr = Expr::tuple(vec![
871 Expr::select_index(
872 Expr::identifier_global("request", None),
873 Expr::number(BigDecimal::from(1)),
874 ),
875 Expr::select_index(
876 Expr::identifier_global("request", None),
877 Expr::number(BigDecimal::from(2)),
878 ),
879 ]);
880 let expr_str = to_string(&input_expr).unwrap();
881 let expected_str = "(request[1], request[2])".to_string();
882 let output_expr = from_string(expr_str.as_str()).unwrap();
883 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
884 }
885
886 #[test]
887 fn test_round_trip_read_write_tuple_of_tuple() {
888 let input_expr = Expr::tuple(vec![
889 Expr::tuple(vec![
890 Expr::identifier_global("request", None),
891 Expr::identifier_global("request", None),
892 ]),
893 Expr::tuple(vec![
894 Expr::identifier_global("request", None),
895 Expr::identifier_global("request", None),
896 ]),
897 ]);
898 let expr_str = to_string(&input_expr).unwrap();
899 let expected_str = "((request, request), (request, request))".to_string();
900 let output_expr = from_string(expr_str.as_str()).unwrap();
901 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
902 }
903
904 #[test]
905 fn test_round_trip_read_write_tuple_of_sequence() {
906 let input_expr = Expr::tuple(vec![
907 Expr::sequence(
908 vec![
909 Expr::identifier_global("request", None),
910 Expr::identifier_global("request", None),
911 ],
912 None,
913 ),
914 Expr::sequence(
915 vec![
916 Expr::identifier_global("request", None),
917 Expr::identifier_global("request", None),
918 ],
919 None,
920 ),
921 ]);
922 let expr_str = to_string(&input_expr).unwrap();
923 let expected_str = "([request, request], [request, request])".to_string();
924 let output_expr = from_string(expr_str.as_str()).unwrap();
925 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
926 }
927
928 #[test]
929 fn test_round_trip_read_write_tuple_of_record() {
930 let input_expr = Expr::tuple(vec![
931 Expr::record(vec![(
932 "field".to_string(),
933 Expr::identifier_global("request", None),
934 )]),
935 Expr::record(vec![(
936 "field".to_string(),
937 Expr::identifier_global("request", None),
938 )]),
939 ]);
940 let expr_str = to_string(&input_expr).unwrap();
941 let expected_str = "({field: request}, {field: request})".to_string();
942 let output_expr = from_string(expr_str.as_str()).unwrap();
943 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
944 }
945
946 #[test]
947 fn test_round_trip_read_write_tuple_of_flags() {
948 let input_expr = Expr::tuple(vec![
949 Expr::flags(vec!["flag1".to_string(), "flag2".to_string()]),
950 Expr::flags(vec!["flag3".to_string(), "flag4".to_string()]),
951 ]);
952 let expr_str = to_string(&input_expr).unwrap();
953 let expected_str = "({flag1, flag2}, {flag3, flag4})".to_string();
954 let output_expr = from_string(expr_str.as_str()).unwrap();
955 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
956 }
957
958 #[test]
959 fn test_round_trip_read_write_tuple_of_concat() {
960 let input_expr = Expr::tuple(vec![
961 Expr::concat(vec![
962 Expr::literal("user-id-1-"),
963 Expr::select_field(Expr::identifier_global("request", None), "user-id-1", None),
964 ]),
965 Expr::concat(vec![
966 Expr::literal("user-id-2-"),
967 Expr::select_field(Expr::identifier_global("request", None), "user-id-2", None),
968 ]),
969 ]);
970 let expr_str = to_string(&input_expr).unwrap();
971 let expected_str =
972 r#"("user-id-1-${request.user-id-1}", "user-id-2-${request.user-id-2}")"#.to_string();
973 let output_expr = from_string(expr_str.as_str()).unwrap();
974 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
975 }
976
977 #[test]
978 fn test_round_trip_read_write_tuple_of_math_op() {
979 let input_expr = Expr::tuple(vec![
980 Expr::greater_than(
981 Expr::number(BigDecimal::from(1)),
982 Expr::number(BigDecimal::from(2)),
983 ),
984 Expr::less_than(
985 Expr::number(BigDecimal::from(1)),
986 Expr::number(BigDecimal::from(2)),
987 ),
988 ]);
989 let expr_str = to_string(&input_expr).unwrap();
990 let expected_str = "(1 > 2, 1 < 2)".to_string();
991 let output_expr = from_string(expr_str.as_str()).unwrap();
992 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
993 }
994
995 #[test]
996 fn test_round_trip_read_write_tuple_of_constructor() {
997 let input_expr = Expr::tuple(vec![
998 Expr::ok(Expr::literal("foo"), None),
999 Expr::err(Expr::literal("msg"), None),
1000 ]);
1001 let expr_str = to_string(&input_expr).unwrap();
1002 let expected_str = r#"(ok("foo"), err("msg"))"#.to_string();
1003 let output_expr = from_string(expr_str.as_str()).unwrap();
1004 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1005 }
1006}
1007
1008#[cfg(test)]
1009mod simple_values_test {
1010 use bigdecimal::BigDecimal;
1011 use std::str::FromStr;
1012 use test_r::test;
1013
1014 use crate::expr::Expr;
1015 use crate::text::{from_string, to_string};
1016
1017 #[test]
1018 fn test_round_trip_read_write_literal() {
1019 let input_expr = Expr::literal("hello");
1020 let expr_str = to_string(&input_expr).unwrap();
1021 let expected_str = "\"hello\"".to_string();
1022 let output_expr = from_string(expr_str.as_str()).unwrap();
1023 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1024 }
1025
1026 #[test]
1027 fn test_round_trip_read_write_request() {
1028 let input_expr = Expr::identifier_global("request", None);
1029 let expr_str = to_string(&input_expr).unwrap();
1030 let expected_str = "request".to_string();
1031 let output_expr = from_string(expr_str.as_str()).unwrap();
1032 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1033 }
1034
1035 #[test]
1036 fn test_round_trip_read_write_number_float() {
1037 let input_expr = Expr::number(BigDecimal::from_str("1.1").unwrap());
1038 let expr_str = to_string(&input_expr).unwrap();
1039 let output_expr = from_string(expr_str.as_str()).unwrap();
1040 assert_eq!(input_expr, output_expr);
1041 }
1042
1043 #[test]
1044 fn test_round_trip_read_write_number_u64() {
1045 let input_expr = Expr::number(BigDecimal::from(1));
1046 let expr_str = to_string(&input_expr).unwrap();
1047 let expected_str = "1".to_string();
1048 let output_expr = from_string(expr_str.as_str()).unwrap();
1049 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1050 }
1051
1052 #[test]
1053 fn test_round_trip_read_write_number_i64() {
1054 let input_expr = Expr::number(BigDecimal::from(-1));
1055 let expr_str = to_string(&input_expr).unwrap();
1056 let expected_str = "-1".to_string();
1057 let output_expr = from_string(expr_str.as_str()).unwrap();
1058 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1059 }
1060
1061 #[test]
1062 fn test_round_trip_read_write_worker() {
1063 let input_expr = Expr::identifier_global("worker", None);
1064 let expr_str = to_string(&input_expr).unwrap();
1065 let expected_str = "worker".to_string();
1066 let output_expr = from_string(expr_str.as_str()).unwrap();
1067 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1068 }
1069
1070 #[test]
1071 fn test_round_trip_read_write_variable() {
1072 let input_expr = Expr::identifier_global("variable", None);
1073 let expr_str = to_string(&input_expr).unwrap();
1074 let expected_str = "variable".to_string();
1075 let output_expr = from_string(expr_str.as_str()).unwrap();
1076 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1077 }
1078
1079 #[test]
1080 fn test_round_trip_read_write_boolean() {
1081 let input_expr = Expr::boolean(true);
1082 let expr_str = to_string(&input_expr).unwrap();
1083 let expected_str = "true".to_string();
1084 let output_expr = from_string(expr_str.as_str()).unwrap();
1085 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1086 }
1087}
1088
1089#[cfg(test)]
1090mod let_tests {
1091 use bigdecimal::BigDecimal;
1092 use test_r::test;
1093
1094 use crate::expr::Expr;
1095 use crate::parser::type_name::TypeName;
1096 use crate::text::{from_string, to_string};
1097 use crate::{InferredType, VariableId};
1098
1099 #[test]
1100 fn test_round_trip_read_write_let() {
1101 let input_expr = Expr::expr_block(vec![
1102 Expr::let_binding("x", Expr::literal("hello"), None),
1103 Expr::let_binding("y", Expr::literal("bar"), None),
1104 ]);
1105 let expr_str = to_string(&input_expr).unwrap();
1106 let expected_str = "let x = \"hello\";\nlet y = \"bar\"".to_string();
1107 let output_expr = from_string(expr_str.as_str()).unwrap();
1108 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1109 }
1110
1111 #[test]
1112 fn test_round_trip_read_write_let_with_type_binding_str() {
1113 let input_expr = Expr::expr_block(vec![
1114 Expr::let_binding_with_variable_id(
1115 VariableId::global("x".to_string()),
1116 Expr::literal("hello"),
1117 Some(TypeName::Str),
1118 ),
1119 Expr::let_binding_with_variable_id(
1120 VariableId::global("y".to_string()),
1121 Expr::literal("bar"),
1122 Some(TypeName::Str),
1123 ),
1124 ]);
1125 let expr_str = to_string(&input_expr).unwrap();
1126 let expected_str = "let x: string = \"hello\";\nlet y: string = \"bar\"".to_string();
1127 let output_expr = from_string(expr_str.as_str()).unwrap();
1128 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1129 }
1130
1131 #[test]
1132 fn test_round_trip_read_write_let_with_type_binding_u8() {
1133 let input_expr = Expr::expr_block(vec![
1134 Expr::let_binding_with_variable_id(
1135 VariableId::global("x".to_string()),
1136 Expr::number(BigDecimal::from(1)),
1137 Some(TypeName::U8),
1138 ),
1139 Expr::let_binding_with_variable_id(
1140 VariableId::global("y".to_string()),
1141 Expr::number(BigDecimal::from(2)),
1142 Some(TypeName::U8),
1143 ),
1144 ]);
1145 let expr_str = to_string(&input_expr).unwrap();
1146 let expected_str = "let x: u8 = 1;\nlet y: u8 = 2".to_string();
1147 let output_expr = from_string(expr_str.as_str()).unwrap();
1148 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1149 }
1150
1151 #[test]
1152 fn test_round_trip_read_write_let_with_type_binding_u16() {
1153 let input_expr = Expr::expr_block(vec![
1154 Expr::let_binding_with_variable_id(
1155 VariableId::global("x".to_string()),
1156 Expr::number(BigDecimal::from(1)),
1157 Some(TypeName::U16),
1158 ),
1159 Expr::let_binding_with_variable_id(
1160 VariableId::global("y".to_string()),
1161 Expr::number(BigDecimal::from(2)),
1162 Some(TypeName::U16),
1163 ),
1164 ]);
1165 let expr_str = to_string(&input_expr).unwrap();
1166 let expected_str = "let x: u16 = 1;\nlet y: u16 = 2".to_string();
1167 let output_expr = from_string(expr_str.as_str()).unwrap();
1168 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1169 }
1170
1171 #[test]
1172 fn test_round_trip_read_write_let_with_type_binding_u32() {
1173 let input_expr = Expr::expr_block(vec![
1174 Expr::let_binding_with_variable_id(
1175 VariableId::global("x".to_string()),
1176 Expr::number(BigDecimal::from(1)),
1177 Some(TypeName::U32),
1178 ),
1179 Expr::let_binding_with_variable_id(
1180 VariableId::global("y".to_string()),
1181 Expr::number(BigDecimal::from(2)),
1182 Some(TypeName::U32),
1183 ),
1184 ]);
1185 let expr_str = to_string(&input_expr).unwrap();
1186 let expected_str = "let x: u32 = 1;\nlet y: u32 = 2".to_string();
1187 let output_expr = from_string(expr_str.as_str()).unwrap();
1188 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1189 }
1190
1191 #[test]
1192 fn test_round_trip_read_write_let_with_type_binding_option() {
1193 let input_expr = Expr::expr_block(vec![
1194 Expr::let_binding_with_variable_id(
1195 VariableId::global("x".to_string()),
1196 Expr::option(Some(Expr::literal("foo")))
1197 .with_inferred_type(InferredType::option(InferredType::string())),
1198 Some(TypeName::Option(Box::new(TypeName::Str))),
1199 ),
1200 Expr::let_binding_with_variable_id(
1201 VariableId::global("y".to_string()),
1202 Expr::option(Some(Expr::literal("bar")))
1203 .with_inferred_type(InferredType::option(InferredType::string())),
1204 Some(TypeName::Option(Box::new(TypeName::Str))),
1205 ),
1206 ]);
1207 let expr_str = to_string(&input_expr).unwrap();
1208 let expected_str =
1209 "let x: option<string> = some(\"foo\");\nlet y: option<string> = some(\"bar\")"
1210 .to_string();
1211 let output_expr = from_string(expr_str.as_str()).unwrap();
1212 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1213 }
1214
1215 #[test]
1216 fn test_round_trip_read_write_let_with_type_binding_list() {
1217 let input_expr = Expr::expr_block(vec![
1218 Expr::let_binding_with_variable_id(
1219 VariableId::global("x".to_string()),
1220 Expr::sequence(vec![Expr::literal("foo")], None)
1221 .with_inferred_type(InferredType::list(InferredType::string())),
1222 Some(TypeName::List(Box::new(TypeName::Str))),
1223 ),
1224 Expr::let_binding_with_variable_id(
1225 VariableId::global("y".to_string()),
1226 Expr::sequence(vec![Expr::literal("bar")], None)
1227 .with_inferred_type(InferredType::list(InferredType::string())),
1228 Some(TypeName::List(Box::new(TypeName::Str))),
1229 ),
1230 ]);
1231 let expr_str = to_string(&input_expr).unwrap();
1232 let expected_str =
1233 "let x: list<string> = [\"foo\"];\nlet y: list<string> = [\"bar\"]".to_string();
1234 let output_expr = from_string(expr_str.as_str()).unwrap();
1235 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1236 }
1237
1238 #[test]
1239 fn test_round_trip_read_write_let_with_type_binding_tuple() {
1240 let input_expr = Expr::expr_block(vec![
1241 Expr::let_binding_with_variable_id(
1242 VariableId::global("x".to_string()),
1243 Expr::tuple(vec![Expr::literal("foo")])
1244 .with_inferred_type(InferredType::tuple(vec![InferredType::string()])),
1245 Some(TypeName::Tuple(vec![TypeName::Str])),
1246 ),
1247 Expr::let_binding_with_variable_id(
1248 VariableId::global("y".to_string()),
1249 Expr::tuple(vec![Expr::literal("bar")])
1250 .with_inferred_type(InferredType::tuple(vec![InferredType::string()])),
1251 Some(TypeName::Tuple(vec![TypeName::Str])),
1252 ),
1253 ]);
1254 let expr_str = to_string(&input_expr).unwrap();
1255 let expected_str =
1256 "let x: tuple<string> = (\"foo\");\nlet y: tuple<string> = (\"bar\")".to_string();
1257 let output_expr = from_string(expr_str.as_str()).unwrap();
1258 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1259 }
1260}
1261
1262#[cfg(test)]
1263mod selection_tests {
1264 use bigdecimal::BigDecimal;
1265 use test_r::test;
1266
1267 use crate::expr::Expr;
1268 use crate::text::{from_string, to_string};
1269
1270 #[test]
1271 fn test_round_trip_read_write_select_field_from_request() {
1272 let input_expr =
1273 Expr::select_field(Expr::identifier_global("request", None), "field", None);
1274 let expr_str = to_string(&input_expr).unwrap();
1275 let expected_str = "request.field".to_string();
1276 let output_expr = from_string(expr_str.as_str()).unwrap();
1277 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1278 }
1279
1280 #[test]
1281 fn test_round_trip_read_write_select_index_from_request() {
1282 let input_expr = Expr::select_index(
1283 Expr::identifier_global("request", None),
1284 Expr::number(BigDecimal::from(1)),
1285 );
1286 let expr_str = to_string(&input_expr).unwrap();
1287 let expected_str = "request[1]".to_string();
1288 let output_expr = from_string(expr_str.as_str()).unwrap();
1289 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1290 }
1291
1292 #[test]
1293 fn test_round_trip_read_write_select_field_from_record() {
1294 let input_expr = Expr::select_field(
1295 Expr::record(vec![(
1296 "field".to_string(),
1297 Expr::identifier_global("request", None),
1298 )]),
1299 "field",
1300 None,
1301 );
1302 let expr_str = to_string(&input_expr).unwrap();
1303 let expected_str = "{field: request}.field".to_string();
1304 let output_expr = from_string(expr_str.as_str()).unwrap();
1305 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1306 }
1307
1308 #[test]
1309 fn test_round_trip_read_write_select_index_from_sequence() {
1310 let input_expr = Expr::select_index(
1311 Expr::sequence(
1312 vec![
1313 Expr::identifier_global("request", None),
1314 Expr::identifier_global("request", None),
1315 ],
1316 None,
1317 ),
1318 Expr::number(BigDecimal::from(1)),
1319 );
1320 let expr_str = to_string(&input_expr).unwrap();
1321 let expected_str = "[request, request][1]".to_string();
1322 let output_expr = from_string(expr_str.as_str()).unwrap();
1323 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1324 }
1325}
1326
1327#[cfg(test)]
1328mod flag_tests {
1329 use test_r::test;
1330
1331 use crate::expr::Expr;
1332 use crate::text::{from_string, to_string};
1333
1334 #[test]
1335 fn test_round_trip_read_write_flags_single() {
1336 let input_expr = Expr::flags(vec!["flag1".to_string()]);
1337 let expr_str = to_string(&input_expr).unwrap();
1338 let expected_str = "{flag1}".to_string();
1339 let output_expr = from_string(expr_str.as_str()).unwrap();
1340 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1341 }
1342
1343 #[test]
1344 fn test_round_trip_read_write_flags() {
1345 let input_expr = Expr::flags(vec![
1346 "flag1".to_string(),
1347 "flag2".to_string(),
1348 "flag3".to_string(),
1349 ]);
1350 let expr_str = to_string(&input_expr).unwrap();
1351 let expected_str = "{flag1, flag2, flag3}".to_string();
1352 let output_expr = from_string(expr_str.as_str()).unwrap();
1353 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1354 }
1355}
1356
1357#[cfg(test)]
1358mod match_tests {
1359 use bigdecimal::BigDecimal;
1360 use std::str::FromStr;
1361 use test_r::test;
1362
1363 use crate::expr::ArmPattern;
1364 use crate::expr::Expr;
1365 use crate::expr::MatchArm;
1366 use crate::text::{from_string, to_string};
1367
1368 #[test]
1369 fn test_round_trip_match_expr() {
1370 let mut input_expr = Expr::pattern_match(
1371 Expr::identifier_global("request", None),
1372 vec![
1373 MatchArm::new(
1374 ArmPattern::constructor(
1375 "ok",
1376 vec![ArmPattern::literal(Expr::identifier_global("foo", None))],
1377 ),
1378 Expr::literal("success"),
1379 ),
1380 MatchArm::new(
1381 ArmPattern::constructor(
1382 "err",
1383 vec![ArmPattern::literal(Expr::identifier_global("msg", None))],
1384 ),
1385 Expr::literal("failure"),
1386 ),
1387 ],
1388 );
1389
1390 input_expr.reset_type();
1391
1392 let expr_str = to_string(&input_expr).unwrap();
1393 let expected_str =
1394 r#"match request { ok(foo) => "success", err(msg) => "failure" } "#.to_string();
1395 let mut output_expr = from_string(expr_str.as_str()).unwrap();
1396 output_expr.reset_type();
1397 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1398 }
1399
1400 #[test]
1401 fn test_round_trip_match_expr_of_flags() {
1402 let input_expr = Expr::pattern_match(
1403 Expr::identifier_global("request", None),
1404 vec![
1405 MatchArm::new(
1406 ArmPattern::constructor(
1407 "ok",
1408 vec![ArmPattern::literal(Expr::identifier_global("foo", None))],
1409 ),
1410 Expr::flags(vec!["flag1".to_string(), "flag2".to_string()]),
1411 ),
1412 MatchArm::new(
1413 ArmPattern::constructor(
1414 "err",
1415 vec![ArmPattern::literal(Expr::identifier_global("msg", None))],
1416 ),
1417 Expr::literal("failure"),
1418 ),
1419 ],
1420 );
1421
1422 let expr_str = to_string(&input_expr).unwrap();
1423 let expected_str =
1424 r#"match request { ok(foo) => {flag1, flag2}, err(msg) => "failure" } "#.to_string();
1425 let output_expr = from_string(expr_str.as_str()).unwrap();
1426 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1427 }
1428
1429 #[test]
1430 fn test_round_trip_match_expr_of_tuple() {
1431 let input_expr = Expr::pattern_match(
1432 Expr::identifier_global("request", None),
1433 vec![
1434 MatchArm::new(
1435 ArmPattern::constructor(
1436 "ok",
1437 vec![ArmPattern::literal(Expr::identifier_global("foo", None))],
1438 ),
1439 Expr::tuple(vec![
1440 Expr::identifier_global("request", None),
1441 Expr::identifier_global("request", None),
1442 ]),
1443 ),
1444 MatchArm::new(
1445 ArmPattern::constructor(
1446 "err",
1447 vec![ArmPattern::literal(Expr::identifier_global("msg", None))],
1448 ),
1449 Expr::literal("failure"),
1450 ),
1451 ],
1452 );
1453
1454 let expr_str = to_string(&input_expr).unwrap();
1455 let expected_str =
1456 r#"match request { ok(foo) => (request, request), err(msg) => "failure" } "#
1457 .to_string();
1458 let output_expr = from_string(expr_str.as_str()).unwrap();
1459 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1460 }
1461
1462 #[test]
1463 fn test_round_trip_match_expr_of_sequence() {
1464 let input_expr = Expr::pattern_match(
1465 Expr::identifier_global("request", None),
1466 vec![
1467 MatchArm::new(
1468 ArmPattern::constructor(
1469 "ok",
1470 vec![ArmPattern::literal(Expr::identifier_global("foo", None))],
1471 ),
1472 Expr::sequence(
1473 vec![
1474 Expr::identifier_global("request", None),
1475 Expr::identifier_global("request", None),
1476 ],
1477 None,
1478 ),
1479 ),
1480 MatchArm::new(
1481 ArmPattern::constructor(
1482 "err",
1483 vec![ArmPattern::literal(Expr::identifier_global("msg", None))],
1484 ),
1485 Expr::literal("failure"),
1486 ),
1487 ],
1488 );
1489
1490 let expr_str = to_string(&input_expr).unwrap();
1491 let expected_str =
1492 r#"match request { ok(foo) => [request, request], err(msg) => "failure" } "#
1493 .to_string();
1494 let output_expr = from_string(expr_str.as_str()).unwrap();
1495 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1496 }
1497
1498 #[test]
1499 fn test_round_trip_match_expr_of_record() {
1500 let input_expr = Expr::pattern_match(
1501 Expr::identifier_global("request", None),
1502 vec![
1503 MatchArm::new(
1504 ArmPattern::constructor(
1505 "ok",
1506 vec![ArmPattern::literal(Expr::identifier_global("foo", None))],
1507 ),
1508 Expr::record(vec![(
1509 "field".to_string(),
1510 Expr::identifier_global("request", None),
1511 )]),
1512 ),
1513 MatchArm::new(
1514 ArmPattern::constructor(
1515 "err",
1516 vec![ArmPattern::literal(Expr::identifier_global("msg", None))],
1517 ),
1518 Expr::literal("failure"),
1519 ),
1520 ],
1521 );
1522
1523 let expr_str = to_string(&input_expr).unwrap();
1524 let expected_str =
1525 r#"match request { ok(foo) => {field: request}, err(msg) => "failure" } "#.to_string();
1526 let output_expr = from_string(expr_str.as_str()).unwrap();
1527 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1528 }
1529
1530 #[test]
1531 fn test_round_trip_match_expr_of_math_op() {
1532 let input_expr = Expr::pattern_match(
1533 Expr::identifier_global("request", None),
1534 vec![
1535 MatchArm::new(
1536 ArmPattern::constructor(
1537 "ok",
1538 vec![ArmPattern::literal(Expr::identifier_global("foo", None))],
1539 ),
1540 Expr::greater_than(
1541 Expr::number(BigDecimal::from_str("1.1").unwrap()),
1542 Expr::number(BigDecimal::from(2)),
1543 ),
1544 ),
1545 MatchArm::new(
1546 ArmPattern::constructor(
1547 "err",
1548 vec![ArmPattern::literal(Expr::identifier_global("msg", None))],
1549 ),
1550 Expr::less_than(
1551 Expr::number(BigDecimal::from(1)),
1552 Expr::number(BigDecimal::from(2)),
1553 ),
1554 ),
1555 ],
1556 );
1557
1558 let expr_str = to_string(&input_expr).unwrap();
1559 let expected_str = "match request { ok(foo) => 1.1 > 2, err(msg) => 1 < 2 } ".to_string();
1560 let output_expr = from_string(expr_str.as_str()).unwrap();
1561 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1562 }
1563
1564 #[test]
1565 fn test_round_trip_match_expr_of_if_condition() {
1566 let input_expr = Expr::pattern_match(
1567 Expr::identifier_global("request", None),
1568 vec![
1569 MatchArm::new(
1570 ArmPattern::constructor(
1571 "ok",
1572 vec![ArmPattern::literal(Expr::identifier_global("foo", None))],
1573 ),
1574 Expr::cond(
1575 Expr::equal_to(
1576 Expr::select_field(
1577 Expr::identifier_global("request", None),
1578 "foo",
1579 None,
1580 ),
1581 Expr::literal("bar"),
1582 ),
1583 Expr::literal("success"),
1584 Expr::literal("failed"),
1585 ),
1586 ),
1587 MatchArm::new(
1588 ArmPattern::constructor(
1589 "err",
1590 vec![ArmPattern::literal(Expr::identifier_global("msg", None))],
1591 ),
1592 Expr::literal("failure"),
1593 ),
1594 ],
1595 );
1596
1597 let expr_str = to_string(&input_expr).unwrap();
1598 let expected_str =
1599 r#"match request { ok(foo) => if request.foo == "bar" then "success" else "failed", err(msg) => "failure" } "#.to_string();
1600 let output_expr = from_string(expr_str.as_str()).unwrap();
1601 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1602 }
1603
1604 #[test]
1605 fn test_pattern_match_multiple_constructor_variables() {
1606 let input_expr = Expr::pattern_match(
1607 Expr::identifier_global("request", None),
1608 vec![
1609 MatchArm::new(
1610 ArmPattern::custom_constructor(
1611 "foo",
1612 vec![ArmPattern::identifier("a"), ArmPattern::identifier("b")],
1613 ),
1614 Expr::literal("success"),
1615 ),
1616 MatchArm::new(
1617 ArmPattern::custom_constructor("bar", vec![ArmPattern::identifier("c")]),
1618 Expr::literal("failure"),
1619 ),
1620 ],
1621 );
1622
1623 let expr_str = to_string(&input_expr).unwrap();
1624 let expected_str =
1625 r#"match request { foo(a,b) => "success", bar(c) => "failure" } "#.to_string();
1626 let output_expr = from_string(expr_str.as_str()).unwrap();
1627 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1628 }
1629
1630 #[test]
1631 fn test_pattern_match_empty_constructor_variables() {
1632 let input_expr = Expr::pattern_match(
1633 Expr::identifier_global("request", None),
1634 vec![
1635 MatchArm::new(ArmPattern::identifier("foo"), Expr::literal("success")),
1636 MatchArm::new(
1637 ArmPattern::custom_constructor("bar", vec![ArmPattern::identifier("c")]),
1638 Expr::literal("failure"),
1639 ),
1640 ],
1641 );
1642
1643 let expr_str = to_string(&input_expr).unwrap();
1644 let expected_str =
1645 r#"match request { foo => "success", bar(c) => "failure" } "#.to_string();
1646 let output_expr = from_string(expr_str.as_str()).unwrap();
1647 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1648 }
1649
1650 #[test]
1651 fn test_pattern_match_empty_with_nested_constructor_patterns() {
1652 let input_expr = Expr::pattern_match(
1653 Expr::identifier_global("request", None),
1654 vec![
1655 MatchArm::new(
1656 ArmPattern::custom_constructor(
1657 "foo",
1658 vec![ArmPattern::custom_constructor(
1659 "bar",
1660 vec![ArmPattern::identifier("v1")],
1661 )],
1662 ),
1663 Expr::literal("success"),
1664 ),
1665 MatchArm::new(
1666 ArmPattern::custom_constructor("bar", vec![ArmPattern::identifier("c")]),
1667 Expr::literal("failure"),
1668 ),
1669 ],
1670 );
1671
1672 let expr_str = to_string(&input_expr).unwrap();
1673 let expected_str =
1674 r#"match request { foo(bar(v1)) => "success", bar(c) => "failure" } "#.to_string();
1675 let output_expr = from_string(expr_str.as_str()).unwrap();
1676 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1677 }
1678
1679 #[test]
1680 fn test_pattern_match_variants_in_arm_rhs() {
1681 let input_expr = Expr::pattern_match(
1682 Expr::identifier_global("request", None),
1683 vec![
1684 MatchArm::new(
1685 ArmPattern::identifier("foo1"),
1686 Expr::ok(Expr::literal("foo"), None),
1687 ),
1688 MatchArm::new(
1689 ArmPattern::custom_constructor("bar", vec![ArmPattern::identifier("c")]),
1690 Expr::err(Expr::literal("bar"), None),
1691 ),
1692 ],
1693 );
1694
1695 let expr_str = to_string(&input_expr).unwrap();
1696 let expected_str =
1697 r#"match request { foo1 => ok("foo"), bar(c) => err("bar") } "#.to_string();
1698 let output_expr = from_string(expr_str.as_str()).unwrap();
1699 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1700 }
1701
1702 #[test]
1703 fn test_pattern_match_variants_in_wild_pattern() {
1704 let input_expr = Expr::pattern_match(
1705 Expr::identifier_global("request", None),
1706 vec![
1707 MatchArm::new(
1708 ArmPattern::custom_constructor("foo1", vec![ArmPattern::WildCard]),
1709 Expr::ok(Expr::literal("foo"), None),
1710 ),
1711 MatchArm::new(
1712 ArmPattern::custom_constructor("bar", vec![ArmPattern::identifier("c")]),
1713 Expr::err(Expr::literal("bar"), None),
1714 ),
1715 ],
1716 );
1717
1718 let expr_str = to_string(&input_expr).unwrap();
1719 let expected_str =
1720 r#"match request { foo1(_) => ok("foo"), bar(c) => err("bar") } "#.to_string();
1721 let output_expr = from_string(expr_str.as_str()).unwrap();
1722 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1723 }
1724
1725 #[test]
1726 fn test_pattern_match_variants_with_alias() {
1727 let input_expr = Expr::pattern_match(
1728 Expr::identifier_global("request", None),
1729 vec![
1730 MatchArm::new(
1731 ArmPattern::As(
1732 "name".to_string(),
1733 Box::new(ArmPattern::custom_constructor(
1734 "foo1",
1735 vec![ArmPattern::WildCard],
1736 )),
1737 ),
1738 Expr::ok(Expr::literal("foo"), None),
1739 ),
1740 MatchArm::new(
1741 ArmPattern::custom_constructor("bar", vec![ArmPattern::identifier("c")]),
1742 Expr::err(Expr::literal("bar"), None),
1743 ),
1744 ],
1745 );
1746
1747 let expr_str = to_string(&input_expr).unwrap();
1748 let expected_str =
1749 r#"match request { name @ foo1(_) => ok("foo"), bar(c) => err("bar") } "#.to_string();
1750 let output_expr = from_string(expr_str.as_str()).unwrap();
1751 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1752 }
1753
1754 #[test]
1755 fn test_pattern_match_variants_with_nested_alias() {
1756 let input_expr = Expr::pattern_match(
1757 Expr::identifier_global("request", None),
1758 vec![
1759 MatchArm::new(
1760 ArmPattern::As(
1761 "a".to_string(),
1762 Box::new(ArmPattern::custom_constructor(
1763 "foo",
1764 vec![ArmPattern::As(
1765 "b".to_string(),
1766 Box::new(ArmPattern::WildCard),
1767 )],
1768 )),
1769 ),
1770 Expr::ok(Expr::literal("foo"), None),
1771 ),
1772 MatchArm::new(
1773 ArmPattern::As(
1774 "c".to_string(),
1775 Box::new(ArmPattern::custom_constructor(
1776 "bar",
1777 vec![ArmPattern::As(
1778 "d".to_string(),
1779 Box::new(ArmPattern::custom_constructor(
1780 "baz",
1781 vec![ArmPattern::identifier("x")],
1782 )),
1783 )],
1784 )),
1785 ),
1786 Expr::err(Expr::literal("bar"), None),
1787 ),
1788 ],
1789 );
1790
1791 let expr_str = to_string(&input_expr).unwrap();
1792 let expected_str =
1793 r#"match request { a @ foo(b @ _) => ok("foo"), c @ bar(d @ baz(x)) => err("bar") } "#
1794 .to_string();
1795 let output_expr = from_string(expr_str.as_str()).unwrap();
1796 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1797 }
1798}
1799
1800#[cfg(test)]
1801mod if_cond_tests {
1802 use bigdecimal::BigDecimal;
1803 use test_r::test;
1804
1805 use crate::expr::Expr;
1806 use crate::text::{from_string, to_string};
1807
1808 #[test]
1809 fn test_round_trip_if_condition_literals() {
1810 let input_expr = Expr::cond(
1811 Expr::equal_to(Expr::literal("foo"), Expr::literal("bar")),
1812 Expr::literal("success"),
1813 Expr::literal("failed"),
1814 );
1815
1816 let expr_str = to_string(&input_expr).unwrap();
1817 let expected_str = r#"if "foo" == "bar" then "success" else "failed""#.to_string();
1818 let output_expr = from_string(expected_str.as_str()).unwrap();
1819 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1820 }
1821
1822 #[test]
1823 fn test_round_trip_if_condition_of_select_field() {
1824 let input_expr = Expr::cond(
1825 Expr::equal_to(
1826 Expr::select_field(Expr::identifier_global("request", None), "foo", None),
1827 Expr::literal("bar"),
1828 ),
1829 Expr::literal("success"),
1830 Expr::literal("failed"),
1831 );
1832
1833 let expr_str = to_string(&input_expr).unwrap();
1834 let expected_str = r#"if request.foo == "bar" then "success" else "failed""#.to_string();
1835 let output_expr = from_string(expr_str.as_str()).unwrap();
1836 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1837 }
1838
1839 #[test]
1840 fn test_round_trip_nested_if_condition() {
1841 let input_expr = Expr::cond(
1842 Expr::equal_to(
1843 Expr::select_field(Expr::identifier_global("request", None), "foo", None),
1844 Expr::literal("bar"),
1845 ),
1846 Expr::literal("success"),
1847 Expr::cond(
1848 Expr::equal_to(
1849 Expr::select_field(Expr::identifier_global("request", None), "foo", None),
1850 Expr::literal("baz"),
1851 ),
1852 Expr::literal("success"),
1853 Expr::literal("failed"),
1854 ),
1855 );
1856
1857 let expr_str = to_string(&input_expr).unwrap();
1858 let expected_str = r#"if request.foo == "bar" then "success" else if request.foo == "baz" then "success" else "failed""#.to_string();
1859 let output_expr = from_string(expr_str.as_str()).unwrap();
1860 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1861 }
1862
1863 #[test]
1864 fn test_round_trip_if_condition_of_tuple() {
1865 let input_expr = Expr::cond(
1866 Expr::equal_to(
1867 Expr::identifier_global("foo", None),
1868 Expr::identifier_global("bar", None),
1869 ),
1870 Expr::tuple(vec![
1871 Expr::identifier_global("foo", None),
1872 Expr::identifier_global("bar", None),
1873 ]),
1874 Expr::tuple(vec![
1875 Expr::identifier_global("request", None),
1876 Expr::identifier_global("request", None),
1877 ]),
1878 );
1879
1880 let expr_str = to_string(&input_expr).unwrap();
1881 let expected_str = r#"if foo == bar then (foo, bar) else (request, request)"#.to_string();
1882 let output_expr = from_string(expr_str.as_str()).unwrap();
1883 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1884 }
1885
1886 #[test]
1887 fn test_round_trip_if_condition_of_sequence() {
1888 let input_expr = Expr::cond(
1889 Expr::equal_to(
1890 Expr::identifier_global("foo", None),
1891 Expr::identifier_global("bar", None),
1892 ),
1893 Expr::sequence(
1894 vec![
1895 Expr::identifier_global("request", None),
1896 Expr::identifier_global("request", None),
1897 ],
1898 None,
1899 ),
1900 Expr::sequence(
1901 vec![
1902 Expr::identifier_global("foo", None),
1903 Expr::identifier_global("bar", None),
1904 ],
1905 None,
1906 ),
1907 );
1908
1909 let expr_str = to_string(&input_expr).unwrap();
1910 let expected_str = r#"if foo == bar then [request, request] else [foo, bar]"#.to_string();
1911 let output_expr = from_string(expr_str.as_str()).unwrap();
1912 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1913 }
1914
1915 #[test]
1916 fn test_round_trip_if_condition_of_record() {
1917 let input_expr = Expr::cond(
1918 Expr::equal_to(
1919 Expr::identifier_global("field1", None),
1920 Expr::identifier_global("field2", None),
1921 ),
1922 Expr::record(vec![(
1923 "field".to_string(),
1924 Expr::identifier_global("request", None),
1925 )]),
1926 Expr::literal("failed"),
1927 );
1928
1929 let expr_str = to_string(&input_expr).unwrap();
1930 let expected_str = r#"if field1 == field2 then {field: request} else "failed""#.to_string();
1931 let output_expr = from_string(expr_str.as_str()).unwrap();
1932 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1933 }
1934
1935 #[test]
1936 fn test_round_trip_if_condition_of_flags() {
1937 let input_expr = Expr::cond(
1938 Expr::equal_to(
1939 Expr::select_field(Expr::identifier_global("worker", None), "response", None),
1940 Expr::number(BigDecimal::from(1)),
1941 ),
1942 Expr::flags(vec!["flag1".to_string(), "flag2".to_string()]),
1943 Expr::literal("failed"),
1944 );
1945
1946 let expr_str = to_string(&input_expr).unwrap();
1947 let expected_str =
1948 r#"if worker.response == 1 then {flag1, flag2} else "failed""#.to_string();
1949 let output_expr = from_string(expr_str.as_str()).unwrap();
1950 assert_eq!((expr_str, input_expr), (expected_str, output_expr));
1951 }
1952}