flat/
render.rs

1use crate::abbreviate::find_abbreviations;
2use crate::Aggregate;
3use std::collections::{HashMap, HashSet};
4use std::fmt::{Display, Formatter, Write};
5use std::iter;
6use std::ops::Range;
7
8/// The general configuration for rendering a `flat` widget.
9///
10/// ### Example
11/// ```
12/// # use flat::{Aggregate, HistogramConfig, Render};
13/// let config = Render {
14///     aggregate: Aggregate::Average,
15///     width_hint: 10,
16///     show_aggregate: true,
17///     abbreviate_breakdown: true,
18///     positive_marker: '+',
19///     negative_marker: '-',
20///     widget_config: HistogramConfig::default(),
21///     ..Render::default()
22/// };
23/// ```
24#[derive(Debug)]
25pub struct Render<C> {
26    /// The function to apply when aggregating values in the widget.
27    ///
28    /// Default: `Aggregate::Sum`.
29    pub aggregate: Aggregate,
30    /// The hint to use to determine the width of the rendering.
31    /// `Flat` will try to make the rendering at most `width_hint` wide, with some exceptions:
32    /// * If the rendering can reasonably fit in a smaller width, the `width_hint` is ignored.
33    /// * If the rendering cannot reasonably fit the `width_hint`, then it is minimally extended (such that a reasonable rendering may be produced).
34    ///
35    /// Default: `160`.
36    pub width_hint: usize,
37    /// Whether to show the aggregated result for the *primary* dimension of the dataset.
38    /// While the *rendered* data in `flat` uses a relative representation, this option extends the widget to show the absolute values of the data.
39    /// ```ignore
40    /// r#"
41    /// Show Aggregate          | Rendering of Aggregate
42    /// aggregate([1, 2, 3, 4]) | aggregate([1, 2, 3, 4])"#
43    /// ```
44    ///
45    /// In the case of a breakdown, this represents the aggregate applied to the breakdown aggregates.
46    /// ```ignore
47    /// r#"
48    /// Show Aggregate                                    | Rendering of Aggregate of A | Rendering of Aggregate of B |
49    /// aggregate([aggregate([1, 2, 3]), aggregate([4])]) | aggregate([1, 2, 3])        | aggregate([4])              |"#
50    /// ```
51    ///
52    /// Default: `false`.
53    pub show_aggregate: bool,
54    /// Whether to abbreviate the column headings (which come from dimensional values) in the breakdown or not.
55    /// Use this option when the breakdown dimensions have long `std::fmt::Display` forms.
56    /// Abbreviation is attempted irrespective of the `width_hint`.
57    ///
58    /// Default: `false`.
59    pub abbreviate_breakdown: bool,
60    /// The marker character for positive values of the rendering.
61    ///
62    /// Default: `'*'`.
63    pub positive_marker: char,
64    /// The marker character for negative values of the rendering.
65    ///
66    /// Default: `'⊖'`.
67    pub negative_marker: char,
68    /// The widget specific rendering configuration.
69    ///
70    /// Default: `C::default()`.
71    pub widget_config: C,
72}
73
74impl<C: Default> Default for Render<C> {
75    fn default() -> Self {
76        Self {
77            aggregate: Aggregate::Sum,
78            width_hint: 160,
79            show_aggregate: false,
80            abbreviate_breakdown: false,
81            positive_marker: '*',
82            negative_marker: '⊖',
83            widget_config: C::default(),
84        }
85    }
86}
87
88#[derive(Debug)]
89struct Config {
90    width_hint: usize,
91    abbreviate_breakdown: bool,
92    positive_marker: char,
93    negative_marker: char,
94}
95
96impl<T> From<Render<T>> for Config {
97    fn from(value: Render<T>) -> Self {
98        Self {
99            width_hint: value.width_hint,
100            abbreviate_breakdown: value.abbreviate_breakdown,
101            positive_marker: value.positive_marker,
102            negative_marker: value.negative_marker,
103        }
104    }
105}
106
107#[derive(Debug)]
108pub(crate) struct Column {
109    alignment: Alignment,
110    column_type: ColumnType,
111}
112
113#[derive(Debug)]
114pub(crate) enum ColumnType {
115    String(usize),
116    Count,
117    Breakdown,
118}
119
120impl Column {
121    pub fn string(alignment: Alignment) -> Self {
122        Self {
123            alignment,
124            column_type: ColumnType::String(0),
125        }
126    }
127
128    pub fn count(alignment: Alignment) -> Self {
129        Self {
130            alignment,
131            column_type: ColumnType::Count,
132        }
133    }
134
135    pub fn breakdown(alignment: Alignment) -> Self {
136        Self {
137            alignment,
138            column_type: ColumnType::Breakdown,
139        }
140    }
141}
142
143#[derive(Debug)]
144pub(crate) enum Alignment {
145    Left,
146    Center,
147    Right,
148}
149
150impl Column {
151    fn write(
152        &self,
153        f: &mut Formatter<'_>,
154        cell: &Cell,
155        view: &View,
156        width: usize,
157        overflow_width_override: Option<&usize>,
158    ) -> std::fmt::Result {
159        let mut width = match &self.column_type {
160            ColumnType::String(width) => *width,
161            ColumnType::Count | ColumnType::Breakdown => width,
162        };
163
164        if matches!(cell.value, Value::Overflow(_)) {
165            if let Some(w) = overflow_width_override {
166                width = *w;
167            }
168        }
169
170        let is_breakdown = match &self.column_type {
171            ColumnType::Breakdown => true,
172            _ => false,
173        };
174
175        match &self.alignment {
176            Alignment::Left => {
177                write!(f, "{:<width$}", cell.value.render(&view, is_breakdown))
178            }
179            Alignment::Center => {
180                write!(f, "{:^width$}", cell.value.render(&view, is_breakdown))
181            }
182            Alignment::Right => {
183                write!(f, "{:>width$}", cell.value.render(&view, is_breakdown))
184            }
185        }
186    }
187
188    fn write_final(
189        &self,
190        f: &mut Formatter<'_>,
191        cell: &Cell,
192        view: &View,
193        width: usize,
194    ) -> std::fmt::Result {
195        let width = match &self.column_type {
196            ColumnType::String(width) => *width,
197            ColumnType::Count | ColumnType::Breakdown => width,
198        };
199
200        let is_breakdown = match &self.column_type {
201            ColumnType::Breakdown => true,
202            _ => false,
203        };
204
205        if let Value::Plain(value) = &cell.value {
206            write!(f, "{value}")
207        } else {
208            match &self.alignment {
209                Alignment::Left => {
210                    write!(f, "{}", cell.value.render(&view, is_breakdown))
211                }
212                Alignment::Center => {
213                    let render_string = cell.value.render(&view, is_breakdown);
214                    let render_length = render_string.chars().count();
215
216                    if render_length < width {
217                        let left = (width - render_length) / 2;
218                        write!(f, "{:left$}{}", "", render_string)
219                    } else {
220                        write!(f, "{}", cell.value.render(&view, is_breakdown))
221                    }
222                }
223                Alignment::Right => {
224                    write!(f, "{:>width$}", cell.value.render(&view, is_breakdown))
225                }
226            }
227        }
228    }
229
230    fn fill(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
231        let width = match &self.column_type {
232            ColumnType::String(width) => *width,
233            ColumnType::Count | ColumnType::Breakdown => {
234                unreachable!("should never fill a breakdown");
235            }
236        };
237
238        write!(f, "{:width$}", "")
239    }
240}
241
242#[derive(Debug, PartialEq)]
243pub(crate) struct Cell {
244    column: usize,
245    value: Value,
246}
247
248#[derive(Debug, PartialEq)]
249pub(crate) enum Value {
250    Empty,
251    String(String),
252    Overflow(String),
253    Plain(String),
254    Value(f64),
255    Skip,
256}
257
258impl Value {
259    fn render_width(&self) -> Option<usize> {
260        match &self {
261            Value::Empty => Some(0),
262            Value::String(string) | Value::Overflow(string) => Some(string.chars().count()),
263            Value::Plain(_) | Value::Value(_) | Value::Skip => None,
264        }
265    }
266
267    fn render(&self, view: &View, is_breakdown: bool) -> String {
268        match &self {
269            Value::Empty => "".to_string(),
270            Value::Skip => unreachable!("must never call render for a Skip"),
271            Value::String(string) => {
272                if is_breakdown {
273                    match view.breakdown_abbreviations.get(string) {
274                        Some(abbr) => abbr.clone(),
275                        None => string.clone(),
276                    }
277                } else {
278                    string.clone()
279                }
280            }
281            Value::Overflow(string) | Value::Plain(string) => string.clone(),
282            Value::Value(value) => {
283                let value = value.round();
284
285                let marker = if value.is_sign_positive() {
286                    view.positive_marker
287                } else {
288                    view.negative_marker
289                };
290
291                iter::repeat(marker)
292                    .take((value.abs() * view.scale) as usize)
293                    .collect::<String>()
294            }
295        }
296    }
297}
298
299#[derive(Debug, Default)]
300pub(crate) struct Columns {
301    types: Vec<Column>,
302}
303
304impl Columns {
305    pub fn push(&mut self, column: Column) {
306        self.types.push(column);
307    }
308
309    fn get(&self, index: usize) -> &Column {
310        &self.types[index]
311    }
312
313    fn get_mut(&mut self, index: usize) -> Option<&mut Column> {
314        self.types.get_mut(index)
315    }
316}
317
318#[derive(Debug, Default)]
319pub(crate) struct Row {
320    cells: Vec<Cell>,
321}
322
323impl Row {
324    pub fn push(&mut self, value: Value) {
325        self.cells.push(Cell {
326            column: self.cells.len(),
327            value,
328        });
329    }
330}
331
332#[derive(Debug, PartialEq)]
333struct Overflow {
334    width: usize,
335    columns: Vec<usize>,
336}
337
338#[derive(Debug)]
339pub(crate) struct Grid {
340    columns: Columns,
341    rows: Vec<HashMap<usize, Cell>>,
342    overflows: Vec<Overflow>,
343    breakdown_values: HashSet<String>,
344    /// The minimum width of all the columns (before abbreviation).
345    minimum_breakdown_width: usize,
346    /// The maximum width of all the columns (before abbreviation).
347    maximum_breakdown_width: usize,
348}
349
350impl Grid {
351    pub fn new(columns: Columns) -> Self {
352        Self {
353            columns,
354            rows: Vec::default(),
355            overflows: Vec::default(),
356            breakdown_values: HashSet::default(),
357            minimum_breakdown_width: usize::MAX,
358            maximum_breakdown_width: usize::MIN,
359        }
360    }
361
362    pub fn add(&mut self, row: Row) {
363        assert!(!row.cells.is_empty());
364        let mut overflow_width: Option<usize> = None;
365        let mut overflow_columns = Vec::default();
366
367        for (j, cell) in row.cells.iter().enumerate() {
368            if overflow_width.is_some() {
369                if matches!(&cell.value, Value::Skip) {
370                    overflow_columns.push(j);
371                } else {
372                    self.overflows.push(Overflow {
373                        width: overflow_width.take().unwrap(),
374                        columns: overflow_columns.clone(),
375                    });
376                }
377            }
378
379            let column = self
380                .columns
381                .get_mut(j)
382                .expect(format!("All columns must be accounted for, missing: {j}.").as_str());
383
384            match &mut column.column_type {
385                ColumnType::String(width) => {
386                    if let Some(cell_width) = cell.value.render_width() {
387                        if matches!(&cell.value, Value::Overflow(_)) {
388                            overflow_width.replace(cell_width);
389                            overflow_columns = vec![j];
390                        } else {
391                            if &cell_width > width {
392                                *width = cell_width;
393                            }
394                        }
395                    }
396                }
397                ColumnType::Breakdown => {
398                    if let Value::String(value) = &cell.value {
399                        self.breakdown_values.insert(value.clone());
400                    }
401
402                    if let Some(cell_width) = cell.value.render_width() {
403                        if &cell_width < &self.minimum_breakdown_width {
404                            self.minimum_breakdown_width = cell_width;
405                        }
406
407                        if &cell_width > &self.maximum_breakdown_width {
408                            self.maximum_breakdown_width = cell_width;
409                        }
410                    }
411                }
412                ColumnType::Count => {
413                    // do nothing
414                }
415            }
416        }
417
418        if overflow_width.is_some() {
419            self.overflows.push(Overflow {
420                width: overflow_width.take().unwrap(),
421                columns: overflow_columns.clone(),
422            });
423        }
424
425        self.rows
426            .push(row.cells.into_iter().map(|c| (c.column, c)).collect());
427    }
428
429    /// Build the overflow overrides, which is a map from column index to "override width".
430    fn build_overflow_overrides(&mut self) -> HashMap<usize, usize> {
431        let mut overflow_overrides = HashMap::default();
432
433        for overflow in &self.overflows {
434            let mut remainder = overflow.width;
435            let mut excess = 0;
436
437            for column in &overflow.columns {
438                if let ColumnType::String(width) = self.columns.get(*column).column_type {
439                    if remainder >= width {
440                        remainder -= width;
441                    } else if remainder == 0 {
442                        excess += width;
443                    } else {
444                        excess += width - remainder;
445                        remainder = 0;
446                    }
447                }
448            }
449
450            if remainder > 0 {
451                assert_eq!(excess, 0);
452                // The overflow is longer than the combination of the columns it spans.
453                // Our simple algorithm is to always just add the remainder to the last column.
454                let column = self
455                    .columns
456                    .get_mut(*overflow.columns.last().unwrap())
457                    .unwrap();
458
459                if let ColumnType::String(ref mut width) = column.column_type {
460                    *width += remainder;
461                }
462            } else if excess > 0 {
463                assert_eq!(remainder, 0);
464                // The overflow is shorter than the combination of the columns it spans.
465                // Remember the override to use it when printing the overflow itself.
466                overflow_overrides
467                    .insert(*overflow.columns.first().unwrap(), overflow.width + excess);
468            } else {
469                // They are dead even - do nothing!
470                assert_eq!(excess, 0);
471                assert_eq!(remainder, 0);
472            }
473        }
474
475        overflow_overrides
476    }
477}
478
479/// The textual representation of data.
480/// This is always produced by calling `.render(config)` on a widget.
481/// Use [`std::fmt::Display`] to materialize the flat rendering.
482///
483/// ```
484/// use flat::*;
485///
486/// let schema = Schemas::one("Animal");
487/// let dataset = DatasetBuilder::new(schema)
488///     .add(("whale".to_string(), ))
489///     .add(("shark".to_string(), ))
490///     .add(("shark".to_string(), ))
491///     .add(("tiger".to_string(), ))
492///     .add(("tiger".to_string(), ))
493///     .add(("tiger".to_string(), ))
494///     .build();
495/// let view = dataset.count();
496/// let flat = DagChart::new(&view).render(Render::default());
497/// assert_eq!(
498///     format!("\n{}", flat.to_string()),
499///     r#"
500/// Animal  |Sum(Count)
501/// shark   |**
502/// tiger   |***
503/// whale   |*"#);
504/// ```
505#[derive(Debug)]
506pub struct Flat {
507    config: Config,
508    value_range: Range<f64>,
509    grid: Grid,
510    overflow_overrides: HashMap<usize, usize>,
511}
512
513impl Flat {
514    pub(crate) fn new<C>(render: Render<C>, value_range: Range<f64>, mut grid: Grid) -> Self {
515        let overflow_overrides = grid.build_overflow_overrides();
516
517        Self {
518            config: render.into(),
519            value_range,
520            grid,
521            overflow_overrides,
522        }
523    }
524}
525
526impl Display for Flat {
527    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
528        let mut view_width = self.config.width_hint.saturating_sub(
529            self.grid
530                .columns
531                .types
532                .iter()
533                .filter_map(|c| match &c.column_type {
534                    ColumnType::String(width) => Some(width),
535                    ColumnType::Count | ColumnType::Breakdown => None,
536                })
537                .sum(),
538        );
539        let view_columns = self
540            .grid
541            .columns
542            .types
543            .iter()
544            .map(|c| match &c.column_type {
545                ColumnType::String(_) => 0,
546                ColumnType::Count | ColumnType::Breakdown => 1,
547            })
548            .sum();
549
550        if view_columns != 0 {
551            view_width = view_width.saturating_div(view_columns);
552        }
553
554        if view_width < 2 {
555            view_width = 2;
556        }
557
558        let mut value_width = std::cmp::max(
559            self.value_range.start.abs().round() as i128,
560            self.value_range.end.abs().round() as i128,
561        );
562
563        if value_width == 0 {
564            value_width = 1;
565        }
566
567        let mut scale = view_width as f64 / value_width as f64;
568        let width: usize = if scale >= 1.0 {
569            scale = 1.0;
570            value_width as usize
571        } else {
572            view_width
573        };
574
575        let (abbreviation_width, breakdown_abbreviations) = match (
576            self.config.abbreviate_breakdown,
577            view_width > self.grid.maximum_breakdown_width,
578        ) {
579            // We're supposed to abbreviate, but we don't need to.
580            (true, true) => {
581                if self.grid.minimum_breakdown_width == usize::MAX {
582                    // The config asks to abbreviate the breakdown, but the view isn't actually a breakdown!
583                    (self.grid.maximum_breakdown_width, HashMap::default())
584                } else {
585                    find_abbreviations(
586                        self.grid.minimum_breakdown_width,
587                        self.grid.maximum_breakdown_width,
588                        &self.grid.breakdown_values,
589                    )
590                }
591            }
592            // We're supposed to abbreviate and we need to.
593            (true, false) => find_abbreviations(
594                view_width,
595                self.grid.maximum_breakdown_width,
596                &self.grid.breakdown_values,
597            ),
598            // We're not supposed to abbreviate.
599            (false, _) => (self.grid.maximum_breakdown_width, HashMap::default()),
600        };
601
602        let width = std::cmp::max(width, abbreviation_width);
603        let view = View {
604            breakdown_abbreviations,
605            scale,
606            positive_marker: self.config.positive_marker,
607            negative_marker: self.config.negative_marker,
608        };
609
610        for (i, row) in self.grid.rows.iter().enumerate() {
611            let filled_row = filled(row);
612            let filled_row_length = filled_row.len();
613
614            for (j, wrapped_cell) in filled_row.into_iter() {
615                match wrapped_cell {
616                    WrappedCell::Cell(cell) => {
617                        if j + 1 == filled_row_length {
618                            self.grid
619                                .columns
620                                .get(j)
621                                .write_final(f, cell, &view, width)?;
622                        } else {
623                            self.grid.columns.get(j).write(
624                                f,
625                                cell,
626                                &view,
627                                width,
628                                self.overflow_overrides.get(&j),
629                            )?;
630                        }
631                    }
632                    WrappedCell::Skip => {
633                        // Do nothing.
634                    }
635                    WrappedCell::Fill => {
636                        self.grid.columns.get(j).fill(f)?;
637                    }
638                }
639            }
640
641            if i + 1 != self.grid.rows.len() {
642                f.write_char('\n')?;
643            }
644        }
645
646        Ok(())
647    }
648}
649
650#[derive(Debug)]
651struct View {
652    breakdown_abbreviations: HashMap<String, String>,
653    scale: f64,
654    positive_marker: char,
655    negative_marker: char,
656}
657
658#[derive(Debug)]
659enum WrappedCell<'a> {
660    Cell(&'a Cell),
661    Skip,
662    Fill,
663}
664
665fn filled<'a>(rows: &'a HashMap<usize, Cell>) -> Vec<(usize, WrappedCell)> {
666    let maximum_j: usize = *rows.keys().max().expect("Row must not be empty");
667    let mut out = Vec::default();
668    let mut candidates = Vec::default();
669
670    for j in 0..=maximum_j {
671        let optional_cell = rows.get(&&j);
672
673        match &optional_cell {
674            Some(cell) => match &cell {
675                Cell {
676                    value: Value::Empty,
677                    ..
678                } => {
679                    candidates.push((j, WrappedCell::Cell(cell)));
680                }
681                Cell {
682                    value: Value::Skip, ..
683                } => {
684                    candidates.push((j, WrappedCell::Skip));
685                }
686                Cell { .. } => {
687                    candidates.drain(..).for_each(|item| out.push(item));
688                    out.push((j, WrappedCell::Cell(cell)));
689                }
690            },
691            None => {
692                candidates.push((j, WrappedCell::Fill));
693            }
694        }
695    }
696
697    out
698}
699
700#[cfg(test)]
701mod tests {
702    use super::*;
703
704    #[test]
705    fn render_empty() {
706        let view = View {
707            breakdown_abbreviations: Default::default(),
708            scale: 1.0,
709            positive_marker: '+',
710            negative_marker: '-',
711        };
712
713        let value = Value::Empty;
714        assert_eq!(value.render_width(), Some(0));
715        assert_eq!(value.render(&view, false), "");
716        assert_eq!(value.render(&view, true), "");
717    }
718
719    #[test]
720    fn render_string() {
721        let view = View {
722            breakdown_abbreviations: Default::default(),
723            scale: 1.0,
724            positive_marker: '+',
725            negative_marker: '-',
726        };
727
728        let value = Value::String("abc".to_string());
729        assert_eq!(value.render_width(), Some(3));
730        assert_eq!(value.render(&view, false), "abc");
731        assert_eq!(value.render(&view, true), "abc");
732
733        let view = View {
734            breakdown_abbreviations: HashMap::from([("abc".to_string(), "12345".to_string())]),
735            scale: 1.0,
736            positive_marker: '+',
737            negative_marker: '-',
738        };
739        assert_eq!(value.render_width(), Some(3));
740        assert_eq!(value.render(&view, false), "abc");
741        assert_eq!(value.render(&view, true), "12345");
742    }
743
744    #[test]
745    fn render_overflow() {
746        let view = View {
747            breakdown_abbreviations: Default::default(),
748            scale: 1.0,
749            positive_marker: '+',
750            negative_marker: '-',
751        };
752
753        let value = Value::Overflow("abc".to_string());
754        assert_eq!(value.render_width(), Some(3));
755        assert_eq!(value.render(&view, false), "abc");
756        assert_eq!(value.render(&view, true), "abc");
757
758        let view = View {
759            breakdown_abbreviations: HashMap::from([("abc".to_string(), "12345".to_string())]),
760            scale: 1.0,
761            positive_marker: '+',
762            negative_marker: '-',
763        };
764        assert_eq!(value.render_width(), Some(3));
765        assert_eq!(value.render(&view, false), "abc");
766        assert_eq!(value.render(&view, true), "abc");
767    }
768
769    #[test]
770    fn render_plain() {
771        let view = View {
772            breakdown_abbreviations: Default::default(),
773            scale: 1.0,
774            positive_marker: '+',
775            negative_marker: '-',
776        };
777
778        let value = Value::Plain("abc".to_string());
779        assert_eq!(value.render_width(), None);
780        assert_eq!(value.render(&view, false), "abc");
781        assert_eq!(value.render(&view, true), "abc");
782    }
783
784    #[test]
785    fn render_value() {
786        let view = View {
787            breakdown_abbreviations: Default::default(),
788            scale: 1.0,
789            positive_marker: '+',
790            negative_marker: '-',
791        };
792
793        let value = Value::Value(1.49);
794        assert_eq!(value.render_width(), None);
795        assert_eq!(value.render(&view, false), "+");
796        assert_eq!(value.render(&view, true), "+");
797
798        let value = Value::Value(1.5);
799        assert_eq!(value.render_width(), None);
800        assert_eq!(value.render(&view, false), "++");
801        assert_eq!(value.render(&view, true), "++");
802
803        let view = View {
804            breakdown_abbreviations: HashMap::default(),
805            scale: 2.0,
806            positive_marker: '+',
807            negative_marker: '-',
808        };
809        let value = Value::Value(1.49);
810        assert_eq!(value.render_width(), None);
811        assert_eq!(value.render(&view, false), "++");
812        assert_eq!(value.render(&view, true), "++");
813
814        let value = Value::Value(-1.49);
815        assert_eq!(value.render_width(), None);
816        assert_eq!(value.render(&view, false), "--");
817        assert_eq!(value.render(&view, true), "--");
818    }
819
820    #[test]
821    fn render_width_skip() {
822        let value = Value::Skip;
823        assert_eq!(value.render_width(), None);
824    }
825
826    #[test]
827    #[should_panic]
828    fn render_skip() {
829        let view = View {
830            breakdown_abbreviations: Default::default(),
831            scale: 1.0,
832            positive_marker: '+',
833            negative_marker: '-',
834        };
835
836        let value = Value::Skip;
837        value.render(&view, true);
838    }
839
840    #[test]
841    #[should_panic]
842    fn grid_empty_row() {
843        let columns = Columns::default();
844        let mut grid = Grid::new(columns);
845        let row = Row::default();
846        grid.add(row);
847    }
848
849    #[test]
850    #[should_panic]
851    fn grid_unmatched_column() {
852        let columns = Columns::default();
853        let mut grid = Grid::new(columns);
854        let mut row = Row::default();
855        row.push(Value::String("abc".to_string()));
856        grid.add(row);
857    }
858
859    // ColumnType::String
860    #[test]
861    fn grid_add_string_string() {
862        // Setup
863        let mut columns = Columns::default();
864        columns.push(Column::string(Alignment::Center));
865        let mut grid = Grid::new(columns);
866        let mut row = Row::default();
867        row.push(Value::String("abc".to_string()));
868
869        // Execute
870        grid.add(row);
871
872        // Verify
873        assert!(grid.overflows.is_empty());
874        assert!(grid.breakdown_values.is_empty());
875        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
876        assert_eq!(grid.maximum_breakdown_width, 0);
877        assert_eq!(
878            grid.rows,
879            vec![HashMap::from([(
880                0,
881                Cell {
882                    column: 0,
883                    value: Value::String("abc".to_string()),
884                }
885            )])]
886        );
887
888        if let ColumnType::String(size) = grid.columns.types[0].column_type {
889            assert_eq!(size, 3);
890        } else {
891            panic!("unexpected column type");
892        }
893
894        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
895        if let ColumnType::String(size) = grid.columns.types[0].column_type {
896            assert_eq!(size, 3);
897        } else {
898            panic!("unexpected column type");
899        }
900    }
901
902    #[test]
903    fn grid_add_string_overflow() {
904        // Setup
905        let mut columns = Columns::default();
906        columns.push(Column::string(Alignment::Center));
907        let mut grid = Grid::new(columns);
908        let mut row = Row::default();
909        row.push(Value::Overflow("abc".to_string()));
910
911        // Execute
912        grid.add(row);
913
914        // Verify
915        assert_eq!(
916            grid.overflows,
917            vec![Overflow {
918                width: 3,
919                columns: vec![0]
920            }]
921        );
922        assert!(grid.breakdown_values.is_empty());
923        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
924        assert_eq!(grid.maximum_breakdown_width, 0);
925        assert_eq!(
926            grid.rows,
927            vec![HashMap::from([(
928                0,
929                Cell {
930                    column: 0,
931                    value: Value::Overflow("abc".to_string()),
932                }
933            )])]
934        );
935
936        if let ColumnType::String(size) = grid.columns.types[0].column_type {
937            assert_eq!(size, 0);
938        } else {
939            panic!("unexpected column type");
940        }
941
942        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
943        if let ColumnType::String(size) = grid.columns.types[0].column_type {
944            assert_eq!(size, 3);
945        } else {
946            panic!("unexpected column type");
947        }
948    }
949
950    #[test]
951    fn grid_add_string_overflow_skip() {
952        // Setup
953        let mut columns = Columns::default();
954        columns.push(Column::string(Alignment::Center));
955        columns.push(Column::string(Alignment::Center));
956        let mut grid = Grid::new(columns);
957        let mut row = Row::default();
958        row.push(Value::Overflow("abc".to_string()));
959        row.push(Value::Skip);
960
961        // Execute
962        grid.add(row);
963
964        // Verify
965        assert_eq!(
966            grid.overflows,
967            vec![Overflow {
968                width: 3,
969                columns: vec![0, 1]
970            }]
971        );
972        assert!(grid.breakdown_values.is_empty());
973        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
974        assert_eq!(grid.maximum_breakdown_width, 0);
975        assert_eq!(
976            grid.rows,
977            vec![HashMap::from([
978                (
979                    0,
980                    Cell {
981                        column: 0,
982                        value: Value::Overflow("abc".to_string()),
983                    }
984                ),
985                (
986                    1,
987                    Cell {
988                        column: 1,
989                        value: Value::Skip,
990                    }
991                )
992            ])]
993        );
994        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
995
996        if let ColumnType::String(size) = grid.columns.types[0].column_type {
997            assert_eq!(size, 0);
998        } else {
999            panic!("unexpected column type");
1000        }
1001    }
1002
1003    #[test]
1004    fn grid_add_string_overflow_skip_next() {
1005        // Setup
1006        let mut columns = Columns::default();
1007        columns.push(Column::string(Alignment::Center));
1008        columns.push(Column::string(Alignment::Center));
1009        columns.push(Column::count(Alignment::Center));
1010        let mut grid = Grid::new(columns);
1011        let mut row = Row::default();
1012        row.push(Value::Overflow("abc".to_string()));
1013        row.push(Value::Skip);
1014        row.push(Value::Value(0.0));
1015
1016        // Execute
1017        grid.add(row);
1018
1019        // Verify
1020        assert_eq!(
1021            grid.overflows,
1022            vec![Overflow {
1023                width: 3,
1024                columns: vec![0, 1]
1025            }]
1026        );
1027        assert!(grid.breakdown_values.is_empty());
1028        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1029        assert_eq!(grid.maximum_breakdown_width, 0);
1030        assert_eq!(
1031            grid.rows,
1032            vec![HashMap::from([
1033                (
1034                    0,
1035                    Cell {
1036                        column: 0,
1037                        value: Value::Overflow("abc".to_string()),
1038                    }
1039                ),
1040                (
1041                    1,
1042                    Cell {
1043                        column: 1,
1044                        value: Value::Skip,
1045                    }
1046                ),
1047                (
1048                    2,
1049                    Cell {
1050                        column: 2,
1051                        value: Value::Value(0.0),
1052                    }
1053                )
1054            ])]
1055        );
1056        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1057
1058        if let ColumnType::String(size) = grid.columns.types[0].column_type {
1059            assert_eq!(size, 0);
1060        } else {
1061            panic!("unexpected column type");
1062        }
1063    }
1064
1065    #[test]
1066    fn grid_add_string_plain() {
1067        // Setup
1068        let mut columns = Columns::default();
1069        columns.push(Column::string(Alignment::Center));
1070        let mut grid = Grid::new(columns);
1071        let mut row = Row::default();
1072        row.push(Value::Plain("abc".to_string()));
1073
1074        // Execute
1075        grid.add(row);
1076
1077        // Verify
1078        assert!(grid.overflows.is_empty());
1079        assert!(grid.breakdown_values.is_empty());
1080        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1081        assert_eq!(grid.maximum_breakdown_width, 0);
1082        assert_eq!(
1083            grid.rows,
1084            vec![HashMap::from([(
1085                0,
1086                Cell {
1087                    column: 0,
1088                    value: Value::Plain("abc".to_string()),
1089                }
1090            )])]
1091        );
1092        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1093
1094        if let ColumnType::String(size) = grid.columns.types[0].column_type {
1095            assert_eq!(size, 0);
1096        } else {
1097            panic!("unexpected column type");
1098        }
1099    }
1100
1101    #[test]
1102    fn grid_add_string_empty() {
1103        // Setup
1104        let mut columns = Columns::default();
1105        columns.push(Column::string(Alignment::Center));
1106        let mut grid = Grid::new(columns);
1107        let mut row = Row::default();
1108        row.push(Value::Empty);
1109
1110        // Execute
1111        grid.add(row);
1112
1113        // Verify
1114        assert!(grid.overflows.is_empty());
1115        assert!(grid.breakdown_values.is_empty());
1116        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1117        assert_eq!(grid.maximum_breakdown_width, 0);
1118        assert_eq!(
1119            grid.rows,
1120            vec![HashMap::from([(
1121                0,
1122                Cell {
1123                    column: 0,
1124                    value: Value::Empty,
1125                }
1126            )])]
1127        );
1128        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1129
1130        if let ColumnType::String(size) = grid.columns.types[0].column_type {
1131            assert_eq!(size, 0);
1132        } else {
1133            panic!("unexpected column type");
1134        }
1135    }
1136
1137    #[test]
1138    fn grid_add_string_skip() {
1139        // Setup
1140        let mut columns = Columns::default();
1141        columns.push(Column::string(Alignment::Center));
1142        let mut grid = Grid::new(columns);
1143        let mut row = Row::default();
1144        row.push(Value::Skip);
1145
1146        // Execute
1147        grid.add(row);
1148
1149        // Verify
1150        assert!(grid.overflows.is_empty());
1151        assert!(grid.breakdown_values.is_empty());
1152        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1153        assert_eq!(grid.maximum_breakdown_width, 0);
1154        assert_eq!(
1155            grid.rows,
1156            vec![HashMap::from([(
1157                0,
1158                Cell {
1159                    column: 0,
1160                    value: Value::Skip,
1161                }
1162            )])]
1163        );
1164        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1165
1166        if let ColumnType::String(size) = grid.columns.types[0].column_type {
1167            assert_eq!(size, 0);
1168        } else {
1169            panic!("unexpected column type");
1170        }
1171    }
1172
1173    #[test]
1174    fn grid_add_string_value() {
1175        // Setup
1176        let mut columns = Columns::default();
1177        columns.push(Column::string(Alignment::Center));
1178        let mut grid = Grid::new(columns);
1179        let mut row = Row::default();
1180        row.push(Value::Value(0.0));
1181
1182        // Execute
1183        grid.add(row);
1184
1185        // Verify
1186        assert!(grid.overflows.is_empty());
1187        assert!(grid.breakdown_values.is_empty());
1188        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1189        assert_eq!(grid.maximum_breakdown_width, 0);
1190        assert_eq!(
1191            grid.rows,
1192            vec![HashMap::from([(
1193                0,
1194                Cell {
1195                    column: 0,
1196                    value: Value::Value(0.0),
1197                }
1198            )])]
1199        );
1200        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1201
1202        if let ColumnType::String(size) = grid.columns.types[0].column_type {
1203            assert_eq!(size, 0);
1204        } else {
1205            panic!("unexpected column type");
1206        }
1207    }
1208
1209    #[test]
1210    fn grid_add_string_overflow_remainder() {
1211        // Setup
1212        let mut columns = Columns::default();
1213        columns.push(Column::string(Alignment::Center));
1214        let mut grid = Grid::new(columns);
1215        let mut row = Row::default();
1216        row.push(Value::Overflow("qwerty".to_string()));
1217
1218        // Execute
1219        grid.add(row);
1220        let mut row = Row::default();
1221        row.push(Value::String("abc".to_string()));
1222        grid.add(row);
1223
1224        // Verify
1225        assert_eq!(
1226            grid.overflows,
1227            vec![Overflow {
1228                width: 6,
1229                columns: vec![0]
1230            }]
1231        );
1232        assert!(grid.breakdown_values.is_empty());
1233        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1234        assert_eq!(grid.maximum_breakdown_width, 0);
1235        assert_eq!(
1236            grid.rows,
1237            vec![
1238                HashMap::from([(
1239                    0,
1240                    Cell {
1241                        column: 0,
1242                        value: Value::Overflow("qwerty".to_string()),
1243                    }
1244                )]),
1245                HashMap::from([(
1246                    0,
1247                    Cell {
1248                        column: 0,
1249                        value: Value::String("abc".to_string()),
1250                    }
1251                )])
1252            ]
1253        );
1254
1255        if let ColumnType::String(size) = grid.columns.types[0].column_type {
1256            assert_eq!(size, 3);
1257        } else {
1258            panic!("unexpected column type");
1259        }
1260
1261        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1262        if let ColumnType::String(size) = grid.columns.types[0].column_type {
1263            assert_eq!(size, 6);
1264        } else {
1265            panic!("unexpected column type");
1266        }
1267    }
1268
1269    #[test]
1270    fn grid_add_string_overflow_excess() {
1271        // Setup
1272        let mut columns = Columns::default();
1273        columns.push(Column::string(Alignment::Center));
1274        let mut grid = Grid::new(columns);
1275        let mut row = Row::default();
1276        row.push(Value::Overflow("abc".to_string()));
1277
1278        // Execute
1279        grid.add(row);
1280        let mut row = Row::default();
1281        row.push(Value::String("qwerty".to_string()));
1282        grid.add(row);
1283
1284        // Verify
1285        assert_eq!(
1286            grid.overflows,
1287            vec![Overflow {
1288                width: 3,
1289                columns: vec![0]
1290            }]
1291        );
1292        assert!(grid.breakdown_values.is_empty());
1293        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1294        assert_eq!(grid.maximum_breakdown_width, 0);
1295        assert_eq!(
1296            grid.rows,
1297            vec![
1298                HashMap::from([(
1299                    0,
1300                    Cell {
1301                        column: 0,
1302                        value: Value::Overflow("abc".to_string()),
1303                    }
1304                )]),
1305                HashMap::from([(
1306                    0,
1307                    Cell {
1308                        column: 0,
1309                        value: Value::String("qwerty".to_string()),
1310                    }
1311                )])
1312            ]
1313        );
1314
1315        if let ColumnType::String(size) = grid.columns.types[0].column_type {
1316            assert_eq!(size, 6);
1317        } else {
1318            panic!("unexpected column type");
1319        }
1320
1321        assert_eq!(grid.build_overflow_overrides(), HashMap::from([(0, 6)]));
1322        if let ColumnType::String(size) = grid.columns.types[0].column_type {
1323            assert_eq!(size, 6);
1324        } else {
1325            panic!("unexpected column type");
1326        }
1327    }
1328
1329    #[test]
1330    fn grid_add_string_overflow_deadeven() {
1331        // Setup
1332        let mut columns = Columns::default();
1333        columns.push(Column::string(Alignment::Center));
1334        let mut grid = Grid::new(columns);
1335        let mut row = Row::default();
1336        row.push(Value::Overflow("qwerty".to_string()));
1337
1338        // Execute
1339        grid.add(row);
1340        let mut row = Row::default();
1341        row.push(Value::String("qwerty".to_string()));
1342        grid.add(row);
1343
1344        // Verify
1345        assert_eq!(
1346            grid.overflows,
1347            vec![Overflow {
1348                width: 6,
1349                columns: vec![0]
1350            }]
1351        );
1352        assert!(grid.breakdown_values.is_empty());
1353        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1354        assert_eq!(grid.maximum_breakdown_width, 0);
1355        assert_eq!(
1356            grid.rows,
1357            vec![
1358                HashMap::from([(
1359                    0,
1360                    Cell {
1361                        column: 0,
1362                        value: Value::Overflow("qwerty".to_string()),
1363                    }
1364                )]),
1365                HashMap::from([(
1366                    0,
1367                    Cell {
1368                        column: 0,
1369                        value: Value::String("qwerty".to_string()),
1370                    }
1371                )])
1372            ]
1373        );
1374
1375        if let ColumnType::String(size) = grid.columns.types[0].column_type {
1376            assert_eq!(size, 6);
1377        } else {
1378            panic!("unexpected column type");
1379        }
1380
1381        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1382        if let ColumnType::String(size) = grid.columns.types[0].column_type {
1383            assert_eq!(size, 6);
1384        } else {
1385            panic!("unexpected column type");
1386        }
1387    }
1388
1389    // ColumnType::Count
1390    #[test]
1391    fn grid_add_count_string() {
1392        // Setup
1393        let mut columns = Columns::default();
1394        columns.push(Column::count(Alignment::Center));
1395        let mut grid = Grid::new(columns);
1396        let mut row = Row::default();
1397        row.push(Value::String("abc".to_string()));
1398
1399        // Execute
1400        grid.add(row);
1401
1402        // Verify
1403        assert!(grid.overflows.is_empty());
1404        assert!(grid.breakdown_values.is_empty());
1405        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1406        assert_eq!(grid.maximum_breakdown_width, 0);
1407        assert_eq!(
1408            grid.rows,
1409            vec![HashMap::from([(
1410                0,
1411                Cell {
1412                    column: 0,
1413                    value: Value::String("abc".to_string()),
1414                }
1415            )])]
1416        );
1417        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1418    }
1419
1420    #[test]
1421    fn grid_add_count_overflow() {
1422        // Setup
1423        let mut columns = Columns::default();
1424        columns.push(Column::count(Alignment::Center));
1425        let mut grid = Grid::new(columns);
1426        let mut row = Row::default();
1427        row.push(Value::Overflow("abc".to_string()));
1428
1429        // Execute
1430        grid.add(row);
1431
1432        // Verify
1433        assert!(grid.overflows.is_empty());
1434        assert!(grid.breakdown_values.is_empty());
1435        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1436        assert_eq!(grid.maximum_breakdown_width, 0);
1437        assert_eq!(
1438            grid.rows,
1439            vec![HashMap::from([(
1440                0,
1441                Cell {
1442                    column: 0,
1443                    value: Value::Overflow("abc".to_string()),
1444                }
1445            )])]
1446        );
1447        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1448    }
1449
1450    #[test]
1451    fn grid_add_count_plain() {
1452        // Setup
1453        let mut columns = Columns::default();
1454        columns.push(Column::count(Alignment::Center));
1455        let mut grid = Grid::new(columns);
1456        let mut row = Row::default();
1457        row.push(Value::Plain("abc".to_string()));
1458
1459        // Execute
1460        grid.add(row);
1461
1462        // Verify
1463        assert!(grid.overflows.is_empty());
1464        assert!(grid.breakdown_values.is_empty());
1465        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1466        assert_eq!(grid.maximum_breakdown_width, 0);
1467        assert_eq!(
1468            grid.rows,
1469            vec![HashMap::from([(
1470                0,
1471                Cell {
1472                    column: 0,
1473                    value: Value::Plain("abc".to_string()),
1474                }
1475            )])]
1476        );
1477        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1478    }
1479
1480    #[test]
1481    fn grid_add_count_empty() {
1482        // Setup
1483        let mut columns = Columns::default();
1484        columns.push(Column::count(Alignment::Center));
1485        let mut grid = Grid::new(columns);
1486        let mut row = Row::default();
1487        row.push(Value::Empty);
1488
1489        // Execute
1490        grid.add(row);
1491
1492        // Verify
1493        assert!(grid.overflows.is_empty());
1494        assert!(grid.breakdown_values.is_empty());
1495        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1496        assert_eq!(grid.maximum_breakdown_width, 0);
1497        assert_eq!(
1498            grid.rows,
1499            vec![HashMap::from([(
1500                0,
1501                Cell {
1502                    column: 0,
1503                    value: Value::Empty,
1504                }
1505            )])]
1506        );
1507        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1508    }
1509
1510    #[test]
1511    fn grid_add_count_skip() {
1512        // Setup
1513        let mut columns = Columns::default();
1514        columns.push(Column::count(Alignment::Center));
1515        let mut grid = Grid::new(columns);
1516        let mut row = Row::default();
1517        row.push(Value::Skip);
1518
1519        // Execute
1520        grid.add(row);
1521
1522        // Verify
1523        assert!(grid.overflows.is_empty());
1524        assert!(grid.breakdown_values.is_empty());
1525        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1526        assert_eq!(grid.maximum_breakdown_width, 0);
1527        assert_eq!(
1528            grid.rows,
1529            vec![HashMap::from([(
1530                0,
1531                Cell {
1532                    column: 0,
1533                    value: Value::Skip,
1534                }
1535            )])]
1536        );
1537        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1538    }
1539
1540    #[test]
1541    fn grid_add_count_value() {
1542        // Setup
1543        let mut columns = Columns::default();
1544        columns.push(Column::count(Alignment::Center));
1545        let mut grid = Grid::new(columns);
1546        let mut row = Row::default();
1547        row.push(Value::Value(0.0));
1548
1549        // Execute
1550        grid.add(row);
1551
1552        // Verify
1553        assert!(grid.overflows.is_empty());
1554        assert!(grid.breakdown_values.is_empty());
1555        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1556        assert_eq!(grid.maximum_breakdown_width, 0);
1557        assert_eq!(
1558            grid.rows,
1559            vec![HashMap::from([(
1560                0,
1561                Cell {
1562                    column: 0,
1563                    value: Value::Value(0.0),
1564                }
1565            )])]
1566        );
1567        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1568    }
1569
1570    // ColumnType::Breakdown
1571    #[test]
1572    fn grid_add_breakdown_string() {
1573        // Setup
1574        let mut columns = Columns::default();
1575        columns.push(Column::breakdown(Alignment::Center));
1576        let mut grid = Grid::new(columns);
1577        let mut row = Row::default();
1578        row.push(Value::String("abc".to_string()));
1579
1580        // Execute
1581        grid.add(row);
1582
1583        // Verify
1584        assert!(grid.overflows.is_empty());
1585        assert_eq!(grid.breakdown_values, HashSet::from(["abc".to_string()]));
1586        assert_eq!(grid.minimum_breakdown_width, 3);
1587        assert_eq!(grid.maximum_breakdown_width, 3);
1588        assert_eq!(
1589            grid.rows,
1590            vec![HashMap::from([(
1591                0,
1592                Cell {
1593                    column: 0,
1594                    value: Value::String("abc".to_string()),
1595                }
1596            )])]
1597        );
1598        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1599    }
1600
1601    #[test]
1602    fn grid_add_breakdown_overflow() {
1603        // Setup
1604        let mut columns = Columns::default();
1605        columns.push(Column::breakdown(Alignment::Center));
1606        let mut grid = Grid::new(columns);
1607        let mut row = Row::default();
1608        row.push(Value::Overflow("abc".to_string()));
1609
1610        // Execute
1611        grid.add(row);
1612
1613        // Verify
1614        assert!(grid.overflows.is_empty());
1615        assert!(grid.breakdown_values.is_empty());
1616        assert_eq!(grid.minimum_breakdown_width, 3);
1617        assert_eq!(grid.maximum_breakdown_width, 3);
1618        assert_eq!(
1619            grid.rows,
1620            vec![HashMap::from([(
1621                0,
1622                Cell {
1623                    column: 0,
1624                    value: Value::Overflow("abc".to_string()),
1625                }
1626            )])]
1627        );
1628        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1629    }
1630
1631    #[test]
1632    fn grid_add_breakdown_plain() {
1633        // Setup
1634        let mut columns = Columns::default();
1635        columns.push(Column::breakdown(Alignment::Center));
1636        let mut grid = Grid::new(columns);
1637        let mut row = Row::default();
1638        row.push(Value::Plain("abc".to_string()));
1639
1640        // Execute
1641        grid.add(row);
1642
1643        // Verify
1644        assert!(grid.overflows.is_empty());
1645        assert!(grid.breakdown_values.is_empty());
1646        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1647        assert_eq!(grid.maximum_breakdown_width, 0);
1648        assert_eq!(
1649            grid.rows,
1650            vec![HashMap::from([(
1651                0,
1652                Cell {
1653                    column: 0,
1654                    value: Value::Plain("abc".to_string()),
1655                }
1656            )])]
1657        );
1658        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1659    }
1660
1661    #[test]
1662    fn grid_add_breakdown_empty() {
1663        // Setup
1664        let mut columns = Columns::default();
1665        columns.push(Column::breakdown(Alignment::Center));
1666        let mut grid = Grid::new(columns);
1667        let mut row = Row::default();
1668        row.push(Value::Empty);
1669
1670        // Execute
1671        grid.add(row);
1672
1673        // Verify
1674        assert!(grid.overflows.is_empty());
1675        assert!(grid.breakdown_values.is_empty());
1676        assert_eq!(grid.minimum_breakdown_width, 0);
1677        assert_eq!(grid.maximum_breakdown_width, 0);
1678        assert_eq!(
1679            grid.rows,
1680            vec![HashMap::from([(
1681                0,
1682                Cell {
1683                    column: 0,
1684                    value: Value::Empty,
1685                }
1686            )])]
1687        );
1688        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1689    }
1690
1691    #[test]
1692    fn grid_add_breakdown_skip() {
1693        // Setup
1694        let mut columns = Columns::default();
1695        columns.push(Column::breakdown(Alignment::Center));
1696        let mut grid = Grid::new(columns);
1697        let mut row = Row::default();
1698        row.push(Value::Skip);
1699
1700        // Execute
1701        grid.add(row);
1702
1703        // Verify
1704        assert!(grid.overflows.is_empty());
1705        assert!(grid.breakdown_values.is_empty());
1706        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1707        assert_eq!(grid.maximum_breakdown_width, 0);
1708        assert_eq!(
1709            grid.rows,
1710            vec![HashMap::from([(
1711                0,
1712                Cell {
1713                    column: 0,
1714                    value: Value::Skip,
1715                }
1716            )])]
1717        );
1718        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1719    }
1720
1721    #[test]
1722    fn grid_add_breakdown_value() {
1723        // Setup
1724        let mut columns = Columns::default();
1725        columns.push(Column::breakdown(Alignment::Center));
1726        let mut grid = Grid::new(columns);
1727        let mut row = Row::default();
1728        row.push(Value::Value(0.0));
1729
1730        // Execute
1731        grid.add(row);
1732
1733        // Verify
1734        assert!(grid.overflows.is_empty());
1735        assert!(grid.breakdown_values.is_empty());
1736        assert_eq!(grid.minimum_breakdown_width, 18446744073709551615);
1737        assert_eq!(grid.maximum_breakdown_width, 0);
1738        assert_eq!(
1739            grid.rows,
1740            vec![HashMap::from([(
1741                0,
1742                Cell {
1743                    column: 0,
1744                    value: Value::Value(0.0),
1745                }
1746            )])]
1747        );
1748        assert_eq!(grid.build_overflow_overrides(), HashMap::default());
1749    }
1750
1751    #[derive(Default)]
1752    struct TestConfig {}
1753
1754    #[test]
1755    fn display_flat_empty() {
1756        let render: Render<TestConfig> = Render::default();
1757        let value_range = 0.0..1.0;
1758        let columns = Columns::default();
1759        let grid = Grid::new(columns);
1760        let flat = Flat::new(render, value_range, grid);
1761
1762        assert_eq!(flat.to_string(), "");
1763    }
1764
1765    #[test]
1766    fn display_flat() {
1767        let render: Render<TestConfig> = Render::default();
1768        let value_range = 0.0..1.0;
1769        let mut columns = Columns::default();
1770        columns.push(Column::string(Alignment::Left));
1771        let mut grid = Grid::new(columns);
1772        let mut row1 = Row::default();
1773        row1.push(Value::Value(1.0));
1774        grid.add(row1);
1775        let mut row2 = Row::default();
1776        row2.push(Value::Value(0.0));
1777        grid.add(row2);
1778        let mut row3 = Row::default();
1779        row3.push(Value::Value(2.0));
1780        grid.add(row3);
1781        let flat = Flat::new(render, value_range, grid);
1782
1783        assert_eq!(flat.to_string(), "*\n\n**");
1784    }
1785}