use std::time::Duration;
use sz_rust_core::cache::{Cache, MemoryCacheDriver};
fn make_cache() -> Cache {
let cache = Cache::new();
cache.register_default(MemoryCacheDriver::new());
cache
}
#[test]
fn test_r5_p1_set_get_string_alignment() {
let cache = make_cache();
cache.set("name", "Alice", None).unwrap();
let val: String = cache.get("name").unwrap().unwrap();
assert_eq!(val, "Alice");
}
#[test]
fn test_r5_p1_set_get_struct_alignment() {
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)]
struct User {
id: i64,
name: String,
}
let cache = make_cache();
let user = User {
id: 1,
name: "Bob".to_string(),
};
cache.set("user", &user, None).unwrap();
let val: User = cache.get("user").unwrap().unwrap();
assert_eq!(val, user);
}
#[test]
fn test_r5_p1_set_get_overwrite_alignment() {
let cache = make_cache();
cache.set("key", "v1", None).unwrap();
cache.set("key", "v2", None).unwrap();
let val: String = cache.get("key").unwrap().unwrap();
assert_eq!(val, "v2");
}
#[test]
fn test_r5_p1_get_nonexistent_returns_none() {
let cache = make_cache();
let val: Option<String> = cache.get("nonexistent").unwrap();
assert_eq!(val, None);
}
#[test]
fn test_r5_p2_is_numeric_int_returns_string() {
let cache = make_cache();
cache.set("count", 42i64, None).unwrap();
let s: String = cache.get("count").unwrap().unwrap();
assert_eq!(s, "42");
}
#[test]
fn test_r5_p2_is_negative_numeric_returns_string() {
let cache = make_cache();
cache.set("temp", -42i64, None).unwrap();
let s: String = cache.get("temp").unwrap().unwrap();
assert_eq!(s, "-42");
}
#[test]
fn test_r5_p2_is_zero_numeric_returns_string() {
let cache = make_cache();
cache.set("zero", 0i64, None).unwrap();
let s: String = cache.get("zero").unwrap().unwrap();
assert_eq!(s, "0");
}
#[test]
fn test_r5_p3_delete_then_get_returns_none() {
let cache = make_cache();
cache.set("key", "value", None).unwrap();
assert_eq!(
cache.get::<String>("key").unwrap(),
Some("value".to_string())
);
cache.delete("key").unwrap();
let val: Option<String> = cache.get("key").unwrap();
assert_eq!(val, None);
}
#[test]
fn test_r5_p3_delete_then_has_returns_false() {
let cache = make_cache();
cache.set("key", "value", None).unwrap();
assert!(cache.has("key").unwrap());
cache.delete("key").unwrap();
assert!(!cache.has("key").unwrap());
}
#[test]
fn test_r5_p3_delete_does_not_affect_other_keys() {
let cache = make_cache();
cache.set("k1", "v1", None).unwrap();
cache.set("k2", "v2", None).unwrap();
cache.delete("k1").unwrap();
assert_eq!(cache.get::<String>("k1").unwrap(), None);
assert_eq!(cache.get::<String>("k2").unwrap(), Some("v2".to_string()));
}
#[test]
fn test_r5_p3_delete_then_recreate() {
let cache = make_cache();
cache.set("key", "v1", None).unwrap();
cache.delete("key").unwrap();
cache.set("key", "v2", None).unwrap();
let val: String = cache.get("key").unwrap().unwrap();
assert_eq!(val, "v2");
}
#[test]
fn test_r5_p4_delete_nonexistent_no_error() {
let cache = make_cache();
let result = cache.delete("nonexistent");
assert!(result.is_ok());
}
#[test]
fn test_r5_p4_delete_nonexistent_does_not_create_key() {
let cache = make_cache();
cache.delete("nonexistent").unwrap();
assert!(!cache.has("nonexistent").unwrap());
assert_eq!(cache.get::<String>("nonexistent").unwrap(), None);
}
#[test]
fn test_r5_p4_delete_multiple_times_no_error() {
let cache = make_cache();
cache.set("key", "value", None).unwrap();
cache.delete("key").unwrap();
cache.delete("key").unwrap();
cache.delete("key").unwrap();
assert_eq!(cache.get::<String>("key").unwrap(), None);
}
#[test]
fn test_r5_p5_has_returns_true_for_existing_key() {
let cache = make_cache();
cache.set("key", "value", None).unwrap();
assert!(cache.has("key").unwrap());
}
#[test]
fn test_r5_p5_has_returns_false_for_nonexistent_key() {
let cache = make_cache();
assert!(!cache.has("nonexistent").unwrap());
}
#[test]
fn test_r5_p5_has_returns_false_after_ttl_expiration() {
let cache = make_cache();
cache
.set("key", "value", Some(Duration::from_millis(50)))
.unwrap();
assert!(cache.has("key").unwrap());
std::thread::sleep(Duration::from_millis(100));
assert!(!cache.has("key").unwrap());
}
#[test]
fn test_r5_p5_has_returns_true_for_no_ttl() {
let cache = make_cache();
cache.set("key", "value", None).unwrap();
std::thread::sleep(Duration::from_millis(50));
assert!(cache.has("key").unwrap());
}
#[test]
fn test_r5_p6_clear_all_keys() {
let cache = make_cache();
cache.set("k1", "v1", None).unwrap();
cache.set("k2", "v2", None).unwrap();
cache.set("k3", "v3", None).unwrap();
cache.clear().unwrap();
assert!(!cache.has("k1").unwrap());
assert!(!cache.has("k2").unwrap());
assert!(!cache.has("k3").unwrap());
}
#[test]
fn test_r5_p6_clear_empty_cache_no_error() {
let cache = make_cache();
let result = cache.clear();
assert!(result.is_ok());
}
#[test]
fn test_r5_p6_clear_then_recreate() {
let cache = make_cache();
cache.set("k1", "v1", None).unwrap();
cache.clear().unwrap();
cache.set("k1", "v2", None).unwrap();
let val: String = cache.get("k1").unwrap().unwrap();
assert_eq!(val, "v2");
}
#[test]
fn test_r5_p7_inc_existing_key() {
let cache = make_cache();
cache.set("counter", 100i64, None).unwrap();
let new_val = cache.inc("counter", 50).unwrap();
assert_eq!(new_val, 150);
}
#[test]
fn test_r5_p7_inc_nonexistent_key() {
let cache = make_cache();
let new_val = cache.inc("new_counter", 5).unwrap();
assert_eq!(new_val, 5);
}
#[test]
fn test_r5_p7_inc_stores_numeric_string() {
let cache = make_cache();
cache.inc("counter", 10).unwrap();
let s: String = cache.get("counter").unwrap().unwrap();
assert_eq!(s, "10");
}
#[test]
fn test_r5_p7_dec_existing_key() {
let cache = make_cache();
cache.set("counter", 100i64, None).unwrap();
let new_val = cache.dec("counter", 30).unwrap();
assert_eq!(new_val, 70);
}
#[test]
fn test_r5_p7_dec_nonexistent_key() {
let cache = make_cache();
let new_val = cache.dec("new_counter", 5).unwrap();
assert_eq!(new_val, -5);
}
#[test]
fn test_r5_p8_remember_cache_miss() {
let cache = make_cache();
let val: i64 = cache.remember("key", None, || 42).unwrap();
assert_eq!(val, 42);
assert_eq!(cache.get::<String>("key").unwrap(), Some("42".to_string()));
}
#[test]
fn test_r5_p8_remember_cache_hit() {
let cache = make_cache();
cache.set("key", "existing", None).unwrap();
let val: String = cache.remember("key", None, || "new".to_string()).unwrap();
assert_eq!(val, "existing");
}
#[test]
fn test_r5_p8_remember_lock_released() {
let cache = make_cache();
let val: i64 = cache.remember("key", None, || 42).unwrap();
assert_eq!(val, 42);
assert!(!cache.has("key_lock").unwrap());
}
#[test]
fn test_r5_p8_remember_lock_key_naming() {
let cache = make_cache();
let val: i64 = cache.remember("mykey", None, || 100).unwrap();
assert_eq!(val, 100);
assert!(!cache.has("mykey_lock").unwrap());
}
#[test]
fn test_r5_p9_push_basic_append() {
let cache = make_cache();
cache.push("list", "a".to_string(), None).unwrap();
cache.push("list", "b".to_string(), None).unwrap();
let list: Vec<String> = cache.get("list").unwrap().unwrap();
assert_eq!(list, vec!["a".to_string(), "b".to_string()]);
}
#[test]
fn test_r5_p9_push_max_1000_array_shift() {
let cache = make_cache();
for i in 0..1001i64 {
cache.push("list", i, None).unwrap();
}
let list: Vec<i64> = cache.get("list").unwrap().unwrap();
assert_eq!(list.len(), 1000);
assert_eq!(list[0], 1); assert_eq!(list[999], 1000);
}
#[test]
fn test_r5_p9_push_array_unique_keep_first() {
let cache = make_cache();
cache.push("list", "a".to_string(), None).unwrap();
cache.push("list", "a".to_string(), None).unwrap();
cache.push("list", "b".to_string(), None).unwrap();
cache.push("list", "a".to_string(), None).unwrap();
let list: Vec<String> = cache.get("list").unwrap().unwrap();
assert_eq!(list, vec!["a".to_string(), "b".to_string()]);
}
#[test]
fn test_r5_p9_push_empty_cache_initializes() {
let cache = make_cache();
cache.push("list", "first".to_string(), None).unwrap();
let list: Vec<String> = cache.get("list").unwrap().unwrap();
assert_eq!(list, vec!["first".to_string()]);
}
#[test]
fn test_r5_p10_pull_returns_value_and_deletes() {
let cache = make_cache();
cache.set("key", "value", None).unwrap();
let val: Option<String> = cache.pull("key").unwrap();
assert_eq!(val, Some("value".to_string()));
assert!(!cache.has("key").unwrap());
}
#[test]
fn test_r5_p10_pull_nonexistent_returns_none() {
let cache = make_cache();
let val: Option<String> = cache.pull("nonexistent").unwrap();
assert_eq!(val, None);
}
#[test]
fn test_r5_p10_pull_after_pull_returns_none() {
let cache = make_cache();
cache.set("key", "value", None).unwrap();
let first: Option<String> = cache.pull("key").unwrap();
let second: Option<String> = cache.pull("key").unwrap();
assert_eq!(first, Some("value".to_string()));
assert_eq!(second, None);
}
#[test]
fn test_r5_p11_ttl_expiration_get_returns_none() {
let cache = make_cache();
cache
.set("key", "value", Some(Duration::from_millis(50)))
.unwrap();
assert_eq!(
cache.get::<String>("key").unwrap(),
Some("value".to_string())
);
std::thread::sleep(Duration::from_millis(100));
assert_eq!(cache.get::<String>("key").unwrap(), None);
}
#[test]
fn test_r5_p11_no_ttl_never_expires() {
let cache = make_cache();
cache.set("key", "value", None).unwrap();
std::thread::sleep(Duration::from_millis(50));
let val: String = cache.get("key").unwrap().unwrap();
assert_eq!(val, "value");
}
#[test]
fn test_r5_p11_long_ttl_still_valid() {
let cache = make_cache();
cache
.set("key", "value", Some(Duration::from_secs(60)))
.unwrap();
std::thread::sleep(Duration::from_millis(50));
let val: String = cache.get("key").unwrap().unwrap();
assert_eq!(val, "value");
}
#[test]
fn test_r5_p12_set_with_ttl_expires() {
let cache = make_cache();
cache
.set("key", "value", Some(Duration::from_millis(50)))
.unwrap();
std::thread::sleep(Duration::from_millis(100));
assert_eq!(cache.get::<String>("key").unwrap(), None);
}
#[test]
fn test_r5_p12_set_with_zero_ttl_permanent() {
let cache = make_cache();
cache.set("key", "value", None).unwrap();
std::thread::sleep(Duration::from_millis(50));
let val: String = cache.get("key").unwrap().unwrap();
assert_eq!(val, "value");
}
#[test]
fn test_r5_p12_set_with_various_ttls() {
let cache = make_cache();
cache
.set("short", "v1", Some(Duration::from_millis(30)))
.unwrap();
cache
.set("long", "v2", Some(Duration::from_secs(60)))
.unwrap();
cache.set("permanent", "v3", None).unwrap();
std::thread::sleep(Duration::from_millis(60));
assert_eq!(cache.get::<String>("short").unwrap(), None);
assert_eq!(cache.get::<String>("long").unwrap(), Some("v2".to_string()));
assert_eq!(
cache.get::<String>("permanent").unwrap(),
Some("v3".to_string())
);
}
#[test]
fn test_r5_p13_tag_set_and_clear() {
let cache = make_cache();
cache.tag("user").set("user:1", "Alice", None).unwrap();
cache.tag("user").set("user:2", "Bob", None).unwrap();
assert_eq!(
cache.get::<String>("user:1").unwrap(),
Some("Alice".to_string())
);
cache.tag("user").clear().unwrap();
assert_eq!(cache.get::<String>("user:1").unwrap(), None);
assert_eq!(cache.get::<String>("user:2").unwrap(), None);
}
#[test]
fn test_r5_p13_tag_clear_does_not_affect_other_tags() {
let cache = make_cache();
cache.tag("user").set("u1", "Alice", None).unwrap();
cache.tag("order").set("o1", 100i64, None).unwrap();
cache.tag("user").clear().unwrap();
assert_eq!(cache.get::<String>("u1").unwrap(), None);
assert_eq!(cache.get::<String>("o1").unwrap(), Some("100".to_string()));
}
#[test]
fn test_r5_p13_tag_multiple_tags() {
let cache = make_cache();
cache
.tag_many(&["user", "admin"])
.set("u1", "Alice", None)
.unwrap();
cache.tag("admin").clear().unwrap();
assert_eq!(cache.get::<String>("u1").unwrap(), None);
}
#[test]
fn test_r5_p14_store_isolation() {
let cache = Cache::new();
cache.register_store("store_a", Box::new(MemoryCacheDriver::new()));
cache.register_store("store_b", Box::new(MemoryCacheDriver::new()));
cache.set("key", "from_default", None).unwrap();
cache.set_default_store("store_b").unwrap();
cache.set("key", "from_store_b", None).unwrap();
cache.set_default_store("store_a").unwrap();
let val_a: String = cache.get("key").unwrap().unwrap();
assert_eq!(val_a, "from_default");
cache.set_default_store("store_b").unwrap();
let val_b: String = cache.get("key").unwrap().unwrap();
assert_eq!(val_b, "from_store_b");
}
#[test]
fn test_r5_p14_store_delete_does_not_affect_other() {
let cache = Cache::new();
cache.register_store("store_a", Box::new(MemoryCacheDriver::new()));
cache.register_store("store_b", Box::new(MemoryCacheDriver::new()));
cache.set_default_store("store_a").unwrap();
cache.set("key", "value_a", None).unwrap();
cache.set_default_store("store_b").unwrap();
cache.set("key", "value_b", None).unwrap();
cache.set_default_store("store_a").unwrap();
cache.delete("key").unwrap();
assert_eq!(cache.get::<String>("key").unwrap(), None);
cache.set_default_store("store_b").unwrap();
assert_eq!(
cache.get::<String>("key").unwrap(),
Some("value_b".to_string())
);
}
#[test]
fn test_r5_p15_set_returns_ok() {
let cache = make_cache();
let result = cache.set("key", "value", None);
assert!(result.is_ok());
}
#[test]
fn test_r5_p15_set_with_ttl_returns_ok() {
let cache = make_cache();
let result = cache.set("key", "value", Some(Duration::from_secs(60)));
assert!(result.is_ok());
}
#[test]
fn test_r5_p15_set_overwrite_returns_ok() {
let cache = make_cache();
cache.set("key", "v1", None).unwrap();
let result = cache.set("key", "v2", None);
assert!(result.is_ok());
let val: String = cache.get("key").unwrap().unwrap();
assert_eq!(val, "v2");
}