diff --git a/Cargo.toml b/Cargo.toml index d9bc766..5d52b6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "re_set-lib" -version = "2.10.2" +version = "2.11.0" edition = "2021" description = "Data structure library for ReSet" repository = "https://github.com/Xetibo/ReSet-Lib" diff --git a/src/lib.rs b/src/lib.rs index 772c01c..03d1f8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,7 @@ #![feature(trait_upcasting)] #![feature(unsized_fn_params)] +#![feature(unboxed_closures)] +#![feature(fn_traits)] use directories_next as dirs; use std::{fmt, fs, path::PathBuf, slice::Iter}; use utils::{ diff --git a/src/tests.rs b/src/tests.rs index aa08327..2c0c600 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,3 +1,8 @@ +#[cfg(test)] +use crate::utils::plugin::plugin_tests; +#[cfg(test)] +use crate::{utils::plugin::PluginTestError, utils::plugin::PluginTestFunc}; + #[test] fn test_config_dir() { use crate::create_config; @@ -96,3 +101,13 @@ fn test_custom_error_flag() { let flags = parse_flags(&command_flags); assert!(flags.0.is_empty()); } + +#[test] +fn test_custom_tests() { + let func1 = || -> Result<(), PluginTestError> { Ok(()) }; + let func2 = || -> Result<(), PluginTestError> { Err(PluginTestError::new("fail")) }; + let func1 = PluginTestFunc::new(func1, "henlo"); + let func2 = PluginTestFunc::new(func2, "fail"); + let funcs = vec![func1, func2]; + plugin_tests(funcs); +} diff --git a/src/utils/flags.rs b/src/utils/flags.rs index 9193e8a..af84a85 100644 --- a/src/utils/flags.rs +++ b/src/utils/flags.rs @@ -5,7 +5,7 @@ use super::variant::Variant; pub enum Flag<'a> { ConfigDir(&'a String), PluginDir(&'a String), - Other((String,Variant)) + Other((String, Variant)), } #[derive(Debug)] diff --git a/src/utils/macros.rs b/src/utils/macros.rs index a427049..a74c202 100644 --- a/src/utils/macros.rs +++ b/src/utils/macros.rs @@ -51,3 +51,14 @@ pub enum ErrorLevel { PartialBreakage, Critical, } + +#[cfg(test)] +#[macro_export] +macro_rules! plug_assert { + ($e:expr) => {{ + if !$e { + return Err(PluginTestError::new("Failed")); + } + Ok(()) + }}; +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 925ac0b..f0b7e42 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,5 +1,5 @@ pub mod dbus_utils; +pub mod flags; pub mod macros; -pub mod variant; pub mod plugin; -pub mod flags; +pub mod variant; diff --git a/src/utils/plugin.rs b/src/utils/plugin.rs index 0787297..b7cd4c7 100644 --- a/src/utils/plugin.rs +++ b/src/utils/plugin.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, error::Error, fmt::Display}; use dbus::Path; @@ -37,7 +37,6 @@ impl PluginData { &self.0 } - pub fn new(map: HashMap) -> Self { Self(map) } @@ -63,3 +62,101 @@ impl Plugin { } } } + +#[derive(Debug)] +pub struct PluginTestError(&'static str); + +impl PluginTestError { + pub fn new(message: &'static str) -> Self { + Self(message) + } + + pub fn message(&self) -> &'static str { + self.0 + } +} + +impl Display for PluginTestError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.0) + } +} + +impl Error for PluginTestError {} + +unsafe impl Send for PluginTestError {} +unsafe impl Sync for PluginTestError {} + +pub struct PluginTestFunc( + Box Result<(), PluginTestError>>, + &'static str, +); + +impl PluginTestFunc { + pub fn new( + func: impl Fn() -> Result<(), PluginTestError> + 'static, + name: &'static str, + ) -> Self { + Self(Box::new(func), name) + } + + pub fn name(&self) -> &'static str { + self.1 + } +} + +impl FnOnce<()> for PluginTestFunc { + type Output = Result<(), PluginTestError>; + + extern "rust-call" fn call_once(self, _: ()) -> Self::Output { + self.0.call_once(()) + } +} + +unsafe impl Send for PluginTestFunc {} +unsafe impl Sync for PluginTestFunc {} + +#[cfg(test)] +pub fn plugin_tests(tests: Vec) { + use std::thread; + + let mut running = String::from(""); + let running_index = tests.len(); + let mut crashed = String::from(""); + let mut crashed_index = 0; + let mut failed = String::from(""); + let mut failed_index = 0; + let mut success = String::from(""); + let mut success_index = 0; + for func in tests { + let name = func.name(); + running += &format!("running test {}\n", name); + let test = thread::spawn(func).join(); + if test.is_err() { + // panic is currently handled differently + crashed += &format!("Thread of test {} crashed!\n", name); + crashed_index += 1; + } else if let Ok(Err(error)) = test { + failed += &format!("Test {} failed with error: {}\n", name, error.message()); + failed_index += 1; + } else { + success += &format!("Success: {}\n", name); + success_index += 1; + } + } + let mut buffer = String::from(""); + buffer += "\n----------- Plugin Tests -----------\n\n"; + buffer += &format!("running {} tests:\n", running_index); + buffer += &running; + buffer += &format!("\n{} test crashed:\n", crashed_index); + buffer += &crashed; + buffer += &format!("\n{} tests failed:\n", failed_index); + buffer += &failed; + buffer += &format!("\n{} tests successful:\n", success_index); + buffer += &success; + buffer += "\n----------- Plugin Tests end -----------\n\n"; + print!("{}", buffer); + // this combination is done to avoid conflicts with other tests + // -> the cli only has one buffer, e.g. multiple threads writing + // to it could cause conflicts with the terminal output +}