use data::Flow;
use doublets::{split, unit, Doublets, Error, Links};
use mem::Global;
#[test]
fn unit_delete_middle_link_exercises_unused_list() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
let a = store.create_point()?; let b = store.create_point()?; let c = store.create_point()?;
assert_eq!(store.count(), 3);
store.delete(b)?;
assert_eq!(store.count(), 2);
assert!(store.exist(a));
assert!(!store.exist(b)); assert!(store.exist(c));
let d = store.create_point()?;
assert_eq!(store.count(), 3);
assert_eq!(d, b);
Ok(())
}
#[test]
fn unit_delete_last_with_preceding_unused() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
let a = store.create_point()?; let b = store.create_point()?; let c = store.create_point()?;
store.delete(b)?;
store.delete(c)?;
assert_eq!(store.count(), 1);
assert!(store.exist(a));
assert!(!store.exist(b));
assert!(!store.exist(c));
Ok(())
}
#[test]
fn unit_multiple_non_sequential_deletes() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
let _a = store.create_point()?; let b = store.create_point()?; let _c = store.create_point()?; let d = store.create_point()?; let _e = store.create_point()?;
store.delete(b)?; store.delete(d)?;
assert_eq!(store.count(), 3);
let f = store.create_point()?;
let g = store.create_point()?;
assert!(f == d || f == b);
assert!(g == d || g == b);
assert_ne!(f, g);
assert_eq!(store.count(), 5);
Ok(())
}
#[test]
fn unit_delete_all_and_recreate() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
for _ in 0..5 {
store.create_point()?;
}
assert_eq!(store.count(), 5);
store.delete_all()?;
assert_eq!(store.count(), 0);
let a = store.create_point()?;
assert_eq!(a, 1);
Ok(())
}
#[test]
fn split_delete_middle_link_exercises_unused_list() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let _a = store.create_point()?;
let b = store.create_point()?;
let _c = store.create_point()?;
store.delete(b)?;
assert!(!store.exist(b));
let d = store.create_point()?;
assert_eq!(d, b);
Ok(())
}
#[test]
fn split_delete_last_with_preceding_unused() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
store.delete(b)?;
store.delete(c)?;
assert_eq!(store.count(), 1);
assert!(store.exist(a));
Ok(())
}
#[test]
fn unit_delete_with_usages_first() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let _c = store.create_link(a, b)?;
let _d = store.create_link(b, a)?;
assert!(store.has_usages(a));
store.delete_usages(a)?;
assert!(!store.has_usages(a));
store.delete(a)?;
assert!(!store.exist(a));
Ok(())
}
#[test]
fn unit_many_operations_tree_balance() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
let mut links = Vec::new();
for _ in 0..50 {
let a = store.create_point()?;
links.push(a);
}
for i in 0..25 {
store.create_link(links[i], links[49 - i])?;
}
for i in (0..50).step_by(2) {
if !store.has_usages(links[i]) {
store.delete(links[i])?;
}
}
for _ in 0..10 {
store.create_point()?;
}
let total = store.count();
let mut counted = 0;
store.each(|_| {
counted += 1;
Flow::Continue
});
assert_eq!(total, counted);
Ok(())
}
#[test]
fn unit_source_target_tree_consistency() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
let _d = store.create_link(a, b)?;
let _e = store.create_link(a, c)?;
let source_usages = store.count_usages(a)?;
assert_eq!(source_usages, 2);
let _f = store.create_link(b, c)?;
let _g = store.get_or_create(a, c)?;
let target_usages_c = store.usages(c)?;
assert!(target_usages_c.len() >= 2);
Ok(())
}
#[test]
fn unit_search_through_source_tree() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
let ab = store.create_link(a, b)?;
let ac = store.create_link(a, c)?;
let bc = store.create_link(b, c)?;
assert_eq!(store.search(a, b), Some(ab));
assert_eq!(store.search(a, c), Some(ac));
assert_eq!(store.search(b, c), Some(bc));
assert_eq!(store.search(c, a), None);
assert_eq!(store.search(b, a), None);
Ok(())
}
#[test]
fn unit_each_with_source_filter() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
let any = Links::constants(&store).any;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
store.create_link(a, b)?;
store.create_link(a, c)?;
store.create_link(b, c)?;
let mut count = 0;
store.each_by([any, a, any], |_| {
count += 1;
Flow::Continue
});
assert!(count >= 2);
Ok(())
}
#[test]
fn unit_each_with_target_filter() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
let any = Links::constants(&store).any;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
store.create_link(a, c)?;
store.create_link(b, c)?;
let mut count = 0;
store.each_by([any, any, c], |_| {
count += 1;
Flow::Continue
});
assert!(count >= 2);
Ok(())
}
#[test]
fn split_source_target_tree_consistency() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
store.create_link(a, b)?;
store.create_link(a, c)?;
let usages = store.count_usages(a)?;
assert_eq!(usages, 2);
Ok(())
}
#[test]
fn unit_delete_first_link() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
let a = store.create_point()?;
assert_eq!(a, 1);
store.delete(a)?;
assert_eq!(store.count(), 0);
let b = store.create_point()?;
assert_eq!(b, 1);
Ok(())
}
#[test]
fn unit_alternating_create_delete() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
for _ in 0..20 {
let a = store.create_point()?;
let b = store.create_point()?;
store.delete(a)?;
let c = store.create_point()?;
assert_eq!(c, a);
store.delete(b)?;
store.delete(c)?;
}
assert_eq!(store.count(), 0);
Ok(())
}
#[test]
fn unit_is_unused_detection() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
assert!(store.exist(a));
assert!(store.exist(b));
assert!(store.exist(c));
store.delete(b)?;
assert!(!store.exist(b));
assert!(store.exist(a));
assert!(store.exist(c));
Ok(())
}
#[test]
fn unit_each_with_early_break() -> Result<(), Error<usize>> {
let mut store = unit::Store::<usize, _>::new(Global::new())?;
for _ in 0..10 {
store.create_point()?;
}
let mut count = 0;
store.each(|_| {
count += 1;
if count >= 5 {
Flow::Break
} else {
Flow::Continue
}
});
assert_eq!(count, 5);
Ok(())
}
#[test]
fn split_each_with_early_break() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
for _ in 0..10 {
store.create_point()?;
}
let mut count = 0;
store.each(|_| {
count += 1;
if count >= 5 {
Flow::Break
} else {
Flow::Continue
}
});
assert_eq!(count, 5);
Ok(())
}
#[test]
fn split_count_usages_single_link() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let _ab = store.create_link(a, b)?;
let source_usages = store.count_usages(a)?;
assert!(source_usages >= 1);
let target_usages = store.count_usages(b)?;
assert!(target_usages >= 1);
Ok(())
}
#[test]
fn split_count_usages_many_links() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let base = store.create_point()?;
for _ in 0..20 {
let t = store.create_point()?;
store.create_link(base, t)?;
}
let usages = store.count_usages(base)?;
assert!(usages >= 20);
Ok(())
}
#[test]
fn split_each_usages_with_handler() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
store.create_link(a, b)?;
store.create_link(a, c)?;
store.create_link(b, a)?;
let mut usage_count = 0;
store.usages(a)?.iter().for_each(|_| usage_count += 1);
assert!(usage_count >= 2);
Ok(())
}
#[test]
fn split_search_operations() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
let ab = store.create_link(a, b)?;
let ac = store.create_link(a, c)?;
let bc = store.create_link(b, c)?;
assert_eq!(store.search(a, b), Some(ab));
assert_eq!(store.search(a, c), Some(ac));
assert_eq!(store.search(b, c), Some(bc));
assert_eq!(store.search(c, a), None);
Ok(())
}
#[test]
fn split_complex_link_patterns() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let mut points = Vec::new();
for _ in 0..10 {
points.push(store.create_point()?);
}
for i in 0..10 {
for j in (i + 1)..10 {
store.create_link(points[i], points[j])?;
}
}
for i in 0..10 {
for j in (i + 1)..10 {
let result = store.search(points[i], points[j]);
assert!(result.is_some(), "Link {i}->{j} should exist");
}
}
Ok(())
}
#[test]
fn split_delete_updates_trees() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
let ab = store.create_link(a, b)?;
let ac = store.create_link(a, c)?;
assert!(store.search(a, b).is_some());
assert!(store.search(a, c).is_some());
let usages_before = store.count_usages(a)?;
store.delete(ab)?;
assert!(store.search(a, b).is_none());
assert!(store.search(a, c).is_some());
assert!(store.has_usages(a));
store.delete(ac)?;
let usages_after = store.count_usages(a)?;
assert!(usages_after < usages_before || usages_before == 0);
Ok(())
}
#[test]
fn split_tree_rebalancing_stress() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let base = store.create_point()?;
let mut links = Vec::new();
for _ in 0..100 {
let t = store.create_point()?;
let link = store.create_link(base, t)?;
links.push(link);
}
for link in links.iter().step_by(2) {
store.delete(*link)?;
}
let remaining_count = store.count_usages(base)?;
assert!(remaining_count > 0);
let total = store.count();
let mut counted = 0;
store.each(|_| {
counted += 1;
Flow::Continue
});
assert_eq!(total, counted);
Ok(())
}
#[test]
fn split_ordered_insertions() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let base = store.create_point()?;
for i in 0..50 {
let t = store.create_point()?;
store.create_link(base, t)?;
let found = store.search(base, t);
assert!(found.is_some(), "Link to target {i} should be found");
}
Ok(())
}
#[test]
fn split_reverse_insertions() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let mut targets = Vec::new();
for _ in 0..50 {
targets.push(store.create_point()?);
}
let base = store.create_point()?;
for t in targets.iter().rev() {
store.create_link(base, *t)?;
}
for t in &targets {
assert!(store.search(base, *t).is_some());
}
Ok(())
}
#[test]
fn split_same_target_multiple_sources() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let target = store.create_point()?;
for _ in 0..20 {
let src = store.create_point()?;
store.create_link(src, target)?;
}
let usages = store.usages(target)?;
assert!(usages.len() >= 20);
Ok(())
}
#[test]
fn split_mixed_crud_operations() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
for _ in 0..10 {
let link = store.create_link(a, b)?;
assert!(store.search(a, b).is_some());
store.delete(link)?;
let count_after = store.count();
assert!(count_after >= 2); }
Ok(())
}
#[test]
fn split_update_operations() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
let link = store.create_link(a, b)?;
store.update(link, a, c)?;
assert!(store.search(a, b).is_none());
assert!(store.search(a, c).is_some());
Ok(())
}
#[test]
fn split_count_usages_no_usages() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let a = store.create_point()?;
let b = store.create_point()?;
let usages_a = store.count_usages(a)?;
let usages_b = store.count_usages(b)?;
let link = store.create_link(a, b)?;
let usages_with_link = store.count_usages(a)?;
assert!(usages_with_link >= usages_a);
store.delete(link)?;
assert_eq!(store.count_usages(a)?, usages_a);
assert_eq!(store.count_usages(b)?, usages_b);
Ok(())
}
#[test]
fn split_iteration_with_filters() -> Result<(), Error<usize>> {
let mut store = split::Store::<usize, _, _>::new(Global::new(), Global::new())?;
let any = Links::constants(&store).any;
let a = store.create_point()?;
let b = store.create_point()?;
let c = store.create_point()?;
store.create_link(a, b)?;
store.create_link(a, c)?;
store.create_link(b, c)?;
let mut source_a_count = 0;
store.each_by([any, a, any], |_| {
source_a_count += 1;
Flow::Continue
});
assert!(source_a_count >= 2);
let mut target_c_count = 0;
store.each_by([any, any, c], |_| {
target_c_count += 1;
Flow::Continue
});
assert!(target_c_count >= 2);
Ok(())
}