1#![feature(rustc_private)]
23#![feature(str_as_str)]
24extern crate rumtk_core;
25pub mod hl7_v2_base_types;
26pub mod hl7_v2_complex_types;
27pub mod hl7_v2_constants;
28pub mod hl7_v2_datasets;
29pub mod hl7_v2_field_descriptors;
30pub mod hl7_v2_interpreter;
31pub mod hl7_v2_mllp;
32mod hl7_v2_optionality_rules;
33pub mod hl7_v2_parser;
34mod hl7_v2_scripting;
35pub mod hl7_v2_search;
36pub mod hl7_v2_types;
37#[cfg(test)]
39mod tests {
40 use crate::hl7_v2_base_types::v2_base_types::{
41 V2DateTime, V2ParserCharacters, V2SearchIndex, V2String,
42 };
43 use crate::hl7_v2_base_types::v2_primitives::{
44 V2PrimitiveCasting, V2PrimitiveType, TRUNCATE_FT,
45 };
46 use crate::hl7_v2_complex_types::hl7_v2_complex_types::{cast_component, V2Type};
47 use crate::hl7_v2_constants::{V2_SEGMENT_IDS, V2_SEGMENT_NAMES};
48 use crate::hl7_v2_field_descriptors::v2_field_descriptor::{
49 V2ComponentType, V2ComponentTypeDescriptor,
50 };
51 use crate::hl7_v2_mllp::mllp_v2::{mllp_decode, mllp_encode, CR, EB, MLLP_FILTER_POLICY, SB};
52 use crate::hl7_v2_optionality_rules::Optionality;
53 use crate::hl7_v2_parser::v2_parser::{V2Field, V2Message};
54 use crate::hl7_v2_search::REGEX_V2_SEARCH_DEFAULT;
55 use crate::{
56 rumtk_v2_find_component, rumtk_v2_generate_message, rumtk_v2_mllp_connect,
57 rumtk_v2_mllp_get_client_ids, rumtk_v2_mllp_get_ip_port, rumtk_v2_mllp_iter_channels,
58 rumtk_v2_mllp_listen, rumtk_v2_mllp_send, rumtk_v2_parse_message,
59 };
60 use rumtk_core::core::RUMResult;
61 use rumtk_core::search::rumtk_search::{string_search_named_captures, SearchGroups};
62 use rumtk_core::strings::{
63 basic_escape, rumtk_format, AsStr, RUMArrayConversions, RUMString, RUMStringConversions,
64 StringUtils,
65 };
66 use rumtk_core::{
67 rumtk_create_task, rumtk_deserialize, rumtk_exec_task, rumtk_init_threads, rumtk_serialize,
68 rumtk_sleep,
69 };
70 use std::thread::spawn;
71 use crate::hl7_v2_datasets::{hl7_v2_messages::*, hl7_v2_test_fragments::*};
73
74 #[test]
76 fn test_hl7_v2_field_parsing() {
77 let field_str = DEFAULT_HL7_V2_FIELD_STRING;
78 let encode_chars = V2ParserCharacters::new();
79 let field = V2Field::from_str(&field_str, &encode_chars);
80 println!("{:#?}", &field);
81 assert_eq!(field.len(), 3, "Wrong number of components in field");
82 println!(
83 "Value in component {} => {}!",
84 0,
85 field.get(1).unwrap().as_str()
86 );
87 assert_eq!(
88 field.get(1).unwrap().as_str(),
89 "2000",
90 "Wrong value in component!"
91 );
92 println!(
93 "Value in component {} => {}!",
94 1,
95 field.get(2).unwrap().as_str()
96 );
97 assert_eq!(
98 field.get(2).unwrap().as_str(),
99 "2012",
100 "Wrong value in component!"
101 );
102 println!(
103 "Value in component {} => {}!",
104 2,
105 field.get(3).unwrap().as_str()
106 );
107 assert_eq!(
108 field.get(3).unwrap().as_str(),
109 "01",
110 "Wrong value in component!"
111 );
112 }
113
114 #[test]
115 fn test_sanitize_hl7_v2_message() {
116 let message = DEFAULT_HL7_V2_MESSAGE;
117 let sanitized_message = V2Message::sanitize(message);
118 println!("{}", message);
119 println!("{}", sanitized_message);
120 assert!(
121 message.contains('\n'),
122 "Raw message has new line characters."
123 );
124 assert!(
125 !sanitized_message.contains('\n'),
126 "Sanitized message has new line characters."
127 );
128 assert!(!sanitized_message.contains("\r\r"), "Sanitizer failed to consolidate double carriage returns into a single carriage return per instance..");
129 }
130
131 #[test]
132 fn test_tokenize_hl7_v2_message() {
133 let message = DEFAULT_HL7_V2_MESSAGE;
134 let sanitized_message = V2Message::sanitize(message);
135 let tokens = V2Message::tokenize_segments(&sanitized_message.as_str());
136 println!("Token count {}", tokens.len());
137 assert_eq!(
138 tokens.len(),
139 5,
140 "Tokenizer generated the wrong number of tokens! We expected 5 segment tokens."
141 );
142 }
143
144 #[test]
145 fn test_load_hl7_v2_encoding_characters() {
146 let message = DEFAULT_HL7_V2_MESSAGE;
147 let sanitized_message = V2Message::sanitize(message);
148 let tokens = V2Message::tokenize_segments(&sanitized_message.as_str());
149 let encode_chars = V2ParserCharacters::from_msh(tokens[0]).unwrap();
150 println!("{:#?}", encode_chars);
151 assert!(
152 encode_chars.segment_terminator.contains('\r'),
153 "Wrong segment character!"
154 );
155 assert!(
156 encode_chars.field_separator.contains('|'),
157 "Wrong field character!"
158 );
159 assert!(
160 encode_chars.component_separator.contains('^'),
161 "Wrong component character!"
162 );
163 assert!(
164 encode_chars.repetition_separator.contains('~'),
165 "Wrong repetition character!"
166 );
167 assert!(
168 encode_chars.escape_character.contains('\\'),
169 "Wrong escape character!"
170 );
171 assert!(
172 encode_chars.subcomponent_separator.contains('&'),
173 "Wrong subcomponent character!"
174 );
175 assert!(
176 encode_chars.truncation_character.contains('#'),
177 "Wrong truncation character!"
178 );
179 }
180
181 #[test]
182 fn test_extract_hl7_v2_message_segments() {
183 let message = DEFAULT_HL7_V2_MESSAGE;
184 let sanitized_message = V2Message::sanitize(message);
185 let tokens = V2Message::tokenize_segments(&sanitized_message.as_str());
186 let msh = V2Message::find_msh(&tokens).unwrap();
187 let encode_chars = V2ParserCharacters::from_msh(&msh.as_str()).unwrap();
188 let parsed_segments = V2Message::extract_segments(&tokens, &encode_chars).unwrap();
189 let keys = parsed_segments.keys();
190 print!("Keys: ");
191 for k in keys {
192 print!("{} ", V2_SEGMENT_NAMES[k]);
193 }
194 assert_eq!(
195 parsed_segments.len(),
196 5,
197 "Number of segments mismatching what was expected!"
198 );
199 assert!(
200 parsed_segments.contains_key(&V2_SEGMENT_IDS["MSH"]),
201 "Missing MSH segment!"
202 );
203 assert!(
204 parsed_segments.contains_key(&V2_SEGMENT_IDS["PID"]),
205 "Missing PID segment!"
206 );
207 assert!(
208 parsed_segments.contains_key(&V2_SEGMENT_IDS["PV1"]),
209 "Missing PV1 segment!"
210 );
211 assert!(
212 parsed_segments.contains_key(&V2_SEGMENT_IDS["EVN"]),
213 "Missing EVN segment!"
214 );
215 assert!(
216 parsed_segments.contains_key(&V2_SEGMENT_IDS["NK1"]),
217 "Missing NK1 segment!"
218 );
219 }
220
221 #[test]
222 fn test_extract_hl7_v2_message_scrambled_segments() {
223 let message = HL7_V2_SCRAMBLED;
224 let sanitized_message = V2Message::sanitize(message);
225 let tokens = V2Message::tokenize_segments(&sanitized_message.as_str());
226 let msh = V2Message::find_msh(&tokens).unwrap();
227 let encode_chars = V2ParserCharacters::from_msh(&msh.as_str()).unwrap();
228 let parsed_segments = V2Message::extract_segments(&tokens, &encode_chars).unwrap();
229 let keys = parsed_segments.keys();
230 print!("Keys: ");
231 for k in keys {
232 print!("{} ", V2_SEGMENT_NAMES[k]);
233 }
234 assert_eq!(
235 parsed_segments.len(),
236 4,
237 "Number of segments mismatching what was expected!"
238 );
239 assert!(
240 parsed_segments.contains_key(&V2_SEGMENT_IDS["MSH"]),
241 "Missing MSH segment!"
242 );
243 assert!(
244 parsed_segments.contains_key(&V2_SEGMENT_IDS["PID"]),
245 "Missing PID segment!"
246 );
247 assert!(
248 parsed_segments.contains_key(&V2_SEGMENT_IDS["PD1"]),
249 "Missing PV1 segment!"
250 );
251 assert!(
252 parsed_segments.contains_key(&V2_SEGMENT_IDS["RXA"]),
253 "Missing EVN segment!"
254 );
255 }
256
257 #[test]
258 fn test_load_hl7_v2_message() {
259 let message = V2Message::from_str(DEFAULT_HL7_V2_MESSAGE);
260 assert!(
261 message.segment_exists(&V2_SEGMENT_IDS["MSH"]),
262 "Missing MSH segment!"
263 );
264 assert!(
265 message.segment_exists(&V2_SEGMENT_IDS["PID"]),
266 "Missing PID segment!"
267 );
268 assert!(
269 message.segment_exists(&V2_SEGMENT_IDS["PV1"]),
270 "Missing PV1 segment!"
271 );
272 assert!(
273 message.segment_exists(&V2_SEGMENT_IDS["EVN"]),
274 "Missing EVN segment!"
275 );
276 assert!(
277 message.segment_exists(&V2_SEGMENT_IDS["NK1"]),
278 "Missing NK1 segment!"
279 );
280 }
281
282 #[test]
289 fn test_load_hl7_v2_message_wir_iis() {
290 let message = V2Message::from_str(HL7_V2_MESSAGE);
291 assert!(
292 message.segment_exists(&V2_SEGMENT_IDS["MSH"]),
293 "Missing MSH segment!"
294 );
295 assert!(
296 message.segment_exists(&V2_SEGMENT_IDS["FHS"]),
297 "Missing FHS segment!"
298 );
299 assert!(
300 message.segment_exists(&V2_SEGMENT_IDS["NK1"]),
301 "Missing NK1 segment!"
302 );
303 assert!(
304 message.segment_exists(&V2_SEGMENT_IDS["PV1"]),
305 "Missing PV1 segment!"
306 );
307 assert!(
308 message.segment_exists(&V2_SEGMENT_IDS["FTS"]),
309 "Missing FTS segment!"
310 );
311 assert!(
312 message.segment_exists(&V2_SEGMENT_IDS["BHS"]),
313 "Missing BHS segment!"
314 );
315 }
316 #[test]
317 fn test_load_hl7_v2_message_scrambled() {
318 let message = V2Message::from_str(HL7_V2_SCRAMBLED);
319 assert!(
320 message.segment_exists(&V2_SEGMENT_IDS["MSH"]),
321 "Missing MSH segment!"
322 );
323 assert!(
324 message.segment_exists(&V2_SEGMENT_IDS["PID"]),
325 "Missing PID segment!"
326 );
327 assert!(
328 message.segment_exists(&V2_SEGMENT_IDS["PD1"]),
329 "Missing PV1 segment!"
330 );
331 assert!(
332 message.segment_exists(&V2_SEGMENT_IDS["RXA"]),
333 "Missing EVN segment!"
334 );
335 }
336
337 #[test]
341 fn test_load_hl7_v2_utf8_message() {
342 let message = V2Message::from_str(HL7_V2_PDF_MESSAGE);
343 let pid = message.get(&V2_SEGMENT_IDS["PID"], 1).unwrap();
344 let orc = message.get(&V2_SEGMENT_IDS["ORC"], 1).unwrap();
345 let obr = message.get(&V2_SEGMENT_IDS["OBR"], 1).unwrap();
346 let name1 = pid.get(5).unwrap().get(0).unwrap().get(1).unwrap().as_str();
347 let name2 = orc
348 .get(12)
349 .unwrap()
350 .get(0)
351 .unwrap()
352 .get(3)
353 .unwrap()
354 .as_str();
355 let name3 = obr
356 .get(16)
357 .unwrap()
358 .get(0)
359 .unwrap()
360 .get(3)
361 .unwrap()
362 .as_str();
363 println!("{}", name1);
364 println!("{}", name2);
365 println!("{}", name3);
366 assert_eq!(name1, SPANISH_NAME, "Wrong name/string found in PID(1)5.1!");
367 assert_eq!(
368 name2, SANSKRIT_NAME,
369 "Wrong name/string found in ORC(1)12.3!"
370 );
371 assert_eq!(
372 name3, HIRAGANA_NAME,
373 "Wrong name/string found in OBR(1)16.3!"
374 );
375 }
376
377 #[test]
381 fn test_handle_hl7_v2_message_with_repeating_fields() {
382 let message = V2Message::from_str(HL7_V2_REPEATING_FIELD_MESSAGE);
383 let msh = message.get(&V2_SEGMENT_IDS["MSH"], 1).unwrap();
384 let field1 = msh
385 .get(-1)
386 .unwrap()
387 .get(0)
388 .unwrap()
389 .get(4)
390 .unwrap()
391 .as_str();
392 let field2 = msh
393 .get(-1)
394 .unwrap()
395 .get(1)
396 .unwrap()
397 .get(1)
398 .unwrap()
399 .as_str();
400 let field3 = msh
401 .get(-1)
402 .unwrap()
403 .get(2)
404 .unwrap()
405 .get(1)
406 .unwrap()
407 .as_str();
408 assert_eq!(
409 msh.get(-1).unwrap().len(),
410 3,
411 "Wrong number of subfields in group in MSH(1)-1!"
412 );
413 assert_eq!(
414 field1, repeate_field1,
415 "Wrong field contents found in MSH(1)-1(0).4!"
416 );
417 assert_eq!(
418 field2, repeate_field2,
419 "Wrong field contents found in MSH(1)-1(1).1!"
420 );
421 assert_eq!(
422 field3, repeate_field3,
423 "Wrong field contents found in MSH(1)-1(2).1!"
424 );
425 }
426
427 #[test]
428 fn test_generating_v2_message() {
429 let message = rumtk_v2_parse_message!(&DEFAULT_HL7_V2_MESSAGE).unwrap();
430 let generated_message_string = rumtk_v2_generate_message!(&message);
431 let generated_message = rumtk_v2_parse_message!(&generated_message_string).unwrap();
432 assert_eq!(
433 &message, &generated_message,
434 "Messages are not equal! Expected: {:?} Got: {:?}",
435 &message, &generated_message
436 );
437 }
438
439 #[test]
440 fn test_generating_v2_message_wir() {
441 let message = rumtk_v2_parse_message!(&HL7_V2_MESSAGE).unwrap();
442 let generated_message_string = rumtk_v2_generate_message!(&message);
443 let generated_message = rumtk_v2_parse_message!(&generated_message_string).unwrap();
444 assert_eq!(
445 &message, &generated_message,
446 "Messages are not equal! Expected: {:?} Got: {:?}",
447 &message, &generated_message
448 );
449 }
450
451 #[test]
452 fn test_generating_v2_message_pdf() {
453 let message = rumtk_v2_parse_message!(&HL7_V2_PDF_MESSAGE).unwrap();
454 let generated_message_string = rumtk_v2_generate_message!(&message);
455 let generated_message = rumtk_v2_parse_message!(&generated_message_string).unwrap();
456 assert_eq!(
457 &message, &generated_message,
458 "Messages are not equal! Expected: {:?} Got: {:?}",
459 &message, &generated_message
460 );
461 }
462
463 #[test]
464 fn test_generating_v2_message_repeated_fields() {
465 let message = rumtk_v2_parse_message!(&HL7_V2_REPEATING_FIELD_MESSAGE).unwrap();
466 let generated_message_string = rumtk_v2_generate_message!(&message);
467 let generated_message = rumtk_v2_parse_message!(&generated_message_string).unwrap();
468 assert_eq!(
469 &message, &generated_message,
470 "Messages are not equal! Expected: {:?} Got: {:?}",
471 &message, &generated_message
472 );
473 }
474
475 #[test]
476 fn test_handle_hl7_v2_search_pattern_parsing_full() {
477 let pattern = "MSH(1)-1[5].4";
478 let groups = string_search_named_captures(pattern, REGEX_V2_SEARCH_DEFAULT, "1");
479 let expected = SearchGroups::from([
480 (RUMString::new("segment_group"), RUMString::new("1")),
481 (RUMString::new("sub_field"), RUMString::new("5")),
482 (RUMString::new("segment"), RUMString::new("MSH")),
483 (RUMString::new("field"), RUMString::new("-1")),
484 (RUMString::new("component"), RUMString::new("4")),
485 ]);
486 println!(
487 "Input: {:?} Expected: {:?} Got: {:?}",
488 pattern, expected, groups
489 );
490 assert_eq!(
491 groups, expected,
492 "Misparsed search expression MSH(1)-1[5].4!"
493 );
494 }
495
496 #[test]
497 fn test_handle_hl7_v2_search_pattern_parsing_simple() {
498 let pattern = "MSH1.4";
499 let groups = string_search_named_captures(pattern, REGEX_V2_SEARCH_DEFAULT, "1");
500 let expected = SearchGroups::from([
501 (RUMString::new("segment_group"), RUMString::new("1")),
502 (RUMString::new("sub_field"), RUMString::new("1")),
503 (RUMString::new("segment"), RUMString::new("MSH")),
504 (RUMString::new("field"), RUMString::new("1")),
505 (RUMString::new("component"), RUMString::new("4")),
506 ]);
507 println!(
508 "Input: {:?} Expected: {:?} Got: {:?}",
509 pattern, expected, groups
510 );
511 assert_eq!(groups, expected, "Misparsed search expression MSH1.4!");
512 }
513
514 #[test]
515 fn test_v2_search_index() {
516 let expr = "MSH(1)-1[5].4";
517 let v2_search_index = V2SearchIndex::from(expr);
518 let expected = V2SearchIndex::new("MSH", 1, -1, 5, 4);
519 println!(
520 "Input: {:?} Expected: {:?} Got: {:?}",
521 expr, expected, v2_search_index
522 );
523 assert_eq!(
524 v2_search_index, expected,
525 "Failed to parse expression into correct SearchIndex object."
526 );
527 }
528
529 #[test]
530 fn test_load_hl7_v2_message_macro() {
531 let message = rumtk_v2_parse_message!(DEFAULT_HL7_V2_MESSAGE).unwrap();
532 assert!(
533 message.segment_exists(&V2_SEGMENT_IDS["MSH"]),
534 "Missing MSH segment!"
535 );
536 assert!(
537 message.segment_exists(&V2_SEGMENT_IDS["PID"]),
538 "Missing PID segment!"
539 );
540 assert!(
541 message.segment_exists(&V2_SEGMENT_IDS["PV1"]),
542 "Missing PV1 segment!"
543 );
544 assert!(
545 message.segment_exists(&V2_SEGMENT_IDS["EVN"]),
546 "Missing EVN segment!"
547 );
548 assert!(
549 message.segment_exists(&V2_SEGMENT_IDS["NK1"]),
550 "Missing NK1 segment!"
551 );
552 }
553
554 #[test]
555 fn test_load_hl7_v2_message_macro_failure() {
556 let input = "Hello World!";
557 let err_msg = rumtk_format!(
558 "Parsing did not fail as expected. Input {} => parsed?",
559 input
560 );
561 match rumtk_v2_parse_message!(input) {
562 Ok(v) => panic!("{}", err_msg.as_str()),
563 Err(e) => {
564 println!("{}", rumtk_format!("Got error => {}", e).as_str());
565 println!("Passed failed case!");
566 }
567 };
568 }
569
570 #[test]
571 fn test_find_hl7_v2_message_component_macro() {
572 let pattern = "PID(1)5.4";
573 let message = rumtk_v2_parse_message!(DEFAULT_HL7_V2_MESSAGE).unwrap();
574 let component = rumtk_v2_find_component!(message, pattern).unwrap();
575 let expected = "III";
576 assert_eq!(
577 component.as_str(),
578 expected,
579 "Wrong component found! Looked for {} expecting {}, but got {}",
580 pattern,
581 expected,
582 component.as_str()
583 );
584 }
585
586 #[test]
587 fn test_find_hl7_v2_message_component_simple_macro() {
588 let pattern = "PID5.4";
589 let message = rumtk_v2_parse_message!(DEFAULT_HL7_V2_MESSAGE).unwrap();
590 let component = rumtk_v2_find_component!(message, pattern).unwrap();
591 let expected = "III";
592 assert_eq!(
593 component.as_str(),
594 expected,
595 "Wrong component found! Looked for {} expecting {}, but got {}",
596 pattern,
597 expected,
598 component.as_str()
599 );
600 }
601
602 #[test]
603 fn test_find_hl7_v2_message_msh_field() {
604 let pattern = "MSH1.1";
605 let message = rumtk_v2_parse_message!(HL7_V2_MSH_ONLY).unwrap();
606 let component = rumtk_v2_find_component!(message, pattern).unwrap();
607 let expected = "^~\\&";
608 assert_eq!(
609 component.as_str(),
610 expected,
611 "Wrong component found! Looked for {} expecting {}, but got {}",
612 pattern,
613 expected,
614 component.as_str()
615 );
616 }
617
618 #[test]
619 fn test_find_hl7_v2_message_component_macro_failure() {
620 let pattern = "PID(1)15.4";
621 let err_msg = rumtk_format!(
622 "Search did not fail as expected. Input {} => found component?",
623 pattern
624 );
625 let message = rumtk_v2_parse_message!(DEFAULT_HL7_V2_MESSAGE).unwrap();
626 match rumtk_v2_find_component!(message, pattern) {
627 Ok(v) => panic!("{}", err_msg.as_str()),
628 Err(e) => {
629 println!("{}", rumtk_format!("Got error => {}", e).as_str());
630 println!("Passed failed case!");
631 }
632 }
633 }
634
635 #[test]
636 fn test_cast_component_to_datetime_expected_functionality() {
637 let inputs = [
638 "2007",
639 "200708",
640 "20070818",
641 "200708181123",
642 "20070818112355",
643 "20070818112355.55",
644 "20070818112355.5555-5000",
645 "20070818112355-5000",
646 ];
647 let expected_outputs = [
648 "2007-01-01T00:00:00.0000",
649 "2007-08-01T00:00:00.0000",
650 "2007-08-18T00:00:00.0000",
651 "2007-08-18T11:23:00.0000",
652 "2007-08-18T11:23:55.0000",
653 "2007-08-18T11:23:55.5500",
654 "2007-08-18T11:23:55.5555-5000",
655 "2007-08-18T11:23:55.0000-5000",
656 ];
657 for i in 0..inputs.len() {
658 let input = inputs[i];
659 let expected_utc = expected_outputs[i];
660 print!(
661 "Testing input #{} \"{}\". Expected output is \"{}\". Casting to datetime type.",
662 i, input, expected_utc
663 );
664 let date = input.to_v2datetime().unwrap();
665 let err_msg = rumtk_format!("The expected date time string does not match the date time string generated from the input [In: {}, Got: {}]", input, date.as_utc_string());
666 assert_eq!(expected_utc, date.as_utc_string().as_str(), "{}", &err_msg);
667 println!(" ... Got: {} ✅ ", date.as_utc_string());
668 }
669 }
670
671 #[test]
672 fn test_cast_component_to_datetime_validation() {
673 let inputs = ["200"];
674 for input in inputs {
675 match input.to_v2datetime() {
676 Ok(date) => {
677 panic!(
678 "Validation failed [In: {} Got: {} Expected: None] ... ✕",
679 input,
680 date.as_utc_string()
681 );
682 }
683 Err(e) => println!(
684 "Validation correctly identified malformed input with message => [{}] ✅",
685 e.as_str()
686 ),
687 }
688 }
689 }
690
691 #[test]
692 fn test_cast_component_to_datetime_base_example() {
693 let location = "EVN2"; let expected_component = "200708181123";
695 let message = rumtk_v2_parse_message!(DEFAULT_HL7_V2_MESSAGE).unwrap();
696 let component = rumtk_v2_find_component!(message, location).unwrap();
697 assert_eq!(expected_component, component.as_str(), "We are not using the correct component for this test. Check that the original test message has not changed and update the location string appropriately!");
698 let date = component.to_v2datetime().unwrap();
699 let expected_utc = "2007-08-18T11:23:00.0000";
700 let err_msg = rumtk_format!("The expected date time string does not match the date time string generated from the input [{}]", component.as_str());
701 assert_eq!(expected_utc, date.as_utc_string().as_str(), "{}", &err_msg)
702 }
703
704 #[test]
705 fn test_datetime_default() {
706 let input = V2DateTime::default().as_utc_string();
707 let expected_val = V2String::from("1970-01-01T00:00:00.00000");
708 let err_msg = rumtk_format!("The expected formatted string does not match the formatted string generated from the input [In: {}, Got: {}]", input, input);
709 assert_eq!(expected_val, input, "{}", &err_msg);
710 }
711
712 #[test]
713 fn test_cast_component_to_date_expected_functionality() {
714 let inputs = ["2007", "200708", "20070818"];
715 let expected_outputs = [
716 "2007-01-01T00:00:00.0000",
717 "2007-08-01T00:00:00.0000",
718 "2007-08-18T00:00:00.0000",
719 ];
720 for i in 0..inputs.len() {
721 let input = inputs[i];
722 let expected_utc = expected_outputs[i];
723 print!(
724 "Testing input #{} \"{}\". Expected output is \"{}\". Casting to datetime type.",
725 i, input, expected_utc
726 );
727 let date = input.to_v2date().unwrap();
728 let err_msg = rumtk_format!("The expected date time string does not match the date time string generated from the input [In: {}, Got: {}]", input, date.as_utc_string());
729 assert_eq!(expected_utc, date.as_utc_string().as_str(), "{}", &err_msg);
730 println!(" ... Got: {} ✅ ", date.as_utc_string());
731 }
732 }
733
734 #[test]
735 fn test_cast_component_to_date_validation() {
736 let inputs = ["200"];
737 for input in inputs {
738 match input.to_v2date() {
739 Ok(date) => {
740 panic!(
741 "Validation failed [In: {} Got: {} Expected: None] ... ✕",
742 input,
743 date.as_utc_string()
744 );
745 }
746 Err(e) => println!(
747 "Validation correctly identified malformed input with message => [{}] ✅",
748 e.as_str()
749 ),
750 }
751 }
752 }
753
754 #[test]
755 fn test_cast_component_to_date_base_example() {
756 let location = "PD113"; let expected_component = "20150625";
758 let message = rumtk_v2_parse_message!(VXU_HL7_V2_MESSAGE).unwrap();
759 let component = rumtk_v2_find_component!(message, location).unwrap();
760 assert_eq!(expected_component, component.as_str(), "We are not using the correct component for this test. Check that the original test message has not changed and update the location string appropriately!");
761 let date = component.to_v2date().unwrap();
762 let expected_utc = "2015-06-25T00:00:00.0000";
763 let err_msg = rumtk_format!(
764 "The expected date string does not match the date string generated from the input [{}]",
765 component.as_str()
766 );
767 assert_eq!(expected_utc, date.as_utc_string().as_str(), "{}", &err_msg)
768 }
769
770 #[test]
771 fn test_cast_component_to_time_expected_functionality() {
772 let inputs = ["1123", "112355", "112355.5555", "112355.5555-5000"];
773 let expected_outputs = [
774 "1970-01-01T11:23:00.0000",
775 "1970-01-01T11:23:55.0000",
776 "1970-01-01T11:23:55.5555",
777 "1970-01-01T11:23:55.5555-5000",
778 ];
779 for i in 0..inputs.len() {
780 let input = inputs[i];
781 let expected_utc = expected_outputs[i];
782 print!(
783 "Testing input #{} \"{}\". Expected output is \"{}\". Casting to datetime type.",
784 i, input, expected_utc
785 );
786 let date = input.to_v2time().unwrap();
787 let err_msg = rumtk_format!("The expected date time string does not match the date time string generated from the input [In: {}, Got: {}]", input, date.as_utc_string());
788 assert_eq!(expected_utc, date.as_utc_string().as_str(), "{}", &err_msg);
789 println!(" ... Got: {} ✅ ", date.as_utc_string());
790 }
791 }
792
793 #[test]
794 fn test_cast_component_to_time_validation() {
795 let inputs = ["2"];
796 for input in inputs {
797 match input.to_v2time() {
798 Ok(date) => {
799 panic!(
800 "Validation failed [In: {} Got: {} Expected: None] ... ✕",
801 input,
802 date.as_utc_string()
803 );
804 }
805 Err(e) => println!(
806 "Validation correctly identified malformed input with message => [{}] ✅",
807 e.as_str()
808 ),
809 }
810 }
811 }
812
813 #[test]
814 fn test_cast_component_to_number_expected_functionality() {
815 let inputs = [
816 "5e3",
817 "5E3",
818 "112355.5555",
819 "5F",
820 "5.5F",
821 "5f",
822 "5.5e2",
823 "-5f",
824 "-05e1",
825 ];
826 let expected_outputs = [
827 5000.0,
828 5000.0,
829 112355.5555,
830 5.0,
831 5.5,
832 5.0,
833 550.0,
834 -5.0,
835 -50.0,
836 ];
837 for i in 0..inputs.len() {
838 let input = inputs[i];
839 let expected_val = expected_outputs[i];
840 print!(
841 "Testing input #{} \"{}\". Expected output is \"{}\". Casting to NM type.",
842 i, input, expected_val
843 );
844 let val = input.to_v2number().unwrap();
845 let err_msg = rumtk_format!("The expected date time string does not match the date time string generated from the input [In: {}, Got: {}]", input, val);
846 assert_eq!(expected_val, val, "{}", &err_msg);
847 println!(" ... Got: {} ✅ ", val);
848 }
849 }
850
851 #[test]
852 fn test_cast_component_to_number_validation() {
853 let inputs = [".2"];
854 for input in inputs {
855 match input.to_v2number() {
856 Ok(val) => {
857 panic!(
858 "Validation failed [In: {} Got: {} Expected: None] ... ✕",
859 input, val
860 );
861 }
862 Err(e) => println!(
863 "Validation correctly identified malformed input with message => [{}] ✅",
864 e.as_str()
865 ),
866 }
867 }
868 }
869
870 #[test]
871 fn test_cast_component_to_st_expected_functionality() {
872 let inputs = [" Hello World!"];
873 let expected_outputs = ["Hello World!"];
874 for i in 0..inputs.len() {
875 let input = inputs[i];
876 let expected_val = expected_outputs[i];
877 print!(
878 "Testing input #{} \"{}\". Expected output is \"{}\". Casting to ST type.",
879 i, input, expected_val
880 );
881 let val = input.to_v2stringdata().unwrap();
882 let err_msg = rumtk_format!("The expected date time string does not match the date time string generated from the input [In: {}, Got: {}]", input, val);
883 assert_eq!(expected_val, val, "{}", &err_msg);
884 println!(" ... Got: {} ✅ ", val);
885 }
886 }
887
888 #[test]
889 fn test_cast_component_to_st_validation() {
890 let input = "2".duplicate(1001);
891 println!("{}", input);
892 match input.to_v2stringdata() {
893 Ok(val) => {
894 panic!(
895 "Validation failed [In: {} Got: {} Expected: None] ... ✕",
896 input, val
897 );
898 }
899 Err(e) => println!(
900 "Validation correctly identified malformed input with message => [{}] ✅",
901 e.as_str()
902 ),
903 }
904 }
905
906 #[test]
907 fn test_cast_component_to_ft_expected_functionality() {
908 let inputs = ["H", &"e".duplicate(120000)];
909 let expected_outputs = ["H", &"e".duplicate(TRUNCATE_FT as usize)];
910 for i in 0..inputs.len() {
911 let input = inputs[i];
912 let expected_val = expected_outputs[i];
913 print!(
914 "Testing input #{} \"{}\". Expected output is \"{}\". Casting to FT type.",
915 i, input, expected_val
916 );
917 let val = input.to_v2formattedtext("~").unwrap();
918 println!("{}", val.len());
919 let err_msg = rumtk_format!("The expected formatted string does not match the formatted string generated from the input [In: {}, Got: {}]", input, val);
920 assert_eq!(expected_val, val, "{}", &err_msg);
921 println!(" ... Got: {} ✅ ", val);
922 }
923 }
924
925 #[test]
926 fn test_validated_cast_component_to_type() {
927 let message = DEFAULT_HL7_V2_MESSAGE;
928 let sanitized_message = V2Message::sanitize(message);
929 let tokens = V2Message::tokenize_segments(&sanitized_message.as_str());
930 let encode_chars = V2ParserCharacters::from_msh(tokens[0]).unwrap();
931 let v2_component = V2ComponentTypeDescriptor::new(
932 "date",
933 "Date",
934 V2ComponentType::Primitive(V2PrimitiveType::Date),
935 4,
936 1,
937 1,
938 Optionality::O,
939 true,
940 );
941 let input = "2007";
942 let val = cast_component(vec![&input], &v2_component, &encode_chars);
943 let expected = "2007-01-01T00:00:00.0000";
944 let err_msg = rumtk_format!("The expected formatted string does not match the formatted string generated from the input [In: {}, Got: {}]", input, expected);
945
946 match val {
947 V2Type::V2Date(result) => {
948 assert_eq!(expected, result.unwrap().as_utc_string(), "{}", &err_msg)
949 }
950 _ => panic!("Wrong type received!"),
951 }
952 }
953
954 #[test]
958 fn test_mllp_encode() {
959 let expected_message = RUMString::from("I ❤ my wife!");
960 let encoded = mllp_encode(&expected_message);
961 let payload = &encoded[1..encoded.len() - 2];
962
963 assert_eq!(encoded[0], SB, "Incorrect start byte in MLLP message!");
964
965 assert_eq!(
966 encoded[encoded.len() - 2],
967 EB,
968 "Incorrect end byte in MLLP message!"
969 );
970
971 assert_eq!(
972 encoded[encoded.len() - 1],
973 CR,
974 "Missing mandatory carriage return in MLLP message!"
975 );
976
977 assert_eq!(
978 expected_message,
979 payload.to_rumstring(),
980 "{}",
981 rumtk_format!(
982 "Malformed payload! Expected: {} Found: {}",
983 expected_message,
984 payload.to_rumstring()
985 )
986 );
987 }
988
989 #[test]
990 fn test_mllp_decode() {
991 let expected_message = RUMString::from("I ❤ my wife!");
992 let message_size = expected_message.len();
993 let encoded = mllp_encode(&expected_message);
994 let encoded_size = encoded.len();
995
996 assert_eq!(
997 encoded_size,
998 message_size + 3,
999 "Incorrect encoded message size!"
1000 );
1001
1002 let decoded = mllp_decode(&encoded).unwrap();
1003 let decoded_size = decoded.len();
1004
1005 assert_eq!(
1006 decoded_size, message_size,
1007 "Incorrect decoded message size! Expected: {} Got: {}",
1008 expected_message, decoded
1009 );
1010
1011 assert_eq!(
1012 expected_message,
1013 decoded,
1014 "{}",
1015 rumtk_format!(
1016 "Malformed decoded message! Expected: {} Found: {}",
1017 expected_message,
1018 decoded
1019 )
1020 );
1021 }
1022
1023 #[test]
1024 fn test_mllp_listen() {
1025 let mllp_layer = match rumtk_v2_mllp_listen!(0, MLLP_FILTER_POLICY::NONE, true) {
1026 Ok(mllp_layer) => mllp_layer,
1027 Err(e) => panic!("{}", e),
1028 };
1029 let (ip, port) = rumtk_v2_mllp_get_ip_port!(&mllp_layer);
1030 let client_id = rumtk_exec_task!(async || -> RUMResult<RUMString> {
1031 Ok(mllp_layer.lock().await.get_address_info().await.unwrap())
1032 });
1033 assert_eq!(
1034 client_id,
1035 Ok(rumtk_format!("127.0.0.1:{}", &port)),
1036 "Failed to bind local port!"
1037 )
1038 }
1039
1040 #[test]
1041 fn test_mllp_get_ip() {
1042 let mllp_layer = match rumtk_v2_mllp_listen!(0, MLLP_FILTER_POLICY::NONE, true) {
1043 Ok(mllp_layer) => mllp_layer,
1044 Err(e) => panic!("{}", e),
1045 };
1046 let (ip, port) = rumtk_v2_mllp_get_ip_port!(&mllp_layer);
1047 }
1048
1049 #[test]
1050 fn test_mllp_connect() {
1051 let mllp_layer = match rumtk_v2_mllp_listen!(0, MLLP_FILTER_POLICY::NONE, true) {
1052 Ok(mllp_layer) => mllp_layer,
1053 Err(e) => panic!("{}", e),
1054 };
1055 let (ip, port) = rumtk_v2_mllp_get_ip_port!(&mllp_layer);
1056 let client = match rumtk_v2_mllp_connect!(port, MLLP_FILTER_POLICY::NONE) {
1057 Ok(client) => client,
1058 Err(e) => panic!("{}", e),
1059 };
1060 rumtk_sleep!(1);
1061 let mut connected_clients = rumtk_v2_mllp_get_client_ids!(&mllp_layer);
1062 for i in 0..10 {
1063 if connected_clients.is_empty() {
1064 rumtk_sleep!(1);
1065 connected_clients = rumtk_v2_mllp_get_client_ids!(&mllp_layer);
1066 }
1067 }
1068 let connected_address = connected_clients.get(0).unwrap();
1069 let client_ids = rumtk_v2_mllp_get_client_ids!(&client);
1070 let client_id = client_ids.get(0).unwrap();
1071 assert_eq!(connected_address, client_id, "Failed to bind local port!")
1072 }
1073
1074 #[test]
1075 fn test_mllp_channel() {
1076 let empty_string = |s: RUMString| Ok::<RUMString, RUMString>(RUMString::from(""));
1077 let safe_listener = match rumtk_v2_mllp_listen!(0, MLLP_FILTER_POLICY::NONE, true) {
1078 Ok(mllp_layer) => mllp_layer,
1079 Err(e) => panic!("{}", e),
1080 };
1081 let (ip, port) = rumtk_v2_mllp_get_ip_port!(&safe_listener);
1082 let safe_client = match rumtk_v2_mllp_connect!(port, MLLP_FILTER_POLICY::NONE) {
1083 Ok(client) => client,
1084 Err(e) => panic!("{}", e),
1085 };
1086 rumtk_sleep!(1);
1087 let client_ids = rumtk_v2_mllp_get_client_ids!(&safe_listener);
1088 let client_id = client_ids.get(0).unwrap();
1089 let mut server_channels = rumtk_v2_mllp_iter_channels!(&safe_client);
1090 let mut server_channel = server_channels.get_mut(0).unwrap().clone();
1091 let channel_address = server_channel.lock().unwrap().get_address_info().unwrap();
1092 assert_eq!(
1093 &client_id,
1094 &channel_address,
1095 "{}",
1096 rumtk_format!(
1097 "Issue stablishing MLLP communication channel! Expected: {} Received: {}",
1098 &client_id,
1099 &channel_address
1100 )
1101 )
1102 }
1103
1104 #[test]
1105 fn test_mllp_channel_async_communication() {
1106 let mut safe_listener = match rumtk_v2_mllp_listen!(0, MLLP_FILTER_POLICY::NONE, true) {
1107 Ok(mllp_layer) => mllp_layer,
1108 Err(e) => panic!("{}", e),
1109 };
1110 let (ip, port) = rumtk_v2_mllp_get_ip_port!(&safe_listener);
1111 let safe_client = match rumtk_v2_mllp_connect!(port, MLLP_FILTER_POLICY::NONE) {
1112 Ok(client) => client,
1113 Err(e) => panic!("{}", e),
1114 };
1115 rumtk_sleep!(1);
1116 let client_ids = rumtk_v2_mllp_get_client_ids!(&safe_listener);
1117 let client_id = client_ids.get(0).unwrap();
1118 let mut server_channels = rumtk_v2_mllp_iter_channels!(&safe_client);
1119 let mut server_channel = server_channels.get_mut(0).unwrap().clone();
1120 let expected_message = RUMString::from("I ❤ my wife!");
1121 let message_copy = expected_message.clone();
1122 let send_thread = spawn(move || -> RUMResult<()> {
1123 Ok(server_channel
1124 .lock()
1125 .unwrap()
1126 .send_message(&message_copy)
1127 .unwrap())
1128 });
1129 rumtk_sleep!(1);
1130 let received_message = rumtk_exec_task!(async || -> RUMResult<RUMString> {
1131 let mut received_message = safe_listener
1132 .lock()
1133 .await
1134 .receive_message(&client_id)
1135 .await?;
1136 while received_message.len() == 0 {
1137 received_message = safe_listener
1138 .lock()
1139 .await
1140 .receive_message(&client_id)
1141 .await?;
1142 }
1143 Ok(received_message)
1144 })
1145 .unwrap();
1146 assert_eq!(
1147 &expected_message,
1148 &received_message,
1149 "{}",
1150 rumtk_format!(
1151 "Issue sending message through channel! Expected: {} Received: {}",
1152 &expected_message,
1153 &received_message
1154 )
1155 )
1156 }
1157
1158 #[test]
1159 fn test_mllp_hl7_echo() {
1160 let empty_string = |s: RUMString| Ok::<RUMString, RUMString>(RUMString::from(""));
1161 let mut safe_listener = match rumtk_v2_mllp_listen!(0, MLLP_FILTER_POLICY::NONE, true) {
1162 Ok(mllp_listener) => mllp_listener,
1163 Err(e) => panic!("{}", e),
1164 };
1165 let (ip, port) = rumtk_v2_mllp_get_ip_port!(&safe_listener);
1166 let safe_client = match rumtk_v2_mllp_connect!(port, MLLP_FILTER_POLICY::NONE) {
1167 Ok(client) => client,
1168 Err(e) => panic!("{}", e),
1169 };
1170 rumtk_sleep!(1);
1171 let client_ids = rumtk_v2_mllp_get_client_ids!(&safe_listener);
1172 let client_id = client_ids.get(0).unwrap();
1173 let mut server_channels = rumtk_v2_mllp_iter_channels!(&safe_client);
1174 let mut server_channel = server_channels.get_mut(0).unwrap().clone();
1175 let server_channel_copy = server_channel.clone();
1176 let send_thread = spawn(move || -> RUMResult<()> {
1177 Ok(server_channel
1178 .lock()
1179 .unwrap()
1180 .send_message(HL7_V2_PDF_MESSAGE)
1181 .unwrap())
1182 });
1183 let safe_listener_copy = safe_listener.clone();
1184 let received_message = rumtk_exec_task!(async || -> RUMResult<RUMString> {
1185 let mut received_message = safe_listener_copy
1186 .lock()
1187 .await
1188 .receive_message(&client_id)
1189 .await?;
1190 while received_message.len() == 0 {
1191 received_message = safe_listener_copy
1192 .lock()
1193 .await
1194 .receive_message(&client_id)
1195 .await?;
1196 }
1197 Ok(received_message)
1198 })
1199 .unwrap();
1200 assert_eq!(
1201 &HL7_V2_PDF_MESSAGE,
1202 &received_message,
1203 "{}",
1204 rumtk_format!(
1205 "Issue sending message through channel! Expected: {} Received: {}",
1206 &HL7_V2_PDF_MESSAGE,
1207 &received_message
1208 )
1209 );
1210 let client_id_copy = client_id.clone();
1211 let safe_listener_copy2 = safe_listener.clone();
1212 println!("Echoing message back to client!");
1213 let echo_thread = spawn(move || {
1214 println!("Sending echo message!");
1215 rumtk_v2_mllp_send!(safe_listener_copy2, client_id_copy, HL7_V2_PDF_MESSAGE).unwrap();
1216 println!("Sent echo message!");
1217 });
1218 rumtk_sleep!(1);
1219 let echoed_message = rumtk_exec_task!(async || -> RUMResult<RUMString> {
1220 println!("Echoing message back to client!");
1221 let mut echoed_message = safe_client.lock().await.receive_message(&client_id).await?;
1222 while echoed_message.len() == 0 {
1223 echoed_message = safe_client.lock().await.receive_message(&client_id).await?;
1224 }
1225 println!("Echoed message: {}", &echoed_message);
1226 Ok(echoed_message)
1227 })
1228 .unwrap();
1229 assert_eq!(
1230 &HL7_V2_PDF_MESSAGE,
1231 &echoed_message,
1232 "{}",
1233 rumtk_format!(
1234 "Issue echoing message through channel! Expected: {} Received: {}",
1235 &HL7_V2_PDF_MESSAGE,
1236 &echoed_message
1237 )
1238 )
1239 }
1240
1241 #[test]
1243 fn test_deserialize_escaped_v2_message() {
1244 let message = rumtk_v2_parse_message!(V2_JSON_MESSAGE).unwrap();
1245 let serialized = rumtk_serialize!(&message).unwrap();
1246 let escaped = basic_escape(&serialized, &vec![]);
1247 let deserialized = rumtk_deserialize!(&escaped).unwrap();
1248
1249 assert_eq!(
1250 message, deserialized,
1251 "Deserialized JSON does not match the expected value!"
1252 );
1253 }
1254
1255 #[test]
1256 fn test_deserialize_v2_message() {
1257 let message = rumtk_v2_parse_message!(DEFAULT_HL7_V2_MESSAGE).unwrap();
1258 let message_str = rumtk_serialize!(&message, true).unwrap();
1259 let deserialized: V2Message = rumtk_deserialize!(&message_str).unwrap();
1260
1261 assert_eq!(
1262 message, deserialized,
1263 "Deserialized JSON does not match the expected value!"
1264 );
1265 }
1266
1267 #[test]
1268 fn test_deserialize_stdin_v2_message_basic() {
1269 let expected_message: V2Message = rumtk_v2_parse_message!(V2_JSON_MESSAGE_BASIC).unwrap();
1270 let deserialized: V2Message = rumtk_deserialize!(&ESCAPED_V2_JSON_MESSAGE_BASIC).unwrap();
1271
1272 assert_eq!(
1273 expected_message, deserialized,
1274 "Deserialized Escaped JSON does not match the expected value!"
1275 );
1276 }
1277
1278 #[test]
1281 fn test_fuzzed_garbage_parsing() {
1282 let input = "MSH@~��MS";
1283 match rumtk_v2_parse_message!(&input) {
1284 Err(e) => println!("Correctly identified input as garbage! => {}", &e),
1285 Ok(message) => {
1286 println!("Test input [{}] Result => {:?}", &input, message);
1287 panic!("Message parsed without errors despite being malformed!")
1288 }
1289 }
1290 }
1291}