use crate::Store;
use crate::value::Value;
use crate::zset_seg::Z_PROMOTE;
fn encoding(st: &Store, key: &[u8]) -> &'static str {
match st.map.get(key).map(|e| &e.value) {
None => "absent",
Some(Value::SmallZSetInline(_)) => "inline",
Some(Value::ZSet(_)) => "flat",
Some(Value::SegZSet(_)) => "seg",
Some(_) => "not-a-zset",
}
}
#[test]
fn the_encoding_ladder() {
let mut st = Store::new();
assert_eq!(encoding(&st, b"k"), "absent");
st.zadd(b"k", &[(1.0, b"a")]).unwrap();
assert_eq!(encoding(&st, b"k"), "inline", "one short member fits 22 bytes");
for m in [b"bb".as_ref(), b"cc", b"dd"] {
st.zadd(b"k", &[(1.0, m)]).unwrap();
}
assert_eq!(encoding(&st, b"k"), "flat", "past SMALL_ZSET_COUNT_MAX");
for i in 0..Z_PROMOTE {
let m = alloc::format!("member-{i:08}");
st.zadd(b"k", &[((i % 977) as f64, m.as_bytes())]).unwrap();
}
assert_eq!(encoding(&st, b"k"), "seg", "past Z_PROMOTE");
st.set(b"s", alloc::vec![b'x'; 4], None, false, false);
assert_eq!(encoding(&st, b"s"), "not-a-zset");
}
#[test]
fn same_score_readd_is_invisible_flat() {
let mut st = Store::new();
for (i, m) in [b"a".as_ref(), b"b", b"c", b"d", b"e"].iter().enumerate() {
st.zadd(b"k", &[(i as f64, m)]).unwrap();
}
assert_eq!(encoding(&st, b"k"), "flat", "fixture must be past the inline encoding");
let before = st.zrange(b"k", 0, -1).unwrap();
let added = st.zadd(b"k", &[(1.0, b"b")]).unwrap();
assert_eq!(added, 0, "an existing member is not a new one");
assert_eq!(encoding(&st, b"k"), "flat");
assert_eq!(st.zscore(b"k", b"b").unwrap(), Some(1.0));
assert_eq!(st.zrank(b"k", b"b").unwrap(), Some(1));
assert_eq!(st.zrange(b"k", 0, -1).unwrap(), before, "order moved");
}
#[test]
fn same_score_readd_is_invisible_seg() {
let mut st = Store::new();
let n = Z_PROMOTE + 64;
for i in 0..n {
let m = alloc::format!("member-{i:08}");
st.zadd(b"k", &[((i % 977) as f64, m.as_bytes())]).unwrap();
}
assert_eq!(encoding(&st, b"k"), "seg", "the fixture must reach the Seg encoding");
let probe = alloc::format!("member-{:08}", 7);
let score = 7.0;
let rank_before = st.zrank(b"k", probe.as_bytes()).unwrap();
let order_before = st.zrange(b"k", 0, -1).unwrap();
let added = st.zadd(b"k", &[(score, probe.as_bytes())]).unwrap();
assert_eq!(added, 0);
assert_eq!(st.zscore(b"k", probe.as_bytes()).unwrap(), Some(score));
assert_eq!(st.zrank(b"k", probe.as_bytes()).unwrap(), rank_before);
assert!(st.zrange(b"k", 0, -1).unwrap() == order_before, "the order moved");
}
#[test]
fn the_two_zeros_are_one_score() {
let mut st = Store::new();
for m in [b"f1".as_ref(), b"f2", b"f3"] {
st.zadd(b"k", &[(9.0, m)]).unwrap();
}
st.zadd(b"k", &[(0.0, b"zhi"), (-0.0, b"zlo")]).unwrap();
assert_eq!(encoding(&st, b"k"), "flat", "fixture must be on the heap-backed encoding");
assert_eq!(
st.zrange(b"k", 0, 1).unwrap().iter().map(|(m, _)| m.clone()).collect::<Vec<_>>(),
alloc::vec![b"zhi".to_vec(), b"zlo".to_vec()],
"-0 and 0 must be one score, ordered by member",
);
let sc = st.zscore(b"k", b"zlo").unwrap().unwrap();
assert!(sc == 0.0 && sc.is_sign_positive(), "the sign was not folded");
}
#[test]
fn the_two_zeros_are_one_score_seg() {
let mut st = Store::new();
let n = Z_PROMOTE + 64;
for i in 0..n {
let m = alloc::format!("member-{i:08}");
st.zadd(b"k", &[((i % 977) as f64 + 1.0, m.as_bytes())]).unwrap();
}
assert_eq!(encoding(&st, b"k"), "seg");
st.zadd(b"k", &[(0.0, b"zhi"), (-0.0, b"zlo")]).unwrap();
let first_two: Vec<Vec<u8>> =
st.zrange(b"k", 0, 1).unwrap().iter().map(|(m, _)| m.clone()).collect();
assert_eq!(first_two, alloc::vec![b"zhi".to_vec(), b"zlo".to_vec()]);
let sc = st.zscore(b"k", b"zlo").unwrap().unwrap();
assert!(sc == 0.0 && sc.is_sign_positive(), "the sign was not folded");
}