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