Skip to main content

rumtk_core/
lib.rs

1/*
2 * rumtk attempts to implement HL7 and medical protocols for interoperability in medicine.
3 * This toolkit aims to be reliable, simple, performant, and standards compliant.
4 * Copyright (C) 2024  Luis M. Santos, M.D.
5 * Copyright (C) 2025  MedicalMasses L.L.C.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22//#![feature(unboxed_closures)]
23//#![feature(inherent_associated_types)]
24#![feature(type_alias_impl_trait)]
25#![feature(unboxed_closures)]
26#![feature(buf_read_has_data_left)]
27#![feature(mapped_lock_guards)]
28
29pub mod cache;
30pub mod cli;
31pub mod core;
32pub mod dependencies;
33pub mod hash;
34pub mod id;
35pub mod json;
36pub mod log;
37pub mod maths;
38pub mod net;
39pub mod scripting;
40pub mod search;
41pub mod strings;
42pub mod threading;
43pub mod types;
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use crate::cache::RUMCache;
49    use crate::core::{clamp_index, RUMResult};
50    use crate::search::rumtk_search::*;
51    use crate::strings::{
52        rumtk_format, RUMArrayConversions, RUMString, RUMStringConversions, StringUtils,
53    };
54    use crate::types::{RUMDeserialize, RUMDeserializer, RUMSerialize, RUMSerializer};
55    use compact_str::CompactString;
56    use serde_json::to_string;
57    use std::sync::Arc;
58    use tokio::sync::RwLock;
59
60    #[test]
61    fn test_is_escaped_str() {
62        let input = "\r\n\'\\\"";
63        let expected = false;
64        let result = strings::is_escaped_str(input);
65        println!("Input: {} Expected: {} Got: {}", input, expected, result);
66        assert_eq!(
67            expected, result,
68            "Incorrect detection of unescaped string as escaped!!"
69        );
70        println!("Passed!")
71    }
72
73    #[test]
74    fn test_escaping_control() {
75        let input = "\r\n\'\"\\";
76        let expected = "\\r\\n\\'\\\"\\\\";
77        let result = strings::escape(input);
78        println!(
79            "Input: {} Expected: {} Got: {}",
80            input,
81            expected,
82            result.as_str()
83        );
84        assert_eq!(expected, result, "Incorrect string escaping!");
85        println!("Passed!")
86    }
87
88    #[test]
89    fn test_escaping_unicode() {
90        let input = "❤";
91        let expected = "\\u2764";
92        let result = strings::escape(input);
93        println!(
94            "Input: {} Expected: {} Got: {}",
95            input,
96            expected,
97            result.as_str()
98        );
99        assert_eq!(expected, result, "Incorrect string escaping!");
100        println!("Passed!")
101    }
102
103    #[test]
104    fn test_unescaping_unicode() {
105        let input = "❤";
106        let escaped = strings::escape(input);
107        let expected = "❤";
108        let result = RUMString::from_utf8(strings::unescape(escaped.as_str()).unwrap()).unwrap();
109        println!(
110            "Input: {} Expected: {} Got: {}",
111            input,
112            expected,
113            result.as_str()
114        );
115        assert_eq!(expected, result.as_str(), "Incorrect string unescaping!");
116        println!("Passed!")
117    }
118
119    #[test]
120    fn test_unescaping_string() {
121        let input = "I \\u2764 my wife!";
122        let expected = "I ❤ my wife!";
123        let result = strings::unescape_string(input).unwrap();
124        println!(
125            "Input: {} Expected: {} Got: {}",
126            input,
127            expected,
128            result.as_str()
129        );
130        assert_eq!(expected, result.as_str(), "Incorrect string unescaping!");
131        println!("Passed!")
132    }
133
134    #[test]
135    fn test_is_escaped_string() {
136        let input = "I \\u2764 my wife!";
137        let expected = true;
138        let result = strings::is_escaped_str(input);
139        println!("Input: {} Expected: {} Got: {}", input, expected, result);
140        assert_eq!(
141            expected, result,
142            "Escaped string detected as unescaped string!"
143        );
144        println!("Passed!")
145    }
146
147    #[test]
148    fn test_is_unescaped_string() {
149        let input = "I ❤ my wife!";
150        let expected = false;
151        let result = strings::is_escaped_str(input);
152        println!("Input: {} Expected: {} Got: {}", input, expected, result);
153        assert_eq!(
154            expected, result,
155            "Unescaped string detected as escaped string!"
156        );
157        println!("Passed!")
158    }
159
160    #[test]
161    fn test_unique_string() {
162        let input = "I❤mywife!";
163        assert!(input.is_unique(), "String was not detected as unique.");
164    }
165
166    #[test]
167    fn test_non_unique_string() {
168        let input = "I❤❤mywife!";
169        assert!(!input.is_unique(), "String was detected as unique.");
170    }
171
172    #[test]
173    fn test_escaping_string() {
174        let input = "I ❤ my wife!";
175        let expected = "I \\u2764 my wife!";
176        let result = strings::escape(input);
177        println!(
178            "Input: {} Expected: {} Got: {}",
179            input,
180            expected,
181            result.as_str()
182        );
183        assert_eq!(expected, result.as_str(), "Incorrect string escaping!");
184        println!("Passed!")
185    }
186
187    #[test]
188    fn test_autodecode_utf8() {
189        let input = "I ❤ my wife!";
190        let result = strings::try_decode(input.as_bytes());
191        println!(
192            "Input: {} Expected: {} Got: {}",
193            input,
194            input,
195            result.as_str()
196        );
197        assert_eq!(input, result, "Incorrect string decoding!");
198        println!("Passed!")
199    }
200
201    #[test]
202    fn test_autodecode_other() {
203        //TODO: Need an example of other encoding texts.
204        let input = "I ❤ my wife!";
205        let result = input;
206        println!("Input: {} Expected: {} Got: {}", input, input, result);
207        assert_eq!(input, result, "Incorrect string decoding!");
208        println!("Passed!")
209    }
210
211    #[test]
212    fn test_decode() {
213        let input = "I ❤ my wife!";
214        let result = strings::try_decode_with(input.as_bytes(), "utf-8");
215        println!(
216            "Input: {} Expected: {} Got: {}",
217            input,
218            input,
219            result.as_str()
220        );
221        assert_eq!(input, result, "Incorrect string decoding!");
222        println!("Passed!")
223    }
224
225    #[test]
226    fn test_rumcache_insertion() {
227        let mut cache: RUMCache<&str, CompactString> = RUMCache::with_capacity(5);
228        cache.insert("❤", CompactString::from("I ❤ my wife!"));
229        println!("Contents: {:#?}", &cache);
230        assert_eq!(cache.len(), 1, "Incorrect number of items in cache!");
231        println!("Passed!")
232    }
233
234    #[test]
235    fn test_search_string_letters() {
236        let input = "Hello World!";
237        let expr = r"\w";
238        let result = string_search(input, expr, "");
239        let expected: RUMString = RUMString::from("HelloWorld");
240        println!(
241            "Input: {:?} Expected: {:?} Got: {:?}",
242            input, expected, result
243        );
244        assert_eq!(expected, result, "String search results mismatch");
245        println!("Passed!")
246    }
247
248    #[test]
249    fn test_search_string_words() {
250        let input = "Hello World!";
251        let expr = r"\w+";
252        let result = string_search(input, expr, " ");
253        let expected: RUMString = RUMString::from("Hello World");
254        println!(
255            "Input: {:?} Expected: {:?} Got: {:?}",
256            input, expected, result
257        );
258        assert_eq!(expected, result, "String search results mismatch");
259        println!("Passed!")
260    }
261
262    #[test]
263    fn test_search_string_named_groups() {
264        let input = "Hello World!";
265        let expr = r"(?<hello>\w{5}) (?<world>\w{5})";
266        let result = string_search_named_captures(input, expr, "");
267        let expected: RUMString = RUMString::from("World");
268        println!(
269            "Input: {:?} Expected: {:?} Got: {:?}",
270            input, expected, result
271        );
272        assert_eq!(expected, result["world"], "String search results mismatch");
273        println!("Passed!")
274    }
275
276    #[test]
277    fn test_search_string_all_groups() {
278        let input = "Hello World!";
279        let expr = r"(?<hello>\w{5}) (?<world>\w{5})";
280        let result = string_search_all_captures(input, expr, "");
281        let expected: Vec<&str> = vec!["Hello", "World"];
282        println!(
283            "Input: {:?} Expected: {:?} Got: {:?}",
284            input, expected, result
285        );
286        assert_eq!(expected, result, "String search results mismatch");
287        println!("Passed!")
288    }
289
290    ///////////////////////////////////Threading Tests/////////////////////////////////////////////////
291    #[test]
292    fn test_default_num_threads() {
293        use num_cpus;
294        let threads = threading::threading_functions::get_default_system_thread_count();
295        assert_eq!(
296            threads >= num_cpus::get(),
297            true,
298            "Default thread count is incorrect! We got {}, but expected {}!",
299            threads,
300            num_cpus::get()
301        );
302    }
303
304    #[test]
305    fn test_execute_job() {
306        let rt = rumtk_init_threads!();
307        let expected = vec![1, 2, 3];
308        let task_processor = async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
309            let owned_args = Arc::clone(args);
310            let lock_future = owned_args.read();
311            let locked_args = lock_future.await;
312            let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
313            print!("Contents: ");
314            for arg in locked_args.iter() {
315                results.push(arg.clone());
316                println!("{} ", &arg);
317            }
318            Ok(results)
319        };
320        let locked_args = RwLock::new(expected.clone());
321        let task_args = SafeTaskArgs::<i32>::new(locked_args);
322        let task_result = rumtk_wait_on_task!(rt, task_processor, &task_args);
323        let result = task_result.unwrap();
324        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
325    }
326
327    #[test]
328    fn test_execute_job_macros() {
329        let rt = rumtk_init_threads!();
330        let expected = vec![1, 2, 3];
331        let task_processor = async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
332            let owned_args = Arc::clone(args);
333            let lock_future = owned_args.read();
334            let locked_args = lock_future.await;
335            let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
336            print!("Contents: ");
337            for arg in locked_args.iter() {
338                results.push(arg.clone());
339                println!("{} ", &arg);
340            }
341            Ok(results)
342        };
343        let task_args = rumtk_create_task_args!(1, 2, 3);
344        let task_result = rumtk_wait_on_task!(rt, task_processor, &task_args);
345        let result = task_result.unwrap();
346        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
347    }
348
349    #[test]
350    fn test_execute_job_macros_one_line() {
351        let rt = rumtk_init_threads!();
352        let expected = vec![1, 2, 3];
353        let result = rumtk_exec_task!(
354            async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
355                let owned_args = Arc::clone(args);
356                let lock_future = owned_args.read();
357                let locked_args = lock_future.await;
358                let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
359                print!("Contents: ");
360                for arg in locked_args.iter() {
361                    results.push(arg.clone());
362                    println!("{} ", &arg);
363                }
364                Ok(results)
365            },
366            vec![1, 2, 3]
367        )
368        .unwrap();
369        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
370    }
371
372    #[test]
373    fn test_clamp_index_positive_index() {
374        let values = vec![1, 2, 3, 4];
375        let given_index = 3isize;
376        let max_size = values.len() as isize;
377        let index = clamp_index(&given_index, &max_size).unwrap();
378        assert_eq!(
379            index, 3,
380            "Index mismatch! Requested index {} but got {}",
381            &given_index, &index
382        );
383        assert_eq!(
384            values[index], 4,
385            "Value mismatch! Expected {} but got {}",
386            &values[3], &values[index]
387        );
388    }
389
390    #[test]
391    fn test_clamp_index_reverse_index() {
392        let values = vec![1, 2, 3, 4];
393        let given_index = -1isize;
394        let max_size = values.len() as isize;
395        let index = clamp_index(&given_index, &max_size).unwrap();
396        assert_eq!(
397            index, 4,
398            "Index mismatch! Requested index {} but got {}",
399            &given_index, &index
400        );
401        assert_eq!(
402            values[index - 1],
403            4,
404            "Value mismatch! Expected {} but got {}",
405            &values[3],
406            &values[index]
407        );
408    }
409
410    ///////////////////////////////////Queue Tests/////////////////////////////////////////////////
411    use crate::cli::cli_utils::print_license_notice;
412    use crate::net::tcp::LOCALHOST;
413    use crate::threading::threading_functions::sleep;
414    use crate::threading::threading_manager::*;
415
416    #[test]
417    fn test_queue_data() {
418        let expected = vec![
419            RUMString::from("Hello"),
420            RUMString::from("World!"),
421            RUMString::from("Overcast"),
422            RUMString::from("and"),
423            RUMString::from("Sad"),
424        ];
425        type TestResult = RUMResult<Vec<RUMString>>;
426        let mut queue: TaskManager<TestResult> = TaskManager::new(&5).unwrap();
427        let locked_args = RwLock::new(expected.clone());
428        let task_args = SafeTaskArgs::<RUMString>::new(locked_args);
429        let processor = rumtk_create_task!(
430            async |args: &SafeTaskArgs<RUMString>| -> TestResult {
431                let owned_args = Arc::clone(args);
432                let lock_future = owned_args.read();
433                let locked_args = lock_future.await;
434                let mut results = TaskItems::<RUMString>::with_capacity(locked_args.len());
435                print!("Contents: ");
436                for arg in locked_args.iter() {
437                    print!("{} ", &arg);
438                    results.push(RUMString::new(arg));
439                }
440                Ok(results)
441            },
442            task_args
443        );
444
445        queue.add_task::<_>(processor);
446        let results = queue.wait();
447
448        let mut result_data = Vec::<RUMString>::with_capacity(5);
449        for r in results {
450            for v in r.unwrap().result.clone().unwrap().iter() {
451                for value in v.iter() {
452                    result_data.push(value.clone());
453                }
454            }
455        }
456        assert_eq!(result_data, expected, "Results do not match expected!");
457    }
458
459    ///////////////////////////////////Net Tests/////////////////////////////////////////////////
460    #[test]
461    fn test_server_start() {
462        let mut server = match rumtk_create_server!("localhost", 0) {
463            Ok(server) => server,
464            Err(e) => panic!("Failed to create server because {}", e),
465        };
466        match server.start(false) {
467            Ok(_) => (),
468            Err(e) => panic!("Failed to start server because {}", e),
469        }
470    }
471
472    #[test]
473    fn test_server_send() {
474        let msg = RUMString::from("Hello World!");
475        let mut server = match rumtk_create_server!(LOCALHOST, 0, 1) {
476            Ok(server) => server,
477            Err(e) => panic!("Failed to create server because {}", e),
478        };
479        match server.start(false) {
480            Ok(_) => (),
481            Err(e) => panic!("Failed to start server because {}", e),
482        };
483        let address_info = server.get_address_info().unwrap();
484        let (ip, port) = rumtk_get_ip_port!(address_info);
485        println!("Sleeping");
486        rumtk_sleep!(1);
487        let mut client = match rumtk_connect!(port) {
488            Ok(client) => client,
489            Err(e) => panic!("Failed to create server because {}", e),
490        };
491        let client_id = client.get_address().unwrap();
492        rumtk_sleep!(1);
493        match server.send(&client_id, &msg.to_raw()) {
494            Ok(_) => (),
495            Err(e) => panic!("Server failed to send message because {}", e),
496        };
497        rumtk_sleep!(1);
498        let received_message = client.receive().unwrap();
499        assert_eq!(
500            &msg.to_raw(),
501            &received_message,
502            "{}",
503            rumtk_format!(
504                "Received message does not match sent message by server {:?}",
505                &received_message
506            )
507        );
508    }
509
510    #[test]
511    fn test_server_receive() {
512        let msg = RUMString::from("Hello World!");
513        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
514            Ok(server) => server,
515            Err(e) => panic!("Failed to create server because {}", e),
516        };
517        match server.start(false) {
518            Ok(_) => (),
519            Err(e) => panic!("Failed to start server because {}", e),
520        };
521        let address_info = server.get_address_info().unwrap();
522        let (ip, port) = rumtk_get_ip_port!(address_info);
523        println!("Sleeping");
524        rumtk_sleep!(1);
525        let mut client = match rumtk_connect!(port) {
526            Ok(client) => client,
527            Err(e) => panic!("Failed to create server because {}", e),
528        };
529        match client.send(&msg.to_raw()) {
530            Ok(_) => (),
531            Err(e) => panic!("Failed to send message because {}", e),
532        };
533        rumtk_sleep!(1);
534        let client_id = client.get_address().expect("Failed to get client id");
535        let incoming_message = server.receive(&client_id).unwrap().to_rumstring();
536        println!("Received message => {:?}", &incoming_message);
537        assert_eq!(&incoming_message, msg, "Received message corruption!");
538    }
539
540    #[test]
541    fn test_server_get_clients() {
542        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
543            Ok(server) => server,
544            Err(e) => panic!("Failed to create server because {}", e),
545        };
546        match server.start(false) {
547            Ok(_) => (),
548            Err(e) => panic!("Failed to start server because {}", e),
549        };
550        let address_info = server.get_address_info().unwrap();
551        let (ip, port) = rumtk_get_ip_port!(address_info);
552        println!("Sleeping");
553        rumtk_sleep!(1);
554        let mut client = match rumtk_connect!(port) {
555            Ok(client) => client,
556            Err(e) => panic!("Failed to create server because {}", e),
557        };
558        rumtk_sleep!(1);
559        let expected_client_id = client.get_address().expect("Failed to get client id");
560        let clients = server.get_client_ids();
561        let incoming_client_id = clients.get(0).expect("Expected client to have connected!");
562        println!("Connected client id => {}", &incoming_client_id);
563        assert_eq!(
564            &incoming_client_id, &expected_client_id,
565            "Connected client does not match the connecting client! Client id => {}",
566            &incoming_client_id
567        );
568    }
569
570    #[test]
571    fn test_server_stop() {
572        let msg = RUMString::from("Hello World!");
573        let mut server = match rumtk_create_server!("localhost", 0) {
574            Ok(server) => server,
575            Err(e) => panic!("Failed to create server because {}", e),
576        };
577        match server.start(false) {
578            Ok(_) => (),
579            Err(e) => panic!("Failed to start server because {}", e),
580        };
581        println!("Sleeping");
582        rumtk_sleep!(1);
583        match server.stop() {
584            Ok(_) => (),
585            Err(e) => panic!("Failed to stop server because {}", e),
586        };
587    }
588
589    #[test]
590    fn test_server_get_address_info() {
591        let msg = RUMString::from("Hello World!");
592        let mut server = match rumtk_create_server!("localhost", 0) {
593            Ok(server) => server,
594            Err(e) => panic!("Failed to create server because {}", e),
595        };
596        match server.start(false) {
597            Ok(_) => (),
598            Err(e) => panic!("Failed to start server because {}", e),
599        };
600        println!("Sleeping");
601        rumtk_sleep!(1);
602        match server.get_address_info() {
603            Some(addr) => println!("Server address info => {}", addr),
604            None => panic!("No address. Perhaps the server was never initialized?"),
605        };
606    }
607
608    #[test]
609    fn test_client_send() {
610        let msg = RUMString::from("Hello World!");
611        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
612            Ok(server) => server,
613            Err(e) => panic!("Failed to create server because {}", e),
614        };
615        match server.start(false) {
616            Ok(_) => (),
617            Err(e) => panic!("Failed to start server because {}", e),
618        };
619        let address_info = server.get_address_info().unwrap();
620        let (ip, port) = rumtk_get_ip_port!(address_info);
621        println!("Sleeping");
622        rumtk_sleep!(1);
623        let mut client = match rumtk_connect!(port) {
624            Ok(client) => client,
625            Err(e) => panic!("Failed to create server because {}", e),
626        };
627        rumtk_sleep!(2);
628        match client.send(&msg.to_raw()) {
629            Ok(_) => (),
630            Err(e) => panic!("Failed to send message because {}", e),
631        };
632        rumtk_sleep!(1);
633        let clients = server.get_client_ids();
634        let incoming_client_id = clients.first().expect("Expected client to have connected!");
635        let mut received_message = server.receive(incoming_client_id).unwrap();
636        if received_message.is_empty() {
637            rumtk_sleep!(1);
638            received_message = server.receive(incoming_client_id).unwrap();
639        }
640        assert_eq!(
641            &msg.to_raw(),
642            &received_message,
643            "{}",
644            rumtk_format!(
645                "Received message does not match sent message by client {:?}",
646                &received_message
647            )
648        );
649    }
650
651    ////////////////////////////JSON Tests/////////////////////////////////
652
653    #[test]
654    fn test_serialize_json() {
655        #[derive(RUMSerialize)]
656        struct MyStruct {
657            hello: RUMString,
658        }
659
660        let hw = MyStruct {
661            hello: RUMString::from("World"),
662        };
663        let hw_str = rumtk_serialize!(&hw, true).unwrap();
664
665        assert!(
666            !hw_str.is_empty(),
667            "Empty JSON string generated from the test struct!"
668        );
669    }
670
671    #[test]
672    fn test_deserialize_serde_json() {
673        use serde_json::{from_str, to_string};
674
675        #[derive(RUMSerialize, RUMDeserialize, PartialEq, Debug, Clone)]
676        struct MyStruct {
677            hello: RUMString,
678        }
679
680        let hw = MyStruct {
681            hello: RUMString::from("World"),
682        };
683        let hw_str = to_string(&hw).unwrap();
684        let new_hw: MyStruct = from_str(&hw_str).unwrap();
685
686        assert_eq!(
687            new_hw, hw,
688            "Deserialized JSON does not match the expected value!"
689        );
690    }
691
692    #[test]
693    fn test_deserialize_json() {
694        #[derive(RUMSerialize, RUMDeserialize, PartialEq)]
695        struct MyStruct {
696            hello: RUMString,
697        }
698
699        let hw = MyStruct {
700            hello: RUMString::from("World"),
701        };
702        let hw_str = rumtk_serialize!(&hw, true).unwrap();
703        let new_hw: MyStruct = rumtk_deserialize!(&hw_str).unwrap();
704
705        assert!(
706            new_hw == hw,
707            "Deserialized JSON does not match the expected value!"
708        );
709    }
710
711    /*
712    #[test]
713    fn test_escape_unescape_json() {
714        #[derive(Serialize, Deserialize, PartialEq)]
715        struct MyStruct {
716            hello: RUMString,
717        }
718
719        let hw = MyStruct {
720            hello: RUMString::from("World"),
721        };
722
723        let hw_str = rumtk_serialize!(&hw, true).unwrap();
724        let hw_escaped_str = strings::basic_escape(&hw_str);
725        println!("Escaped => {}", hw_escaped_str);
726
727        let hw_unescaped_str = strings::unescape_string(&hw_escaped_str).unwrap();
728        println!("Unescaped => {}", hw_unescaped_str);
729        assert_eq!(
730            hw_str.to_rumstring(),
731            hw_unescaped_str.to_rumstring(),
732            "Unescaped serialized JSON mismatch!"
733        );
734
735        let new_hw: MyStruct = rumtk_deserialize!(&hw_unescaped_str).unwrap();
736
737        assert!(
738            new_hw == hw,
739            "Deserialized JSON does not match the expected value!"
740        );
741    }
742    */
743
744    ////////////////////////////CLI Tests/////////////////////////////////
745
746    #[test]
747    fn test_print_license_notice() {
748        print_license_notice("RUMTK", "2025", &vec!["Luis M. Santos, M.D."]);
749    }
750
751    //////////////////////////////////////////////////////////////////////////////////////////////
752}