#![allow(
clippy::arithmetic_side_effects,
clippy::unused_async,
clippy::needless_pass_by_value,
clippy::unnecessary_wraps,
clippy::unwrap_used
)]
use kash::kash;
use std::sync::Arc;
use std::thread::{self, sleep};
use std::time::Duration;
#[kash]
fn fib0(n: u32) -> u32 {
if n == 0 || n == 1 {
return n;
}
fib0(n - 1) + fib0(n - 2)
}
#[test]
fn test_unbound_cache() {
fib0(20);
{
FIB0.run_pending_tasks();
let cache_size = FIB0.entry_count();
assert_eq!(21, cache_size);
}
}
#[kash(size = "3")]
fn fib1(n: u32) -> u32 {
if n == 0 || n == 1 {
return n;
}
fib1(n - 1) + fib1(n - 2)
}
#[test]
fn test_sized_cache() {
fib1(20);
{
FIB1.run_pending_tasks();
let cache_size = FIB1.entry_count();
assert_eq!(3, cache_size);
let items = FIB1.iter().collect::<Vec<_>>();
assert_eq!(3, items.len());
}
}
#[kash(size = "1")]
fn string_1(a: String, b: String) -> String {
a + &b
}
#[test]
fn test_string_cache() {
string_1("a".into(), "b".into());
STRING_1.run_pending_tasks();
assert_eq!(1, STRING_1.entry_count());
}
#[kash(
size = "2",
key(ty = "String", expr = r#"format!("{a}{b}")"#),
eviction_policy = "lru"
)]
fn sized_key(a: &str, b: &str) -> usize {
let size = a.len() + b.len();
sleep(Duration::new(size as u64, 0));
size
}
#[test]
fn test_sized_cache_key() {
sized_key("a", "1");
sized_key("a", "1");
SIZED_KEY.run_pending_tasks();
assert_eq!(1, SIZED_KEY.entry_count());
sized_key("a", "2");
SIZED_KEY.run_pending_tasks();
assert_eq!(2, SIZED_KEY.entry_count());
let (keys, values): (Vec<_>, Vec<_>) = SIZED_KEY.into_iter().unzip();
assert!(keys.contains(&Arc::new("a1".to_string())));
assert!(keys.contains(&Arc::new("a2".to_string())));
assert_eq!(vec![2, 2], values);
sized_key("a", "3");
SIZED_KEY.run_pending_tasks();
assert_eq!(2, SIZED_KEY.entry_count());
let (keys, values): (Vec<_>, Vec<_>) = SIZED_KEY.into_iter().unzip();
assert!(keys.contains(&Arc::new("a3".to_string())));
assert!(keys.contains(&Arc::new("a2".to_string())));
assert_eq!(vec![2, 2], values);
sized_key("a", "4");
sized_key("a", "5");
SIZED_KEY.run_pending_tasks();
assert_eq!(2, SIZED_KEY.entry_count());
let (keys, values): (Vec<_>, Vec<_>) = SIZED_KEY.into_iter().unzip();
assert!(keys.contains(&Arc::new("a4".to_string())));
assert!(keys.contains(&Arc::new("a5".to_string())));
assert_eq!(vec![2, 2], values);
sized_key("a", "67");
sized_key("a", "8");
SIZED_KEY.run_pending_tasks();
assert_eq!(2, SIZED_KEY.entry_count());
let (keys, values): (Vec<_>, Vec<_>) = SIZED_KEY.into_iter().unzip();
assert!(keys.contains(&Arc::new("a67".to_string())));
assert!(keys.contains(&Arc::new("a8".to_string())));
assert!(values.contains(&2));
assert!(values.contains(&3));
}
#[kash(result)]
fn test_result_key(n: u32) -> Result<u32, ()> {
if n < 5 { Ok(n) } else { Err(()) }
}
#[test]
fn cache_result_key() {
assert!(test_result_key(2).is_ok());
assert!(test_result_key(4).is_ok());
assert!(test_result_key(6).is_err());
assert!(test_result_key(6).is_err());
assert!(test_result_key(2).is_ok());
assert!(test_result_key(4).is_ok());
TEST_RESULT_KEY.run_pending_tasks();
assert_eq!(2, TEST_RESULT_KEY.entry_count());
}
#[kash(result)]
fn test_result_no_default(n: u32) -> Result<u32, ()> {
if n < 5 { Ok(n) } else { Err(()) }
}
#[test]
fn cache_result_no_default() {
assert!(test_result_no_default(2).is_ok());
assert!(test_result_no_default(4).is_ok());
assert!(test_result_no_default(6).is_err());
assert!(test_result_no_default(6).is_err());
assert!(test_result_no_default(2).is_ok());
assert!(test_result_no_default(4).is_ok());
TEST_RESULT_NO_DEFAULT.run_pending_tasks();
assert_eq!(2, TEST_RESULT_NO_DEFAULT.entry_count());
}
#[kash(
size = "2",
key(ty = "String", expr = r#"format!("{a}/{b}")"#),
eviction_policy = "lru"
)]
fn slow_small_cache(a: &str, b: &str) -> String {
sleep(Duration::new(1, 0));
format!("{a}:{b}")
}
#[test]
fn test_racing_duplicate_keys_do_not_duplicate_sized_cache_ordering() {
let a = thread::spawn(|| slow_small_cache("a", "b"));
sleep(Duration::new(0, 500_000));
let b = thread::spawn(|| slow_small_cache("a", "b"));
a.join().unwrap();
b.join().unwrap();
slow_small_cache("c", "d");
slow_small_cache("e", "f");
slow_small_cache("g", "h");
}
#[kash(option)]
fn proc_kash_option(n: u32) -> Option<Vec<u32>> {
(n < 5).then(|| vec![n])
}
#[test]
fn test_proc_kash_option() {
assert!(proc_kash_option(2).is_some());
assert!(proc_kash_option(4).is_some());
assert!(proc_kash_option(1).is_some());
assert!(proc_kash_option(6).is_none());
assert!(proc_kash_option(6).is_none());
assert!(proc_kash_option(2).is_some());
assert!(proc_kash_option(1).is_some());
assert!(proc_kash_option(4).is_some());
PROC_KASH_OPTION.run_pending_tasks();
assert_eq!(3, PROC_KASH_OPTION.entry_count());
}
#[kash]
fn test_result_missing_result_arm(n: u32) -> Result<u32, ()> {
Ok(n)
}
#[kash]
fn test_result_key_missing_result_arm(n: u32) -> Result<u32, ()> {
Ok(n)
}
#[allow(unused_mut)]
#[kash]
fn mutable_args(mut a: i32, mut b: i32) -> (i32, i32) {
a += 1;
b += 1;
(a, b)
}
#[test]
fn test_mutable_args() {
assert_eq!((2, 2), mutable_args(1, 1));
assert_eq!((2, 2), mutable_args(1, 1));
}
#[allow(unused_mut)]
#[kash]
fn mutable_args_str(mut a: String) -> String {
a.push_str("-ok");
a
}
#[test]
fn test_mutable_args_str() {
assert_eq!("a-ok", mutable_args_str(String::from("a")));
assert_eq!("a-ok", mutable_args_str(String::from("a")));
}
#[kash(result, ttl = "1")]
fn always_failing() -> Result<String, ()> {
Err(())
}