use std::time::Duration;
use crate::Config;
use crate::store::Store;
fn s() -> Store {
Store::open(Config::default().with_ttl_reaper_manual()).unwrap()
}
#[test]
fn mset_then_mget_round_trip() {
let s = s();
s.mset(&[(b"a", b"1"), (b"b", b"2"), (b"c", b"3")]).unwrap();
let got = s.mget(&[b"a", b"b", b"missing", b"c"]).unwrap();
assert_eq!(
got,
vec![
Some(b"1".to_vec()),
Some(b"2".to_vec()),
None,
Some(b"3".to_vec()),
]
);
}
#[test]
fn mset_empty_is_noop() {
let s = s();
s.mset(&[]).unwrap();
assert_eq!(s.dbsize(), 0);
}
#[test]
fn keys_no_pattern_returns_all() {
let s = s();
s.set(b"a", b"1").unwrap();
s.set(b"b", b"2").unwrap();
s.set(b"c", b"3").unwrap();
let mut got = s.keys(None, None);
got.sort();
assert_eq!(got, vec![b"a".to_vec(), b"b".to_vec(), b"c".to_vec()]);
}
#[test]
fn keys_with_glob_filters() {
let s = s();
s.set(b"user:1", b"x").unwrap();
s.set(b"user:2", b"y").unwrap();
s.set(b"other:1", b"z").unwrap();
let mut got = s.keys(Some(b"user:*"), None);
got.sort();
assert_eq!(got, vec![b"user:1".to_vec(), b"user:2".to_vec()]);
}
#[test]
fn keys_limit_caps_results() {
let s = s();
for i in 0..10 {
s.set(format!("k{i}").as_bytes(), b"v").unwrap();
}
let got = s.keys(None, Some(3));
assert_eq!(got.len(), 3);
}
#[test]
fn getex_returns_value_and_sets_ttl() {
let s = s();
s.set(b"k", b"v").unwrap();
let got = s.getex(b"k", Duration::from_secs(60)).unwrap();
assert_eq!(got, Some(b"v".to_vec()));
let ttl = s.ttl_ms(b"k");
assert!(
(1..=60_000).contains(&ttl),
"expected TTL in (0..60_000], got {ttl}"
);
}
#[test]
fn getex_on_absent_returns_none_no_ttl() {
let s = s();
let got = s.getex(b"absent", Duration::from_secs(60)).unwrap();
assert_eq!(got, None);
}
#[test]
fn sinter_two_sets() {
let s = s();
s.sadd(b"a", &[b"x", b"y", b"z"]).unwrap();
s.sadd(b"b", &[b"y", b"z", b"w"]).unwrap();
let mut got = s.sinter(&[b"a", b"b"]).unwrap();
got.sort();
assert_eq!(got, vec![b"y".to_vec(), b"z".to_vec()]);
}
#[test]
fn sinter_empty_intersection() {
let s = s();
s.sadd(b"a", &[b"x"]).unwrap();
s.sadd(b"b", &[b"y"]).unwrap();
assert!(s.sinter(&[b"a", b"b"]).unwrap().is_empty());
}
#[test]
fn sunion_three_sets() {
let s = s();
s.sadd(b"a", &[b"x"]).unwrap();
s.sadd(b"b", &[b"y"]).unwrap();
s.sadd(b"c", &[b"z"]).unwrap();
let mut got = s.sunion(&[b"a", b"b", b"c"]).unwrap();
got.sort();
assert_eq!(got, vec![b"x".to_vec(), b"y".to_vec(), b"z".to_vec()]);
}
#[test]
fn sdiff_first_minus_rest() {
let s = s();
s.sadd(b"a", &[b"x", b"y", b"z"]).unwrap();
s.sadd(b"b", &[b"y"]).unwrap();
s.sadd(b"c", &[b"z"]).unwrap();
let mut got = s.sdiff(&[b"a", b"b", b"c"]).unwrap();
got.sort();
assert_eq!(got, vec![b"x".to_vec()]);
}
#[test]
fn pexpireat_sets_deadline() {
let s = s();
s.set(b"k", b"v").unwrap();
let unix_ms = 4_102_444_800_000; assert!(s.pexpireat(b"k", unix_ms).unwrap());
let ttl = s.ttl_ms(b"k");
assert!(ttl > 0, "expected positive TTL after pexpireat, got {ttl}");
}
#[test]
fn pexpireat_on_absent_returns_false() {
let s = s();
let unix_ms = 4_102_444_800_000;
assert!(!s.pexpireat(b"absent", unix_ms).unwrap());
}
#[test]
fn pexpire_sets_relative_ms() {
let s = s();
s.set(b"k", b"v").unwrap();
assert!(s.pexpire(b"k", 30_000).unwrap());
let ttl = s.ttl_ms(b"k");
assert!(
(1..=30_000).contains(&ttl),
"expected TTL in (0..30_000], got {ttl}"
);
}
#[test]
fn hincrbyfloat_creates_and_increments() {
let s = s();
let v1 = s.hincrbyfloat(b"h", b"f", 1.5).unwrap();
assert!((v1 - 1.5).abs() < 1e-9, "got {v1}");
let v2 = s.hincrbyfloat(b"h", b"f", 2.25).unwrap();
assert!((v2 - 3.75).abs() < 1e-9, "got {v2}");
}
#[test]
fn hincrbyfloat_negative_delta() {
let s = s();
s.hset(b"h", &[(b"f", b"10")]).unwrap();
let v = s.hincrbyfloat(b"h", b"f", -2.5).unwrap();
assert!((v - 7.5).abs() < 1e-9, "got {v}");
}
#[test]
fn linsert_before_pivot() {
let s = s();
s.rpush(b"l", &[b"a", b"b", b"d"]).unwrap();
let new_len = s.linsert(b"l", true, b"d", b"c").unwrap();
assert_eq!(new_len, 4);
assert_eq!(
s.lrange(b"l", 0, -1).unwrap(),
vec![b"a".to_vec(), b"b".to_vec(), b"c".to_vec(), b"d".to_vec()]
);
}
#[test]
fn linsert_after_pivot() {
let s = s();
s.rpush(b"l", &[b"a", b"b", b"d"]).unwrap();
let new_len = s.linsert(b"l", false, b"b", b"c").unwrap();
assert_eq!(new_len, 4);
assert_eq!(
s.lrange(b"l", 0, -1).unwrap(),
vec![b"a".to_vec(), b"b".to_vec(), b"c".to_vec(), b"d".to_vec()]
);
}
#[test]
fn linsert_pivot_not_found_returns_negative_one() {
let s = s();
s.rpush(b"l", &[b"a", b"b"]).unwrap();
assert_eq!(s.linsert(b"l", true, b"missing", b"x").unwrap(), -1);
}
#[test]
fn linsert_absent_key_returns_zero() {
let s = s();
assert_eq!(s.linsert(b"absent", true, b"p", b"v").unwrap(), 0);
}
#[test]
fn ping_ns_returns_positive_value() {
let s = s();
let n = s.ping_ns();
assert!(n < 1_000_000_000, "ping_ns suspiciously large: {n}");
}