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