1use crate::objects::connection::{Connection, ConnectionType};
2use crate::objects::node::{ActionType, Node};
3use crate::syntax::{CoreSyntaxFunctions, FlowDirection, SyntaxConfigFile};
4use enum_as_inner::EnumAsInner;
5use strum::EnumProperty;
6use strum_macros::EnumProperty;
7
8#[derive(EnumProperty, Debug)]
10pub enum Shape {
11 #[strum(props(Left = "((", Right = "))"))]
12 Circle,
13 #[strum(props(Left = "{{", Right = "}}"))]
14 Hexagon,
15 #[strum(props(Left = "[", Right = "]"))]
16 Rectangle,
17 #[strum(props(Left = ">", Right = "]"))]
18 Flag,
19}
20
21#[derive(EnumProperty, Debug)]
23pub enum LineType {
24 #[strum(props(Complete = "--", Addition = "-"))]
25 Solid,
26 #[strum(props(Left = "-.", Right = ".-", Addition = "."))]
27 Dashed,
28}
29
30#[derive(AsRefStr, EnumProperty, Debug, Clone, Copy)]
32pub enum ArrowType {
33 #[strum(props(Left = "<", Right = ">"))]
34 Standard,
35 #[strum(props(Left = "x", Right = "x"))]
36 X,
37 #[strum(props(Left = "o", Right = "o"))]
38 O,
39}
40
41#[derive(AsRefStr, Debug)]
43pub enum ArrowDirection {
44 BiDirectional,
45 Left,
46 Right,
47 None,
48}
49
50#[derive(EnumProperty, EnumAsInner, Debug)]
52pub enum ObjectConfig<'a> {
53 NodeConfig(NodeConfig<'a>),
54 ConnectionConfig(ConnectionConfig),
55}
56
57#[derive(Debug)]
59pub struct NodeConfig<'a> {
60 pub id: &'a str,
62 pub class: Option<String>,
64 pub shape: Shape,
66 pub inner_text: &'a str,
68}
69
70#[derive(Debug)]
72pub struct ConnectionConfig {
73 pub line_type: LineType,
75 pub arrow_type: ArrowType,
77 pub arrow_direction: ArrowDirection,
79 pub extra_length_num: Option<u8>,
81}
82
83pub struct FlowChart {
85 data: String,
87}
88
89impl FlowChart {
90 fn add_dashed_line(
96 &mut self,
97 extra_length_num: Option<u8>,
98 ) {
99 self.data
101 .push_str(LineType::Dashed.get_str("Left").unwrap());
102
103 if let Some(extra_length_num) = extra_length_num {
105 for _ in 0..extra_length_num {
107 self.data
109 .push_str(LineType::Dashed.get_str("Addition").unwrap());
110 }
111 }
112
113 self.data
115 .push_str(LineType::Dashed.get_str("Right").unwrap());
116 }
117
118 fn add_solid_line(
124 &mut self,
125 extra_length_num: Option<u8>,
126 ) {
127 self.data
129 .push_str(LineType::Solid.get_str("Complete").unwrap());
130
131 if let Some(extra_length_num) = extra_length_num {
133 for _ in 0..extra_length_num {
135 self.data
137 .push_str(LineType::Solid.get_str("Addition").unwrap());
138 }
139 }
140 }
141
142 fn add_line(
149 &mut self,
150 line_type: LineType,
151 extra_length_num: Option<u8>,
152 ) {
153 match line_type {
154 LineType::Solid => self.add_solid_line(extra_length_num),
155 LineType::Dashed => self.add_dashed_line(extra_length_num),
156 }
157 }
158
159 fn add_arrow(
166 &mut self,
167 arrow_type: ArrowType,
168 arrow_direction: ArrowDirection,
169 ) {
170 self.data
172 .push_str(arrow_type.get_str(arrow_direction.as_ref()).unwrap())
173 }
174
175 fn get_shape_from_node(
181 &self,
182 node: &Node,
183 ) -> Shape {
184 match node.action {
185 ActionType::Mutation => Shape::Hexagon,
186 ActionType::View => Shape::Circle,
187 ActionType::Process => Shape::Rectangle,
188 ActionType::Event => Shape::Flag,
189 ActionType::None => Shape::Rectangle,
190 }
191 }
192
193 fn get_line_and_arrow_type_from_connection(
199 &self,
200 connection: &Connection,
201 ) -> (LineType, ArrowType, ArrowDirection) {
202 match connection.connection_type {
203 ConnectionType::DirectConnection => {
204 (LineType::Solid, ArrowType::Standard, ArrowDirection::Right)
205 }
206 ConnectionType::CrossContractConnection => {
207 (LineType::Dashed, ArrowType::Standard, ArrowDirection::Right)
208 }
209 ConnectionType::Emission => {
210 (LineType::Dashed, ArrowType::O, ArrowDirection::None)
211 }
212 }
213 }
214}
215
216impl CoreSyntaxFunctions for FlowChart {
217 fn new(direction: FlowDirection) -> Self {
218 let mut schema_root = "flowchart ".to_string();
220
221 schema_root.push_str(direction.as_ref());
223
224 let mut result = FlowChart { data: schema_root };
226
227 result.add_linebreak(None);
229
230 result
231 }
232
233 fn add_node(
234 &mut self,
235 node_config: SyntaxConfigFile,
236 ) {
237 let node_config: NodeConfig = node_config
238 .into_flow_chart()
239 .unwrap()
240 .into_node_config()
241 .unwrap();
242
243 self.data.push_str(node_config.id);
245
246 self.data
248 .push_str(node_config.shape.get_str("Left").unwrap());
249
250 self.data.push_str(node_config.inner_text);
252
253 self.data
255 .push_str(node_config.shape.get_str("Right").unwrap());
256
257 if let Some(class) = node_config.class {
259 self.data.push_str(":::");
260 self.data.push_str(class.as_str());
261 }
262 }
263
264 fn add_connection(
265 &mut self,
266 connection_config: SyntaxConfigFile,
267 ) {
268 let connection_config: ConnectionConfig = connection_config
270 .into_flow_chart()
271 .unwrap()
272 .into_connection_config()
273 .unwrap();
274
275 self.data.push(' ');
277
278 match connection_config.arrow_direction {
280 ArrowDirection::BiDirectional => {
281 self.add_arrow(connection_config.arrow_type, ArrowDirection::Left);
282 self.add_line(
283 connection_config.line_type,
284 connection_config.extra_length_num,
285 );
286 self.add_arrow(connection_config.arrow_type, ArrowDirection::Right)
287 }
288 ArrowDirection::Left => {
289 self.add_arrow(
290 connection_config.arrow_type,
291 connection_config.arrow_direction,
292 );
293 self.add_line(
294 connection_config.line_type,
295 connection_config.extra_length_num,
296 )
297 }
298 ArrowDirection::Right => {
299 self.add_line(
300 connection_config.line_type,
301 connection_config.extra_length_num,
302 );
303 self.add_arrow(
304 connection_config.arrow_type,
305 connection_config.arrow_direction,
306 )
307 }
308 ArrowDirection::None => {
309 self.add_line(
310 connection_config.line_type,
311 connection_config.extra_length_num,
312 );
313 }
314 }
315
316 self.data.push(' ');
318 }
319
320 fn add_linebreak(
321 &mut self,
322 num_of_indents: Option<u8>,
323 ) {
324 let number_of_indents = num_of_indents.unwrap_or(1);
326
327 self.data += "\n";
329
330 for _ in 0..number_of_indents {
332 self.data += "\t";
334 }
335 }
336
337 fn build_node_config<'a>(
338 &self,
339 node: &'a Node,
340 id: Option<&'a str>,
341 ) -> SyntaxConfigFile<'a> {
342 if let Some(id) = id {
343
344 SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
346 id,
347 class: Some(format!("{}-{}",node.scope.as_ref(),node.action.as_ref())),
348 shape: self.get_shape_from_node(node),
349 inner_text: &node.name,
350 }))
351 } else {
352 SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
354 id: &node.name,
355 class: Some(format!("{}-{}",node.scope.as_ref(),node.action.as_ref())),
356 shape: self.get_shape_from_node(node),
357 inner_text: &node.name,
358 }))
359 }
360 }
361
362 fn build_connection_config<'a>(
363 &self,
364 connection: &'a Connection,
365 extra_length_num: Option<u8>,
366 ) -> SyntaxConfigFile<'a> {
367 let (line_type, arrow_type, arrow_direction) =
368 self.get_line_and_arrow_type_from_connection(connection);
369
370 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
371 line_type,
372 arrow_type,
373 arrow_direction,
374 extra_length_num,
375 }))
376 }
377
378 fn return_schema(&self) -> String {
379 self.data.clone()
380 }
381}
382
383#[cfg(test)]
384mod tests {
385 use super::*;
386
387 #[test]
388 fn it_creates_a_circle() {
389 let mut flow_chart = FlowChart::new(FlowDirection::TD);
391
392 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
393 id: "A",
394 class: None,
395 shape: Shape::Circle,
396 inner_text: "inner text",
397 }));
398
399 flow_chart.add_node(node_config);
401
402 let expected = r"flowchart TD
404 A((inner text))";
405
406 println!("{}", flow_chart.data);
407
408 assert_eq!(flow_chart.data, expected);
409 }
410
411 #[test]
412 fn it_creates_a_rectangle() {
413 let mut flow_chart = FlowChart::new(FlowDirection::TD);
415
416 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
417 id: "A",
418 class: None,
419 shape: Shape::Rectangle,
420 inner_text: "inner text",
421 }));
422
423 flow_chart.add_node(node_config);
425
426 let expected = r"flowchart TD
428 A[inner text]";
429
430 assert_eq!(flow_chart.data, expected);
431 }
432
433 #[test]
434 fn it_creates_a_hexagon() {
435 let mut flow_chart = FlowChart::new(FlowDirection::TD);
437
438 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
439 id: "A",
440 class: None,
441 shape: Shape::Hexagon,
442 inner_text: "inner text",
443 }));
444
445 flow_chart.add_node(node_config);
447
448 let expected = r"flowchart TD
450 A{{inner text}}";
451
452 assert_eq!(flow_chart.data, expected);
453 }
454
455 #[test]
456 fn it_creates_a_flag() {
457 let mut flow_chart = FlowChart::new(FlowDirection::TD);
459
460 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
461 id: "A",
462 class: None,
463 shape: Shape::Flag,
464 inner_text: "inner text",
465 }));
466
467 flow_chart.add_node(node_config);
469
470 let expected = r"flowchart TD
472 A>inner text]";
473
474 assert_eq!(flow_chart.data, expected);
475 }
476
477 #[test]
478 fn it_adds_a_dashed_line_with_right_arrow() {
479 let mut flow_chart = FlowChart::new(FlowDirection::TD);
481
482 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
483 id: "A",
484 class: None,
485 shape: Shape::Flag,
486 inner_text: "inner text",
487 }));
488
489 flow_chart.add_node(node_config);
491
492 let connection_config =
493 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
494 line_type: LineType::Dashed,
495 arrow_type: ArrowType::Standard,
496 arrow_direction: ArrowDirection::Right,
497 extra_length_num: None,
498 }));
499
500 flow_chart.add_connection(connection_config);
502
503 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
504 id: "B",
505 class: None,
506 shape: Shape::Flag,
507 inner_text: "inner text",
508 }));
509
510 flow_chart.add_node(node_config);
512
513 let expected = r"flowchart TD
515 A>inner text] -..-> B>inner text]";
516
517 assert_eq!(flow_chart.data, expected);
518 }
519
520 #[test]
521 fn it_adds_a_dashed_line_with_no_arrow() {
522 let mut flow_chart = FlowChart::new(FlowDirection::TD);
524
525 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
526 id: "A",
527 class: None,
528 shape: Shape::Flag,
529 inner_text: "inner text",
530 }));
531
532 flow_chart.add_node(node_config);
534
535 let connection_config =
536 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
537 line_type: LineType::Dashed,
538 arrow_type: ArrowType::Standard,
539 arrow_direction: ArrowDirection::None,
540 extra_length_num: None,
541 }));
542
543 flow_chart.add_connection(connection_config);
545
546 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
547 id: "B",
548 class: None,
549 shape: Shape::Flag,
550 inner_text: "inner text",
551 }));
552
553 flow_chart.add_node(node_config);
555
556 let expected = r"flowchart TD
558 A>inner text] -..- B>inner text]";
559
560 assert_eq!(flow_chart.data, expected);
561 }
562
563 #[test]
564 fn it_adds_a_dashed_line_with_left_arrow() {
565 let mut flow_chart = FlowChart::new(FlowDirection::TD);
567
568 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
569 id: "A",
570 class: None,
571 shape: Shape::Flag,
572 inner_text: "inner text",
573 }));
574
575 flow_chart.add_node(node_config);
577
578 let connection_config =
579 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
580 line_type: LineType::Dashed,
581 arrow_type: ArrowType::Standard,
582 arrow_direction: ArrowDirection::Left,
583 extra_length_num: None,
584 }));
585
586 flow_chart.add_connection(connection_config);
588
589 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
590 id: "B",
591 class: None,
592 shape: Shape::Flag,
593 inner_text: "inner text",
594 }));
595
596 flow_chart.add_node(node_config);
598
599 let expected = r"flowchart TD
601 A>inner text] <-..- B>inner text]";
602
603 assert_eq!(flow_chart.data, expected);
604 }
605
606 #[test]
607 fn it_adds_a_dashed_line_with_bidirectional_arrow() {
608 let mut flow_chart = FlowChart::new(FlowDirection::TD);
610
611 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
612 id: "A",
613 class: None,
614 shape: Shape::Flag,
615 inner_text: "inner text",
616 }));
617
618 flow_chart.add_node(node_config);
620
621 let connection_config =
622 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
623 line_type: LineType::Dashed,
624 arrow_type: ArrowType::Standard,
625 arrow_direction: ArrowDirection::BiDirectional,
626 extra_length_num: None,
627 }));
628
629 flow_chart.add_connection(connection_config);
631
632 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
633 id: "B",
634 class: None,
635 shape: Shape::Flag,
636 inner_text: "inner text",
637 }));
638
639 flow_chart.add_node(node_config);
641
642 let expected = r"flowchart TD
644 A>inner text] <-..-> B>inner text]";
645
646 assert_eq!(flow_chart.data, expected);
647 }
648
649 #[test]
650 fn it_adds_a_dashed_line_with_right_o_arrow() {
651 let mut flow_chart = FlowChart::new(FlowDirection::TD);
653
654 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
655 id: "A",
656 class: None,
657 shape: Shape::Flag,
658 inner_text: "inner text",
659 }));
660
661 flow_chart.add_node(node_config);
663
664 let connection_config =
665 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
666 line_type: LineType::Dashed,
667 arrow_type: ArrowType::O,
668 arrow_direction: ArrowDirection::Right,
669 extra_length_num: None,
670 }));
671
672 flow_chart.add_connection(connection_config);
674
675 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
676 id: "B",
677 class: None,
678 shape: Shape::Flag,
679 inner_text: "inner text",
680 }));
681
682 flow_chart.add_node(node_config);
684
685 let expected = r"flowchart TD
687 A>inner text] -..-o B>inner text]";
688
689 assert_eq!(flow_chart.data, expected);
690 }
691
692 #[test]
693 fn it_adds_a_dashed_line_with_left_o_arrow() {
694 let mut flow_chart = FlowChart::new(FlowDirection::TD);
696
697 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
698 id: "A",
699 class: None,
700 shape: Shape::Flag,
701 inner_text: "inner text",
702 }));
703
704 flow_chart.add_node(node_config);
706
707 let connection_config =
708 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
709 line_type: LineType::Dashed,
710 arrow_type: ArrowType::O,
711 arrow_direction: ArrowDirection::Left,
712 extra_length_num: None,
713 }));
714
715 flow_chart.add_connection(connection_config);
717
718 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
719 id: "B",
720 class: None,
721 shape: Shape::Flag,
722 inner_text: "inner text",
723 }));
724
725 flow_chart.add_node(node_config);
727
728 let expected = r"flowchart TD
730 A>inner text] o-..- B>inner text]";
731
732 assert_eq!(flow_chart.data, expected);
733 }
734
735 #[test]
736 fn it_adds_a_dashed_line_with_bidirectional_o_arrow() {
737 let mut flow_chart = FlowChart::new(FlowDirection::TD);
739
740 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
741 id: "A",
742 class: None,
743 shape: Shape::Flag,
744 inner_text: "inner text",
745 }));
746
747 flow_chart.add_node(node_config);
749
750 let connection_config =
751 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
752 line_type: LineType::Dashed,
753 arrow_type: ArrowType::O,
754 arrow_direction: ArrowDirection::BiDirectional,
755 extra_length_num: None,
756 }));
757
758 flow_chart.add_connection(connection_config);
760
761 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
762 id: "B",
763 class: None,
764 shape: Shape::Flag,
765 inner_text: "inner text",
766 }));
767
768 flow_chart.add_node(node_config);
770
771 let expected = r"flowchart TD
773 A>inner text] o-..-o B>inner text]";
774
775 assert_eq!(flow_chart.data, expected);
776 }
777
778 #[test]
779 fn it_adds_a_dashed_line_with_right_x_arrow() {
780 let mut flow_chart = FlowChart::new(FlowDirection::TD);
782
783 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
784 id: "A",
785 class: None,
786 shape: Shape::Flag,
787 inner_text: "inner text",
788 }));
789
790 flow_chart.add_node(node_config);
792
793 let connection_config =
794 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
795 line_type: LineType::Dashed,
796 arrow_type: ArrowType::X,
797 arrow_direction: ArrowDirection::Right,
798 extra_length_num: None,
799 }));
800
801 flow_chart.add_connection(connection_config);
803
804 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
805 id: "B",
806 class: None,
807 shape: Shape::Flag,
808 inner_text: "inner text",
809 }));
810
811 flow_chart.add_node(node_config);
813
814 let expected = r"flowchart TD
816 A>inner text] -..-x B>inner text]";
817
818 assert_eq!(flow_chart.data, expected);
819 }
820
821 #[test]
822 fn it_adds_a_dashed_line_with_left_x_arrow() {
823 let mut flow_chart = FlowChart::new(FlowDirection::TD);
825
826 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
827 id: "A",
828 class: None,
829 shape: Shape::Flag,
830 inner_text: "inner text",
831 }));
832
833 flow_chart.add_node(node_config);
835
836 let connection_config =
837 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
838 line_type: LineType::Dashed,
839 arrow_type: ArrowType::X,
840 arrow_direction: ArrowDirection::Left,
841 extra_length_num: None,
842 }));
843
844 flow_chart.add_connection(connection_config);
846
847 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
848 id: "B",
849 class: None,
850 shape: Shape::Flag,
851 inner_text: "inner text",
852 }));
853
854 flow_chart.add_node(node_config);
856
857 let expected = r"flowchart TD
859 A>inner text] x-..- B>inner text]";
860
861 assert_eq!(flow_chart.data, expected);
862 }
863
864 #[test]
865 fn it_adds_a_dashed_line_with_bidirectional_x_arrow() {
866 let mut flow_chart = FlowChart::new(FlowDirection::TD);
868
869 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
870 id: "A",
871 class: None,
872 shape: Shape::Flag,
873 inner_text: "inner text",
874 }));
875
876 flow_chart.add_node(node_config);
878
879 let connection_config =
880 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
881 line_type: LineType::Dashed,
882 arrow_type: ArrowType::X,
883 arrow_direction: ArrowDirection::BiDirectional,
884 extra_length_num: None,
885 }));
886
887 flow_chart.add_connection(connection_config);
889
890 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
891 id: "B",
892 class: None,
893 shape: Shape::Flag,
894 inner_text: "inner text",
895 }));
896
897 flow_chart.add_node(node_config);
899
900 let expected = r"flowchart TD
902 A>inner text] x-..-x B>inner text]";
903
904 assert_eq!(flow_chart.data, expected);
905 }
906
907 #[test]
908 fn it_adds_a_dashed_line_with_bidirectional_x_arrow_and_extra_length() {
909 let mut flow_chart = FlowChart::new(FlowDirection::TD);
911
912 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
913 id: "A",
914 class: None,
915 shape: Shape::Flag,
916 inner_text: "inner text",
917 }));
918
919 flow_chart.add_node(node_config);
921
922 let connection_config =
923 SyntaxConfigFile::FlowChart(ObjectConfig::ConnectionConfig(ConnectionConfig {
924 line_type: LineType::Dashed,
925 arrow_type: ArrowType::X,
926 arrow_direction: ArrowDirection::BiDirectional,
927 extra_length_num: Some(1),
928 }));
929
930 flow_chart.add_connection(connection_config);
932
933 let node_config = SyntaxConfigFile::FlowChart(ObjectConfig::NodeConfig(NodeConfig {
934 id: "B",
935 class: None,
936 shape: Shape::Flag,
937 inner_text: "inner text",
938 }));
939
940 flow_chart.add_node(node_config);
942
943 let expected = r"flowchart TD
945 A>inner text] x-...-x B>inner text]";
946
947 assert_eq!(flow_chart.data, expected);
948 }
949}