mermaid_markdown_api/syntax/
flow_chart.rs

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/// The various different shapes enabled by this syntax.
9#[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/// The various different line types enabled by this syntax.
22#[derive(EnumProperty, Debug)]
23pub enum LineType {
24    #[strum(props(Complete = "--", Addition = "-"))]
25    Solid,
26    #[strum(props(Left = "-.", Right = ".-", Addition = "."))]
27    Dashed,
28}
29
30/// The various different arrow types enabled by this syntax.
31#[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/// The various different arrow directions enabled by this syntax.
42#[derive(AsRefStr, Debug)]
43pub enum ArrowDirection {
44    BiDirectional,
45    Left,
46    Right,
47    None,
48}
49
50/// An enum representation of either a [NodeConfig] or a [ConnectionConfig].
51#[derive(EnumProperty, EnumAsInner, Debug)]
52pub enum ObjectConfig<'a> {
53    NodeConfig(NodeConfig<'a>),
54    ConnectionConfig(ConnectionConfig),
55}
56
57/// A struct representing the possible attributes for a [Node].
58#[derive(Debug)]
59pub struct NodeConfig<'a> {
60    /// The ID that will be assigned to this node
61    pub id: &'a str,
62    /// An optional class name to assign to the node
63    pub class: Option<String>,
64    /// The shape of the node
65    pub shape: Shape,
66    /// The text to be displayed within the node
67    pub inner_text: &'a str,
68}
69
70/// A struct representing the possible attributes for a [Connection].
71#[derive(Debug)]
72pub struct ConnectionConfig {
73    /// The enum representation of the type of line you want
74    pub line_type: LineType,
75    /// The enum representation of the type of arrow you want
76    pub arrow_type: ArrowType,
77    /// The enum representation of the direction you want the arrows to point
78    pub arrow_direction: ArrowDirection,
79    /// An optional amount of additional flags to increase line length
80    pub extra_length_num: Option<u8>,
81}
82
83/// This is the root struct for an individual flow chart.
84pub struct FlowChart {
85    /// This is the data location of the string data for the markdown
86    data: String,
87}
88
89impl FlowChart {
90    /// Creates a [Mermaid.js Dotted/Dashed Line](https://mermaid-js.github.io/mermaid/#/flowchart?id=dotted-link) with the supplied attributes & appends it to the current data of the flow chart struct (i.e. `self.data`).
91    ///
92    /// # Arguments
93    ///
94    /// * `extra_length_num` - An optional amount of additional flags to increase line length
95    fn add_dashed_line(
96        &mut self,
97        extra_length_num: Option<u8>,
98    ) {
99        // Push the left half of the dashed line flag
100        self.data
101            .push_str(LineType::Dashed.get_str("Left").unwrap());
102
103        // Check to see if an additional length was requested
104        if let Some(extra_length_num) = extra_length_num {
105            // Range over `extra_length_num` to add the appropriate number of length additions
106            for _ in 0..extra_length_num {
107                // Add in a `.`
108                self.data
109                    .push_str(LineType::Dashed.get_str("Addition").unwrap());
110            }
111        }
112
113        // Push the right half of the dashed line flag
114        self.data
115            .push_str(LineType::Dashed.get_str("Right").unwrap());
116    }
117
118    /// Creates a [Mermaid.js Solid Line](https://mermaid-js.github.io/mermaid/#/flowchart?id=a-link-with-arrow-head) with the supplied attributes & appends it to the current data of the flow chart struct (i.e. `self.data`).
119    ///
120    /// # Arguments
121    ///
122    /// * `extra_length_num` - An optional amount of additional flags to increase line length
123    fn add_solid_line(
124        &mut self,
125        extra_length_num: Option<u8>,
126    ) {
127        // Push the main portion of the solid line flag
128        self.data
129            .push_str(LineType::Solid.get_str("Complete").unwrap());
130
131        // Check to see if an additional length was requested
132        if let Some(extra_length_num) = extra_length_num {
133            // Range over `extra_length_num` to add the appropriate number of length additions
134            for _ in 0..extra_length_num {
135                // Add in a `-`
136                self.data
137                    .push_str(LineType::Solid.get_str("Addition").unwrap());
138            }
139        }
140    }
141
142    /// Creates a [Mermaid.js Connection Line with no arrow](https://mermaid-js.github.io/mermaid/#/flowchart?id=links-between-nodes) with the supplied attributes & appends it to the current data of the flow chart struct (i.e. `self.data`).
143    ///
144    /// # Arguments
145    ///
146    /// * `line_type` - The enum representation of the line type you want
147    /// * `extra_length_num` - An optional amount of additional flags to increase line length
148    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    /// Creates a [Mermaid.js Arrow](https://mermaid-js.github.io/mermaid/#/flowchart?id=new-arrow-types) with the supplied attributes & appends it to the current data of the flow chart struct (i.e. `self.data`).
160    ///
161    /// # Arguments
162    ///
163    /// * `arrow_type` - The enum representation of the arrow type you want
164    /// * `arrow_direction` - The enum representation of the direction you want the arrow to
165    fn add_arrow(
166        &mut self,
167        arrow_type: ArrowType,
168        arrow_direction: ArrowDirection,
169    ) {
170        // Get the `arrow_direction` as a str to use as the key for the `ArrowType` enum property to then add the correct arrow flag
171        self.data
172            .push_str(arrow_type.get_str(arrow_direction.as_ref()).unwrap())
173    }
174
175    /// Determines which [Shape] to put in a [NodeConfig].
176    ///
177    /// # Arguments
178    ///
179    /// * `node` - The [Node] that is being represented
180    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    /// Determines which [LineType] & [ArrowType] to put in a [ConnectionConfig].
194    ///
195    /// # Arguments
196    ///
197    /// * `connection` - The [Connection] that is being represented
198    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        // Instantiate the starting point for the diagram schema
219        let mut schema_root = "flowchart ".to_string();
220
221        // Add in `direction`
222        schema_root.push_str(direction.as_ref());
223
224        // Instantiate `FlowChart`
225        let mut result = FlowChart { data: schema_root };
226
227        // Add a new line
228        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        // Push the ID
244        self.data.push_str(node_config.id);
245
246        // Push the left shape flag
247        self.data
248            .push_str(node_config.shape.get_str("Left").unwrap());
249
250        // Push the inner text
251        self.data.push_str(node_config.inner_text);
252
253        // Push the left shape flag
254        self.data
255            .push_str(node_config.shape.get_str("Right").unwrap());
256
257        // If a class name was passed push it to `self.data`
258        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        // Unwrap the `SyntaxConfigFile` into the needed `ConnectionConfig`
269        let connection_config: ConnectionConfig = connection_config
270            .into_flow_chart()
271            .unwrap()
272            .into_connection_config()
273            .unwrap();
274
275        // Push a preceding space
276        self.data.push(' ');
277
278        // Depending on the arrow direction wanted make calls to `self.add_arrow` & `self.add_line`
279        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        // Push a trailing space
317        self.data.push(' ');
318    }
319
320    fn add_linebreak(
321        &mut self,
322        num_of_indents: Option<u8>,
323    ) {
324        // Get the number of indents to use
325        let number_of_indents = num_of_indents.unwrap_or(1);
326
327        // Add the new line
328        self.data += "\n";
329
330        // Range over `number_of_indents` to add the appropriate number of tabs
331        for _ in 0..number_of_indents {
332            // Add in a tab
333            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            // If an ID was passed use it
345            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            // Else use the Node's name
353            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        // Instantiate the flow chart
390        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        // Add the node to check afterwards
400        flow_chart.add_node(node_config);
401
402        // The string we are expecting
403        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        // Instantiate the flow chart
414        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        // Add the node to check afterwards
424        flow_chart.add_node(node_config);
425
426        // The string we are expecting
427        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        // Instantiate the flow chart
436        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        // Add the node to check afterwards
446        flow_chart.add_node(node_config);
447
448        // The string we are expecting
449        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        // Instantiate the flow chart
458        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        // Add the node to check afterwards
468        flow_chart.add_node(node_config);
469
470        // The string we are expecting
471        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        // Instantiate the flow chart
480        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        // Add the beginning node
490        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        // Add the line to check afterwards
501        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        // Add the trailing node
511        flow_chart.add_node(node_config);
512
513        // The string we are expecting
514        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        // Instantiate the flow chart
523        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        // Add the beginning node
533        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        // Add the line to check afterwards
544        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        // Add the trailing node
554        flow_chart.add_node(node_config);
555
556        // The string we are expecting
557        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        // Instantiate the flow chart
566        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        // Add the beginning node
576        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        // Add the line to check afterwards
587        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        // Add the trailing node
597        flow_chart.add_node(node_config);
598
599        // The string we are expecting
600        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        // Instantiate the flow chart
609        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        // Add the beginning node
619        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        // Add the line to check afterwards
630        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        // Add the trailing node
640        flow_chart.add_node(node_config);
641
642        // The string we are expecting
643        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        // Instantiate the flow chart
652        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        // Add the beginning node
662        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        // Add the line to check afterwards
673        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        // Add the trailing node
683        flow_chart.add_node(node_config);
684
685        // The string we are expecting
686        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        // Instantiate the flow chart
695        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        // Add the beginning node
705        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        // Add the line to check afterwards
716        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        // Add the trailing node
726        flow_chart.add_node(node_config);
727
728        // The string we are expecting
729        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        // Instantiate the flow chart
738        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        // Add the beginning node
748        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        // Add the line to check afterwards
759        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        // Add the trailing node
769        flow_chart.add_node(node_config);
770
771        // The string we are expecting
772        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        // Instantiate the flow chart
781        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        // Add the beginning node
791        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        // Add the line to check afterwards
802        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        // Add the trailing node
812        flow_chart.add_node(node_config);
813
814        // The string we are expecting
815        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        // Instantiate the flow chart
824        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        // Add the beginning node
834        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        // Add the line to check afterwards
845        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        // Add the trailing node
855        flow_chart.add_node(node_config);
856
857        // The string we are expecting
858        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        // Instantiate the flow chart
867        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        // Add the beginning node
877        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        // Add the line to check afterwards
888        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        // Add the trailing node
898        flow_chart.add_node(node_config);
899
900        // The string we are expecting
901        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        // Instantiate the flow chart
910        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        // Add the beginning node
920        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        // Add the line to check afterwards
931        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        // Add the trailing node
941        flow_chart.add_node(node_config);
942
943        // The string we are expecting
944        let expected = r"flowchart TD
945	A>inner text] x-...-x B>inner text]";
946
947        assert_eq!(flow_chart.data, expected);
948    }
949}