/*
 * rumtk attempts to implement HL7 and medical protocols for interoperability in medicine.
 * This toolkit aims to be reliable, simple, performant, and standards compliant.
 * Copyright (C) 2024  Luis M. Santos, M.D. <lsantos@medicalmasses.com>
 * Copyright (C) 2025  MedicalMasses L.L.C. <contact@medicalmasses.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

//#![feature(unboxed_closures)]
//#![feature(inherent_associated_types)]
#![feature(type_alias_impl_trait)]
#![feature(unboxed_closures)]
#![feature(buf_read_has_data_left)]
#![feature(mapped_lock_guards)]
#![feature(str_as_str)]
#![feature(const_trait_impl)]
#![feature(const_cmp)]
#![feature(macro_metavar_expr)]
#![feature(const_default)]
#![feature(portable_simd)]

pub mod cache;
pub mod cli;
pub mod base;
pub mod dependencies;
pub mod hash;
pub mod id;
pub mod serde;
pub mod log;
pub mod maths;
pub mod net;
pub mod pipelines;
pub mod scripting;
pub mod search;
pub mod strings;
pub mod threading;
pub mod types;
pub mod buffers;

#[cfg(test)]
mod tests {
    use super::*;
    use crate::base::{clamp_index, RUMResult};
    use crate::buffers::{buffer_find, buffer_replace, buffer_replace_in_place, buffer_slice_trim, buffer_split_fast, buffer_to_string, buffer_trim};
    use crate::cache::RUMCache;
    use crate::search::rumtk_search::*;
    use crate::serde::{from_json, to_json, RUMDeJson, RUMSerJson};
    use crate::strings::{rumtk_format, AsStr, RUMArrayConversions, RUMString, RUMStringConversions, StringUtils};
    use crate::types::RUMBuffer;
    use std::process::Stdio;
    use std::sync::Arc;
    use tokio::io::AsyncBufReadExt;
    use tokio::sync::RwLock;

    #[test]
    fn test_is_escaped_str() {
        let input = "\r\n\'\\\"";
        let expected = false;
        let result = strings::is_escaped_str(input);
        println!("Input: {} Expected: {} Got: {}", input, expected, result);
        assert_eq!(
            expected, result,
            "Incorrect detection of unescaped string as escaped!!"
        );
        println!("Passed!")
    }

    #[test]
    fn test_escaping_control() {
        let input = "\r\n\'\"\\";
        let expected = "\\r\\n\\'\\\"\\\\";
        let result = strings::escape(input);
        println!(
            "Input: {} Expected: {} Got: {}",
            input,
            expected,
            result.as_str()
        );
        assert_eq!(expected, result, "Incorrect string escaping!");
        println!("Passed!")
    }

    #[test]
    fn test_escaping_unicode() {
        let input = "❤";
        let expected = "\\u2764";
        let result = strings::escape(input);
        println!(
            "Input: {} Expected: {} Got: {}",
            input,
            expected,
            result.as_str()
        );
        assert_eq!(expected, result, "Incorrect string escaping!");
        println!("Passed!")
    }

    #[test]
    fn test_unescaping_unicode() {
        let input = "❤";
        let escaped = strings::escape(input);
        let expected = "❤";
        let result = RUMString::from_utf8(strings::unescape(escaped.as_str()).unwrap()).unwrap();
        println!(
            "Input: {} Expected: {} Got: {}",
            input,
            expected,
            result.as_str()
        );
        assert_eq!(expected, result.as_str(), "Incorrect string unescaping!");
        println!("Passed!")
    }

    #[test]
    fn test_unescaping_string() {
        let input = "I \\u2764 my wife!";
        let expected = "I ❤ my wife!";
        let result = strings::unescape_string(input).unwrap();
        println!(
            "Input: {} Expected: {} Got: {}",
            input,
            expected,
            result.as_str()
        );
        assert_eq!(expected, result.as_str(), "Incorrect string unescaping!");
        println!("Passed!")
    }

    #[test]
    fn test_is_escaped_string() {
        let input = "I \\u2764 my wife!";
        let expected = true;
        let result = strings::is_escaped_str(input);
        println!("Input: {} Expected: {} Got: {}", input, expected, result);
        assert_eq!(
            expected, result,
            "Escaped string detected as unescaped string!"
        );
        println!("Passed!")
    }

    #[test]
    fn test_is_unescaped_string() {
        let input = "I ❤ my wife!";
        let expected = false;
        let result = strings::is_escaped_str(input);
        println!("Input: {} Expected: {} Got: {}", input, expected, result);
        assert_eq!(
            expected, result,
            "Unescaped string detected as escaped string!"
        );
        println!("Passed!")
    }

    #[test]
    fn test_unique_string() {
        let input = "I❤mywife!";
        assert!(
            input.as_grapheme_str().is_unique(),
            "String was not detected as unique."
        );
    }

    #[test]
    fn test_non_unique_string() {
        let input = "I❤❤mywife!";
        assert!(
            !input.as_grapheme_str().is_unique(),
            "String was detected as unique."
        );
    }

    #[test]
    fn test_escaping_string() {
        let input = "I ❤ my wife!";
        let expected = "I \\u2764 my wife!";
        let result = strings::escape(input);
        println!(
            "Input: {} Expected: {} Got: {}",
            input,
            expected,
            result.as_str()
        );
        assert_eq!(expected, result.as_str(), "Incorrect string escaping!");
        println!("Passed!")
    }

    #[test]
    fn test_autodecode_utf8() {
        let input = "I ❤ my wife!";
        let result = strings::try_decode(input.as_bytes()).unwrap();
        println!(
            "Input: {} Expected: {} Got: {}",
            input,
            input,
            result.as_str()
        );
        assert_eq!(input, result, "Incorrect string decoding!");
        println!("Passed!")
    }

    #[test]
    fn test_autodecode_other() {
        //TODO: Need an example of other encoding texts.
        let input = "I ❤ my wife!";
        let result = input;
        println!("Input: {} Expected: {} Got: {}", input, input, result);
        assert_eq!(input, result, "Incorrect string decoding!");
        println!("Passed!")
    }

    #[test]
    fn test_decode() {
        let input = "I ❤ my wife!";
        let result = strings::try_decode_with(input.as_bytes(), "utf-8").unwrap();
        println!(
            "Input: {} Expected: {} Got: {}",
            input,
            input,
            result.as_str()
        );
        assert_eq!(input, result, "Incorrect string decoding!");
        println!("Passed!")
    }

    #[test]
    fn test_rumcache_insertion() {
        let mut cache: RUMCache<&str, RUMString> = RUMCache::with_capacity(5);
        cache.insert("❤", RUMString::from("I ❤ my wife!"));
        println!("Contents: {:#?}", &cache);
        assert_eq!(cache.len(), 1, "Incorrect number of items in cache!");
        println!("Passed!")
    }

    #[test]
    fn test_search_string_letters() {
        let input = "Hello World!";
        let expr = r"\w";
        let result = string_search(input, expr, "").unwrap();
        let expected: RUMString = RUMString::from("HelloWorld");
        println!(
            "Input: {:?} Expected: {:?} Got: {:?}",
            input, expected, result
        );
        assert_eq!(expected, result, "String search results mismatch");
        println!("Passed!")
    }

    #[test]
    fn test_search_string_words() {
        let input = "Hello World!";
        let expr = r"\w+";
        let result = string_search(input, expr, " ").unwrap();
        let expected: RUMString = RUMString::from("Hello World");
        println!(
            "Input: {:?} Expected: {:?} Got: {:?}",
            input, expected, result
        );
        assert_eq!(expected, result, "String search results mismatch");
        println!("Passed!")
    }

    #[test]
    fn test_search_string_named_groups() {
        let input = "Hello World!";
        let expr = r"(?<hello>\w{5}) (?<world>\w{5})";
        let result = string_search_named_captures(input, expr, "").unwrap();
        let expected: RUMString = RUMString::from("World");
        println!(
            "Input: {:?} Expected: {:?} Got: {:?}",
            input, expected, result
        );
        assert_eq!(expected, result["world"], "String search results mismatch");
        println!("Passed!")
    }

    #[test]
    fn test_search_string_all_groups() {
        let input = "Hello World!";
        let expr = r"(?<hello>\w{5}) (?<world>\w{5})";
        let result = string_search_all_captures(input, expr, "").unwrap();
        let expected: Vec<&str> = vec!["Hello", "World"];
        println!(
            "Input: {:?} Expected: {:?} Got: {:?}",
            input, expected, result
        );
        assert_eq!(expected, result, "String search results mismatch");
        println!("Passed!")
    }

    #[test]
    fn test_find_value_in_string() {
        let haystack = "Range (min \\xe2\\x80\\xa6 max):     0.6 ms \\xe2\\x80\\xa6   2.9 ms    1273 runs";
        let patterns = ["\\d+ runs", "\\d+"];
        let expected = 1273;
        let result = string_find_value::<usize>(haystack, &patterns);

        assert_eq!(result, Ok(expected), "Did not find the needle in the haystack or returned the wrong type!");
    }

    ///////////////////////////////////Threading Tests/////////////////////////////////////////////////
    #[test]
    fn test_default_num_threads() {
        use num_cpus;
        let threads = threading::threading_functions::get_default_system_thread_count();
        assert_eq!(
            threads >= num_cpus::get(),
            true,
            "Default thread count is incorrect! We got {}, but expected {}!",
            threads,
            num_cpus::get()
        );
    }

    #[test]
    fn test_execute_job() {
        let expected = vec![1, 2, 3];
        let task_processor = async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
            let owned_args = Arc::clone(args);
            let lock_future = owned_args.read();
            let locked_args = lock_future.await;
            let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
            print!("Contents: ");
            for arg in locked_args.iter() {
                results.push(arg.clone());
                println!("{} ", &arg);
            }
            Ok(results)
        };
        let locked_args = RwLock::new(expected.clone());
        let task_args = SafeTaskArgs::<i32>::new(locked_args);
        let task_result = rumtk_wait_on_task!(task_processor, &task_args);
        let result = task_result.unwrap();
        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
    }

    #[test]
    fn test_execute_job_macros() {
        let expected = vec![1, 2, 3];
        let task_processor = async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
            let owned_args = Arc::clone(args);
            let lock_future = owned_args.read();
            let locked_args = lock_future.await;
            let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
            print!("Contents: ");
            for arg in locked_args.iter() {
                results.push(arg.clone());
                println!("{} ", &arg);
            }
            Ok(results)
        };
        let task_args = rumtk_create_task_args!(1, 2, 3);
        let task_result = rumtk_wait_on_task!(task_processor, &task_args);
        let result = task_result.unwrap();
        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
    }

    #[test]
    fn test_execute_job_macros_one_line() {
        let expected = vec![1, 2, 3];
        let result = rumtk_exec_task!(
            async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
                let owned_args = Arc::clone(args);
                let lock_future = owned_args.read();
                let locked_args = lock_future.await;
                let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
                print!("Contents: ");
                for arg in locked_args.iter() {
                    results.push(arg.clone());
                    println!("{} ", &arg);
                }
                Ok(results)
            },
            vec![1, 2, 3]
        )
        .unwrap();
        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
    }

    #[test]
    fn test_clamp_index_positive_index() {
        let values = vec![1, 2, 3, 4];
        let given_index = 3isize;
        let max_size = values.len() as isize;
        let index = clamp_index(&given_index, &max_size).unwrap();
        assert_eq!(
            index, 3,
            "Index mismatch! Requested index {} but got {}",
            &given_index, &index
        );
        assert_eq!(
            values[index], 4,
            "Value mismatch! Expected {} but got {}",
            &values[3], &values[index]
        );
    }

    #[test]
    fn test_clamp_index_reverse_index() {
        let values = vec![1, 2, 3, 4];
        let given_index = -1isize;
        let max_size = values.len() as isize;
        let index = clamp_index(&given_index, &max_size).unwrap();
        assert_eq!(
            index, 4,
            "Index mismatch! Requested index {} but got {}",
            &given_index, &index
        );
        assert_eq!(
            values[index - 1],
            4,
            "Value mismatch! Expected {} but got {}",
            &values[3],
            &values[index]
        );
    }

    #[test]
    fn test_block_on_task() {
        let expect = 5;
        let value = block_on_task(async move { 5 });
        assert_eq!(
            value, 5,
            "Value mismatch from async task! Expected {} but got {}",
            &expect, &value
        );
    }

    ///////////////////////////////////Queue Tests/////////////////////////////////////////////////
    use crate::cli::cli_utils::print_license_notice;
    use crate::net::tcp::LOCALHOST;
    use crate::pipelines::pipeline_functions::{pipeline_add_stdin_data_to_pipeline, pipeline_create_command, pipeline_patch_args, pipeline_pipe_processes, pipeline_spawn_process};
    use crate::pipelines::pipeline_types::RUMCommand;
    use crate::threading::threading_functions::block_on_task;
    use crate::threading::threading_manager::*;

    #[test]
    fn test_queue_data() {
        let expected = vec![
            RUMString::from("Hello"),
            RUMString::from("World!"),
            RUMString::from("Overcast"),
            RUMString::from("and"),
            RUMString::from("Sad"),
        ];
        type TestResult = RUMResult<Vec<RUMString>>;
        let mut queue: TaskManager<TestResult> = TaskManager::new(&5).unwrap();
        let locked_args = RwLock::new(expected.clone());
        let task_args = SafeTaskArgs::<RUMString>::new(locked_args);
        let processor = rumtk_create_task!(
            async |args: &SafeTaskArgs<RUMString>| -> TestResult {
                let owned_args = Arc::clone(args);
                let lock_future = owned_args.read();
                let locked_args = lock_future.await;
                let mut results = TaskItems::<RUMString>::with_capacity(locked_args.len());
                print!("Contents: ");
                for arg in locked_args.iter() {
                    print!("{} ", &arg);
                    results.push(RUMString::from(arg));
                }
                Ok(results)
            },
            task_args
        );

        queue.add_task::<_>(processor);
        let results = queue.wait();

        let mut result_data = Vec::<RUMString>::with_capacity(5);
        for r in results {
            for v in r.unwrap().result.clone().unwrap().iter() {
                for value in v.iter() {
                    result_data.push(value.clone());
                }
            }
        }
        assert_eq!(result_data, expected, "Results do not match expected!");
    }

    ///////////////////////////////////Net Tests/////////////////////////////////////////////////
    #[test]
    fn test_server_start() {
        let server = match rumtk_create_server!("localhost", 0) {
            Ok(server) => server,
            Err(e) => panic!("Failed to create server because {}", e),
        };
    }

    #[test]
    fn test_server_send() {
        let msg = RUMString::from("Hello World!");
        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
            Ok(server) => server,
            Err(e) => panic!("Failed to create server because {}", e),
        };
        let address_info = server.get_address_info().unwrap();
        let (ip, port) = rumtk_get_ip_port!(address_info);
        rumtk_sleep!(1);
        let mut client = match rumtk_connect!(port) {
            Ok(client) => client,
            Err(e) => panic!("Failed to create server because {}", e),
        };
        let client_id = client.get_address().unwrap();
        match server.send(&client_id, &msg.to_raw()) {
            Ok(_) => (),
            Err(e) => panic!("Server failed to send message because {}", e),
        };
        let received_message = client.receive().unwrap();
        assert_eq!(
            &msg.len(),
            &received_message.len(),
            "Received message does not match expected length!"
        );
        assert_eq!(
            &msg.to_raw(),
            &received_message,
            "{}",
            rumtk_format!(
                "Received message does not match sent message by server {:?}",
                &received_message
            )
        );
    }

    #[test]
    fn test_server_receive() {
        let msg = RUMString::from("Hello World!");
        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
            Ok(server) => server,
            Err(e) => panic!("Failed to create server because {}", e),
        };
        let address_info = server.get_address_info().unwrap();
        let (ip, port) = rumtk_get_ip_port!(address_info);
        println!("Sleeping");
        rumtk_sleep!(1);
        let mut client = match rumtk_connect!(port) {
            Ok(client) => client,
            Err(e) => panic!("Failed to create server because {}", e),
        };
        println!("Sleeping");
        rumtk_sleep!(1);
        match client.send(msg.to_raw()) {
            Ok(_) => (),
            Err(e) => panic!("Failed to send message because {}", e),
        };
        let client_id = client.get_address().expect("Failed to get client id");
        let incoming_message = server.receive(&client_id, true).unwrap().to_string().unwrap();
        println!("Received message => {:?}", &incoming_message);
        assert_eq!(incoming_message, msg, "Received message corruption!");
    }

    #[test]
    fn test_server_get_clients() {
        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
            Ok(server) => server,
            Err(e) => panic!("Failed to create server because {}", e),
        };
        let address_info = server.get_address_info().unwrap();
        let (ip, port) = rumtk_get_ip_port!(address_info);
        println!("Sleeping");
        rumtk_sleep!(1);
        let mut client = match rumtk_connect!(port) {
            Ok(client) => client,
            Err(e) => panic!("Failed to create client because {}", e),
        };
        println!("Sleeping");
        rumtk_sleep!(1);
        let expected_client_id = client.get_address().expect("Failed to get client id");
        let clients = server.get_client_ids();
        let incoming_client_id = clients.get(0).expect("Expected client to have connected!");
        println!("Connected client id => {}", &incoming_client_id);
        assert_eq!(
            incoming_client_id, &expected_client_id,
            "Connected client does not match the connecting client! Client id => {}",
            &incoming_client_id
        );
    }

    #[test]
    fn test_server_stop() {
        let msg = RUMString::from("Hello World!");
        let server = match rumtk_create_server!("localhost", 0) {
            Ok(server) => server,
            Err(e) => panic!("Failed to create server because {}", e),
        };
        println!("Sleeping");
    }

    #[test]
    fn test_server_get_address_info() {
        let msg = RUMString::from("Hello World!");
        let mut server = match rumtk_create_server!("localhost", 0) {
            Ok(server) => server,
            Err(e) => panic!("Failed to create server because {}", e),
        };
        let addr = server.get_address_info().unwrap();
        assert!(!addr.is_empty(), "No address returned....Got => {}", addr)
    }

    #[test]
    fn test_client_send() {
        let msg = RUMString::from("Hello World!");
        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
            Ok(server) => server,
            Err(e) => panic!("Failed to create server because {}", e),
        };
        let address_info = server.get_address_info().unwrap();
        let (ip, port) = rumtk_get_ip_port!(address_info);
        println!("Sleeping");
        rumtk_sleep!(1);
        let mut client = match rumtk_connect!(port) {
            Ok(client) => client,
            Err(e) => panic!("Failed to create server because {}", e),
        };
        match client.send(msg.to_raw()) {
            Ok(_) => (),
            Err(e) => panic!("Failed to send message because {}", e),
        };
        let clients = server.get_client_ids();
        let incoming_client_id = clients.first().expect("Expected client to have connected!");
        let mut received_message = server.receive(incoming_client_id, true).unwrap();
        if received_message.is_empty() {
            received_message = server.receive(incoming_client_id, true).unwrap();
        }
        assert_eq!(
            &msg.to_raw(),
            &received_message,
            "{}",
            rumtk_format!(
                "Received message does not match sent message by client {:?}",
                &received_message
            )
        );
    }

    ////////////////////////////JSON Tests/////////////////////////////////

    #[test]
    fn test_serialize_json() {
        #[derive(RUMSerJson)]
        struct MyStruct {
            hello: RUMString,
        }

        let hw = MyStruct {
            hello: RUMString::from("World"),
        };
        let hw_str = rumtk_serialize!(&hw).unwrap();

        assert!(
            !hw_str.is_empty(),
            "Empty JSON string generated from the test struct!"
        );
    }

    #[test]
    fn test_deserialize_serde_json() {
        #[derive(RUMSerJson, RUMDeJson, PartialEq, Debug, Clone)]
        struct MyStruct {
            hello: RUMString,
        }

        let hw = MyStruct {
            hello: RUMString::from("World"),
        };
        let hw_str = to_json(&hw).unwrap();
        let new_hw: MyStruct = from_json(&hw_str).unwrap();

        assert_eq!(
            new_hw, hw,
            "Deserialized JSON does not match the expected value!"
        );
    }

    #[test]
    fn test_deserialize_json() {
        #[derive(RUMSerJson, RUMDeJson, PartialEq)]
        struct MyStruct {
            hello: RUMString,
        }

        let hw = MyStruct {
            hello: RUMString::from("World"),
        };
        let hw_str = rumtk_serialize!(&hw).unwrap();
        let new_hw: MyStruct = rumtk_deserialize!(&hw_str).unwrap();

        assert!(
            new_hw == hw,
            "Deserialized JSON does not match the expected value!"
        );
    }


    #[test]
    fn test_escape_unescape_json() {
        #[derive(RUMSerJson, RUMDeJson, PartialEq)]
        struct MyStruct {
            hello: RUMString,
        }

        let hw = MyStruct {
            hello: RUMString::from("World"),
        };

        let hw_str = rumtk_serialize!(&hw).unwrap();
        let hw_escaped_str = strings::basic_escape(&hw_str, None);
        println!("Escaped => {}", hw_escaped_str);

        let hw_unescaped_str = strings::unescape_string(&hw_escaped_str).unwrap();
        println!("Unescaped => {}", hw_unescaped_str);
        assert_eq!(
            hw_str.to_string(),
            hw_unescaped_str.to_string(),
            "Unescaped serialized JSON mismatch!"
        );

        let new_hw: MyStruct = rumtk_deserialize!(&hw_unescaped_str).unwrap();

        assert!(
            new_hw == hw,
            "Deserialized JSON does not match the expected value!"
        );
    }

    ////////////////////////////CLI Tests/////////////////////////////////

    #[test]
    fn test_print_license_notice() {
        print_license_notice("RUMTK", "2025", &vec!["Luis M. Santos, M.D."]);
    }

    //////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////Pipeline Tests/////////////////////////////////

    #[test]
    fn test_pipe_processes() {
        let ls_name = "ls";
        let mut ls_command = RUMCommand::default();
        ls_command.path = RUMString::from(ls_name);
        let mut sys_ls_command = pipeline_create_command(&ls_command);
        sys_ls_command.stdin(Stdio::piped());
        sys_ls_command.stdout(Stdio::piped());

        let wc_name = "wc";
        let mut wc_command = RUMCommand::default();
        wc_command.path = RUMString::from(wc_name);
        let mut sys_wc_command = pipeline_create_command(&wc_command);

        let mut sys_ls_process = pipeline_spawn_process(&mut sys_ls_command).unwrap();
        pipeline_pipe_processes(&mut sys_ls_process, &mut sys_wc_command).unwrap();
        let mut sys_wc_process = pipeline_spawn_process(&mut sys_wc_command).unwrap();

        sys_ls_process.wait();
        sys_wc_process.wait();
    }

    #[test]
    fn test_quick_pipe() {let data = RUMBuffer::from_static(b"Hello World");
        let wc_name = "wc";
        let mut wc_command = RUMCommand::default();
        wc_command.path = RUMString::from(wc_name);
        let mut pipeline = vec![
            wc_command
        ];

        let processor = || -> RUMResult<RUMBuffer> {rumtk_pipeline_run!(&pipeline, &data)};
        let result_string = buffer_to_string(&processor().unwrap()).unwrap();
        let binding = result_string.as_str().replace('\n', "");
        let result_items: Vec<&str> = binding.split("      ").collect();
        let result = result_items.get(2).unwrap().trim().parse::<i32>().unwrap();

        assert_eq!(result, 2, "Data was not piped properly!");
    }

    #[test]
    fn test_patch_pipeline_arguments() {let data = RUMBuffer::from_static(b"Hello World");
        let ls_name = "ls";
        let mut ls_command = RUMCommand::default();
        ls_command.path = RUMString::from(ls_name);
        ls_command.args.push(RUMString::from("{options}"));
        let mut pipeline = vec![
            ls_command
        ];
        pipeline_patch_args(&mut pipeline, &[("{options}", "-la")]);

        let processor = || -> RUMResult<RUMBuffer> {rumtk_pipeline_run!(&pipeline)};
        let result_string = buffer_to_string(&processor().unwrap()).unwrap();
        let results: Vec<&str> = result_string.as_str().split("\n").collect();
        let dot_dir = results.get(1).unwrap().chars().last().unwrap();

        assert_eq!(dot_dir, '.', "Incorrect options passed!");
    }

    //////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////Buffer Tests/////////////////////////////////
    #[test]
    fn test_buffer_split() {
        let data = RUMBuffer::from_static(b"Hello|World|Test|||||||||||||||||||");
        let splits = buffer_split_fast(data, '|' as u8);

        assert_eq!(splits.len(), 22, "Bad buffer split! Got {:?}", splits);
    }

    #[test]
    fn test_buffer_find() {
        let data = RUMBuffer::from_static(b"Hello|World|Test|||||||||||||||||||");
        let indx = buffer_find(data.as_slice(), &['|' as u8]);

        assert_eq!(indx, 5, "Bad buffer find! Got {:?}", indx);
    }

    #[test]
    fn test_buffer_find_long() {
        let pattern = "|Test";
        let data = RUMBuffer::from_static(b"Hello|World|Test|||||||||||||||||||");
        let indx = buffer_find(data.as_slice(), pattern.as_bytes());

        assert_eq!(indx, 11, "Bad buffer find! Got {:?}", indx);
    }

    #[test]
    fn test_buffer_replace() {
        let pattern = "|Test";
        let replacement = "|Test123";
        let data = RUMBuffer::from_static(b"Hello|World|Test|||||||||||||||||||");
        let expected = RUMBuffer::from_static(b"Hello|World|Test123|||||||||||||||||||");
        let new = buffer_replace(data.as_slice(), pattern.as_bytes(), replacement.as_bytes());

        assert_eq!(new, expected, "Bad buffer replace! Got {:?}", new);
    }

    #[test]
    fn test_buffer_replace_in_place() {
        let pattern = "|Test";
        let replacement = "|Tes1";
        let mut data = RUMBuffer::copy_from_slice(b"Hello|World|Test|||||||||||||||||||");
        let expected = RUMBuffer::from_static(b"Hello|World|Tes1|||||||||||||||||||");

        data = match data.try_into_mut() {
            Ok(mut data) => {
                buffer_replace_in_place(&mut data, pattern.as_bytes(), replacement.as_bytes());
                data.freeze()
            },
            Err(data) => data
        };


        assert_eq!(data, expected, "Bad buffer replace! Got {:?}", data);
    }

    #[test]
    fn test_buffer_trim() {
        let data = RUMBuffer::from_static(b"\n Hello|World \n");
        let expected = RUMBuffer::from_static(b"Hello|World");
        let new = buffer_trim(&data);

        assert_eq!(new, expected, "Bad buffer trim! Got {:?}", new);
    }

    #[test]
    fn test_buffer_slice_trim() {
        let data = b"\n Hello|World \n";
        let expected = b"Hello|World";
        let new = buffer_slice_trim(data);

        assert_eq!(new, expected, "Bad buffer slice trim! Got {:?}", new);
    }
}
