use crate::error::Error;
use crate::model::{ColWidthRange, Sheet};
pub(crate) const MAX_COLUMN_WIDTH_RANGES: usize = 2_000;
pub(crate) fn resolve(
sheet: &mut Sheet,
mut ranges: Vec<ColWidthRange>,
default_col_width: Option<f64>,
) -> Result<(), Error> {
if ranges.len() > MAX_COLUMN_WIDTH_RANGES {
return Err(Error::TooManyColumnWidthRanges {
count: ranges.len(),
limit: MAX_COLUMN_WIDTH_RANGES,
});
}
for range in &ranges {
if range.min > range.max {
return Err(Error::InvalidColumnWidthRange {
min: range.min,
max: range.max,
reason: "min must not be greater than max".to_string(),
});
}
}
ranges.sort_by_key(|r| r.min);
for pair in ranges.windows(2) {
let (prev, next) = (&pair[0], &pair[1]);
if prev.max >= next.min {
return Err(Error::InvalidColumnWidthRange {
min: next.min,
max: next.max,
reason: "overlaps another column width range".to_string(),
});
}
}
sheet.set_col_widths(ranges, default_col_width);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::model::SheetVisibility;
fn range(min: u32, max: u32, width: f64) -> ColWidthRange {
ColWidthRange { min, max, width }
}
fn new_sheet() -> Sheet {
Sheet::new("Sheet1".into(), SheetVisibility::Visible)
}
#[test]
fn registers_non_overlapping_ranges_in_sorted_order() {
let mut sheet = new_sheet();
resolve(
&mut sheet,
vec![range(10, 20, 20.0), range(1, 5, 10.0)],
None,
)
.unwrap();
assert_eq!(sheet.column_width(1), Some(10.0));
assert_eq!(sheet.column_width(10), Some(20.0));
assert_eq!(
sheet.col_width_ranges(),
&[range(1, 5, 10.0), range(10, 20, 20.0)]
);
}
#[test]
fn reversed_min_max_is_an_error() {
let mut sheet = new_sheet();
let err = resolve(&mut sheet, vec![range(10, 5, 99.0)], None).unwrap_err();
assert!(matches!(err, Error::InvalidColumnWidthRange { .. }));
assert_eq!(sheet.col_width_ranges().len(), 0);
}
#[test]
fn overlapping_ranges_are_an_error() {
let mut sheet = new_sheet();
let err = resolve(
&mut sheet,
vec![range(1, 10, 10.0), range(5, 15, 20.0)],
None,
)
.unwrap_err();
assert!(matches!(err, Error::InvalidColumnWidthRange { .. }));
assert_eq!(sheet.col_width_ranges().len(), 0);
}
#[test]
fn touching_ranges_are_not_overlapping() {
let mut sheet = new_sheet();
resolve(&mut sheet, vec![range(1, 2, 10.0), range(3, 4, 20.0)], None).unwrap();
assert_eq!(sheet.column_width(2), Some(10.0));
assert_eq!(sheet.column_width(3), Some(20.0));
}
#[test]
fn identical_duplicate_ranges_are_an_error() {
let mut sheet = new_sheet();
let err =
resolve(&mut sheet, vec![range(1, 5, 10.0), range(1, 5, 10.0)], None).unwrap_err();
assert!(matches!(err, Error::InvalidColumnWidthRange { .. }));
}
#[test]
fn range_count_at_the_limit_is_accepted() {
let mut sheet = new_sheet();
let ranges: Vec<ColWidthRange> = (1..=MAX_COLUMN_WIDTH_RANGES as u32)
.map(|i| range(i, i, 1.0))
.collect();
resolve(&mut sheet, ranges, None).unwrap();
assert_eq!(sheet.col_width_ranges().len(), MAX_COLUMN_WIDTH_RANGES);
}
#[test]
fn range_count_over_the_limit_is_too_many_column_width_ranges() {
let mut sheet = new_sheet();
let ranges: Vec<ColWidthRange> = (1..=(MAX_COLUMN_WIDTH_RANGES as u32 + 1))
.map(|i| range(i, i, 1.0))
.collect();
let err = resolve(&mut sheet, ranges, None).unwrap_err();
assert!(matches!(
err,
Error::TooManyColumnWidthRanges {
count,
limit
} if count == MAX_COLUMN_WIDTH_RANGES + 1 && limit == MAX_COLUMN_WIDTH_RANGES
));
}
#[test]
fn empty_range_list_still_registers_default_col_width() {
let mut sheet = new_sheet();
resolve(&mut sheet, vec![], Some(9.0)).unwrap();
assert_eq!(sheet.column_width(1), Some(9.0));
assert_eq!(sheet.default_col_width(), Some(9.0));
}
#[test]
fn a_full_width_single_range_does_not_expand_into_per_column_entries() {
let mut sheet = new_sheet();
resolve(&mut sheet, vec![range(1, 16_384, 8.43)], None).unwrap();
assert_eq!(sheet.col_width_ranges().len(), 1);
assert_eq!(sheet.column_width(1), Some(8.43));
assert_eq!(sheet.column_width(16_384), Some(8.43));
}
}