1use std::collections::BTreeMap;
8
9use sheetkit_xml::worksheet::{Col, Cols, WorksheetXml};
10
11use crate::cell::CellValue;
12use crate::error::{Error, Result};
13use crate::row::get_rows;
14use crate::sst::SharedStringTable;
15use crate::utils::cell_ref::{
16 cell_name_to_coordinates, column_name_to_number, coordinates_to_cell_name,
17};
18use crate::utils::constants::{MAX_COLUMNS, MAX_COLUMN_WIDTH};
19
20#[allow(clippy::type_complexity)]
26pub fn get_cols(
27 ws: &WorksheetXml,
28 sst: &SharedStringTable,
29) -> Result<Vec<(String, Vec<(u32, CellValue)>)>> {
30 let rows = get_rows(ws, sst)?;
31
32 let mut col_map: BTreeMap<String, Vec<(u32, CellValue)>> = BTreeMap::new();
35
36 for (row_num, cells) in rows {
37 for (col_name, value) in cells {
38 col_map.entry(col_name).or_default().push((row_num, value));
39 }
40 }
41
42 let mut result: Vec<(String, Vec<(u32, CellValue)>)> = col_map.into_iter().collect();
46 result.sort_by(|(a, _), (b, _)| a.len().cmp(&b.len()).then_with(|| a.cmp(b)));
47
48 Ok(result)
49}
50
51pub fn set_col_width(ws: &mut WorksheetXml, col: &str, width: f64) -> Result<()> {
56 let col_num = column_name_to_number(col)?;
57 if !(0.0..=MAX_COLUMN_WIDTH).contains(&width) {
58 return Err(Error::ColumnWidthExceeded {
59 width,
60 max: MAX_COLUMN_WIDTH,
61 });
62 }
63
64 let col_entry = find_or_create_col(ws, col_num);
65 col_entry.width = Some(width);
66 col_entry.custom_width = Some(true);
67 Ok(())
68}
69
70pub fn get_col_width(ws: &WorksheetXml, col: &str) -> Option<f64> {
73 let col_num = column_name_to_number(col).ok()?;
74 ws.cols
75 .as_ref()
76 .and_then(|cols| {
77 cols.cols
78 .iter()
79 .find(|c| col_num >= c.min && col_num <= c.max)
80 })
81 .and_then(|c| c.width)
82}
83
84pub fn set_col_visible(ws: &mut WorksheetXml, col: &str, visible: bool) -> Result<()> {
86 let col_num = column_name_to_number(col)?;
87 let col_entry = find_or_create_col(ws, col_num);
88 col_entry.hidden = if visible { None } else { Some(true) };
89 Ok(())
90}
91
92pub fn get_col_visible(ws: &WorksheetXml, col: &str) -> Result<bool> {
97 let col_num = column_name_to_number(col)?;
98 let hidden = ws
99 .cols
100 .as_ref()
101 .and_then(|cols| {
102 cols.cols
103 .iter()
104 .find(|c| col_num >= c.min && col_num <= c.max)
105 })
106 .and_then(|c| c.hidden)
107 .unwrap_or(false);
108 Ok(!hidden)
109}
110
111pub fn set_col_outline_level(ws: &mut WorksheetXml, col: &str, level: u8) -> Result<()> {
115 let col_num = column_name_to_number(col)?;
116 if level > 7 {
117 return Err(Error::OutlineLevelExceeded { level, max: 7 });
118 }
119
120 let col_entry = find_or_create_col(ws, col_num);
121 col_entry.outline_level = if level == 0 { None } else { Some(level) };
122 Ok(())
123}
124
125pub fn get_col_outline_level(ws: &WorksheetXml, col: &str) -> Result<u8> {
127 let col_num = column_name_to_number(col)?;
128 let level = ws
129 .cols
130 .as_ref()
131 .and_then(|cols| {
132 cols.cols
133 .iter()
134 .find(|c| col_num >= c.min && col_num <= c.max)
135 })
136 .and_then(|c| c.outline_level)
137 .unwrap_or(0);
138 Ok(level)
139}
140
141pub fn insert_cols(ws: &mut WorksheetXml, col: &str, count: u32) -> Result<()> {
147 let start_col = column_name_to_number(col)?;
148 if count == 0 {
149 return Ok(());
150 }
151
152 let max_existing = ws
154 .sheet_data
155 .rows
156 .iter()
157 .flat_map(|r| r.cells.iter())
158 .filter_map(|c| cell_name_to_coordinates(&c.r).ok())
159 .map(|(col_n, _)| col_n)
160 .max()
161 .unwrap_or(0);
162 let furthest = max_existing.max(start_col);
163 if furthest.checked_add(count).is_none_or(|v| v > MAX_COLUMNS) {
164 return Err(Error::InvalidColumnNumber(furthest + count));
165 }
166
167 for row in ws.sheet_data.rows.iter_mut() {
169 for cell in row.cells.iter_mut() {
170 let (c, r) = cell_name_to_coordinates(&cell.r)?;
171 if c >= start_col {
172 cell.r = coordinates_to_cell_name(c + count, r)?;
173 }
174 }
175 }
176
177 if let Some(ref mut cols) = ws.cols {
179 for c in cols.cols.iter_mut() {
180 if c.min >= start_col {
181 c.min += count;
182 }
183 if c.max >= start_col {
184 c.max += count;
185 }
186 }
187 }
188
189 Ok(())
190}
191
192pub fn remove_col(ws: &mut WorksheetXml, col: &str) -> Result<()> {
194 let col_num = column_name_to_number(col)?;
195
196 for row in ws.sheet_data.rows.iter_mut() {
198 row.cells.retain(|cell| {
200 cell_name_to_coordinates(&cell.r)
201 .map(|(c, _)| c != col_num)
202 .unwrap_or(true)
203 });
204
205 for cell in row.cells.iter_mut() {
207 let (c, r) = cell_name_to_coordinates(&cell.r)?;
208 if c > col_num {
209 cell.r = coordinates_to_cell_name(c - 1, r)?;
210 }
211 }
212 }
213
214 if let Some(ref mut cols) = ws.cols {
216 cols.cols
218 .retain(|c| !(c.min == col_num && c.max == col_num));
219
220 for c in cols.cols.iter_mut() {
221 if c.min > col_num {
222 c.min -= 1;
223 }
224 if c.max >= col_num {
225 c.max -= 1;
226 }
227 }
228
229 if cols.cols.is_empty() {
231 ws.cols = None;
232 }
233 }
234
235 Ok(())
236}
237
238pub fn set_col_style(ws: &mut WorksheetXml, col: &str, style_id: u32) -> Result<()> {
241 let col_num = column_name_to_number(col)?;
242 let col_entry = find_or_create_col(ws, col_num);
243 col_entry.style = Some(style_id);
244 Ok(())
245}
246
247pub fn get_col_style(ws: &WorksheetXml, col: &str) -> Result<u32> {
250 let col_num = column_name_to_number(col)?;
251 let style = ws
252 .cols
253 .as_ref()
254 .and_then(|cols| {
255 cols.cols
256 .iter()
257 .find(|c| col_num >= c.min && col_num <= c.max)
258 })
259 .and_then(|c| c.style)
260 .unwrap_or(0);
261 Ok(style)
262}
263
264fn find_or_create_col(ws: &mut WorksheetXml, col_num: u32) -> &mut Col {
267 if ws.cols.is_none() {
269 ws.cols = Some(Cols { cols: vec![] });
270 }
271 let cols = ws.cols.as_mut().unwrap();
272
273 let existing = cols
275 .cols
276 .iter()
277 .position(|c| c.min == col_num && c.max == col_num);
278
279 if let Some(idx) = existing {
280 return &mut cols.cols[idx];
281 }
282
283 cols.cols.push(Col {
285 min: col_num,
286 max: col_num,
287 width: None,
288 style: None,
289 hidden: None,
290 custom_width: None,
291 outline_level: None,
292 });
293 let last = cols.cols.len() - 1;
294 &mut cols.cols[last]
295}
296
297#[cfg(test)]
298mod tests {
299 use super::*;
300 use sheetkit_xml::worksheet::{Cell, Row, SheetData};
301
302 fn sample_ws() -> WorksheetXml {
304 let mut ws = WorksheetXml::default();
305 ws.sheet_data = SheetData {
306 rows: vec![
307 Row {
308 r: 1,
309 spans: None,
310 s: None,
311 custom_format: None,
312 ht: None,
313 hidden: None,
314 custom_height: None,
315 outline_level: None,
316 cells: vec![
317 Cell {
318 r: "A1".to_string(),
319 s: None,
320 t: None,
321 v: Some("10".to_string()),
322 f: None,
323 is: None,
324 },
325 Cell {
326 r: "B1".to_string(),
327 s: None,
328 t: None,
329 v: Some("20".to_string()),
330 f: None,
331 is: None,
332 },
333 Cell {
334 r: "D1".to_string(),
335 s: None,
336 t: None,
337 v: Some("40".to_string()),
338 f: None,
339 is: None,
340 },
341 ],
342 },
343 Row {
344 r: 2,
345 spans: None,
346 s: None,
347 custom_format: None,
348 ht: None,
349 hidden: None,
350 custom_height: None,
351 outline_level: None,
352 cells: vec![
353 Cell {
354 r: "A2".to_string(),
355 s: None,
356 t: None,
357 v: Some("100".to_string()),
358 f: None,
359 is: None,
360 },
361 Cell {
362 r: "C2".to_string(),
363 s: None,
364 t: None,
365 v: Some("300".to_string()),
366 f: None,
367 is: None,
368 },
369 ],
370 },
371 ],
372 };
373 ws
374 }
375
376 #[test]
377 fn test_set_and_get_col_width() {
378 let mut ws = WorksheetXml::default();
379 set_col_width(&mut ws, "A", 15.0).unwrap();
380 assert_eq!(get_col_width(&ws, "A"), Some(15.0));
381 }
382
383 #[test]
384 fn test_set_col_width_creates_cols_container() {
385 let mut ws = WorksheetXml::default();
386 assert!(ws.cols.is_none());
387 set_col_width(&mut ws, "B", 20.0).unwrap();
388 assert!(ws.cols.is_some());
389 let cols = ws.cols.as_ref().unwrap();
390 assert_eq!(cols.cols.len(), 1);
391 assert_eq!(cols.cols[0].min, 2);
392 assert_eq!(cols.cols[0].max, 2);
393 assert_eq!(cols.cols[0].custom_width, Some(true));
394 }
395
396 #[test]
397 fn test_set_col_width_zero_is_valid() {
398 let mut ws = WorksheetXml::default();
399 set_col_width(&mut ws, "A", 0.0).unwrap();
400 assert_eq!(get_col_width(&ws, "A"), Some(0.0));
401 }
402
403 #[test]
404 fn test_set_col_width_max_is_valid() {
405 let mut ws = WorksheetXml::default();
406 set_col_width(&mut ws, "A", 255.0).unwrap();
407 assert_eq!(get_col_width(&ws, "A"), Some(255.0));
408 }
409
410 #[test]
411 fn test_set_col_width_exceeds_max_returns_error() {
412 let mut ws = WorksheetXml::default();
413 let result = set_col_width(&mut ws, "A", 256.0);
414 assert!(result.is_err());
415 assert!(matches!(
416 result.unwrap_err(),
417 Error::ColumnWidthExceeded { .. }
418 ));
419 }
420
421 #[test]
422 fn test_set_col_width_negative_returns_error() {
423 let mut ws = WorksheetXml::default();
424 let result = set_col_width(&mut ws, "A", -1.0);
425 assert!(result.is_err());
426 }
427
428 #[test]
429 fn test_get_col_width_nonexistent_returns_none() {
430 let ws = WorksheetXml::default();
431 assert_eq!(get_col_width(&ws, "Z"), None);
432 }
433
434 #[test]
435 fn test_set_col_width_invalid_column_returns_error() {
436 let mut ws = WorksheetXml::default();
437 let result = set_col_width(&mut ws, "XFE", 10.0);
438 assert!(result.is_err());
439 }
440
441 #[test]
442 fn test_set_col_hidden() {
443 let mut ws = WorksheetXml::default();
444 set_col_visible(&mut ws, "A", false).unwrap();
445
446 let col = &ws.cols.as_ref().unwrap().cols[0];
447 assert_eq!(col.hidden, Some(true));
448 }
449
450 #[test]
451 fn test_set_col_visible_clears_hidden() {
452 let mut ws = WorksheetXml::default();
453 set_col_visible(&mut ws, "A", false).unwrap();
454 set_col_visible(&mut ws, "A", true).unwrap();
455
456 let col = &ws.cols.as_ref().unwrap().cols[0];
457 assert_eq!(col.hidden, None);
458 }
459
460 #[test]
461 fn test_insert_cols_shifts_cells_right() {
462 let mut ws = sample_ws();
463 insert_cols(&mut ws, "B", 2).unwrap();
464
465 let r1 = &ws.sheet_data.rows[0];
467 assert_eq!(r1.cells[0].r, "A1");
468 assert_eq!(r1.cells[1].r, "D1"); assert_eq!(r1.cells[2].r, "F1"); let r2 = &ws.sheet_data.rows[1];
473 assert_eq!(r2.cells[0].r, "A2");
474 assert_eq!(r2.cells[1].r, "E2"); }
476
477 #[test]
478 fn test_insert_cols_at_column_a() {
479 let mut ws = sample_ws();
480 insert_cols(&mut ws, "A", 1).unwrap();
481
482 let r1 = &ws.sheet_data.rows[0];
484 assert_eq!(r1.cells[0].r, "B1"); assert_eq!(r1.cells[1].r, "C1"); assert_eq!(r1.cells[2].r, "E1"); }
488
489 #[test]
490 fn test_insert_cols_count_zero_is_noop() {
491 let mut ws = sample_ws();
492 insert_cols(&mut ws, "B", 0).unwrap();
493 assert_eq!(ws.sheet_data.rows[0].cells[0].r, "A1");
494 assert_eq!(ws.sheet_data.rows[0].cells[1].r, "B1");
495 }
496
497 #[test]
498 fn test_insert_cols_on_empty_sheet() {
499 let mut ws = WorksheetXml::default();
500 insert_cols(&mut ws, "A", 5).unwrap();
501 assert!(ws.sheet_data.rows.is_empty());
502 }
503
504 #[test]
505 fn test_insert_cols_shifts_col_definitions() {
506 let mut ws = WorksheetXml::default();
507 set_col_width(&mut ws, "C", 20.0).unwrap();
508 insert_cols(&mut ws, "B", 2).unwrap();
509
510 let col = &ws.cols.as_ref().unwrap().cols[0];
512 assert_eq!(col.min, 5);
513 assert_eq!(col.max, 5);
514 }
515
516 #[test]
517 fn test_remove_col_shifts_cells_left() {
518 let mut ws = sample_ws();
519 remove_col(&mut ws, "B").unwrap();
520
521 let r1 = &ws.sheet_data.rows[0];
523 assert_eq!(r1.cells.len(), 2);
524 assert_eq!(r1.cells[0].r, "A1");
525 assert_eq!(r1.cells[1].r, "C1"); assert_eq!(r1.cells[1].v, Some("40".to_string()));
527
528 let r2 = &ws.sheet_data.rows[1];
530 assert_eq!(r2.cells[0].r, "A2");
531 assert_eq!(r2.cells[1].r, "B2"); }
533
534 #[test]
535 fn test_remove_first_col() {
536 let mut ws = sample_ws();
537 remove_col(&mut ws, "A").unwrap();
538
539 let r1 = &ws.sheet_data.rows[0];
541 assert_eq!(r1.cells.len(), 2);
542 assert_eq!(r1.cells[0].r, "A1");
543 assert_eq!(r1.cells[0].v, Some("20".to_string())); assert_eq!(r1.cells[1].r, "C1");
545 assert_eq!(r1.cells[1].v, Some("40".to_string())); }
547
548 #[test]
549 fn test_remove_col_with_col_definitions() {
550 let mut ws = WorksheetXml::default();
551 set_col_width(&mut ws, "B", 20.0).unwrap();
552 remove_col(&mut ws, "B").unwrap();
553
554 assert!(ws.cols.is_none());
556 }
557
558 #[test]
559 fn test_remove_col_shrinks_range_ending_at_removed_column() {
560 let mut ws = WorksheetXml::default();
562 set_col_width(&mut ws, "B", 15.0).unwrap();
563 ws.cols.as_mut().unwrap().cols[0].max = 3;
565 remove_col(&mut ws, "C").unwrap();
566 let col = &ws.cols.as_ref().unwrap().cols[0];
567 assert_eq!(col.min, 2);
568 assert_eq!(col.max, 2);
569 }
570
571 #[test]
572 fn test_remove_col_shrinks_range_spanning_removed_column() {
573 let mut ws = WorksheetXml::default();
575 set_col_width(&mut ws, "B", 15.0).unwrap();
576 ws.cols.as_mut().unwrap().cols[0].max = 5;
577 remove_col(&mut ws, "C").unwrap();
578 let col = &ws.cols.as_ref().unwrap().cols[0];
579 assert_eq!(col.min, 2);
580 assert_eq!(col.max, 4);
581 }
582
583 #[test]
584 fn test_remove_col_invalid_column_returns_error() {
585 let mut ws = WorksheetXml::default();
586 let result = remove_col(&mut ws, "XFE");
587 assert!(result.is_err());
588 }
589
590 #[test]
591 fn test_remove_col_invalid_cell_reference_returns_error() {
592 let mut ws = sample_ws();
593 ws.sheet_data.rows[0].cells.push(Cell {
594 r: "INVALID".to_string(),
595 s: None,
596 t: None,
597 v: Some("1".to_string()),
598 f: None,
599 is: None,
600 });
601 let result = remove_col(&mut ws, "A");
602 assert!(result.is_err());
603 }
604
605 #[test]
606 fn test_set_multiple_col_widths() {
607 let mut ws = WorksheetXml::default();
608 set_col_width(&mut ws, "A", 10.0).unwrap();
609 set_col_width(&mut ws, "C", 30.0).unwrap();
610
611 assert_eq!(get_col_width(&ws, "A"), Some(10.0));
612 assert_eq!(get_col_width(&ws, "B"), None);
613 assert_eq!(get_col_width(&ws, "C"), Some(30.0));
614 }
615
616 #[test]
617 fn test_overwrite_col_width() {
618 let mut ws = WorksheetXml::default();
619 set_col_width(&mut ws, "A", 10.0).unwrap();
620 set_col_width(&mut ws, "A", 25.0).unwrap();
621
622 assert_eq!(get_col_width(&ws, "A"), Some(25.0));
623 }
624
625 #[test]
626 fn test_get_col_visible_default_is_true() {
627 let ws = WorksheetXml::default();
628 assert!(get_col_visible(&ws, "A").unwrap());
629 }
630
631 #[test]
632 fn test_get_col_visible_after_hide() {
633 let mut ws = WorksheetXml::default();
634 set_col_visible(&mut ws, "B", false).unwrap();
635 assert!(!get_col_visible(&ws, "B").unwrap());
636 }
637
638 #[test]
639 fn test_get_col_visible_after_hide_then_show() {
640 let mut ws = WorksheetXml::default();
641 set_col_visible(&mut ws, "A", false).unwrap();
642 set_col_visible(&mut ws, "A", true).unwrap();
643 assert!(get_col_visible(&ws, "A").unwrap());
644 }
645
646 #[test]
647 fn test_get_col_visible_invalid_column_returns_error() {
648 let ws = WorksheetXml::default();
649 let result = get_col_visible(&ws, "XFE");
650 assert!(result.is_err());
651 }
652
653 #[test]
654 fn test_set_col_outline_level() {
655 let mut ws = WorksheetXml::default();
656 set_col_outline_level(&mut ws, "A", 3).unwrap();
657
658 let col = &ws.cols.as_ref().unwrap().cols[0];
659 assert_eq!(col.outline_level, Some(3));
660 }
661
662 #[test]
663 fn test_set_col_outline_level_zero_clears() {
664 let mut ws = WorksheetXml::default();
665 set_col_outline_level(&mut ws, "A", 3).unwrap();
666 set_col_outline_level(&mut ws, "A", 0).unwrap();
667
668 let col = &ws.cols.as_ref().unwrap().cols[0];
669 assert_eq!(col.outline_level, None);
670 }
671
672 #[test]
673 fn test_set_col_outline_level_exceeds_max_returns_error() {
674 let mut ws = WorksheetXml::default();
675 let result = set_col_outline_level(&mut ws, "A", 8);
676 assert!(result.is_err());
677 }
678
679 #[test]
680 fn test_set_col_outline_level_max_valid() {
681 let mut ws = WorksheetXml::default();
682 set_col_outline_level(&mut ws, "A", 7).unwrap();
683
684 let col = &ws.cols.as_ref().unwrap().cols[0];
685 assert_eq!(col.outline_level, Some(7));
686 }
687
688 #[test]
689 fn test_get_col_outline_level_default_is_zero() {
690 let ws = WorksheetXml::default();
691 assert_eq!(get_col_outline_level(&ws, "A").unwrap(), 0);
692 }
693
694 #[test]
695 fn test_get_col_outline_level_after_set() {
696 let mut ws = WorksheetXml::default();
697 set_col_outline_level(&mut ws, "B", 5).unwrap();
698 assert_eq!(get_col_outline_level(&ws, "B").unwrap(), 5);
699 }
700
701 #[test]
702 fn test_get_col_outline_level_after_clear() {
703 let mut ws = WorksheetXml::default();
704 set_col_outline_level(&mut ws, "C", 4).unwrap();
705 set_col_outline_level(&mut ws, "C", 0).unwrap();
706 assert_eq!(get_col_outline_level(&ws, "C").unwrap(), 0);
707 }
708
709 #[test]
710 fn test_get_col_outline_level_invalid_column_returns_error() {
711 let ws = WorksheetXml::default();
712 let result = get_col_outline_level(&ws, "XFE");
713 assert!(result.is_err());
714 }
715
716 #[test]
719 fn test_get_cols_empty_sheet() {
720 let ws = WorksheetXml::default();
721 let sst = SharedStringTable::new();
722 let cols = get_cols(&ws, &sst).unwrap();
723 assert!(cols.is_empty());
724 }
725
726 #[test]
727 fn test_get_cols_transposes_row_data() {
728 let ws = sample_ws();
729 let sst = SharedStringTable::new();
730 let cols = get_cols(&ws, &sst).unwrap();
731
732 assert_eq!(cols.len(), 4);
738
739 assert_eq!(cols[0].0, "A");
741 assert_eq!(cols[0].1.len(), 2);
742 assert_eq!(cols[0].1[0], (1, CellValue::Number(10.0)));
743 assert_eq!(cols[0].1[1], (2, CellValue::Number(100.0)));
744
745 assert_eq!(cols[1].0, "B");
747 assert_eq!(cols[1].1.len(), 1);
748 assert_eq!(cols[1].1[0], (1, CellValue::Number(20.0)));
749
750 assert_eq!(cols[2].0, "C");
752 assert_eq!(cols[2].1.len(), 1);
753 assert_eq!(cols[2].1[0], (2, CellValue::Number(300.0)));
754
755 assert_eq!(cols[3].0, "D");
757 assert_eq!(cols[3].1.len(), 1);
758 assert_eq!(cols[3].1[0], (1, CellValue::Number(40.0)));
759 }
760
761 #[test]
762 fn test_get_cols_with_shared_strings() {
763 let mut sst = SharedStringTable::new();
764 sst.add("Name");
765 sst.add("Age");
766 sst.add("Alice");
767
768 let mut ws = WorksheetXml::default();
769 ws.sheet_data = SheetData {
770 rows: vec![
771 Row {
772 r: 1,
773 spans: None,
774 s: None,
775 custom_format: None,
776 ht: None,
777 hidden: None,
778 custom_height: None,
779 outline_level: None,
780 cells: vec![
781 Cell {
782 r: "A1".to_string(),
783 s: None,
784 t: Some("s".to_string()),
785 v: Some("0".to_string()),
786 f: None,
787 is: None,
788 },
789 Cell {
790 r: "B1".to_string(),
791 s: None,
792 t: Some("s".to_string()),
793 v: Some("1".to_string()),
794 f: None,
795 is: None,
796 },
797 ],
798 },
799 Row {
800 r: 2,
801 spans: None,
802 s: None,
803 custom_format: None,
804 ht: None,
805 hidden: None,
806 custom_height: None,
807 outline_level: None,
808 cells: vec![
809 Cell {
810 r: "A2".to_string(),
811 s: None,
812 t: Some("s".to_string()),
813 v: Some("2".to_string()),
814 f: None,
815 is: None,
816 },
817 Cell {
818 r: "B2".to_string(),
819 s: None,
820 t: None,
821 v: Some("30".to_string()),
822 f: None,
823 is: None,
824 },
825 ],
826 },
827 ],
828 };
829
830 let cols = get_cols(&ws, &sst).unwrap();
831 assert_eq!(cols.len(), 2);
832
833 assert_eq!(cols[0].0, "A");
835 assert_eq!(cols[0].1[0].1, CellValue::String("Name".to_string()));
836 assert_eq!(cols[0].1[1].1, CellValue::String("Alice".to_string()));
837
838 assert_eq!(cols[1].0, "B");
840 assert_eq!(cols[1].1[0].1, CellValue::String("Age".to_string()));
841 assert_eq!(cols[1].1[1].1, CellValue::Number(30.0));
842 }
843
844 #[test]
845 fn test_get_cols_sorted_correctly() {
846 let mut ws = WorksheetXml::default();
849 ws.sheet_data = SheetData {
850 rows: vec![Row {
851 r: 1,
852 spans: None,
853 s: None,
854 custom_format: None,
855 ht: None,
856 hidden: None,
857 custom_height: None,
858 outline_level: None,
859 cells: vec![
860 Cell {
861 r: "AA1".to_string(),
862 s: None,
863 t: None,
864 v: Some("1".to_string()),
865 f: None,
866 is: None,
867 },
868 Cell {
869 r: "B1".to_string(),
870 s: None,
871 t: None,
872 v: Some("2".to_string()),
873 f: None,
874 is: None,
875 },
876 Cell {
877 r: "A1".to_string(),
878 s: None,
879 t: None,
880 v: Some("3".to_string()),
881 f: None,
882 is: None,
883 },
884 ],
885 }],
886 };
887
888 let sst = SharedStringTable::new();
889 let cols = get_cols(&ws, &sst).unwrap();
890
891 assert_eq!(cols.len(), 3);
892 assert_eq!(cols[0].0, "A");
893 assert_eq!(cols[1].0, "B");
894 assert_eq!(cols[2].0, "AA");
895 }
896
897 #[test]
900 fn test_get_col_style_default_is_zero() {
901 let ws = WorksheetXml::default();
902 assert_eq!(get_col_style(&ws, "A").unwrap(), 0);
903 }
904
905 #[test]
906 fn test_set_col_style_applies_style() {
907 let mut ws = WorksheetXml::default();
908 set_col_style(&mut ws, "B", 4).unwrap();
909
910 let col = &ws.cols.as_ref().unwrap().cols[0];
911 assert_eq!(col.style, Some(4));
912 }
913
914 #[test]
915 fn test_get_col_style_after_set() {
916 let mut ws = WorksheetXml::default();
917 set_col_style(&mut ws, "C", 10).unwrap();
918 assert_eq!(get_col_style(&ws, "C").unwrap(), 10);
919 }
920
921 #[test]
922 fn test_set_col_style_creates_cols_container() {
923 let mut ws = WorksheetXml::default();
924 assert!(ws.cols.is_none());
925 set_col_style(&mut ws, "A", 2).unwrap();
926 assert!(ws.cols.is_some());
927 }
928
929 #[test]
930 fn test_set_col_style_overwrite() {
931 let mut ws = WorksheetXml::default();
932 set_col_style(&mut ws, "A", 3).unwrap();
933 set_col_style(&mut ws, "A", 7).unwrap();
934 assert_eq!(get_col_style(&ws, "A").unwrap(), 7);
935 }
936
937 #[test]
938 fn test_get_col_style_invalid_column_returns_error() {
939 let ws = WorksheetXml::default();
940 let result = get_col_style(&ws, "XFE");
941 assert!(result.is_err());
942 }
943
944 #[test]
945 fn test_set_col_style_invalid_column_returns_error() {
946 let mut ws = WorksheetXml::default();
947 let result = set_col_style(&mut ws, "XFE", 1);
948 assert!(result.is_err());
949 }
950}