use super::row_set::{FileRowSet, FileRowSetKind, PositionedRowSet};
#[test]
fn contiguous_rows_choose_a_range() {
let rows = FileRowSet::from_sorted((10..1_010).collect()).unwrap();
assert_eq!(rows.kind(), FileRowSetKind::Range);
assert!(rows.contains(10));
assert!(rows.contains(1_009));
assert!(!rows.contains(1_010));
assert!(rows.estimated_bytes() <= 32);
}
#[test]
fn moderately_sparse_rows_choose_roaring() {
let rows = FileRowSet::from_sorted((0..100_000).map(|row| row * 10).collect()).unwrap();
assert_eq!(rows.kind(), FileRowSetKind::Roaring);
assert!(rows.contains(420));
assert!(!rows.contains(421));
assert!(rows.estimated_bytes() < 800_000);
}
#[test]
fn fragmented_rows_choose_the_predictable_sorted_form() {
let rows = FileRowSet::from_sorted((0..10_000).map(|row| row << 16).collect()).unwrap();
assert_eq!(rows.kind(), FileRowSetKind::Sorted);
assert!(rows.contains(9_999 << 16));
assert!(!rows.contains((9_999 << 16) + 1));
assert_eq!(rows.estimated_bytes(), 80_000);
}
#[test]
fn matching_preserves_query_order_and_ignores_absent_rows() {
let rows = FileRowSet::from_sorted(vec![3, 7, 11, 50]).unwrap();
assert_eq!(rows.matching(&[1, 3, 7, 12, 50]), vec![3, 7, 50]);
}
#[test]
fn duplicate_or_unsorted_input_is_refused() {
assert!(FileRowSet::from_sorted(vec![1, 1]).is_err());
assert!(FileRowSet::from_sorted(vec![2, 1]).is_err());
}
#[test]
fn ascending_input_collapses_through_from_sorted_shapes() {
let range = PositionedRowSet::from_file_order((10..1_010).collect()).unwrap();
assert_eq!(range.rows.kind(), FileRowSetKind::Range);
let roaring =
PositionedRowSet::from_file_order((0..100_000).map(|row| row * 10).collect()).unwrap();
assert_eq!(roaring.rows.kind(), FileRowSetKind::Roaring);
let sorted =
PositionedRowSet::from_file_order((0..10_000).map(|row| row << 16).collect()).unwrap();
assert_eq!(sorted.rows.kind(), FileRowSetKind::Sorted);
}
#[test]
fn non_ascending_input_permutes_the_ascending_representation() {
let rows = PositionedRowSet::from_file_order(vec![30, 40, 10, 20]).unwrap();
assert_eq!(rows.rows.kind(), FileRowSetKind::Sorted);
assert_eq!(
rows.positions_of(&[30, 40, 10, 20, 999]),
vec![Some(0), Some(1), Some(2), Some(3), None]
);
}
#[test]
fn repeated_ids_retain_every_physical_position() {
let rows = PositionedRowSet::from_file_order(vec![30, 10, 30]).unwrap();
let mut positions = Vec::new();
assert!(rows.visit_positions(30, |position| positions.push(position)));
assert_eq!(positions, vec![0, 2]);
assert!(!rows.visit_positions(999, |_| unreachable!()));
}
proptest::proptest! {
#[test]
fn repeated_positions_match_exhaustive_file_order(ids in proptest::collection::vec(0_u64..128, 0..512), requested in 0_u64..256) {
let rows = PositionedRowSet::from_file_order(ids.clone()).unwrap();
let mut actual = Vec::new();
let found = rows.visit_positions(requested, |position| actual.push(position));
let expected: Vec<_> = ids.iter().enumerate().filter(|(_, id)| **id == requested).map(|(position, _)| u64::try_from(position).unwrap()).collect();
proptest::prop_assert_eq!(found, !expected.is_empty());
proptest::prop_assert_eq!(actual, expected);
}
}
#[test]
fn positions_of_range_is_arithmetic() {
let rows = PositionedRowSet::from_file_order((100..110).collect()).unwrap();
assert_eq!(rows.rows.kind(), FileRowSetKind::Range);
assert_eq!(
rows.positions_of(&[100, 105, 109, 110]),
vec![Some(0), Some(5), Some(9), None]
);
}
#[test]
fn positions_of_ascending_roaring_uses_rank() {
let rows =
PositionedRowSet::from_file_order((0..100_000).map(|row| row * 10).collect()).unwrap();
assert_eq!(rows.rows.kind(), FileRowSetKind::Roaring);
assert_eq!(
rows.positions_of(&[0, 10, 420, 421]),
vec![Some(0), Some(1), Some(42), None]
);
}
#[test]
fn positions_of_ascending_sorted_uses_binary_search() {
let rows =
PositionedRowSet::from_file_order((0..10_000).map(|row| row << 16).collect()).unwrap();
assert_eq!(rows.rows.kind(), FileRowSetKind::Sorted);
assert_eq!(
rows.positions_of(&[0, 1 << 16, (9_999 << 16) + 1]),
vec![Some(0), Some(1), None]
);
}
#[test]
fn positions_of_permuted_roaring_uses_rank_then_permutation() {
let sorted_sparse: Vec<u64> = (0..100_000).map(|row| row * 10).collect();
let mut file_order = sorted_sparse.clone();
file_order.swap(0, 1);
let rows = PositionedRowSet::from_file_order(file_order).unwrap();
assert_eq!(rows.rows.kind(), FileRowSetKind::Roaring);
assert_eq!(
rows.positions_of(&[0, 10, 20]),
vec![Some(1), Some(0), Some(2)]
);
}
#[test]
fn positions_of_absent_row_is_none() {
let rows = PositionedRowSet::from_file_order(vec![30, 10, 20]).unwrap();
assert_eq!(rows.positions_of(&[999]), vec![None]);
}