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. <lsantos@medicalmasses.com>
5 * Copyright (C) 2025  MedicalMasses L.L.C. <contact@medicalmasses.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19 */
20
21//#![feature(unboxed_closures)]
22//#![feature(inherent_associated_types)]
23#![feature(type_alias_impl_trait)]
24#![feature(unboxed_closures)]
25#![feature(buf_read_has_data_left)]
26#![feature(mapped_lock_guards)]
27#![feature(str_as_str)]
28#![feature(const_trait_impl)]
29#![feature(const_cmp)]
30#![feature(macro_metavar_expr)]
31#![feature(const_default)]
32#![feature(portable_simd)]
33#![feature(write_all_vectored)]
34
35pub mod cache;
36pub mod cli;
37pub mod base;
38pub mod dependencies;
39pub mod hash;
40pub mod id;
41pub mod serde;
42pub mod log;
43pub mod maths;
44pub mod net;
45pub mod pipelines;
46pub mod scripting;
47pub mod search;
48pub mod strings;
49pub mod threading;
50pub mod types;
51mod instrumentation;
52
53pub use rumtk_arena::buffers;
54pub use rumtk_arena::cpu;
55pub use rumtk_arena::mem;
56
57pub use rumtk_arena::*;
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::base::{clamp_index, RUMResult};
63    use crate::buffers::*;
64    use crate::buffers::{buffer_count, buffer_find, buffer_replace, buffer_replace_in_place, buffer_slice_trim, buffer_to_string, buffer_trim, new_random_buffer, RUMBufferIteratorExt};
65    use crate::cache::RUMCache;
66    use crate::cpu::{cpu_replace_byte, u8xN, CPU_SIMD_64_SIZE};
67    use crate::search::rumtk_search::*;
68    use crate::serde::{from_json, to_json, RUMDeJson, RUMSerJson};
69    use crate::strings::{rumtk_format, AsStr, RUMArrayConversions, RUMString, RUMStringConversions, StringUtils};
70    use std::process::Stdio;
71    use std::sync::Arc;
72    use tokio::io::{split, AsyncBufReadExt};
73    use tokio::sync::RwLock;
74
75    #[test]
76    fn test_is_escaped_str() {
77        let input = "\r\n\'\\\"";
78        let expected = false;
79        let result = strings::is_escaped_str(input);
80        println!("Input: {} Expected: {} Got: {}", input, expected, result);
81        assert_eq!(
82            expected, result,
83            "Incorrect detection of unescaped string as escaped!!"
84        );
85        println!("Passed!")
86    }
87
88    #[test]
89    fn test_escaping_control() {
90        let input = "\r\n\'\"\\";
91        let expected = "\\r\\n\\'\\\"\\\\";
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_escaping_unicode() {
105        let input = "❤";
106        let expected = "\\u2764";
107        let result = strings::escape(input);
108        println!(
109            "Input: {} Expected: {} Got: {}",
110            input,
111            expected,
112            result.as_str()
113        );
114        assert_eq!(expected, result, "Incorrect string escaping!");
115        println!("Passed!")
116    }
117
118    #[test]
119    fn test_unescaping_unicode() {
120        let input = "❤";
121        let escaped = strings::escape(input);
122        let expected = "❤";
123        let result = RUMString::from_utf8(strings::unescape(escaped.as_str()).unwrap()).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_unescaping_string() {
136        let input = "I \\u2764 my wife!";
137        let expected = "I ❤ my wife!";
138        let result = strings::unescape_string(input).unwrap();
139        println!(
140            "Input: {} Expected: {} Got: {}",
141            input,
142            expected,
143            result.as_str()
144        );
145        assert_eq!(expected, result.as_str(), "Incorrect string unescaping!");
146        println!("Passed!")
147    }
148
149    #[test]
150    fn test_is_escaped_string() {
151        let input = "I \\u2764 my wife!";
152        let expected = true;
153        let result = strings::is_escaped_str(input);
154        println!("Input: {} Expected: {} Got: {}", input, expected, result);
155        assert_eq!(
156            expected, result,
157            "Escaped string detected as unescaped string!"
158        );
159        println!("Passed!")
160    }
161
162    #[test]
163    fn test_is_unescaped_string() {
164        let input = "I ❤ my wife!";
165        let expected = false;
166        let result = strings::is_escaped_str(input);
167        println!("Input: {} Expected: {} Got: {}", input, expected, result);
168        assert_eq!(
169            expected, result,
170            "Unescaped string detected as escaped string!"
171        );
172        println!("Passed!")
173    }
174
175    #[test]
176    fn test_unique_string() {
177        let input = "I❤mywife!";
178        assert!(
179            input.as_grapheme_str().is_unique(),
180            "String was not detected as unique."
181        );
182    }
183
184    #[test]
185    fn test_non_unique_string() {
186        let input = "I❤❤mywife!";
187        assert!(
188            !input.as_grapheme_str().is_unique(),
189            "String was detected as unique."
190        );
191    }
192
193    #[test]
194    fn test_escaping_string() {
195        let input = "I ❤ my wife!";
196        let expected = "I \\u2764 my wife!";
197        let result = strings::escape(input);
198        println!(
199            "Input: {} Expected: {} Got: {}",
200            input,
201            expected,
202            result.as_str()
203        );
204        assert_eq!(expected, result.as_str(), "Incorrect string escaping!");
205        println!("Passed!")
206    }
207
208    #[test]
209    fn test_autodecode_utf8() {
210        let input = "I ❤ my wife!";
211        let result = strings::try_decode(input.as_bytes()).unwrap();
212        println!(
213            "Input: {} Expected: {} Got: {}",
214            input,
215            input,
216            result.as_str()
217        );
218        assert_eq!(input, result, "Incorrect string decoding!");
219        println!("Passed!")
220    }
221
222    #[test]
223    fn test_autodecode_other() {
224        //TODO: Need an example of other encoding texts.
225        let input = "I ❤ my wife!";
226        let result = input;
227        println!("Input: {} Expected: {} Got: {}", input, input, result);
228        assert_eq!(input, result, "Incorrect string decoding!");
229        println!("Passed!")
230    }
231
232    #[test]
233    fn test_decode() {
234        let input = "I ❤ my wife!";
235        let result = strings::try_decode_with(input.as_bytes(), "utf-8").unwrap();
236        println!(
237            "Input: {} Expected: {} Got: {}",
238            input,
239            input,
240            result.as_str()
241        );
242        assert_eq!(input, result, "Incorrect string decoding!");
243        println!("Passed!")
244    }
245
246    #[test]
247    fn test_rumcache_insertion() {
248        let mut cache: RUMCache<&str, RUMString> = RUMCache::with_capacity(5);
249        cache.insert("❤", RUMString::from("I ❤ my wife!"));
250        println!("Contents: {:#?}", &cache);
251        assert_eq!(cache.len(), 1, "Incorrect number of items in cache!");
252        println!("Passed!")
253    }
254
255    #[test]
256    fn test_search_string_letters() {
257        let input = "Hello World!";
258        let expr = r"\w";
259        let result = string_search(input, expr, "").unwrap();
260        let expected: RUMString = RUMString::from("HelloWorld");
261        println!(
262            "Input: {:?} Expected: {:?} Got: {:?}",
263            input, expected, result
264        );
265        assert_eq!(expected, result, "String search results mismatch");
266        println!("Passed!")
267    }
268
269    #[test]
270    fn test_search_string_words() {
271        let input = "Hello World!";
272        let expr = r"\w+";
273        let result = string_search(input, expr, " ").unwrap();
274        let expected: RUMString = RUMString::from("Hello World");
275        println!(
276            "Input: {:?} Expected: {:?} Got: {:?}",
277            input, expected, result
278        );
279        assert_eq!(expected, result, "String search results mismatch");
280        println!("Passed!")
281    }
282
283    #[test]
284    fn test_search_string_named_groups() {
285        let input = "Hello World!";
286        let expr = r"(?<hello>\w{5}) (?<world>\w{5})";
287        let result = string_search_named_captures(input, expr, "").unwrap();
288        let expected: RUMString = RUMString::from("World");
289        println!(
290            "Input: {:?} Expected: {:?} Got: {:?}",
291            input, expected, result
292        );
293        assert_eq!(expected, result["world"], "String search results mismatch");
294        println!("Passed!")
295    }
296
297    #[test]
298    fn test_search_string_all_groups() {
299        let input = "Hello World!";
300        let expr = r"(?<hello>\w{5}) (?<world>\w{5})";
301        let result = string_search_all_captures(input, expr, "").unwrap();
302        let expected: Vec<&str> = vec!["Hello", "World"];
303        println!(
304            "Input: {:?} Expected: {:?} Got: {:?}",
305            input, expected, result
306        );
307        assert_eq!(expected, result, "String search results mismatch");
308        println!("Passed!")
309    }
310
311    #[test]
312    fn test_find_value_in_string() {
313        let haystack = "Range (min \\xe2\\x80\\xa6 max):     0.6 ms \\xe2\\x80\\xa6   2.9 ms    1273 runs";
314        let patterns = ["\\d+ runs", "\\d+"];
315        let expected = 1273;
316        let result = string_find_value::<usize>(haystack, &patterns);
317
318        assert_eq!(result, Ok(expected), "Did not find the needle in the haystack or returned the wrong type!");
319    }
320
321    ///////////////////////////////////Threading Tests/////////////////////////////////////////////////
322    #[test]
323    fn test_default_num_threads() {
324        use num_cpus;
325        let threads = threading::threading_functions::get_default_system_thread_count();
326        assert_eq!(
327            threads >= num_cpus::get(),
328            true,
329            "Default thread count is incorrect! We got {}, but expected {}!",
330            threads,
331            num_cpus::get()
332        );
333    }
334
335    #[test]
336    fn test_execute_job() {
337        let expected = vec![1, 2, 3];
338        let task_processor = async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
339            let owned_args = Arc::clone(args);
340            let lock_future = owned_args.read();
341            let locked_args = lock_future.await;
342            let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
343            print!("Contents: ");
344            for arg in locked_args.iter() {
345                results.push(arg.clone());
346                println!("{} ", &arg);
347            }
348            Ok(results)
349        };
350        let locked_args = RwLock::new(expected.clone());
351        let task_args = SafeTaskArgs::<i32>::new(locked_args);
352        let task_result = rumtk_wait_on_task!(task_processor, &task_args);
353        let result = task_result.unwrap();
354        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
355    }
356
357    #[test]
358    fn test_execute_job_macros() {
359        let expected = vec![1, 2, 3];
360        let task_processor = async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
361            let owned_args = Arc::clone(args);
362            let lock_future = owned_args.read();
363            let locked_args = lock_future.await;
364            let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
365            print!("Contents: ");
366            for arg in locked_args.iter() {
367                results.push(arg.clone());
368                println!("{} ", &arg);
369            }
370            Ok(results)
371        };
372        let task_args = rumtk_create_task_args!(1, 2, 3);
373        let task_result = rumtk_wait_on_task!(task_processor, &task_args);
374        let result = task_result.unwrap();
375        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
376    }
377
378    #[test]
379    fn test_execute_job_macros_one_line() {
380        let expected = vec![1, 2, 3];
381        let result = rumtk_exec_task!(
382            async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
383                let owned_args = Arc::clone(args);
384                let lock_future = owned_args.read();
385                let locked_args = lock_future.await;
386                let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
387                print!("Contents: ");
388                for arg in locked_args.iter() {
389                    results.push(arg.clone());
390                    println!("{} ", &arg);
391                }
392                Ok(results)
393            },
394            vec![1, 2, 3]
395        )
396        .unwrap();
397        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
398    }
399
400    #[test]
401    fn test_clamp_index_positive_index() {
402        let values = vec![1, 2, 3, 4];
403        let given_index = 3isize;
404        let max_size = values.len() as isize;
405        let index = clamp_index(&given_index, &max_size).unwrap();
406        assert_eq!(
407            index, 3,
408            "Index mismatch! Requested index {} but got {}",
409            &given_index, &index
410        );
411        assert_eq!(
412            values[index], 4,
413            "Value mismatch! Expected {} but got {}",
414            &values[3], &values[index]
415        );
416    }
417
418    #[test]
419    fn test_clamp_index_reverse_index() {
420        let values = vec![1, 2, 3, 4];
421        let given_index = -1isize;
422        let max_size = values.len() as isize;
423        let index = clamp_index(&given_index, &max_size).unwrap();
424        assert_eq!(
425            index, 4,
426            "Index mismatch! Requested index {} but got {}",
427            &given_index, &index
428        );
429        assert_eq!(
430            values[index - 1],
431            4,
432            "Value mismatch! Expected {} but got {}",
433            &values[3],
434            &values[index]
435        );
436    }
437
438    #[test]
439    fn test_block_on_task() {
440        let expect = 5;
441        let value = block_on_task(async move { 5 });
442        assert_eq!(
443            value, 5,
444            "Value mismatch from async task! Expected {} but got {}",
445            &expect, &value
446        );
447    }
448
449    ///////////////////////////////////Queue Tests/////////////////////////////////////////////////
450    use crate::cli::cli_utils::print_license_notice;
451    use crate::cpu::{cpu_collect, cpu_find, cpu_find_replace_simd_n, cpu_tokenize, CPU_SEARCH_WINDOW_16_SIZE};
452    use crate::net::tcp::LOCALHOST;
453    use crate::pipelines::pipeline_functions::{pipeline_add_stdin_data_to_pipeline, pipeline_create_command, pipeline_patch_args, pipeline_pipe_processes, pipeline_spawn_process};
454    use crate::pipelines::pipeline_types::RUMCommand;
455    use crate::threading::threading_functions::block_on_task;
456    use crate::threading::threading_manager::*;
457
458    #[test]
459    fn test_queue_data() {
460        let expected = vec![
461            RUMString::from("Hello"),
462            RUMString::from("World!"),
463            RUMString::from("Overcast"),
464            RUMString::from("and"),
465            RUMString::from("Sad"),
466        ];
467        type TestResult = RUMResult<Vec<RUMString>>;
468        let mut queue: TaskManager<TestResult> = TaskManager::new(&5).unwrap();
469        let locked_args = RwLock::new(expected.clone());
470        let task_args = SafeTaskArgs::<RUMString>::new(locked_args);
471        let processor = rumtk_create_task!(
472            async |args: &SafeTaskArgs<RUMString>| -> TestResult {
473                let owned_args = Arc::clone(args);
474                let lock_future = owned_args.read();
475                let locked_args = lock_future.await;
476                let mut results = TaskItems::<RUMString>::with_capacity(locked_args.len());
477                print!("Contents: ");
478                for arg in locked_args.iter() {
479                    print!("{} ", &arg);
480                    results.push(RUMString::from(arg));
481                }
482                Ok(results)
483            },
484            task_args
485        );
486
487        queue.add_task::<_>(processor);
488        let results = queue.wait();
489
490        let mut result_data = Vec::<RUMString>::with_capacity(5);
491        for r in results {
492            for v in r.unwrap().result.clone().unwrap().iter() {
493                for value in v.iter() {
494                    result_data.push(value.clone());
495                }
496            }
497        }
498        assert_eq!(result_data, expected, "Results do not match expected!");
499    }
500
501    ///////////////////////////////////Net Tests/////////////////////////////////////////////////
502    #[test]
503    fn test_server_start() {
504        let server = match rumtk_create_server!("localhost", 0) {
505            Ok(server) => server,
506            Err(e) => panic!("Failed to create server because {}", e),
507        };
508    }
509
510    #[test]
511    fn test_server_send() {
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        let address_info = server.get_address_info().unwrap();
518        let (ip, port) = rumtk_get_ip_port!(address_info);
519        rumtk_sleep!(1);
520        let mut client = match rumtk_connect!(port) {
521            Ok(client) => client,
522            Err(e) => panic!("Failed to create server because {}", e),
523        };
524        let client_id = client.get_address().unwrap();
525        match server.send(&client_id, &msg.to_raw()) {
526            Ok(_) => (),
527            Err(e) => panic!("Server failed to send message because {}", e),
528        };
529        let received_message = client.receive().unwrap();
530        assert_eq!(
531            &msg.len(),
532            &received_message.len(),
533            "Received message does not match expected length!"
534        );
535        assert_eq!(
536            &msg.to_raw(),
537            &received_message,
538            "{}",
539            rumtk_format!(
540                "Received message does not match sent message by server {:?}",
541                &received_message
542            )
543        );
544    }
545
546    #[test]
547    fn test_server_receive() {
548        let msg = RUMString::from("Hello World!");
549        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
550            Ok(server) => server,
551            Err(e) => panic!("Failed to create server because {}", e),
552        };
553        let address_info = server.get_address_info().unwrap();
554        let (ip, port) = rumtk_get_ip_port!(address_info);
555        println!("Sleeping");
556        rumtk_sleep!(1);
557        let mut client = match rumtk_connect!(port) {
558            Ok(client) => client,
559            Err(e) => panic!("Failed to create server because {}", e),
560        };
561        println!("Sleeping");
562        rumtk_sleep!(1);
563        match client.send(msg.to_raw()) {
564            Ok(_) => (),
565            Err(e) => panic!("Failed to send message because {}", e),
566        };
567        let client_id = client.get_address().expect("Failed to get client id");
568        let incoming_message = server.receive(&client_id, true).unwrap().to_string().unwrap();
569        println!("Received message => {:?}", &incoming_message);
570        assert_eq!(incoming_message, msg, "Received message corruption!");
571    }
572
573    #[test]
574    fn test_server_get_clients() {
575        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
576            Ok(server) => server,
577            Err(e) => panic!("Failed to create server because {}", e),
578        };
579        let address_info = server.get_address_info().unwrap();
580        let (ip, port) = rumtk_get_ip_port!(address_info);
581        println!("Sleeping");
582        rumtk_sleep!(1);
583        let mut client = match rumtk_connect!(port) {
584            Ok(client) => client,
585            Err(e) => panic!("Failed to create client because {}", e),
586        };
587        println!("Sleeping");
588        rumtk_sleep!(1);
589        let expected_client_id = client.get_address().expect("Failed to get client id");
590        let clients = server.get_client_ids();
591        let incoming_client_id = clients.get(0).expect("Expected client to have connected!");
592        println!("Connected client id => {}", &incoming_client_id);
593        assert_eq!(
594            incoming_client_id, &expected_client_id,
595            "Connected client does not match the connecting client! Client id => {}",
596            &incoming_client_id
597        );
598    }
599
600    #[test]
601    fn test_server_stop() {
602        let msg = RUMString::from("Hello World!");
603        let server = match rumtk_create_server!("localhost", 0) {
604            Ok(server) => server,
605            Err(e) => panic!("Failed to create server because {}", e),
606        };
607        println!("Sleeping");
608    }
609
610    #[test]
611    fn test_server_get_address_info() {
612        let msg = RUMString::from("Hello World!");
613        let mut server = match rumtk_create_server!("localhost", 0) {
614            Ok(server) => server,
615            Err(e) => panic!("Failed to create server because {}", e),
616        };
617        let addr = server.get_address_info().unwrap();
618        assert!(!addr.is_empty(), "No address returned....Got => {}", addr)
619    }
620
621    #[test]
622    fn test_client_send() {
623        let msg = RUMString::from("Hello World!");
624        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
625            Ok(server) => server,
626            Err(e) => panic!("Failed to create server because {}", e),
627        };
628        let address_info = server.get_address_info().unwrap();
629        let (ip, port) = rumtk_get_ip_port!(address_info);
630        println!("Sleeping");
631        rumtk_sleep!(1);
632        let mut client = match rumtk_connect!(port) {
633            Ok(client) => client,
634            Err(e) => panic!("Failed to create server because {}", e),
635        };
636        match client.send(msg.to_raw()) {
637            Ok(_) => (),
638            Err(e) => panic!("Failed to send message because {}", e),
639        };
640        let clients = server.get_client_ids();
641        let incoming_client_id = clients.first().expect("Expected client to have connected!");
642        let mut received_message = server.receive(incoming_client_id, true).unwrap();
643        if received_message.is_empty() {
644            received_message = server.receive(incoming_client_id, true).unwrap();
645        }
646        assert_eq!(
647            &msg.to_raw(),
648            &received_message,
649            "{}",
650            rumtk_format!(
651                "Received message does not match sent message by client {:?}",
652                &received_message
653            )
654        );
655    }
656
657    ////////////////////////////JSON Tests/////////////////////////////////
658
659    #[test]
660    fn test_serialize_json() {
661        #[derive(RUMSerJson)]
662        struct MyStruct {
663            hello: RUMString,
664        }
665
666        let hw = MyStruct {
667            hello: RUMString::from("World"),
668        };
669        let hw_str = rumtk_serialize!(&hw).unwrap();
670
671        assert!(
672            !hw_str.is_empty(),
673            "Empty JSON string generated from the test struct!"
674        );
675    }
676
677    #[test]
678    fn test_deserialize_serde_json() {
679        #[derive(RUMSerJson, RUMDeJson, PartialEq, Debug, Clone)]
680        struct MyStruct {
681            hello: RUMString,
682        }
683
684        let hw = MyStruct {
685            hello: RUMString::from("World"),
686        };
687        let hw_str = to_json(&hw).unwrap();
688        let new_hw: MyStruct = from_json(&hw_str).unwrap();
689
690        assert_eq!(
691            new_hw, hw,
692            "Deserialized JSON does not match the expected value!"
693        );
694    }
695
696    #[test]
697    fn test_deserialize_buffer_serde_json() {
698        let hw = RUMBuffer::from(b"Hello World!");
699        let hw_str = to_json(&hw).unwrap();
700        let new_hw: RUMBuffer = from_json(&hw_str).unwrap();
701
702        assert_eq!(
703            new_hw, hw,
704            "Deserialized Buffer from JSON does not match the expected value!"
705        );
706    }
707
708    #[test]
709    fn test_deserialize_json() {
710        #[derive(RUMSerJson, RUMDeJson, PartialEq)]
711        struct MyStruct {
712            hello: RUMString,
713        }
714
715        let hw = MyStruct {
716            hello: RUMString::from("World"),
717        };
718        let hw_str = rumtk_serialize!(&hw).unwrap();
719        let new_hw: MyStruct = rumtk_deserialize!(&hw_str).unwrap();
720
721        assert!(
722            new_hw == hw,
723            "Deserialized JSON does not match the expected value!"
724        );
725    }
726
727
728    #[test]
729    fn test_escape_unescape_json() {
730        #[derive(RUMSerJson, RUMDeJson, PartialEq)]
731        struct MyStruct {
732            hello: RUMString,
733        }
734
735        let hw = MyStruct {
736            hello: RUMString::from("World"),
737        };
738
739        let hw_str = rumtk_serialize!(&hw).unwrap();
740        let hw_escaped_str = strings::basic_escape(&hw_str, None);
741        println!("Escaped => {}", hw_escaped_str);
742
743        let hw_unescaped_str = strings::unescape_string(&hw_escaped_str).unwrap();
744        println!("Unescaped => {}", hw_unescaped_str);
745        assert_eq!(
746            hw_str.to_string(),
747            hw_unescaped_str.to_string(),
748            "Unescaped serialized JSON mismatch!"
749        );
750
751        let new_hw: MyStruct = rumtk_deserialize!(&hw_unescaped_str).unwrap();
752
753        assert!(
754            new_hw == hw,
755            "Deserialized JSON does not match the expected value!"
756        );
757    }
758
759    ////////////////////////////CLI Tests/////////////////////////////////
760
761    #[test]
762    fn test_print_license_notice() {
763        print_license_notice("RUMTK", "2025", &vec!["Luis M. Santos, M.D."]);
764    }
765
766    //////////////////////////////////////////////////////////////////////////////////////////////
767
768    ////////////////////////////Pipeline Tests/////////////////////////////////
769
770    #[test]
771    fn test_pipe_processes() {
772        let ls_name = "ls";
773        let mut ls_command = RUMCommand::default();
774        ls_command.path = RUMString::from(ls_name);
775        let mut sys_ls_command = pipeline_create_command(&ls_command);
776        sys_ls_command.stdin(Stdio::piped());
777        sys_ls_command.stdout(Stdio::piped());
778
779        let wc_name = "wc";
780        let mut wc_command = RUMCommand::default();
781        wc_command.path = RUMString::from(wc_name);
782        let mut sys_wc_command = pipeline_create_command(&wc_command);
783
784        let mut sys_ls_process = pipeline_spawn_process(&mut sys_ls_command).unwrap();
785        pipeline_pipe_processes(&mut sys_ls_process, &mut sys_wc_command).unwrap();
786        let mut sys_wc_process = pipeline_spawn_process(&mut sys_wc_command).unwrap();
787
788        sys_ls_process.wait();
789        sys_wc_process.wait();
790    }
791
792    #[test]
793    fn test_quick_pipe() {let data = RUMBuffer::from(b"Hello World");
794        let wc_name = "wc";
795        let mut wc_command = RUMCommand::default();
796        wc_command.path = RUMString::from(wc_name);
797        let mut pipeline = vec![
798            wc_command
799        ];
800
801        let processor = || -> RUMResult<RUMBuffer> {rumtk_pipeline_run!(&pipeline, &data)};
802        let result_string = buffer_to_string(&processor().unwrap()).unwrap();
803        let binding = result_string.as_str().replace('\n', "");
804        let result_items: Vec<&str> = binding.split("      ").collect();
805        let result = result_items.get(2).unwrap().trim().parse::<i32>().unwrap();
806
807        assert_eq!(result, 2, "Data was not piped properly!");
808    }
809
810    #[test]
811    fn test_patch_pipeline_arguments() {let data = RUMBuffer::from(b"Hello World");
812        let ls_name = "ls";
813        let mut ls_command = RUMCommand::default();
814        ls_command.path = RUMString::from(ls_name);
815        ls_command.args.push(RUMString::from("{options}"));
816        let mut pipeline = vec![
817            ls_command
818        ];
819        pipeline_patch_args(&mut pipeline, &[("{options}", "-la")]);
820
821        let processor = || -> RUMResult<RUMBuffer> {rumtk_pipeline_run!(&pipeline)};
822        let result_string = buffer_to_string(&processor().unwrap()).unwrap();
823        let results: Vec<&str> = result_string.as_str().split("\n").collect();
824        let dot_dir = results.get(1).unwrap().chars().last().unwrap();
825
826        assert_eq!(dot_dir, '.', "Incorrect options passed!");
827    }
828
829    //////////////////////////////////////////////////////////////////////////////////////////////
830
831    ////////////////////////////Buffer Tests/////////////////////////////////
832    #[test]
833    fn test_buffer_split() {
834        let data = RUMBuffer::from(b"Hello|World|Test|||||||||||||||||||");
835        let mut splits = vec![];
836
837        let mut splitter = data.split_fast('|' as u8);
838        for split in &mut splitter {
839            splits.push(split);
840        }
841        splits.push(splitter.remainder);
842
843        assert_eq!(splits.len(), 22, "Bad buffer split! Got {:?}", splits);
844    }
845
846    #[test]
847    fn test_buffer_find() {
848        let data = RUMBuffer::from(b"Hello|World|Test|||||||||||||||||||");
849        let indx = buffer_find(data.as_slice(), &['|' as u8]);
850
851        assert_eq!(indx, 5, "Bad buffer find! Got {:?}", indx);
852    }
853
854    #[test]
855    fn test_buffer_find_long() {
856        let pattern = "|Test";
857        let data = RUMBuffer::from(b"Hello|World|Test|||||||||||||||||||");
858        let indx = buffer_find(data.as_slice(), pattern.as_bytes());
859
860        assert_eq!(indx, 11, "Bad buffer find! Got {:?}", indx);
861    }
862
863    #[test]
864    fn test_buffer_replace() {
865        let pattern = "|Test";
866        let replacement = "|Test123";
867        let data = RUMBuffer::from(b"Hello|World|Test|||||||||||||||||||");
868        let expected = RUMBuffer::from(b"Hello|World|Test123|||||||||||||||||||");
869        let new = buffer_replace(data.as_slice(), pattern.as_bytes(), replacement.as_bytes());
870
871        assert_eq!(new, expected, "Bad buffer replace! Got {:?}", new);
872    }
873
874    #[test]
875    fn test_buffer_replace_in_place() {
876        let pattern = "|Test";
877        let replacement = "|Tes1";
878        let mut data = RUMBuffer::from(b"Hello|World|Test|||||||||||||||||||");
879        let expected = RUMBuffer::from(b"Hello|World|Tes1|||||||||||||||||||");
880
881        buffer_replace_in_place(&mut data, pattern.as_bytes(), replacement.as_bytes());
882
883        assert_eq!(data, expected, "Bad buffer replace! Got {:?}", data);
884    }
885
886    #[test]
887    fn test_buffer_trim() {
888        let data = RUMBuffer::from(b"\n Hello|World \n");
889        let expected = RUMBuffer::from(b"Hello|World");
890        let new = buffer_trim(&data);
891
892        assert_eq!(new, expected, "Bad buffer trim! Got {:?}", new);
893    }
894
895    #[test]
896    fn test_buffer_slice_trim() {
897        let data = b"\n Hello|World \n";
898        let expected = b"Hello|World";
899        let new = buffer_slice_trim(data);
900
901        assert_eq!(new, expected, "Bad buffer slice trim! Got {:?}", new);
902    }
903
904    #[test]
905    fn test_buffer_count() {
906        let data = b"\n Hello|World \n";
907        let expected = 2;
908        let found = buffer_count(data, b'\n');
909
910        assert_eq!(found, expected, "Incorrect number of occurrences of newline found! Got {:?}", found);
911    }
912
913    #[test]
914    fn test_buffer_count_2mb() {
915        let data = new_random_buffer::<2048>();
916        let expected = 1000;
917        let (found, time) = rumtk_benchmark_snippet!(||{
918            buffer_count(&data, b'\n')
919        });
920
921        assert!(time <= expected, "Counting of instances in buffer was too slow! Took {:?} us", time);
922    }
923
924    #[test]
925    fn test_buffer_split_simple() {
926        let mut data = RUMBuffer::from(b"Hello|World");
927        let split = data.split_to(5);
928        let expected = RUMBuffer::from(b"Hello");
929
930        assert_eq!(split, Some(expected), "Bad buffer trim! Got {:?}", split);
931    }
932
933    #[test]
934    fn test_buffer_struct_size() {
935        let data = RUMBuffer::new();
936        let struct_size = size_of::<RUMBuffer>();
937
938        assert!(struct_size <= 16, "Empty RUMBuffer structure size is too large! Length is {} bytes.", struct_size);
939    }
940
941    //////////////////////////////////////////////////////////////////////////////////////////////
942
943    ////////////////////////////CPU Tests/////////////////////////////////
944
945    #[test]
946    fn test_cpu_find_needle() {
947        let data = b"                                                         n                    ";
948        let expected = Some(57);
949        let indx = cpu_find(data, b'n');
950
951        assert_eq!(indx, expected, "Could not find the needle in the haystack");
952    }
953
954    #[test]
955    fn test_cpu_find_needle_2mb() {
956        let data = new_random_buffer::<2048>();
957        let expected = 1000;
958        let (found, time) = rumtk_benchmark_snippet!(||{
959            cpu_find(&data, b'\n')
960        });
961
962        assert!(time <= expected, "Counting of instances in buffer was too slow! Took {:?} us", time);
963    }
964
965    #[test]
966    fn test_cpu_find_needle_2mb_4096() {
967        let mut all_time = 0;
968        let expected = 1000;
969        for i in 0..4096 {
970            let data = new_random_buffer::<2048>();
971            let (found, time) = rumtk_benchmark_snippet!(||{
972                    cpu_find(&data, b'\n')
973            });
974            all_time += time;
975        }
976
977        assert!(all_time <= expected, "Counting of instances in buffer was too slow! Took {:?} us", all_time);
978    }
979
980    #[test]
981    fn test_cpu_collect_needle() {
982        let data = b"                                                         n                    ";
983        let expected = vec![57];
984        let indices = cpu_collect(data, b'n', 0);
985
986        assert_eq!(indices.1, expected, "Could not find the needle in the haystack");
987    }
988
989    #[test]
990    fn test_cpu_collect_needle_3() {
991        let data = b"                                                         nnn                    ";
992        let expected = vec![57, 58, 59];
993        let indices = cpu_collect(data, b'n', 0);
994
995        assert_eq!(indices.1, expected, "Could not find the needle in the haystack");
996    }
997
998    #[test]
999    fn test_cpu_collect_needle_6() {
1000        let data = b"                 nnn                                        nnn                    ";
1001        let expected = vec![17, 18, 19, 60, 61, 62];
1002        let indices = cpu_collect(data, b'n', 0);
1003
1004        assert_eq!(indices.1, expected, "Could not find the needle in the haystack");
1005    }
1006
1007    #[test]
1008    fn test_cpu_tokenize_needle_6() {
1009        let data = b"                 nnn                                        nnn                    ";
1010        let expected = vec![(110, 17), (110, 18), (110, 19), (110, 60), (110, 61), (110, 62)];
1011        let indices = cpu_tokenize::<CPU_SEARCH_WINDOW_16_SIZE>(data, b"n");
1012
1013        assert_eq!(indices, expected, "Could not find the needle in the haystack");
1014    }
1015
1016    #[test]
1017    fn test_cpu_tokenize_needle_6_benchmark() {
1018        let data = b"                 nnn                                        nnn                    ";
1019        let (indices, time) = rumtk_benchmark_snippet!(||{
1020            cpu_tokenize::<CPU_SEARCH_WINDOW_16_SIZE>(data, b"n")
1021        });
1022
1023        println!("Tokenized message in {} us", &time);
1024
1025        assert!(time <= 10000, "Buffer tokenization took {} microseconds [> 10000 us]!", time);
1026    }
1027
1028    #[test]
1029    fn test_cpu_replace_simd() {
1030        let mut data = b"                                                         n                    ".to_vec();
1031        let expected = b"                                                                              ".to_vec();
1032
1033        cpu_replace_byte(data.as_mut_slice(), b'n', b' ');
1034
1035        assert_eq!(data, expected, "Failed to replace in SIMD!");
1036    }
1037
1038    #[test]
1039    fn test_cpu_replace_simd_multi() {
1040        let mut data = b"              nnnnnnnn                  nnnn                         n    nn                ".to_vec();
1041        let expected = b"                                                                                            ".to_vec();
1042
1043        cpu_replace_byte(data.as_mut_slice(), b'n', b' ');
1044
1045        assert_eq!(data, expected, "Failed to replace in SIMD!");
1046    }
1047
1048}