diff --git a/.gitignore b/.gitignore index 8bb4a569..18f0f307 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ Cargo.lock fuzz.xlsx .idea nyc.rs +.DS_Store diff --git a/Cargo.toml b/Cargo.toml index 675ed428..7662e2e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ chrono = { version = "0.4", features = [ [dev-dependencies] glob = "0.3" env_logger = "0.11" +rstest = { version = "0.21.0", default-features = false } serde_derive = "1.0" sha256 = "1.3" diff --git a/src/ods.rs b/src/ods.rs index f342f479..60f3637a 100644 --- a/src/ods.rs +++ b/src/ods.rs @@ -434,6 +434,7 @@ fn get_range( let mut new_cells = Vec::with_capacity(cells_len); let empty_cells = vec![T::default(); col_max + 1]; let mut empty_row_repeats = 0; + let mut consecutive_empty_rows = 0; for (w, row_repeats) in cols .windows(2) .skip(row_min) @@ -444,12 +445,13 @@ fn get_range( let row_repeats = *row_repeats; if is_empty_row(row) { - empty_row_repeats = row_repeats; + empty_row_repeats += row_repeats; + consecutive_empty_rows += 1; continue; } if empty_row_repeats > 0 { - row_max = row_max + empty_row_repeats - 1; + row_max = row_max + empty_row_repeats - consecutive_empty_rows; for _ in 0..empty_row_repeats { new_cells.extend_from_slice(&empty_cells); } diff --git a/tests/multi-empty.ods b/tests/multi-empty.ods new file mode 100644 index 00000000..f2af74f1 Binary files /dev/null and b/tests/multi-empty.ods differ diff --git a/tests/single-empty.ods b/tests/single-empty.ods new file mode 100644 index 00000000..88a52c8e Binary files /dev/null and b/tests/single-empty.ods differ diff --git a/tests/test.rs b/tests/test.rs index 460af0d1..4ebd92fd 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -5,6 +5,7 @@ use calamine::{ Xlsx, }; use calamine::{CellErrorType::*, Data}; +use rstest::rstest; use std::collections::BTreeSet; use std::fs::File; use std::io::{BufReader, Cursor}; @@ -1786,3 +1787,29 @@ fn test_ref_xlsb() { ] ); } + +#[rstest] +#[case("single-empty.ods")] +#[case("multi-empty.ods")] +fn issue_repeated_empty(#[case] fixture_path: &str) { + let mut ods: Ods<_> = wb(fixture_path); + let range = ods.worksheet_range_at(0).unwrap().unwrap(); + range_eq!( + range, + [ + [String("StringCol".to_string())], + [String("bbb".to_string())], + [String("ccc".to_string())], + [String("ddd".to_string())], + [String("eee".to_string())], + [Empty], + [Empty], + [Empty], + [Empty], + [Empty], + [Empty], + [Empty], + [String("zzz".to_string())], + ] + ); +}