x12_stream_parser/
lib.rs

1pub mod errors;
2pub mod parser;
3pub mod segment;
4
5pub use errors::ParserError;
6pub use parser::Parser;
7pub use segment::{SegmentSlice, ElementIterator, split_sub_elements};
8pub use x12_delimiters::Delimiters; // Re-export for convenience
9
10
11#[cfg(test)]
12mod tests {
13    use super::*;
14    use x12_delimiters::Delimiters;
15
16    const SIMPLE_INPUT: &[u8] = b"ISA*A*B~GS*C*D~ST*E*F~";
17    
18    // Define delimiter values separately as constants
19    const SEG_TERM: u8 = b'~';
20    const ELEM_SEP: u8 = b'*';
21    const SUB_ELEM_SEP: u8 = b':';
22    
23    // Create a function to get delimiters to avoid const initialization issues
24    fn default_delims() -> Delimiters {
25        Delimiters::new(SEG_TERM, ELEM_SEP, SUB_ELEM_SEP)
26    }
27
28    #[test]
29    fn test_simple_parse() {
30        let parser = Parser::new(SIMPLE_INPUT, default_delims());
31        let segments: Vec<_> = parser.collect::<Result<Vec<_>, _>>().unwrap();
32
33        assert_eq!(segments.len(), 3);
34
35        assert_eq!(segments[0].id(), b"ISA");
36        let isa_elements: Vec<&[u8]> = segments[0].elements().collect();
37        assert_eq!(isa_elements, vec![b"A", b"B"]);
38
39        assert_eq!(segments[1].id(), b"GS");
40        let gs_elements: Vec<&[u8]> = segments[1].elements().collect();
41        assert_eq!(gs_elements, vec![b"C", b"D"]);
42
43        assert_eq!(segments[2].id(), b"ST");
44        let st_elements: Vec<&[u8]> = segments[2].elements().collect();
45        assert_eq!(st_elements, vec![b"E", b"F"]);
46    }
47
48    #[test]
49    fn test_empty_elements() {
50        let input = b"SEG*A**C~";
51        let parser = Parser::new(input, default_delims());
52        let segments = parser.collect::<Result<Vec<_>, _>>().unwrap();
53
54        assert_eq!(segments.len(), 1);
55        assert_eq!(segments[0].id(), b"SEG");
56        let elements: Vec<&[u8]> = segments[0].elements().collect();
57        assert_eq!(elements, vec![b"A", &b""[..], b"C"]);
58    }
59
60    #[test]
61    fn test_trailing_element_separator() {
62        let input = b"SEG*A*B*~";
63        let parser = Parser::new(input, default_delims());
64        let segments = parser.collect::<Result<Vec<_>, _>>().unwrap();
65
66        assert_eq!(segments.len(), 1);
67        assert_eq!(segments[0].id(), b"SEG");
68        let elements: Vec<&[u8]> = segments[0].elements().collect();
69        // The parser currently doesn't count a trailing separator as an empty element
70        assert_eq!(elements, vec![b"A", b"B"]);
71    }
72
73    #[test]
74    fn test_no_elements() {
75        let input = b"ISE~";
76        let parser = Parser::new(input, default_delims());
77        let segments = parser.collect::<Result<Vec<_>, _>>().unwrap();
78
79        assert_eq!(segments.len(), 1);
80        assert_eq!(segments[0].id(), b"ISE");
81        let elements: Vec<&[u8]> = segments[0].elements().collect();
82        // Data part is empty, iterator should yield nothing
83        assert_eq!(elements, Vec::<&[u8]>::new());
84    }
85
86    #[test]
87    fn test_unterminated_segment() {
88        let input = b"ISA*A*B~GS*C*D"; // Missing final '~'
89        let mut parser = Parser::new(input, default_delims());
90        assert!(parser.next().unwrap().is_ok()); // ISA is fine
91        let last = parser.next(); // Try to get GS
92        assert!(last.is_some());
93        assert_eq!(last.unwrap().err().unwrap(), ParserError::UnterminatedSegment);
94        assert!(parser.next().is_none()); // Iterator is exhausted
95    }
96
97    #[test]
98    fn test_empty_input() {
99        let input = b"";
100        let mut parser = Parser::new(input, default_delims());
101        assert!(parser.next().is_none());
102    }
103
104    #[test]
105    fn test_only_terminators() {
106        let input = b"~~~"; // Should yield nothing valid
107        let mut parser = Parser::new(input, default_delims());
108        assert!(parser.next().is_none()); // Skips empty segments between terminators
109        assert!(parser.next().is_none());
110    }
111
112    #[test]
113    fn test_segment_then_terminators() {
114        let input = b"ABC*1~~\n~"; // Trailing terminators and whitespace chars (like \n) might appear
115        let delim = Delimiters::new(b'~', b'*', b':');
116        let mut parser = Parser::new(input, delim);
117
118        let seg1 = parser.next().unwrap().unwrap();
119        assert_eq!(seg1.id(), b"ABC");
120        let elements: Vec<&[u8]> = seg1.elements().collect();
121        assert_eq!(elements, &[b"1"]);
122
123        // The parser will continue to consume input until it's done
124        // Since it's finding some non-terminator content (likely newline),
125        // we need to consume whatever is left
126        while let Some(_) = parser.next() {}
127    }
128
129    #[test]
130    fn test_sub_element_splitting() {
131        let element_data = b"AA:B:CCC::E";
132        let sub_elements: Vec<&[u8]> = split_sub_elements(element_data, b':').collect();
133        assert_eq!(sub_elements, vec![b"AA", &b"B"[..], b"CCC", &b""[..], b"E"]);
134
135        let element_data_no_sub = b"JUSTONE";
136        let sub_elements_no_sub: Vec<&[u8]> = split_sub_elements(element_data_no_sub, b':').collect();
137        assert_eq!(sub_elements_no_sub, vec![b"JUSTONE"]);
138
139        let element_data_empty = b"";
140        let sub_elements_empty: Vec<&[u8]> = split_sub_elements(element_data_empty, b':').collect();
141        assert_eq!(sub_elements_empty, vec![b""]); // split behavior on empty yields one empty str
142    }
143
144    #[test]
145    fn test_alternative_delimiters() {
146        let input = b"ISA^A^B}GS^C^D}ST^E^F}";
147        let alt_delims = Delimiters::new(b'}', b'^', b'>');
148        let parser = Parser::new(input, alt_delims);
149        let segments: Vec<_> = parser.collect::<Result<Vec<_>, _>>().unwrap();
150
151        assert_eq!(segments.len(), 3);
152        assert_eq!(segments[0].id(), b"ISA");
153        assert_eq!(segments[0].elements().collect::<Vec<_>>(), vec![b"A", b"B"]);
154        assert_eq!(segments[1].id(), b"GS");
155        assert_eq!(segments[1].elements().collect::<Vec<_>>(), vec![b"C", b"D"]);
156        assert_eq!(segments[2].id(), b"ST");
157        assert_eq!(segments[2].elements().collect::<Vec<_>>(), vec![b"E", b"F"]);
158
159        assert_eq!(segments[0].element_separator(), b'^');
160        assert_eq!(segments[0].sub_element_separator(), b'>'); // Check separators stored correctly
161    }
162}