use crate as rust_utils;
#[cfg(test)]
use crate::{
utils::{self, get_input},
logging::*,
config::*,
config,
hash_map,
chainable,
encapsulated,
New
};
use std::{
fs, env,
thread,
path::PathBuf
};
use serde::{Deserialize, Serialize};
use chrono::{Datelike, Local};
use regex::Regex;
#[cfg(feature = "futures")]
use crate::futures::exec_future;
#[test]
fn get_execname() {
println!("get_execname() test:");
println!("This test's executable name is {}", utils::get_execname());
}
#[test]
fn capitalize() {
println!("capitalize() test:");
let text = utils::capitalize("test");
assert_eq!(text, "Test");
}
#[test]
fn get_parent() {
println!("get_parent() test:");
let home_dir = format!("{}/", env::var("HOME").unwrap());
println!("{home_dir}");
let parent = utils::get_parent(home_dir);
assert_eq!(parent, "/home");
}
#[test]
fn get_filename() {
println!("get_filename() test:");
let dir = "/tmp/test.txt";
fs::write("/tmp/test.txt", "test").unwrap();
let file = utils::get_filename(dir);
assert_eq!(file, "test.txt");
fs::remove_file("/tmp/test.txt").unwrap();
}
#[test]
fn alphabetize() {
println!("alphabetize() test:");
const ALPHA_UPPER_EXPECTED: [&str; 26] = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
const ALPHA_LOWER_SCRAMBLED: [&str; 26] = ["e" ,"c", "r", "n", "x", "j", "o", "a", "g", "v", "y", "f", "l", "s", "q", "d", "k", "t", "b", "w", "m", "h", "u", "i", "p", "z"];
const ALPHA_LOWER_EXPECTED: [&str; 26] = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
const ALPHA_UPPER_SCRAMBLED: [&str; 26] = ["J", "B", "R", "L", "C", "P", "Y", "D", "F", "K", "A", "U", "O", "S", "Z", "E", "X", "Q", "I", "W", "T", "V", "H", "M", "N", "G"];
let mut alpha_vec: Vec<String> = utils::alphabetize(&ALPHA_UPPER_SCRAMBLED);
for (count,letter) in alpha_vec.iter().enumerate() {
assert_eq!(letter, ALPHA_UPPER_EXPECTED[count]);
}
println!("Uppercase: {alpha_vec:?}\n");
alpha_vec = utils::alphabetize(&ALPHA_LOWER_SCRAMBLED);
for (count,letter) in alpha_vec.iter().enumerate() {
assert_eq!(letter, ALPHA_LOWER_EXPECTED[count]);
}
println!("Lowercase: {alpha_vec:?}");
}
#[test]
fn logging_test() {
let info_regex = Regex::new(r"\[[0-9]*:[0-9][0-9]:[0-9][0-9]\] \[INFO\]: Yes. Is this useful?").unwrap();
let info_regex2 = Regex::new(r"\[[0-9]*:[0-9][0-9]:[0-9][0-9]\] \[INFO\]: Yes.").unwrap();
let debug_regex = Regex::new(r"\[[0-9]*:[0-9][0-9]:[0-9][0-9]\] \[DEBUG\]: Debug info").unwrap();
let debug_regex2 = Regex::new(r"\[[0-9]*:[0-9][0-9]:[0-9][0-9]\] \[DEBUG\]: This shouldn't show up").unwrap();
let warn_regex = Regex::new(r"\[[0-9]*:[0-9][0-9]:[0-9][0-9]\] \[WARN\]: There may be an issue!").unwrap();
let error_regex = Regex::new(r"\[[0-9]*:[0-9][0-9]:[0-9][0-9]\] \[ERROR\]: Houston, we have a problem!").unwrap();
let expected_name = {
let now = Local::now();
format!("test-{}-{}-{}.log", now.year(), now.month(), now.day())
};
let path = format!("{}/.local/share/coof-testing/{expected_name}", env::var("HOME").expect("Where the hell is your home folder?!"));
fs::remove_file(&path).unwrap_or(());
let log = Log::new("test", "coof-testing");
log.line(LogLevel::Info, "Yes. Is this useful?", true);
log.line_basic("Yes.", true);
log.line(LogLevel::Debug(true), "Debug info", true);
log.line(LogLevel::Debug(false), "This shouldn't show up", true);
log.line(LogLevel::Warn, "There may be an issue!", true);
log.line(LogLevel::Error, "Houston, we have a problem!", true);
let file = fs::read_to_string(&path).unwrap();
assert!(info_regex.is_match(&file));
assert!(info_regex2.is_match(&file));
assert!(debug_regex.is_match(&file));
assert!(!debug_regex2.is_match(&file));
assert!(warn_regex.is_match(&file));
assert!(error_regex.is_match(&file));
let log2 = log.clone();
let thread = thread::spawn(move || {
for _ in 0..100 {
log2.line(LogLevel::Info, "Concurrent logging...", true);
}
});
for _ in 0..100 {
log.line(LogLevel::Info, "Concurrent logging!!!", true);
}
thread.join().expect("thread did not complete successfully!");
}
#[should_panic]
#[test]
fn logging_panic_test() {
let log = Log::new("test", "coof-testing");
log.report_panics(true);
let user = env::var("USER").expect("What is your name again?");
panic!("{user} has tested positive for the coof!");
}
#[test]
fn config_test() {
#[derive(Deserialize, Serialize, PartialEq, Debug)]
struct TestConfig {
string: String,
number: u32,
boolean: bool
}
impl Default for TestConfig {
fn default() -> TestConfig {
TestConfig {
string: "string".into(),
number: 100,
boolean: true
}
}
}
impl Config for TestConfig {
const FILE_NAME: &'static str = "test.toml";
fn get_save_dir() -> PathBuf {
Self::get_config_root()
.join("coof-testing")
}
}
#[derive(Default, PartialEq, Debug)]
#[config(save_dir = "coof-testing", file_name = "test2.toml", cfg_type(ron))]
struct MacroConfig {
name: String,
id: usize,
ok: bool
}
let config_dir = format!("{}/.config/coof-testing", env::var("HOME").expect("Where the hell is your home folder?!"));
fs::remove_dir_all(config_dir).unwrap_or(());
let expected = TestConfig::default();
let mut config = TestConfig::load();
assert_eq!(expected, config);
config.number = 5;
config.save().expect("Unable to save config!");
let expected = TestConfig {
string: "string".to_string(),
number: 5,
boolean: true
};
let config = TestConfig::load();
assert_eq!(expected, config);
let macro_config = MacroConfig::load();
macro_config.save().expect("Unable to save config!");
}
#[test]
fn run_cmd_test() {
let reg_cmd = utils::run_command("nmcli", false, ["networking", "connectivity", "check"]);
let priv_cmd = utils::run_command("nmcli", true, ["networking", "connectivity", "check"]);
assert_eq!(reg_cmd.output, "full");
assert_eq!(priv_cmd.output, "full");
}
#[test]
fn spawn_proc_test() {
utils::spawn_process("firefox-developer-edition", false, false, ["aercloud-systems.net"]);
utils::spawn_process("okular", false, true, ["README.md"]);
utils::spawn_process("echo", false, false, ["yes"]);
}
#[test]
fn user_input() {
let name = get_input("What is your name?");
println!("Your name is {name}.");
}
#[cfg(feature = "futures")]
#[test]
fn futures() {
let val = exec_future(future_fn());
println!("Value from async function: {val}");
}
#[cfg(feature = "futures")]
async fn future_fn() -> String {
let log = Log::new("test", "coof-testing");
log.line_basic("async rust function being executed!", true);
log.line_basic(format!("2 + 2 is {}, not 5!", 2 + 2), true);
"yes".to_string()
}
#[test]
fn map_macro() {
let map = hash_map! {
"yes" => 0.,
"no" => 1.,
"pi" => std::f64::consts::PI
};
for (key, val) in map.iter() {
println!("Key: {key}, Value: {val}");
}
}
#[test]
fn chainable_macro() {
#[allow(unused)]
trait TestTrait: Sized {
#[chainable]
fn set_something(&mut self, val: u32);
#[chainable]
fn set_something_else(&mut self, val: u32) {
self.set_something(val);
}
}
struct Test1 {
field_0: bool
}
impl Test1 {
fn new() -> Self {
Test1 {
field_0: false
}
}
#[chainable]
fn set_field_0(&mut self, val: bool) {
self.field_0 = val;
}
}
#[chainable]
#[derive(Default, Debug)]
struct Test2 {
#[chainable(doc = "Documentation for `field_0`")]
field_0: bool,
field_1: usize,
#[chainable(use_into_impl)]
field_2: f64,
#[chainable(collapse_option, doc = "Documentation for `opt_field`")]
opt_field: Option<usize>
}
#[allow(unused)]
#[derive(Default)]
struct Test3 {
opt_field: Option<u32>
}
impl Test3 {
#[chainable(collapse_options, use_into_impl)]
fn set_opt_field(&mut self, opt_field: Option<u32>, other: f64) {
println!("{other}");
self.opt_field = opt_field;
}
}
let test1 = Test1::new().field_0(true);
println!("Value of field0: {}", test1.field_0);
let test2 = Test2::default()
.field_0(false)
.field_1(100)
.field_2(std::f64::consts::PI)
.opt_field(1);
println!("{test2:?}");
}
#[test]
fn new_macro() {
#[allow(unused)]
#[derive(Default, New)]
struct Test {
a: usize,
b: f64,
c: f32
}
#[allow(unused)]
#[derive(Default, New)]
struct Test2<A, B, C> {
a: A,
b: B,
c: C
}
}
#[test]
fn encapsulated_macro() {
#[allow(unused)]
#[derive(Default, New)]
#[encapsulated]
struct Test {
#[getter(copy_val)]
#[setter]
a: usize,
#[getter]
#[setter(use_into_impl)]
b: f64,
c: f32,
#[setter]
#[chainable]
chainable: u32,
#[setter]
#[chainable(collapse_option)]
thing1: Option<u32>,
#[setter]
#[chainable(collapse_option, use_into_impl)]
thing2: Option<usize>
}
}