use aok::Void;
use tempfile::tempdir;
use wedb_embed::{WeDb, parse_range_spec};
#[ctor::ctor(unsafe)]
fn _log_init() {
log_init::init();
}
#[test]
fn test_sortedint_basic_ops() -> Void {
let dir = tempdir()?;
let db = WeDb::open(dir.path())?;
assert_eq!(db.si_add("sikey", &[10, 20, 30, 40, 50])?, 5);
assert_eq!(db.si_add("sikey", &[20, 60])?, 1);
assert_eq!(db.si_card("sikey")?, 6);
assert!(db.si_exists("sikey", 20)?);
assert!(!db.si_exists("sikey", 99)?);
let mexist = db.si_mexist("sikey", &[10, 25, 30, 99])?;
assert_eq!(mexist, vec![true, false, true, false]);
let range = db.si_range("sikey", 0, 0, 10, false)?;
assert_eq!(range, vec![10, 20, 30, 40, 50, 60]);
let page = db.si_range("sikey", 0, 2, 2, false)?;
assert_eq!(page, vec![30, 40]);
let cursor_range = db.si_range("sikey", 30, 0, 2, false)?;
assert_eq!(cursor_range, vec![40, 50]);
let rev_range = db.si_rev_range("sikey", 0, 0, 10)?;
assert_eq!(rev_range, vec![60, 50, 40, 30, 20, 10]);
let rev_cursor = db.si_rev_range("sikey", 40, 0, 2)?;
assert_eq!(rev_cursor, vec![30, 20]);
assert_eq!(db.si_rem("sikey", &[20, 40, 99])?, 2);
assert_eq!(db.si_card("sikey")?, 4);
Ok(())
}
#[test]
fn test_sortedint_range_by_value() -> Void {
let dir = tempdir()?;
let db = WeDb::open(dir.path())?;
db.si_add("sikey", &[10, 20, 30, 40, 50, 60, 70, 80])?;
let spec1 = parse_range_spec("20", "60")?;
let r1 = db.si_range_by_value("sikey", &spec1)?;
assert_eq!(r1, vec![20, 30, 40, 50, 60]);
let spec2 = parse_range_spec("(20", "(60")?;
let r2 = db.si_range_by_value("sikey", &spec2)?;
assert_eq!(r2, vec![30, 40, 50]);
let mut spec3 = parse_range_spec("-inf", "+inf")?;
spec3.offset = 2;
spec3.count = Some(3);
let r3 = db.si_range_by_value("sikey", &spec3)?;
assert_eq!(r3, vec![30, 40, 50]);
let mut spec_rev = parse_range_spec("20", "60")?;
spec_rev.reversed = true;
let r_rev = db.si_range_by_value("sikey", &spec_rev)?;
assert_eq!(r_rev, vec![60, 50, 40, 30, 20]);
let r_score = db.si_range_by_score("sikey", &spec1)?;
assert_eq!(r_score, r1);
let r_rev_score = db.si_rev_range_by_score("sikey", &spec_rev)?;
assert_eq!(r_rev_score, r_rev);
Ok(())
}
#[test]
fn test_sortedint_rank_revrank_and_count() -> Void {
let dir = tempdir()?;
let db = WeDb::open(dir.path())?;
db.si_add("rank_k", &[10, 20, 30, 40, 50])?;
assert_eq!(db.si_rank("rank_k", 10)?, Some(0));
assert_eq!(db.si_rank("rank_k", 30)?, Some(2));
assert_eq!(db.si_rank("rank_k", 50)?, Some(4));
assert_eq!(db.si_rank("rank_k", 25)?, None);
assert_eq!(db.si_rank("rank_k", 99)?, None);
assert_eq!(db.si_revrank("rank_k", 50)?, Some(0));
assert_eq!(db.si_revrank("rank_k", 30)?, Some(2));
assert_eq!(db.si_revrank("rank_k", 10)?, Some(4));
assert_eq!(db.si_revrank("rank_k", 99)?, None);
let spec = parse_range_spec("20", "40")?;
assert_eq!(db.si_count("rank_k", &spec)?, 3);
let spec_ex = parse_range_spec("(20", "(40")?;
assert_eq!(db.si_count("rank_k", &spec_ex)?, 1);
Ok(())
}
#[test]
fn test_sortedint_rem_range_by_value_and_rank() -> Void {
let dir = tempdir()?;
let db = WeDb::open(dir.path())?;
db.si_add("rem_k", &[10, 20, 30, 40, 50, 60, 70, 80])?;
let spec = parse_range_spec("(20", "50")?;
assert_eq!(db.si_rem_range_by_value("rem_k", &spec)?, 3);
assert_eq!(db.si_card("rem_k")?, 5);
assert_eq!(
db.si_range("rem_k", 0, 0, 10, false)?,
vec![10, 20, 60, 70, 80]
);
assert_eq!(db.si_rem_range_by_rank("rem_k", 0, 1)?, 2);
assert_eq!(db.si_card("rem_k")?, 3);
assert_eq!(db.si_range("rem_k", 0, 0, 10, false)?, vec![60, 70, 80]);
assert_eq!(db.si_rem_range_by_rank("rem_k", -1, -1)?, 1);
assert_eq!(db.si_card("rem_k")?, 2);
assert_eq!(db.si_range("rem_k", 0, 0, 10, false)?, vec![60, 70]);
assert_eq!(db.si_rem_range_by_rank("rem_k", 0, -1)?, 2);
assert_eq!(db.si_card("rem_k")?, 0);
assert!(!db.si_exists("rem_k", 60)?);
assert_eq!(db.si_mexist("rem_k", &[60, 70])?, vec![false, false]);
Ok(())
}
#[test]
fn test_sortedint_duplicates_and_64bit_boundaries() -> Void {
let dir = tempdir()?;
let db = WeDb::open(dir.path())?;
assert_eq!(db.si_add("dup_k", &[100, 100, 200, 100, 300, 200])?, 3);
assert_eq!(db.si_card("dup_k")?, 3);
assert_eq!(db.si_rem("dup_k", &[100, 100, 200, 100])?, 2);
assert_eq!(db.si_card("dup_k")?, 1);
assert_eq!(db.si_card("dup_k")?, 1);
let large_ids = [
0u64,
1,
1000,
1 << 32,
1 << 60,
(1 << 63) - 1,
1 << 63,
u64::MAX,
];
assert_eq!(db.si_add("large_k", &large_ids)?, 8);
assert_eq!(db.si_card("large_k")?, 8);
let range_all = db.si_range("large_k", 0, 0, 100, false)?;
assert_eq!(range_all, large_ids.to_vec());
let rev_all = db.si_rev_range("large_k", 0, 0, 100)?;
let mut expected_rev = large_ids.to_vec();
expected_rev.reverse();
assert_eq!(rev_all, expected_rev);
assert_eq!(db.si_card("non_exist")?, 0);
assert_eq!(db.si_mexist("non_exist", &[1, 2])?, vec![false, false]);
assert_eq!(
db.si_range("non_exist", 0, 0, 10, false)?,
Vec::<u64>::new()
);
assert_eq!(db.si_rem("non_exist", &[1, 2])?, 0);
assert_eq!(db.si_rank("non_exist", 10)?, None);
assert_eq!(db.si_revrank("non_exist", 10)?, None);
assert_eq!(db.si_rem_range_by_rank("non_exist", 0, 10)?, 0);
Ok(())
}
#[test]
fn test_sortedint_edge_cases_and_clear() -> Void {
let dir = tempdir()?;
let db = WeDb::open(dir.path())?;
db.si_add("edge_k", &[10, 20, 30, 40, 50])?;
assert_eq!(db.si_range("edge_k", 0, 0, 0, false)?, Vec::<u64>::new());
assert_eq!(db.si_rev_range("edge_k", 0, 0, 0)?, Vec::<u64>::new());
let mut spec_count_0 = parse_range_spec("10", "50")?;
spec_count_0.count = Some(0);
assert_eq!(
db.si_range_by_value("edge_k", &spec_count_0)?,
Vec::<u64>::new()
);
assert_eq!(
db.si_rev_range_by_value("edge_k", &spec_count_0)?,
Vec::<u64>::new()
);
let spec_min_gt_max = parse_range_spec("100", "50")?;
assert_eq!(
db.si_range_by_value("edge_k", &spec_min_gt_max)?,
Vec::<u64>::new()
);
assert_eq!(
db.si_rev_range_by_value("edge_k", &spec_min_gt_max)?,
Vec::<u64>::new()
);
let spec_ex_eq = parse_range_spec("(30", "30")?;
assert_eq!(
db.si_range_by_value("edge_k", &spec_ex_eq)?,
Vec::<u64>::new()
);
let spec_eq_ex = parse_range_spec("30", "(30")?;
assert_eq!(
db.si_range_by_value("edge_k", &spec_eq_ex)?,
Vec::<u64>::new()
);
assert_eq!(db.si_rev_range("edge_k", 0, 0, 2)?, vec![50, 40]);
assert_eq!(db.si_rev_range("edge_k", 0, 2, 2)?, vec![30, 20]);
assert_eq!(db.si_rev_range("edge_k", 0, 4, 2)?, vec![10]);
assert_eq!(db.si_rev_range("edge_k", 0, 10, 2)?, Vec::<u64>::new());
let mut spec_rev_page = parse_range_spec("20", "50")?;
spec_rev_page.reversed = true;
spec_rev_page.offset = 1;
spec_rev_page.count = Some(2);
assert_eq!(
db.si_range_by_value("edge_k", &spec_rev_page)?,
vec![40, 30]
);
let spec_rem = parse_range_spec("20", "40")?;
assert_eq!(db.si_rem_range_by_score("edge_k", &spec_rem)?, 3); assert_eq!(db.si_card("edge_k")?, 2); assert_eq!(db.si_range("edge_k", 0, 0, 10, false)?, vec![10, 50]);
assert_eq!(db.si_clear("edge_k")?, 2);
assert_eq!(db.si_card("edge_k")?, 0);
assert!(!db.si_exists("edge_k", 10)?);
assert!(!db.si_exists("edge_k", 50)?);
assert_eq!(db.si_range("edge_k", 0, 0, 10, false)?, Vec::<u64>::new());
assert_eq!(db.si_clear("edge_k")?, 0);
Ok(())
}
#[test]
fn test_sortedint_advanced_features_and_builder() -> Void {
use wedb_embed::SortedintRangeSpec;
let dir = tempdir()?;
let db = WeDb::open(dir.path())?;
db.si_add("adv_k", &[10, 20, 30, 40, 50, 60, 70])?;
let spec_builder = SortedintRangeSpec::all().with_offset(2).with_count(3);
assert_eq!(
db.si_range_by_value("adv_k", &spec_builder)?,
vec![30, 40, 50]
);
let spec_builder_rev = SortedintRangeSpec::all()
.with_offset(1)
.with_count(2)
.with_reversed(true);
assert_eq!(
db.si_range_by_value("adv_k", &spec_builder_rev)?,
vec![60, 50]
);
let mut spec_rev_unlimited = SortedintRangeSpec::all().with_reversed(true);
spec_rev_unlimited.offset = 3;
assert_eq!(
db.si_range_by_value("adv_k", &spec_rev_unlimited)?,
vec![40, 30, 20, 10]
);
assert_eq!(db.si_clear("non_existent_key")?, 0);
Ok(())
}