1use crate::disassembler::DisassembledSegment;
7use edifact_primitives::EdifactDelimiters;
8
9pub fn render_edifact(segments: &[DisassembledSegment], delimiters: &EdifactDelimiters) -> String {
17 let mut out = String::new();
18
19 for seg in segments {
20 render_segment(seg, delimiters, &mut out);
21 }
22
23 out
24}
25
26fn render_segment(seg: &DisassembledSegment, delimiters: &EdifactDelimiters, out: &mut String) {
27 let elem_sep = delimiters.element as char;
28 let comp_sep = delimiters.component as char;
29 let seg_term = delimiters.segment as char;
30
31 out.push_str(&seg.tag);
32
33 for element in &seg.elements {
34 out.push(elem_sep);
35 for (j, component) in element.iter().enumerate() {
37 if j > 0 {
38 out.push(comp_sep);
39 }
40 escape_component(component, delimiters, out);
41 }
42 }
43
44 out.push(seg_term);
45}
46
47fn escape_component(value: &str, delimiters: &EdifactDelimiters, out: &mut String) {
53 delimiters.escape_into(value, out);
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn test_render_segments_to_edifact() {
62 let segments = vec![
63 DisassembledSegment {
64 tag: "UNH".to_string(),
65 elements: vec![
66 vec!["1".to_string()],
67 vec!["UTILMD".to_string(), "D".to_string(), "11A".to_string()],
68 ],
69 },
70 DisassembledSegment {
71 tag: "BGM".to_string(),
72 elements: vec![vec!["E01".to_string()]],
73 },
74 ];
75
76 let delimiters = EdifactDelimiters::default();
77 let rendered = render_edifact(&segments, &delimiters);
78
79 assert_eq!(rendered, "UNH+1+UTILMD:D:11A'BGM+E01'");
80 }
81
82 #[test]
83 fn test_render_empty_segments() {
84 let delimiters = EdifactDelimiters::default();
85 let rendered = render_edifact(&[], &delimiters);
86 assert_eq!(rendered, "");
87 }
88
89 #[test]
90 fn test_render_segment_with_empty_components() {
91 let segments = vec![DisassembledSegment {
92 tag: "CAV".to_string(),
93 elements: vec![vec![
94 "SA".to_string(),
95 String::new(),
96 String::new(),
97 String::new(),
98 ]],
99 }];
100
101 let delimiters = EdifactDelimiters::default();
102 let rendered = render_edifact(&segments, &delimiters);
103
104 assert_eq!(rendered, "CAV+SA:::'");
106 }
107
108 #[test]
109 fn test_render_multiple_elements() {
110 let segments = vec![DisassembledSegment {
111 tag: "DTM".to_string(),
112 elements: vec![vec![
113 "137".to_string(),
114 "20250101".to_string(),
115 "102".to_string(),
116 ]],
117 }];
118
119 let delimiters = EdifactDelimiters::default();
120 let rendered = render_edifact(&segments, &delimiters);
121
122 assert_eq!(rendered, "DTM+137:20250101:102'");
123 }
124
125 #[test]
126 fn test_render_escapes_delimiter_chars_in_values() {
127 let segments = vec![DisassembledSegment {
129 tag: "DTM".to_string(),
130 elements: vec![vec![
131 "137".to_string(),
132 "202603021433+00".to_string(),
133 "303".to_string(),
134 ]],
135 }];
136
137 let delimiters = EdifactDelimiters::default();
138 let rendered = render_edifact(&segments, &delimiters);
139
140 assert_eq!(rendered, "DTM+137:202603021433?+00:303'");
141 }
142
143 #[test]
144 fn test_render_escapes_multiple_special_chars() {
145 let segments = vec![DisassembledSegment {
147 tag: "FTX".to_string(),
148 elements: vec![
149 vec!["ABO".to_string()],
150 vec![],
151 vec![],
152 vec!["hello?+world:test".to_string()],
153 ],
154 }];
155
156 let delimiters = EdifactDelimiters::default();
157 let rendered = render_edifact(&segments, &delimiters);
158
159 assert_eq!(rendered, "FTX+ABO+++hello???+world?:test'");
160 }
161
162 #[test]
163 fn test_render_no_escape_needed_for_plain_values() {
164 let segments = vec![DisassembledSegment {
165 tag: "BGM".to_string(),
166 elements: vec![vec!["312".to_string()], vec!["DOC001".to_string()]],
167 }];
168
169 let delimiters = EdifactDelimiters::default();
170 let rendered = render_edifact(&segments, &delimiters);
171
172 assert_eq!(rendered, "BGM+312+DOC001'");
173 }
174}