Repository: zhiburt/tabled
Pull request #104 (2022-03-25 21:04:59)

Handle tabs(\t)


Patch:
diff --git a/papergrid/src/lib.rs b/papergrid/src/lib.rs
index 92d9b28..6e69abd 100644
--- a/papergrid/src/lib.rs
+++ b/papergrid/src/lib.rs
@@ -446,14 +446,14 @@ impl Grid {
 
         let count_rows = self.count_rows();
         let count_columns = self.count_columns();
-        let mut cells = self.collect_cells(count_rows, count_columns);
+        let cells = self.collect_cells(count_rows, count_columns);
         let mut styles = self.collect_styles(count_rows, count_columns);
         let split_borders = (0..count_rows)
             .map(|row| self.get_inner_split_line(row))
             .collect::<Vec<_>>();
 
         let widths = columns_width(
-            &mut cells,
+            &cells,
             &mut styles,
             &split_borders,
             count_rows,
@@ -567,18 +567,22 @@ impl Grid {
         }
     }
 
-    fn collect_cells(&self, count_rows: usize, count_columns: usize) -> Vec<Vec<Vec<&str>>> {
+    fn collect_cells(&self, count_rows: usize, count_columns: usize) -> Vec<Vec<Vec<String>>> {
         let mut rows = Vec::with_capacity(count_rows);
-        (0..count_rows).for_each(|row_index| {
-            let mut row = Vec::with_capacity(count_columns);
-            (0..count_columns).for_each(|column_index| {
-                let content = &self.cells[row_index][column_index];
+        (0..count_rows).for_each(|row| {
+            let mut cells = Vec::with_capacity(row);
+            (0..count_columns).for_each(|col| {
+                let mut content = self.cells[row][col].clone();
+
+                let style = self.style(&Entity::Cell(row, col));
+                replace_tab(&mut content, style.formatting.tab_width);
+
                 // fixme: I guess it can be done in a different place?
-                let cell: Vec<_> = content.lines().collect();
-                row.push(cell);
+                let lines: Vec<_> = content.lines().map(|l| l.to_owned()).collect();
+                cells.push(lines);
             });
 
-            rows.push(row);
+            rows.push(cells);
         });
 
         rows
@@ -765,6 +769,7 @@ impl Default for Style {
                 horizontal_trim: false,
                 vertical_trim: false,
                 allow_lines_alignement: false,
+                tab_width: 4,
             },
         }
     }
@@ -775,6 +780,7 @@ pub struct Formatting {
     pub horizontal_trim: bool,
     pub vertical_trim: bool,
     pub allow_lines_alignement: bool,
+    pub tab_width: usize,
 }
 
 #[derive(Default, Debug, Clone, Copy)]
@@ -1002,7 +1008,7 @@ impl std::fmt::Display for Grid {
             return Ok(());
         }
 
-        let mut cells = self.collect_cells(count_rows, count_columns);
+        let cells = self.collect_cells(count_rows, count_columns);
         let mut styles = self.collect_styles(count_rows, count_columns);
 
         let split_borders = (0..count_rows)
@@ -1011,7 +1017,7 @@ impl std::fmt::Display for Grid {
 
         let row_heights = rows_height(&cells, &styles, count_rows, count_columns);
         let widths = columns_width(
-            &mut cells,
+            &cells,
             &mut styles,
             &split_borders,
             count_rows,
@@ -1055,7 +1061,7 @@ impl std::fmt::Display for Grid {
 #[allow(clippy::too_many_arguments)]
 fn build_row(
     f: &mut std::fmt::Formatter<'_>,
-    cell_contents: &[Vec<&str>],
+    cell_contents: &[Vec<String>],
     cell_styles: &[Style],
     cell_widths: &[usize],
     normal_widths: &[usize],
@@ -1086,7 +1092,7 @@ fn build_row(
 
 fn build_row_internals(
     f: &mut std::fmt::Formatter<'_>,
-    row: &[Vec<&str>],
+    row: &[Vec<String>],
     row_styles: &[Style],
     widths: &[usize],
     height: usize,
@@ -1111,7 +1117,7 @@ fn build_row_internals(
 fn build_row_internal_line(
     f: &mut std::fmt::Formatter<'_>,
     line_index: usize,
-    mut cell: &[&str],
+    mut cell: &[String],
     style: &Style,
     width: usize,
     height: usize,
@@ -1132,7 +1138,7 @@ fn build_row_internal_line(
         return repeat_char(f, style.padding.bottom.fill, width);
     }
 
-    let mut text = cell[cell_line_index];
+    let mut text = cell[cell_line_index].as_str();
 
     if style.formatting.horizontal_trim {
         text = text.trim();
@@ -1158,7 +1164,7 @@ fn build_row_internal_line(
     }
 }
 
-fn skip_empty_lines<'a, 'b>(cell: &'a [&'b str]) -> &'a [&'b str] {
+fn skip_empty_lines(cell: &[String]) -> &[String] {
     let count_lines = cell.len();
 
     let count_empty_lines_before_text = cell
@@ -1181,7 +1187,7 @@ fn skip_empty_lines<'a, 'b>(cell: &'a [&'b str]) -> &'a [&'b str] {
     &cell[text_start_pos..text_end_pos]
 }
 
-fn top_indent(cell: &[&str], style: &Style, height: usize) -> usize {
+fn top_indent(cell: &[String], style: &Style, height: usize) -> usize {
     let height = height - style.padding.top.size;
     let content_height = cell.len();
     let indent = style.alignment_v.top_ident(height, content_height);
@@ -1353,7 +1359,7 @@ fn real_string_width(text: &str) -> usize {
 }
 
 fn columns_width(
-    cells: &mut [Vec<Vec<&str>>],
+    cells: &[Vec<Vec<String>>],
     styles: &mut [Vec<Style>],
     borders: &[Vec<BorderLine>],
     count_rows: usize,
@@ -1619,13 +1625,13 @@ fn inc_cells_width(
         .for_each(|(_, i)| widths[i] += 1);
 }
 
-fn cell_width(cell: &[&str], style: &Style) -> usize {
+fn cell_width(cell: &[String], style: &Style) -> usize {
     let content_width = cell.iter().map(|l| string_width(l)).max().unwrap_or(0);
     content_width + style.padding.left.size + style.padding.right.size
 }
 
 fn rows_height(
-    cells: &[Vec<Vec<&str>>],
+    cells: &[Vec<Vec<String>>],
     styles: &[Vec<Style>],
     count_rows: usize,
     count_columns: usize,
@@ -1653,7 +1659,7 @@ fn rows_height(
     row_heights
 }
 
-fn cell_height(cell: &[&str], style: &Style) -> usize {
+fn cell_height(cell: &[String], style: &Style) -> usize {
     let content_height = cell.len();
     content_height + style.padding.top.size + style.padding.bottom.size
 }
@@ -1696,6 +1702,32 @@ fn normalized_width(
     v
 }
 
+fn replace_tab(cell: &mut String, n: usize) -> &str {
+    let mut skip = 0;
+    while let &Some(pos) = &cell[skip..].find('\t') {
+        let pos = skip + pos;
+
+        let is_escaped = pos > 0 && cell.get(pos - 1..pos) == Some("\\");
+        if is_escaped {
+            skip = pos + 1;
+        } else if n == 0 {
+            cell.remove(pos);
+            skip = pos;
+        } else {
+            // I'am not sure which version is faster a loop of 'replace'
+            // or allacation of a string for replacement;
+            cell.replace_range(pos..pos + 1, &" ".repeat(n));
+            skip = pos + 1;
+        }
+
+        if cell.is_empty() || skip >= cell.len() {
+            break;
+        }
+    }
+
+    cell
+}
+
 #[derive(Debug)]
 struct Borders {
     vertical: HashMap<CellIndex, Line>,
@@ -2034,6 +2066,24 @@ fn bounds_to_usize(left: Bound<&usize>, right: Bound<&usize>, length: usize) ->
 mod tests {
     use super::*;
 
+    #[test]
+    fn replace_tab_test() {
+        assert_eq!(
+            replace_tab(&mut "123\t\tabc\t".to_owned(), 3),
+            "123      abc   "
+        );
+
+        assert_eq!(replace_tab(&mut "\t".to_owned(), 0), "");
+        assert_eq!(replace_tab(&mut "\t".to_owned(), 3), "   ");
+        assert_eq!(replace_tab(&mut "123\tabc".to_owned(), 3), "123   abc");
+        assert_eq!(replace_tab(&mut "123\tabc\tzxc".to_owned(), 0), "123abczxc");
+
+        assert_eq!(replace_tab(&mut "\\t".to_owned(), 0), "\\t");
+        assert_eq!(replace_tab(&mut "\\t".to_owned(), 4), "\\t");
+        assert_eq!(replace_tab(&mut "123\\tabc".to_owned(), 0), "123\\tabc");
+        assert_eq!(replace_tab(&mut "123\\tabc".to_owned(), 4), "123\\tabc");
+    }
+
     #[test]
     fn string_width_emojie_test() {
         // ...emojis such as “joy”, which normally take up two columns when printed in a terminal
diff --git a/src/render_settings.rs b/src/render_settings.rs
index 7f90401..5b7b258 100644
--- a/src/render_settings.rs
+++ b/src/render_settings.rs
@@ -11,6 +11,7 @@ use crate::CellOption;
 pub struct RenderSettings {
     alignment_policy: Option<AlignmentStrategy>,
     trim_policy: Option<TrimStrategy>,
+    tab_size: Option<usize>,
 }
 
 impl RenderSettings {
@@ -25,6 +26,19 @@ impl RenderSettings {
         self.trim_policy = Some(policy);
         self
     }
+
+    /// Set a tab size.
+    ///
+    /// The size is used in order to calculate width correctly.
+    ///
+    /// Default value is 4 (basically 1 '\t' equals 4 spaces).
+    ///
+    /// IMPORTANT: The tab character might be not present in output,
+    /// it might be replaced by spaces.
+    pub fn set_tab_size(mut self, n: usize) -> Self {
+        self.tab_size = Some(n);
+        self
+    }
 }
 
 /// AlignmentStrategy is a responsible for a flow how we apply an aligment.
@@ -222,6 +236,10 @@ impl CellOption for RenderSettings {
             }
         }
 
+        if let &Some(n) = &self.tab_size {
+            formatting.tab_width = n;
+        }
+
         grid.set(
             &Entity::Cell(row, column),
             Settings::new().formatting(formatting),


Test patch:
diff --git a/papergrid/tests/format_configuration.rs b/papergrid/tests/format_configuration.rs
index 71eba36..743c945 100644
--- a/papergrid/tests/format_configuration.rs
+++ b/papergrid/tests/format_configuration.rs
@@ -12,6 +12,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: false,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |A long string|          |\n\
@@ -42,6 +43,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |A long string|          |\n\
@@ -72,6 +74,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: true,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |A long string|A         |\n\
@@ -103,6 +106,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: false,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |A long string|          |\n\
@@ -133,6 +137,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |A long string|          |\n\
@@ -163,6 +168,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: true,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |A long string|    A     |\n\
@@ -194,6 +200,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: false,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |A long string|          |\n\
@@ -224,6 +231,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |A long string|          |\n\
@@ -254,6 +262,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: true,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |A long string|         A|\n\
@@ -286,6 +295,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: false,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -316,6 +326,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -346,6 +357,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: true,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -377,6 +389,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: false,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -407,6 +420,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -437,6 +451,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: true,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -468,6 +483,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: false,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -498,6 +514,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -528,6 +545,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: true,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -560,6 +578,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: false,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -590,6 +609,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -620,6 +640,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: true,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -651,6 +672,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: false,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -681,6 +703,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -711,6 +734,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: true,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -742,6 +766,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: false,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -772,6 +797,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: false,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -802,6 +828,7 @@ fn formatting_test() {
                 allow_lines_alignement: true,
                 horizontal_trim: true,
                 vertical_trim: true,
+                ..Default::default()
             },
             "+-------------+----------+\n\
              |             |          |\n\
@@ -874,6 +901,7 @@ fn formatting_empty_test() {
             allow_lines_alignement: true,
             horizontal_trim: true,
             vertical_trim: true,
+            ..Default::default()
         }),
     );
 
@@ -886,6 +914,7 @@ fn formatting_empty_test() {
             allow_lines_alignement: true,
             horizontal_trim: true,
             vertical_trim: true,
+            ..Default::default()
         }),
     );
 
@@ -898,6 +927,7 @@ fn formatting_empty_test() {
             allow_lines_alignement: true,
             horizontal_trim: true,
             vertical_trim: true,
+            ..Default::default()
         }),
     );
 
@@ -957,6 +987,7 @@ fn formatting_1x1_test() {
             allow_lines_alignement: true,
             horizontal_trim: false,
             vertical_trim: false,
+            ..Default::default()
         }),
     );
 
@@ -989,6 +1020,7 @@ fn formatting_1x1_test() {
             allow_lines_alignement: true,
             horizontal_trim: true,
             vertical_trim: false,
+            ..Default::default()
         }),
     );
 
@@ -1021,6 +1053,7 @@ fn formatting_1x1_test() {
             allow_lines_alignement: true,
             horizontal_trim: true,
             vertical_trim: true,
+            ..Default::default()
         }),
     );
 
@@ -1047,3 +1080,82 @@ fn formatting_1x1_test() {
             + "\n"
     );
 }
+
+#[test]
+fn tab_size_test() {
+    let json = "{
+\t\t \"id\": \"1\",
+\t\t \"name\": \"Hello World\",
+\t\t \"list\": [
+\t\t\t\t [1, 2, 3],
+\t\t\t\t [4, 5, 6],
+\t\t ]
+}";
+
+    let mut grid = util::new_grid::<1, 1>();
+    grid.set(&Entity::Cell(0, 0), Settings::new().text(json));
+
+    println!("{}", grid);
+
+    assert_eq!(
+        grid.to_string(),
+        "+-------------------------------+\n\
+         |{                              |\n\
+         |         \"id\": \"1\",            |\n\
+         |         \"name\": \"Hello World\",|\n\
+         |         \"list\": [             |\n\
+         |                 [1, 2, 3],    |\n\
+         |                 [4, 5, 6],    |\n\
+         |         ]                     |\n\
+         |}                              |\n\
+         +-------------------------------+\n",
+    );
+
+    grid.set(
+        &Entity::Cell(0, 0),
+        Settings::new().formatting(Formatting {
+            tab_width: 1,
+            ..Default::default()
+        }),
+    );
+
+    println!("{}", grid);
+
+    assert_eq!(
+        grid.to_string(),
+        "+-------------------------+\n\
+         |{                        |\n\
+         |   \"id\": \"1\",            |\n\
+         |   \"name\": \"Hello World\",|\n\
+         |   \"list\": [             |\n\
+         |     [1, 2, 3],          |\n\
+         |     [4, 5, 6],          |\n\
+         |   ]                     |\n\
+         |}                        |\n\
+         +-------------------------+\n"
+    );
+
+    grid.set(
+        &Entity::Cell(0, 0),
+        Settings::new().formatting(Formatting {
+            tab_width: 0,
+            ..Default::default()
+        }),
+    );
+
+    println!("{}", grid);
+
+    assert_eq!(
+        grid.to_string(),
+        "+-----------------------+\n\
+         |{                      |\n\
+         | \"id\": \"1\",            |\n\
+         | \"name\": \"Hello World\",|\n\
+         | \"list\": [             |\n\
+         | [1, 2, 3],            |\n\
+         | [4, 5, 6],            |\n\
+         | ]                     |\n\
+         |}                      |\n\
+         +-----------------------+\n"
+    );
+}
diff --git a/tests/render_settings.rs b/tests/render_settings.rs
index 6fdca0f..bcac603 100644
--- a/tests/render_settings.rs
+++ b/tests/render_settings.rs
@@ -1,8 +1,8 @@
 use crate::util::create_vector;
 use tabled::{
-    object::Full,
+    object::{Cell, Full},
     render_settings::{AlignmentStrategy, RenderSettings, TrimStrategy},
-    Alignment, Modify, Style, Table,
+    Alignment, Modify, Span, Style, Table,
 };
 
 mod util;
@@ -117,3 +117,98 @@ fn alignment_per_line_with_trim() {
 
     assert_eq!(table, expected);
 }
+
+#[test]
+fn tab_size_test() {
+    let mut data = create_vector::<3, 3>();
+    data[1][0] = String::from("123\t123\tasdasd");
+    data[2][2] = String::from("htt\tps://\nwww\n.\nred\that\n.c\tom\n/en");
+
+    let mut table = Table::new(&data).with(Style::psql());
+
+    let expected = concat!(
+        "          N           | column 0 |   column 1   | column 2 \n",
+        "----------------------+----------+--------------+----------\n",
+        "          0           |   0-0    |     0-1      |   0-2    \n",
+        " 123    123    asdasd |   1-0    |     1-1      |   1-2    \n",
+        "          2           |   2-0    | htt    ps:// |   2-2    \n",
+        "                      |          | www          |          \n",
+        "                      |          | .            |          \n",
+        "                      |          | red    hat   |          \n",
+        "                      |          | .c    om     |          \n",
+        "                      |          | /en          |          \n",
+    );
+
+    assert_eq!(table.to_string(), expected);
+
+    table = table.with(
+        Modify::new(Full)
+            .with(Alignment::right())
+            .with(RenderSettings::default().set_tab_size(2)),
+    );
+
+    let expected = concat!(
+        "                N | column 0 |   column 1 | column 2 \n",
+        "------------------+----------+------------+----------\n",
+        "                0 |      0-0 |        0-1 |      0-2 \n",
+        " 123  123  asdasd |      1-0 |        1-1 |      1-2 \n",
+        "                2 |      2-0 | htt  ps:// |      2-2 \n",
+        "                  |          | www        |          \n",
+        "                  |          | .          |          \n",
+        "                  |          | red  hat   |          \n",
+        "                  |          | .c  om     |          \n",
+        "                  |          | /en        |          \n",
+    );
+
+    assert_eq!(table.to_string(), expected);
+
+    table = table.with(
+        Modify::new(Full)
+            .with(Alignment::right())
+            .with(RenderSettings::default().set_tab_size(0)),
+    );
+
+    let expected = concat!(
+        "            N | column 0 | column 1 | column 2 \n",
+        "--------------+----------+----------+----------\n",
+        "            0 |      0-0 |      0-1 |      0-2 \n",
+        " 123123asdasd |      1-0 |      1-1 |      1-2 \n",
+        "            2 |      2-0 | https:// |      2-2 \n",
+        "              |          | www      |          \n",
+        "              |          | .        |          \n",
+        "              |          | redhat   |          \n",
+        "              |          | .com     |          \n",
+        "              |          | /en      |          \n",
+    );
+
+    assert_eq!(table.to_string(), expected);
+}
+
+#[test]
+fn tab_size_span_test() {
+    let mut data = create_vector::<3, 3>();
+    data[0][0] = String::from("\tH\t\tello\tWorld");
+    data[1][0] = String::from("123\t123\tasdasd");
+    data[2][2] = String::from("htt\tps://\nwww\n.\nred\that\n.c\tom\n/en");
+
+    let table = Table::new(&data)
+        .with(Style::psql())
+        .with(Modify::new(Cell(0, 0)).with(Span::column(3)))
+        .with(Modify::new(Cell(1, 0)).with(Span::column(2)))
+        .with(Modify::new(Cell(2, 1)).with(Span::column(2)));
+
+    let expected = concat!(
+        "                     N                     | column 2 \n",
+        "----------------------+-----+--------------+----------\n",
+        "     H        ello    World |     0-1      |   0-2    \n",
+        " 123    123    asdasd |        1-0         |   1-2    \n",
+        "          2           | 2-0 | htt    ps:// |   2-2    \n",
+        "                      |     | www          |          \n",
+        "                      |     | .            |          \n",
+        "                      |     | red    hat   |          \n",
+        "                      |     | .c    om     |          \n",
+        "                      |     | /en          |          \n",
+    );
+
+    assert_eq!(table.to_string(), expected);
+}