Repository: zhiburt/tabled
Pull request #35 (2021-11-20 14:03:18)

Working on library interfaces


Patch:
diff --git a/examples/basic.rs b/examples/basic.rs
index dec5864..eaa8df4 100644
--- a/examples/basic.rs
+++ b/examples/basic.rs
@@ -1,7 +1,7 @@
 //! The example can be run by this command
 //! `cargo run --example basic`
 
-use tabled::{papergrid::AlignmentHorizontal, Alignment, Head, Modify, Row, Style, Table, Tabled};
+use tabled::{Alignment, AlignmentHorizontal, Head, Modify, Row, Style, Table, Tabled};
 
 #[derive(Tabled)]
 struct Distribution {
diff --git a/examples/inline.rs b/examples/inline.rs
index 09d48d1..f0ee3ed 100644
--- a/examples/inline.rs
+++ b/examples/inline.rs
@@ -2,8 +2,7 @@
 //! `cargo run --example inline`
 
 use tabled::{
-    papergrid::AlignmentHorizontal, Alignment, Full, Head, Indent, Modify, Row, Style, Table,
-    Tabled,
+    Alignment, AlignmentHorizontal, Full, Head, Indent, Modify, Row, Style, Table, Tabled,
 };
 
 fn main() {
diff --git a/examples/panel.rs b/examples/panel.rs
index 714f8bf..63ba939 100644
--- a/examples/panel.rs
+++ b/examples/panel.rs
@@ -1,9 +1,7 @@
 //! The example can be run by this command
 //! `cargo run --example panel`
 
-use tabled::{
-    papergrid::AlignmentHorizontal, Alignment, Footer, Full, Header, Modify, Style, Table, Tabled,
-};
+use tabled::{Alignment, AlignmentHorizontal, Footer, Full, Header, Modify, Style, Table, Tabled};
 
 #[derive(Tabled)]
 struct Release {
diff --git a/papergrid/src/lib.rs b/papergrid/src/lib.rs
index 4fee0f1..22c29f1 100644
--- a/papergrid/src/lib.rs
+++ b/papergrid/src/lib.rs
@@ -22,8 +22,6 @@
 //!     assert_eq!(expected, grid.to_string());
 //! ```
 
-// todo: Create method Grid::extract(&self) Self
-
 use std::{
     cmp::max,
     collections::HashMap,
@@ -132,11 +130,12 @@ impl Grid {
         }
 
         if let Some(border) = settings.border {
+            let frame = self.frame_from_entity(entity);
             if settings.border_split_check {
-                self.add_split_lines_for_border(entity, &border);
+                self.add_split_lines_for_border(&frame, &border);
             }
 
-            self.set_border(entity, border);
+            self.set_border(&frame, border);
         }
     }
 
@@ -160,31 +159,23 @@ impl Grid {
         );
     }
 
-    pub fn insert_horizontal_split(&mut self, row: usize, line: SplitLine) {
+    fn insert_horizontal_split(&mut self, row: usize, line: SplitLine) {
         self.borders
             .set_horizontal(row, line.borders, &line.intersections)
             .unwrap();
     }
 
-    pub fn insert_vertical_split(&mut self, column: usize, line: SplitLine) {
+    fn insert_vertical_split(&mut self, column: usize, line: SplitLine) {
         self.borders
             .set_vertical(column, line.borders, &line.intersections)
             .unwrap();
     }
 
-    pub fn get_horizontal_split(&mut self, row: usize) -> Option<SplitLine> {
-        self.borders.get_horizontal(row).unwrap()
-    }
-
-    pub fn get_vertical_split(&mut self, row: usize) -> Option<SplitLine> {
-        self.borders.get_vertical(row).unwrap()
-    }
-
-    pub fn is_vertical_present(&mut self, column: usize) -> bool {
+    fn is_vertical_present(&mut self, column: usize) -> bool {
         self.borders.is_there_vertical(column)
     }
 
-    pub fn is_horizontal_present(&mut self, row: usize) -> bool {
+    fn is_horizontal_present(&mut self, row: usize) -> bool {
         self.borders.is_there_horizontal(row)
     }
 
@@ -202,100 +193,88 @@ impl Grid {
         self.borders.clear()
     }
 
-    pub fn set_border(&mut self, entity: &Entity, border: Border) {
-        let [top_left, top_right, bottom_left, bottom_right] = self.frame_from_entity(entity);
-        let left_column_index = top_left.1;
-        let right_column_index = top_right.1;
-        let top_row_index = top_left.0;
-        let bottom_row_index = bottom_left.0;
-
+    fn set_border(&mut self, frame: &EntityFrame, border: Border) {
         if let Some(top) = border.top {
-            for column in left_column_index..right_column_index {
+            for column in frame.left_column..frame.right_column {
                 self.borders
-                    .set_row_symbol((top_row_index, column), top)
+                    .set_row_symbol((frame.top_row, column), top)
                     .unwrap();
 
                 // in case it continues line we change intersection symbol
-                if right_column_index - left_column_index > 1 {
+                if frame.right_column - frame.left_column > 1 {
                     self.borders
-                        .set_intersection((top_row_index, column), top)
+                        .set_intersection((frame.top_row, column), top)
                         .unwrap();
                 }
             }
         }
 
         if let Some(bottom) = border.bottom {
-            for column in left_column_index..right_column_index {
+            for column in frame.left_column..frame.right_column {
                 self.borders
-                    .set_row_symbol((bottom_row_index, column), bottom)
+                    .set_row_symbol((frame.bottom_row, column), bottom)
                     .unwrap();
 
                 // in case it continues line we change intersection symbol
-                if right_column_index - left_column_index > 1 {
+                if frame.right_column - frame.left_column > 1 {
                     self.borders
-                        .set_intersection((bottom_row_index, column), bottom)
+                        .set_intersection((frame.bottom_row, column), bottom)
                         .unwrap();
                 }
             }
         }
 
         if let Some(left) = border.left {
-            for row in top_row_index..bottom_row_index {
+            for row in frame.top_row..frame.bottom_row {
                 self.borders
-                    .set_column_symbol((row, left_column_index), left)
+                    .set_column_symbol((row, frame.left_column), left)
                     .unwrap();
 
                 // in case it continues line we change intersection symbol
-                if bottom_row_index - top_row_index > 1 {
+                if frame.bottom_row - frame.top_row > 1 {
                     self.borders
-                        .set_intersection((row, left_column_index), left)
+                        .set_intersection((row, frame.left_column), left)
                         .unwrap();
                 }
             }
         }
 
         if let Some(right) = border.right {
-            for row in top_row_index..bottom_row_index {
+            for row in frame.top_row..frame.bottom_row {
                 self.borders
-                    .set_column_symbol((row, right_column_index), right)
+                    .set_column_symbol((row, frame.right_column), right)
                     .unwrap();
 
                 // in case it continues line we change intersection symbol
-                if bottom_row_index - top_row_index > 1 {
+                if frame.bottom_row - frame.top_row > 1 {
                     self.borders
-                        .set_intersection((row, right_column_index), right)
+                        .set_intersection((row, frame.right_column), right)
                         .unwrap();
                 }
             }
         }
 
-        if let Some(bottom_right_corner) = border.right_bottom_corner {
-            self.borders
-                .set_intersection(bottom_right, bottom_right_corner)
-                .unwrap();
-        }
-
         if let Some(top_left_corner) = border.left_top_corner {
             self.borders
-                .set_intersection(top_left, top_left_corner)
+                .set_intersection(frame.top_left_corner(), top_left_corner)
                 .unwrap();
         }
 
         if let Some(top_right_corner) = border.right_top_corner {
             self.borders
-                .set_intersection(top_right, top_right_corner)
+                .set_intersection(frame.top_right_corner(), top_right_corner)
                 .unwrap();
         }
 
         if let Some(bottom_left_corner) = border.left_bottom_corner {
             self.borders
-                .set_intersection(bottom_left, bottom_left_corner)
+                .set_intersection(frame.bottom_left_corner(), bottom_left_corner)
                 .unwrap();
         }
 
         if let Some(bottom_right_corner) = border.right_bottom_corner {
             self.borders
-                .set_intersection(bottom_right, bottom_right_corner)
+                .set_intersection(frame.bottom_right_corner(), bottom_right_corner)
                 .unwrap();
         }
     }
@@ -441,27 +420,21 @@ impl Grid {
         new_grid
     }
 
-    fn add_split_lines_for_border(&mut self, entity: &Entity, border: &Border) {
-        let [top_left, top_right, bottom_left, _] = self.frame_from_entity(entity);
-        let left_column = top_left.1;
-        let right_column = top_right.1;
-        let top_row = top_left.0;
-        let bottom_row = bottom_left.0;
-
-        if border.left.is_some() && !self.is_vertical_present(left_column) {
-            self.add_vertical_split(left_column)
+    fn add_split_lines_for_border(&mut self, frame: &EntityFrame, border: &Border) {
+        if border.left.is_some() && !self.is_vertical_present(frame.left_column) {
+            self.add_vertical_split(frame.left_column)
         }
 
-        if border.right.is_some() && !self.is_vertical_present(right_column) {
-            self.add_vertical_split(right_column)
+        if border.right.is_some() && !self.is_vertical_present(frame.right_column) {
+            self.add_vertical_split(frame.right_column)
         }
 
-        if border.top.is_some() && !self.is_horizontal_present(top_row) {
-            self.add_horizontal_split(top_row)
+        if border.top.is_some() && !self.is_horizontal_present(frame.top_row) {
+            self.add_horizontal_split(frame.top_row)
         }
 
-        if border.bottom.is_some() && !self.is_horizontal_present(bottom_row) {
-            self.add_horizontal_split(bottom_row)
+        if border.bottom.is_some() && !self.is_horizontal_present(frame.bottom_row) {
+            self.add_horizontal_split(frame.bottom_row)
         }
     }
 
@@ -497,8 +470,8 @@ impl Grid {
         rows
     }
 
-    fn frame_from_entity(&self, entity: &Entity) -> [GridPosition; 4] {
-        entity_corners(entity, self.count_rows(), self.count_columns())
+    fn frame_from_entity(&self, entity: &Entity) -> EntityFrame {
+        entity_frame(entity, self.count_rows(), self.count_columns())
     }
 
     fn get_split_line(&self, index: usize) -> Vec<BorderLine> {
@@ -633,6 +606,41 @@ pub enum Entity {
     Cell(usize, usize),
 }
 
+#[derive(PartialEq, Eq, Debug, Hash, Clone)]
+struct EntityFrame {
+    left_column: usize,
+    right_column: usize,
+    top_row: usize,
+    bottom_row: usize,
+}
+
+impl EntityFrame {
+    fn new(left_column: usize, right_column: usize, top_row: usize, bottom_row: usize) -> Self {
+        Self {
+            left_column,
+            right_column,
+            top_row,
+            bottom_row,
+        }
+    }
+
+    fn top_left_corner(&self) -> GridPosition {
+        (self.top_row, self.left_column)
+    }
+
+    fn top_right_corner(&self) -> GridPosition {
+        (self.top_row, self.right_column)
+    }
+
+    fn bottom_left_corner(&self) -> GridPosition {
+        (self.bottom_row, self.left_column)
+    }
+
+    fn bottom_right_corner(&self) -> GridPosition {
+        (self.bottom_row, self.right_column)
+    }
+}
+
 #[derive(Debug, Clone)]
 pub struct Style {
     indent: Indent,
@@ -1232,60 +1240,6 @@ impl Borders {
         }
     }
 
-    fn get_horizontal(&self, row: usize) -> Result<Option<SplitLine>, BorderError> {
-        if row > self.count_rows {
-            return Err(BorderError::WrongRowIndex);
-        }
-
-        if !self.horizontal.contains_key(&row) {
-            return Ok(None);
-        }
-
-        let symbols = self.horizontal.get(&row).unwrap();
-        assert_eq!(symbols.len(), self.count_columns);
-
-        let mut borders = Vec::new();
-        for &c in symbols {
-            borders.push(c);
-        }
-
-        let mut intersections = Vec::new();
-        for column in 0..self.count_columns {
-            if let Some(&c) = self.intersections.get(&(row, column)) {
-                intersections.push(c)
-            }
-        }
-
-        Ok(Some(SplitLine::new(borders, intersections)))
-    }
-
-    fn get_vertical(&self, column: usize) -> Result<Option<SplitLine>, BorderError> {
-        if column > self.count_columns {
-            return Err(BorderError::WrongColumnIndex);
-        }
-
-        if !self.horizontal.contains_key(&column) {
-            return Ok(None);
-        }
-
-        let symbols = self.vertical.get(&column).unwrap();
-        assert_eq!(symbols.len(), self.count_rows);
-
-        let mut borders = Vec::new();
-        for &c in symbols {
-            borders.push(c);
-        }
-
-        let mut intersections = Vec::new();
-        for row in 0..self.count_rows {
-            if let Some(&c) = self.intersections.get(&(row, column)) {
-                intersections.push(c)
-            }
-        }
-
-        Ok(Some(SplitLine::new(borders, intersections)))
-    }
-
     fn get_row(&self, row: usize) -> Result<Vec<BorderLine>, BorderError> {
         if row > self.count_rows {
             return Err(BorderError::WrongRowIndex);
@@ -1295,14 +1249,10 @@ impl Borders {
             return Ok(Vec::new());
         }
 
-        let symbols = self.horizontal.get(&row).unwrap();
-
-        assert_eq!(symbols.len(), self.count_columns);
-
-        let mut line = Vec::new();
-        for &main in symbols {
+        let mut line = Vec::with_capacity(self.count_columns);
+        for column in 0..self.count_columns {
             let border = BorderLine {
-                main: Some(main),
+                main: Some(self.get_horizontal_char(row, column).unwrap()),
                 connector1: None,
                 connector2: None,
             };
@@ -1311,13 +1261,8 @@ impl Borders {
         }
 
         for (column, border) in line.iter_mut().enumerate() {
-            if let Some(connector) = self.intersections.get(&(row, column)).cloned() {
-                border.connector1 = Some(connector);
-            }
-
-            if let Some(connector) = self.intersections.get(&(row, column + 1)).cloned() {
-                border.connector2 = Some(connector);
-            }
+            border.connector1 = self.get_intersection_char((row, column));
+            border.connector2 = self.get_intersection_char((row, column + 1));
         }
 
         Ok(line)
@@ -1331,20 +1276,17 @@ impl Borders {
         let mut line: Vec<BorderLine> = Vec::new();
         let mut last_index = None;
         for column in 0..self.count_columns + 1 {
-            let mut border = BorderLine::default();
-
-            if let Some(symbols) = self.vertical.get(&column) {
-                assert_eq!(symbols.len(), self.count_rows);
-
-                let c = symbols[row];
-                border.connector1 = Some(c);
+            let border = BorderLine {
+                connector1: self.get_vertical_char(row, column),
+                ..Default::default()
+            };
 
+            if border.connector1.is_some() {
                 if let Some(last) = last_index {
                     let mut last: &mut BorderLine = &mut line[last];
-                    last.connector2 = Some(c);
+                    last.connector2 = border.connector1;
                 }
             }
-
             last_index = Some(line.len());
 
             line.push(border);
@@ -1361,48 +1303,42 @@ impl Borders {
             return None;
         }
 
-        let [top_left, top_right, bottom_left, bottom_right] = entity_corners(
+        let frame = entity_frame(
             &Entity::Cell(row, column),
             self.count_rows,
             self.count_columns,
         );
 
-        let mut border = Border::default();
-
-        if let Some(top_line) = self.horizontal.get(&top_left.0) {
-            assert_eq!(top_line.len(), self.count_columns);
-            border.top = Some(top_line[column]);
-        }
-
-        if let Some(bottom_line) = self.horizontal.get(&bottom_left.0) {
-            assert_eq!(bottom_line.len(), self.count_columns);
-            border.bottom = Some(bottom_line[column]);
-        }
+        let border = Border {
+            top: self.get_horizontal_char(frame.top_row, column),
+            bottom: self.get_horizontal_char(frame.bottom_row, column),
+            left: self.get_vertical_char(row, frame.left_column),
+            right: self.get_vertical_char(row, frame.right_column),
+            left_top_corner: self.get_intersection_char(frame.top_left_corner()),
+            left_bottom_corner: self.get_intersection_char(frame.bottom_left_corner()),
+            right_top_corner: self.get_intersection_char(frame.top_right_corner()),
+            right_bottom_corner: self.get_intersection_char(frame.bottom_right_corner()),
+        };
 
-        if let Some(left) = self.vertical.get(&top_left.1) {
-            assert_eq!(left.len(), self.count_rows);
-            border.left = Some(left[row]);
-        }
+        Some(border)
+    }
 
-        if let Some(right) = self.vertical.get(&top_right.1) {
-            assert_eq!(right.len(), self.count_rows);
-            border.right = Some(right[row]);
-        }
+    fn get_horizontal_char(&self, row: usize, column: usize) -> Option<char> {
+        self.horizontal.get(&row).map(|line| {
+            assert_eq!(line.len(), self.count_columns);
+            line[column]
+        })
+    }
 
-        if let Some(&c) = self.intersections.get(&top_left) {
-            border.left_top_corner = Some(c);
-        }
-        if let Some(&c) = self.intersections.get(&top_right) {
-            border.right_top_corner = Some(c);
-        }
-        if let Some(&c) = self.intersections.get(&bottom_left) {
-            border.left_bottom_corner = Some(c);
-        }
-        if let Some(&c) = self.intersections.get(&bottom_right) {
-            border.right_bottom_corner = Some(c);
-        }
+    fn get_vertical_char(&self, row: usize, column: usize) -> Option<char> {
+        self.vertical.get(&column).map(|line| {
+            assert_eq!(line.len(), self.count_rows);
+            line[row]
+        })
+    }
 
-        Some(border)
+    fn get_intersection_char(&self, (row, column): GridPosition) -> Option<char> {
+        self.intersections.get(&(row, column)).copied()
     }
 
     fn set_horizontal(
@@ -1565,31 +1501,12 @@ enum BorderError {
     NotEnoughIntersections { expected: usize, got: usize },
 }
 
-fn entity_corners(entity: &Entity, count_rows: usize, count_columns: usize) -> [GridPosition; 4] {
-    // why we bound to self.count_columns() && self.count_rows() but not the one +1
-    // because we do this operation later
-    //
-    // todo: refactoring
+fn entity_frame(entity: &Entity, count_rows: usize, count_columns: usize) -> EntityFrame {
     match entity {
-        Entity::Global => [
-            (0, 0),
-            (0, count_columns),
-            (count_rows, 0),
-            (count_rows, count_columns),
-        ],
-        &Entity::Column(c) => [(0, c), (0, c + 1), (count_rows, c), (count_rows, c + 1)],
-        &Entity::Row(r) => [
-            (r, 0),
-            (r, count_columns),
-            (r + 1, 0),
-            (r + 1, count_columns),
-        ],
-        &Entity::Cell(row, column) => [
-            (row, column),
-            (row, column + 1),
-            (row + 1, column),
-            (row + 1, column + 1),
-        ],
+        Entity::Global => EntityFrame::new(0, count_columns, 0, count_rows),
+        &Entity::Column(c) => EntityFrame::new(c, c + 1, 0, count_rows),
+        &Entity::Row(r) => EntityFrame::new(0, count_columns, r, r + 1),
+        &Entity::Cell(r, c) => EntityFrame::new(c, c + 1, r, r + 1),
     }
 }
 
diff --git a/src/alignment.rs b/src/alignment.rs
index 86ac33d..83be2e7 100644
--- a/src/alignment.rs
+++ b/src/alignment.rs
@@ -1,9 +1,9 @@
 use crate::CellOption;
-#[allow(unused)]
-use crate::Table;
-use papergrid::{AlignmentHorizontal, AlignmentVertical, Entity, Grid, Settings};
+use papergrid::{Entity, Grid, Settings};
 
-/// Alignment represent a horizontal and vertical alignemt setting for any cell on a [Table].
+pub use papergrid::{AlignmentHorizontal, AlignmentVertical};
+
+/// Alignment represent a horizontal and vertical alignemt setting for any cell on a [crate::Table].
 ///
 /// ```rust,no_run
 ///   # use tabled::{Style, Alignment, Modify, Row, Table};
diff --git a/src/highlight.rs b/src/highlight.rs
new file mode 100644
index 0000000..5a772e8
--- /dev/null
+++ b/src/highlight.rs
@@ -0,0 +1,133 @@
+#[allow(unused)]
+use crate::Table;
+use crate::TableOption;
+use papergrid::{Entity, Grid, Settings};
+
+pub use papergrid::Border;
+
+pub struct Highlight {
+    target: Target,
+    border: Border,
+}
+
+impl Highlight {
+    pub fn frame(border: Border) -> Self {
+        Self::new(Target::Frame, border)
+    }
+
+    pub fn cell(row: usize, column: usize, border: Border) -> Self {
+        Self::new(Target::Cell { row, column }, border)
+    }
+
+    pub fn row(row: usize, border: Border) -> Self {
+        Self::row_range(row, row + 1, border)
+    }
+
+    pub fn row_range(start: usize, end: usize, border: Border) -> Self {
+        assert!(end > start);
+        Self::new(
+            Target::Row {
+                from: start,
+                to: end,
+            },
+            border,
+        )
+    }
+
+    pub fn column(column: usize, border: Border) -> Self {
+        Self::column_range(column, column + 1, border)
+    }
+
+    pub fn column_range(start: usize, end: usize, border: Border) -> Self {
+        assert!(end > start);
+        Self::new(
+            Target::Column {
+                from: start,
+                to: end,
+            },
+            border,
+        )
+    }
+
+    fn new(target: Target, border: Border) -> Self {
+        Self { target, border }
+    }
+}
+
+pub enum Target {
+    Cell { row: usize, column: usize },
+    Row { from: usize, to: usize },
+    Column { from: usize, to: usize },
+    Frame,
+}
+
+impl TableOption for Highlight {
+    fn change(&mut self, grid: &mut Grid) {
+        match self.target {
+            Target::Cell { row, column } => {
+                let settings = Settings::default()
+                    .border(self.border.clone())
+                    .border_restriction(false);
+                grid.set(&Entity::Cell(row, column), settings);
+            }
+            Target::Frame => {
+                let settings = Settings::default()
+                    .border(self.border.clone())
+                    .border_restriction(false);
+                grid.set(&Entity::Global, settings);
+            }
+            Target::Row { from, to } => {
+                if to == from + 1 {
+                    let settings = Settings::default()
+                        .border(self.border.clone())
+                        .border_restriction(false);
+                    grid.set(&Entity::Row(from), settings);
+                } else {
+                    for row in from..to {
+                        let mut border = self.border.clone();
+
+                        let is_first_row = row == from;
+                        let is_last_row = row + 1 == to;
+
+                        if !is_first_row {
+                            border.top = None;
+                        }
+
+                        if !is_last_row {
+                            border.bottom = None;
+                        }
+
+                        let settings = Settings::default().border(border).border_restriction(false);
+                        grid.set(&Entity::Row(row), settings);
+                    }
+                }
+            }
+            Target::Column { from, to } => {
+                if to == from + 1 {
+                    let settings = Settings::default()
+                        .border(self.border.clone())
+                        .border_restriction(false);
+                    grid.set(&Entity::Column(from), settings);
+                } else {
+                    for column in from..to {
+                        let mut border = self.border.clone();
+
+                        let is_first_column = column == from;
+                        let is_last_column = column + 1 == to;
+
+                        if !is_first_column {
+                            border.left = None;
+                        }
+
+                        if !is_last_column {
+                            border.right = None;
+                        }
+
+                        let settings = Settings::default().border(border).border_restriction(false);
+                        grid.set(&Entity::Column(column), settings);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 8901db3..1cbb126 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -141,13 +141,14 @@
 //! [README.md](https://github.com/zhiburt/tabled/blob/master/README.md)
 //!
 
-use papergrid::{AlignmentHorizontal, Entity, Grid, Settings};
+use papergrid::{Entity, Grid, Settings};
 use std::fmt;
 
 mod alignment;
 mod disable;
 pub mod display;
 mod formating;
+mod highlight;
 mod indent;
 mod object;
 mod panel;
@@ -156,12 +157,14 @@ pub mod style;
 mod width;
 
 pub use crate::{
-    alignment::*, disable::*, formating::*, indent::*, object::*, panel::*, rotate::*,
-    style::Style, width::*,
+    alignment::*, disable::*, formating::*, highlight::*, indent::*, object::*, panel::*,
+    rotate::*, style::Style, width::*,
 };
-pub use papergrid;
+
 pub use tabled_derive::Tabled;
 
+// todo: change return type to impl Iterator<Cow<str
+
 /// Tabled a trait responsible for providing a header fields and a row fields.
 ///
 /// It's urgent that `header` len is equal to `fields` len.
@@ -246,7 +249,7 @@ impl Table {
         let grid = build_grid(iter);
 
         let table = Self { grid };
-        table.with(Style::default())
+        table.with(Style::ascii())
     }
 
     /// With is a generic function which applies options to the [Table].
diff --git a/src/rotate.rs b/src/rotate.rs
index d0341ce..e542b44 100644
--- a/src/rotate.rs
+++ b/src/rotate.rs
@@ -66,214 +66,3 @@ impl TableOption for Rotate {
         }
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_rotate() {
-        let table = || Table::new([(123, 456, 789), (234, 567, 891)]);
-
-        assert_eq!(
-            table()
-                .with(Rotate::Left)
-                .with(Rotate::Left)
-                .with(Rotate::Left)
-                .with(Rotate::Left)
-                .to_string(),
-            table().to_string()
-        );
-        assert_eq!(
-            table()
-                .with(Rotate::Right)
-                .with(Rotate::Right)
-                .with(Rotate::Right)
-                .with(Rotate::Right)
-                .to_string(),
-            table().to_string()
-        );
-        assert_eq!(
-            table().with(Rotate::Right).with(Rotate::Left).to_string(),
-            table().to_string()
-        );
-        assert_eq!(
-            table().with(Rotate::Left).with(Rotate::Right).to_string(),
-            table().to_string()
-        );
-        assert_eq!(
-            table().with(Rotate::Bottom).with(Rotate::Top).to_string(),
-            table().to_string()
-        );
-        assert_eq!(
-            table()
-                .with(Rotate::Bottom)
-                .with(Rotate::Bottom)
-                .to_string(),
-            table().to_string()
-        );
-        assert_eq!(
-            table().with(Rotate::Top).with(Rotate::Top).to_string(),
-            table().to_string()
-        );
-    }
-
-    #[test]
-    fn test_3x3_box() {
-        let table = Table::new([(123, 456, 789), (234, 567, 891)]);
-        assert_eq!(
-            table.to_string(),
-            "+-----+-----+-----+\n\
-             | i32 | i32 | i32 |\n\
-             +-----+-----+-----+\n\
-             | 123 | 456 | 789 |\n\
-             +-----+-----+-----+\n\
-             | 234 | 567 | 891 |\n\
-             +-----+-----+-----+\n"
-        );
-
-        let table = table.with(Rotate::Left);
-        assert_eq!(
-            table.to_string(),
-            "+-----+-----+-----+\n\
-             | i32 | 789 | 891 |\n\
-             +-----+-----+-----+\n\
-             | i32 | 456 | 567 |\n\
-             +-----+-----+-----+\n\
-             | i32 | 123 | 234 |\n\
-             +-----+-----+-----+\n"
-        );
-
-        let table = table.with(Rotate::Right).with(Rotate::Right);
-        assert_eq!(
-            table.to_string(),
-            "+-----+-----+-----+\n\
-             | 234 | 123 | i32 |\n\
-             +-----+-----+-----+\n\
-             | 567 | 456 | i32 |\n\
-             +-----+-----+-----+\n\
-             | 891 | 789 | i32 |\n\
-             +-----+-----+-----+\n"
-        );
-    }
-
-    #[test]
-    fn test_left_rotate() {
-        let table = Table::new([(123, 456, 789), (234, 567, 891), (111, 222, 333)]);
-        assert_eq!(
-            table.to_string(),
-            "+-----+-----+-----+\n\
-             | i32 | i32 | i32 |\n\
-             +-----+-----+-----+\n\
-             | 123 | 456 | 789 |\n\
-             +-----+-----+-----+\n\
-             | 234 | 567 | 891 |\n\
-             +-----+-----+-----+\n\
-             | 111 | 222 | 333 |\n\
-             +-----+-----+-----+\n"
-        );
-
-        let table = table.with(Rotate::Left);
-        assert_eq!(
-            table.to_string(),
-            "+-----+-----+-----+-----+\n\
-             | i32 | 789 | 891 | 333 |\n\
-             +-----+-----+-----+-----+\n\
-             | i32 | 456 | 567 | 222 |\n\
-             +-----+-----+-----+-----+\n\
-             | i32 | 123 | 234 | 111 |\n\
-             +-----+-----+-----+-----+\n"
-        );
-    }
-
-    #[test]
-    fn test_right_rotate() {
-        let table = Table::new([(123, 456, 789), (234, 567, 891), (111, 222, 333)]);
-        assert_eq!(
-            table.to_string(),
-            "+-----+-----+-----+\n\
-             | i32 | i32 | i32 |\n\
-             +-----+-----+-----+\n\
-             | 123 | 456 | 789 |\n\
-             +-----+-----+-----+\n\
-             | 234 | 567 | 891 |\n\
-             +-----+-----+-----+\n\
-             | 111 | 222 | 333 |\n\
-             +-----+-----+-----+\n"
-        );
-
-        let table = table.with(Rotate::Right);
-        assert_eq!(
-            table.to_string(),
-            "+-----+-----+-----+-----+\n\
-             | 111 | 234 | 123 | i32 |\n\
-             +-----+-----+-----+-----+\n\
-             | 222 | 567 | 456 | i32 |\n\
-             +-----+-----+-----+-----+\n\
-             | 333 | 891 | 789 | i32 |\n\
-             +-----+-----+-----+-----+\n"
-        );
-    }
-
-    #[test]
-    fn test_bottom_rotate() {
-        let table = Table::new([(123, 456, 789), (234, 567, 891), (111, 222, 333)]);
-        assert_eq!(
-            table.to_string(),
-            "+-----+-----+-----+\n\
-             | i32 | i32 | i32 |\n\
-             +-----+-----+-----+\n\
-             | 123 | 456 | 789 |\n\
-             +-----+-----+-----+\n\
-             | 234 | 567 | 891 |\n\
-             +-----+-----+-----+\n\
-             | 111 | 222 | 333 |\n\
-             +-----+-----+-----+\n"
-        );
-
-        let table = table.with(Rotate::Bottom);
-        assert_eq!(
-            table.to_string(),
-            "+-----+-----+-----+\n\
-             | 111 | 222 | 333 |\n\
-             +-----+-----+-----+\n\
-             | 234 | 567 | 891 |\n\
-             +-----+-----+-----+\n\
-             | 123 | 456 | 789 |\n\
-             +-----+-----+-----+\n\
-             | i32 | i32 | i32 |\n\
-             +-----+-----+-----+\n"
-        );
-    }
-
-    #[test]
-    fn test_top_rotate() {
-        let table = Table::new([(123, 456, 789), (234, 567, 891), (111, 222, 333)]);
-        assert_eq!(
-            table.to_string(),
-            "+-----+-----+-----+\n\
-             | i32 | i32 | i32 |\n\
-             +-----+-----+-----+\n\
-             | 123 | 456 | 789 |\n\
-             +-----+-----+-----+\n\
-             | 234 | 567 | 891 |\n\
-             +-----+-----+-----+\n\
-             | 111 | 222 | 333 |\n\
-             +-----+-----+-----+\n"
-        );
-
-        let table = table.with(Rotate::Top);
-        assert_eq!(
-            table.to_string(),
-            "+-----+-----+-----+\n\
-             | 111 | 222 | 333 |\n\
-             +-----+-----+-----+\n\
-             | 234 | 567 | 891 |\n\
-             +-----+-----+-----+\n\
-             | 123 | 456 | 789 |\n\
-             +-----+-----+-----+\n\
-             | i32 | i32 | i32 |\n\
-             +-----+-----+-----+\n"
-        );
-    }
-}
diff --git a/src/style.rs b/src/style.rs
index 073881b..271a55e 100644
--- a/src/style.rs
+++ b/src/style.rs
@@ -25,7 +25,6 @@ pub struct Style {
     header_split_line: Option<Line>,
     split: Option<Line>,
     inner_split_char: char,
-    highlight: Vec<(Entity, Border)>,
 }
 
 impl Style {
@@ -42,7 +41,25 @@ impl Style {
     ///     | 3  | Endeavouros  | https://endeavouros.com/  |
     ///     +----+--------------+---------------------------+
     /// ```
+    #[deprecated(note = "The name is not explicit. Use ascii function instead.")]
     pub fn default() -> Self {
+        Self::ascii()
+    }
+
+    /// Ascii style looks like the following table
+    ///
+    /// ```text
+    ///     +----+--------------+---------------------------+
+    ///     | id | destribution |           link            |
+    ///     +----+--------------+---------------------------+
+    ///     | 0  |    Fedora    |  https://getfedora.org/   |
+    ///     +----+--------------+---------------------------+
+    ///     | 2  |   OpenSUSE   | https://www.opensuse.org/ |
+    ///     +----+--------------+---------------------------+
+    ///     | 3  | Endeavouros  | https://endeavouros.com/  |
+    ///     +----+--------------+---------------------------+
+    /// ```
+    pub fn ascii() -> Self {
         let line = Line::bordered('-', '+', '+', '+');
 
         Self::new(
@@ -197,20 +214,12 @@ impl Style {
         self
     }
 
-    /// Add highlight for a given cell.
-    pub fn highlight(mut self, entity: Entity, border: Border) -> Self {
-        // suppose to be LeftToRight algorithm
-        self.highlight.push((entity, border));
-        self
-    }
-
     fn new(frame: Frame, header: Option<Line>, split: Option<Line>, inner: char) -> Self {
         Self {
             frame,
             split,
             header_split_line: header,
             inner_split_char: inner,
-            highlight: Vec::new(),
         }
     }
 }
@@ -275,15 +284,6 @@ impl TableOption for Style {
                 );
             }
         }
-
-        for (entity, brush) in &self.highlight {
-            grid.set(
-                entity,
-                Settings::default()
-                    .border(brush.clone())
-                    .border_restriction(false),
-            );
-        }
     }
 }
 
diff --git a/tabled_derive/src/lib.rs b/tabled_derive/src/lib.rs
index edbb6d3..8bcbe51 100644
--- a/tabled_derive/src/lib.rs
+++ b/tabled_derive/src/lib.rs
@@ -1,6 +1,6 @@
 extern crate proc_macro;
 
-use proc_macro::TokenStream;
+use proc_macro2::TokenStream;
 use quote::*;
 use std::str;
 use syn::{
@@ -9,19 +9,19 @@ use syn::{
 };
 
 #[proc_macro_derive(Tabled, attributes(header, field))]
-pub fn tabled(input: TokenStream) -> TokenStream {
+pub fn tabled(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
     let input = parse_macro_input!(input as DeriveInput);
-    impl_tabled(&input)
+    let ast = impl_tabled(&input);
+    proc_macro::TokenStream::from(ast)
 }
 
 fn impl_tabled(ast: &DeriveInput) -> TokenStream {
-    let attributes = data_attributes(&ast.data);
-    let headers = get_headers(&ast.data, &attributes);
-    let fields = get_fields(&ast.data, &attributes);
+    let info = collect_info(ast).unwrap();
+    let fields = info.values;
+    let headers = info.headers;
 
     let name = &ast.ident;
     let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
-
     let expanded = quote! {
         impl #impl_generics Tabled for #name #ty_generics #where_clause {
             fn fields(&self) -> Vec<String> {
@@ -34,150 +34,144 @@ fn impl_tabled(ast: &DeriveInput) -> TokenStream {
         }
     };
 
-    TokenStream::from(expanded)
+    expanded
 }
 
-fn get_headers(d: &Data, attrs: &[Attr]) -> proc_macro2::TokenStream {
-    let headers = match d {
-        Data::Struct(st) => get_st_headers(st, attrs),
-        Data::Enum(e) => get_enum_headers(e, attrs).concat(),
-        Data::Union(_) => todo!("it's not clear how to handle union type"),
-    };
-
-    quote!({
-        let v: Vec<Vec<String>> = vec![
-            #(#headers,)*
-        ];
+fn collect_info(ast: &DeriveInput) -> Result<Impl, String> {
+    match &ast.data {
+        Data::Struct(data) => collect_info_struct(data),
+        Data::Enum(data) => collect_info_enum(data),
+        Data::Union(_) => Err("Union type isn't supported".to_owned()),
+    }
+}
 
-        v.concat()
-    })
+fn collect_info_struct(ast: &DataStruct) -> Result<Impl, String> {
+    info_from_fields(&ast.fields, field_var_name, "")
 }
 
-fn data_attributes(d: &Data) -> Vec<Attr> {
-    let attrs_of_fields: Vec<&[Attribute]> = match d {
-        Data::Struct(st) => st.fields.iter().map(|f| f.attrs.as_slice()).collect(),
-        Data::Enum(e) => e.variants.iter().map(|v| v.attrs.as_slice()).collect(),
-        Data::Union(_) => todo!("it's not clear how to handle union type"),
-    };
+// todo: refactoring. instead of using a lambda + prefix
+// we could just not emit `self.` `_x` inside
+// So the calle would prefix it on its own
+fn info_from_fields(
+    fields: &Fields,
+    field_name: impl Fn(usize, &Field) -> TokenStream,
+    header_prefix: &str,
+) -> Result<Impl, String> {
+    let fields = fields.into_iter().enumerate().map(|(i, field)| {
+        let attributes = Attributes::parse(&field.attrs);
+        (i, field, attributes)
+    });
 
-    attrs_of_fields
-        .into_iter()
-        .map(|attrs| Attr::parse(attrs))
-        .collect()
-}
+    let mut headers = Vec::new();
+    let mut values = Vec::new();
 
-fn get_st_headers(st: &DataStruct, attrs: &[Attr]) -> Vec<proc_macro2::TokenStream> {
-    st.fields
-        .iter()
-        .enumerate()
-        .filter(|(i, _)| !attrs[*i].is_ignored())
-        .map(|(i, f)| field_headers(f, &attrs[i], i, ""))
-        .collect()
+    for (i, field, attributes) in fields {
+        if attributes.is_ignored() {
+            continue;
+        }
+
+        let header = field_headers(field, i, &attributes, header_prefix);
+
+        headers.push(header);
+
+        let field_name = field_name(i, field);
+        let value = get_field_fields(field_name, &attributes);
+
+        values.push(value);
+    }
+
+    let headers = quote!({
+        let mut out = Vec::new();
+        #(out.extend(#headers);)*
+        out
+    });
+
+    let values = quote!({
+        let mut out = Vec::new();
+        #(out.extend(#values);)*
+        out
+    });
+
+    Ok(Impl { headers, values })
 }
 
 fn field_headers(
     field: &Field,
-    attr: &Attr,
     index: usize,
+    attributes: &Attributes,
     prefix: &str,
-) -> proc_macro2::TokenStream {
-    if attr.inline {
-        inline_header(&field.ty, attr, prefix)
+) -> TokenStream {
+    if attributes.inline {
+        return get_type_headers(&field.ty, &attributes.inline_prefix, "");
+    }
+
+    let header_name = field_header_name(field, attributes, index);
+    if !prefix.is_empty() {
+        quote!(vec![format!("{}{}", #prefix, #header_name)])
     } else {
-        let header = field_header_name(field, attr, index);
-        if !prefix.is_empty() {
-            quote!(vec![format!("{}{}", #prefix, #header)])
-        } else {
-            quote!(vec![String::from(#header)])
-        }
+        quote!(vec![String::from(#header_name)])
     }
 }
 
-fn inline_header(t: &Type, attr: &Attr, prefix: &str) -> proc_macro2::TokenStream {
-    let inline_prefix = &attr.inline_prefix;
-    if inline_prefix.is_empty() && prefix.is_empty() {
-        quote! {
-            <#t as Tabled>::headers()
-        }
-    } else {
-        quote! {
-            <#t as Tabled>::headers().into_iter()
-                .map(|header| format!("{}{}{}", #prefix, #inline_prefix, header))
-                .collect::<Vec<_>>()
+fn collect_info_enum(ast: &DataEnum) -> Result<Impl, String> {
+    let mut variants = Vec::new();
+    for variant in &ast.variants {
+        let attributes = Attributes::parse(&variant.attrs);
+        if attributes.is_ignored() {
+            continue;
         }
+
+        let info = info_from_variant(variant, &attributes)?;
+        variants.push((variant, info));
     }
-}
 
-fn get_enum_headers(e: &DataEnum, attrs: &[Attr]) -> Vec<Vec<proc_macro2::TokenStream>> {
-    e.variants
-        .iter()
-        .enumerate()
-        .filter(|(i, _)| !attrs[*i].is_ignored())
-        .map(|(i, v)| variant_headers(v, &attrs[i]))
-        .collect::<Vec<_>>()
+    let headers_list = variants.iter().map(|(_, i)| &i.headers).collect::<Vec<_>>();
+    let headers = quote! {
+        vec![
+            #(#headers_list,)*
+        ]
+        .concat()
+    };
+
+    let values = values_for_enum(variants);
+
+    Ok(Impl { headers, values })
 }
 
-fn variant_headers(variant: &Variant, attr: &Attr) -> Vec<proc_macro2::TokenStream> {
-    if attr.inline {
-        let prefix = &attr.inline_prefix;
+fn info_from_variant(variant: &Variant, attributes: &Attributes) -> Result<Impl, String> {
+    if attributes.inline {
+        return info_from_fields(&variant.fields, variant_var_name, &attributes.inline_prefix);
+    }
 
-        let mut calls = Vec::new();
-        for (index, field) in variant.fields.iter().enumerate() {
-            let field_attr = Attr::parse(&field.attrs);
-            if field_attr.is_ignored() {
-                continue;
-            }
+    let variant_name = variant_name(variant, attributes);
+    let value = "+";
 
-            let call = field_headers(field, &field_attr, index, prefix);
-            calls.push(call);
-        }
+    // we need exactly string because of it must be inlined as string
+    let headers = quote! {vec![#variant_name.to_string()]};
+    // we need exactly string because of it must be inlined as string
+    let values = quote! {vec![#value.to_string()]};
 
-        calls
-    } else {
-        let header = attr
-            .name
-            .clone()
-            .unwrap_or_else(|| variant.ident.to_string());
-        vec![quote!(vec![String::from(#header)])]
-    }
+    Ok(Impl { headers, values })
 }
 
-fn get_fields(d: &Data, attrs: &[Attr]) -> proc_macro2::TokenStream {
-    match d {
-        Data::Struct(st) => {
-            let fields = get_st_fields(st, attrs);
-            quote! {
-                {
-                    let v: Vec<Vec<String>> = vec![
-                        #(#fields,)*
-                    ];
-
-                    v.concat()
-                }
-            }
-        }
-        Data::Enum(e) => get_enum_fields(e, attrs),
-        Data::Union(_) => todo!("it's not clear how to handle union type"),
-    }
+struct Impl {
+    headers: TokenStream,
+    values: TokenStream,
 }
 
-fn get_st_fields(st: &DataStruct, attrs: &[Attr]) -> Vec<proc_macro2::TokenStream> {
-    let mut v = Vec::new();
-    for (i, field) in st.fields.iter().enumerate() {
-        if attrs[i].is_ignored() {
-            continue;
+fn get_type_headers(field_type: &Type, inline_prefix: &str, prefix: &str) -> TokenStream {
+    if prefix.is_empty() && inline_prefix.is_empty() {
+        quote! { <#field_type as Tabled>::headers() }
+    } else {
+        quote! {
+            <#field_type as Tabled>::headers().into_iter()
+                .map(|header| format!("{}{}{}", #prefix, #inline_prefix, header))
+                .collect::<Vec<_>>()
         }
-
-        let field_var = field_var_name(field, i);
-        let fields = get_field_fields(field_var, &attrs[i]);
-
-        v.push(fields);
     }
-
-    v
 }
 
-fn get_field_fields(field: proc_macro2::TokenStream, attr: &Attr) -> proc_macro2::TokenStream {
+fn get_field_fields(field: TokenStream, attr: &Attributes) -> TokenStream {
     if attr.inline {
         return quote! { #field.fields() };
     }
@@ -190,7 +184,7 @@ fn get_field_fields(field: proc_macro2::TokenStream, attr: &Attr) -> proc_macro2
     quote!(vec![format!("{}", #field)])
 }
 
-fn use_function_for(field: proc_macro2::TokenStream, function: &str) -> proc_macro2::TokenStream {
+fn use_function_for(field: TokenStream, function: &str) -> TokenStream {
     let path: syn::Result<syn::ExprPath> = syn::parse_str(function);
     match path {
         Ok(path) => {
@@ -203,53 +197,44 @@ fn use_function_for(field: proc_macro2::TokenStream, function: &str) -> proc_mac
     }
 }
 
-fn field_var_name(field: &Field, index: usize) -> proc_macro2::TokenStream {
-    field.ident.as_ref().map_or_else(
-        || {
-            let mut s = quote!(self.);
-            s.extend(Index::from(index).to_token_stream());
-            s
-        },
-        |f| quote!(self.#f),
-    )
+fn field_var_name(index: usize, field: &Field) -> TokenStream {
+    let f = field.ident.as_ref().map_or_else(
+        || Index::from(index).to_token_stream(),
+        |i| i.to_token_stream(),
+    );
+    quote!(self.#f)
 }
 
-fn get_enum_fields(e: &DataEnum, attrs: &[Attr]) -> proc_macro2::TokenStream {
-    let fields = e
-        .variants
+fn variant_var_name(index: usize, field: &Field) -> TokenStream {
+    match &field.ident {
+        Some(indent) => indent.to_token_stream(),
+        None => Ident::new(
+            format!("x_{}", index).as_str(),
+            proc_macro2::Span::call_site(),
+        )
+        .to_token_stream(),
+    }
+}
+
+fn values_for_enum(variants: Vec<(&Variant, Impl)>) -> TokenStream {
+    let branches = variants.iter().map(|(variant, _)| match_variant(variant));
+
+    let headers = variants
         .iter()
-        .enumerate()
-        .filter(|(i, _)| !attrs[*i].is_ignored())
-        .map(|(i, v)| variant_fields(v, &attrs[i]))
+        .map(|(_, info)| &info.headers)
         .collect::<Vec<_>>();
 
-    let branches = e
-        .variants
+    let fields = variants
         .iter()
-        .enumerate()
-        .filter(|(i, _)| !attrs[*i].is_ignored())
-        .map(|(i, v)| variant_match_branches(v, &attrs[i]))
+        .map(|(_, info)| &info.values)
         .collect::<Vec<_>>();
 
-    assert_eq!(branches.len(), fields.len());
-
-    let headers = get_enum_headers(e, attrs)
-        .into_iter()
-        .map(|headers| {
-            quote! {
-                vec![
-                    #(#headers,)*
-                ]
-            }
-        })
-        .collect::<Vec<proc_macro2::TokenStream>>();
-
-    let mut stream = proc_macro2::TokenStream::new();
+    let mut stream = TokenStream::new();
     for (i, (branch, fields)) in branches.into_iter().zip(fields).enumerate() {
         let branch = quote! {
             Self::#branch => {
                 let offset = offsets[#i];
-                let fields: Vec<String> = vec![#(#fields),*].concat();
+                let fields: Vec<String> = #fields;
 
                 for (i, field) in fields.into_iter().enumerate() {
                     out_vec[i+offset] = field;
@@ -268,8 +253,8 @@ fn get_enum_fields(e: &DataEnum, attrs: &[Attr]) -> proc_macro2::TokenStream {
         //
         // It's a bit strange trick but I haven't found any better
         // how to calculate a size and offset.
-        let headers: Vec<Vec<Vec<String>>> = vec![#(#headers,)*];
-        let lengths = headers.iter().map(|values| values.iter().map(|values| values.len()).sum::<usize>()).collect::<Vec<_>>();
+        let headers: Vec<Vec<String>> = vec![#(#headers,)*];
+        let lengths = headers.iter().map(|values| values.len()).collect::<Vec<_>>();
         let size = lengths.iter().sum::<usize>();
         let offsets: Vec<usize> = lengths.iter().fold(Vec::new(), |mut acc, len| {
             // offset of 1 element is 0
@@ -294,65 +279,31 @@ fn get_enum_fields(e: &DataEnum, attrs: &[Attr]) -> proc_macro2::TokenStream {
     }
 }
 
-fn variant_fields(v: &Variant, attr: &Attr) -> Vec<proc_macro2::TokenStream> {
-    if !attr.inline {
-        return vec![quote!(vec!["+".to_string()])];
-    }
-
-    let branch_idents = variant_idents(v);
-    if branch_idents.is_empty() {
-        return vec![quote!(vec!["+".to_string()])];
-    }
-
-    branch_idents
-        .into_iter()
-        .zip(v.fields.iter().map(|field| Attr::parse(&field.attrs)))
-        .filter(|(_, attr)| !attr.is_ignored())
-        .map(|(ident, attr)| get_field_fields(ident.to_token_stream(), &attr))
-        .collect()
-}
-
-fn variant_idents(v: &Variant) -> Vec<Ident> {
+fn variant_idents(v: &Variant) -> Vec<TokenStream> {
     v.fields
         .iter()
         .enumerate()
         // we intentionally not ignore these fields to be able to build a pattern correctly
         // .filter(|(_, field)| !Attr::parse(&field.attrs).is_ignored())
-        .map(|(index, field)| {
-            if let Some(ident) = field.ident.as_ref() {
-                ident.clone()
-            } else {
-                let tmp_var = Ident::new(
-                    format!("x_{}", index).as_str(),
-                    proc_macro2::Span::call_site(),
-                );
-
-                tmp_var
-            }
-        })
+        .map(|(index, field)| variant_var_name(index, field))
         .collect::<Vec<_>>()
 }
 
-fn variant_match_branches(v: &Variant, attr: &Attr) -> proc_macro2::TokenStream {
-    let mut token = proc_macro2::TokenStream::new();
+fn match_variant(v: &Variant) -> TokenStream {
+    let mut token = TokenStream::new();
     token.append_all(v.ident.to_token_stream());
 
-    let fields = if attr.inline {
-        let fields = variant_idents(v);
-        quote! (#(#fields, )*)
-    } else {
-        quote!(..)
-    };
+    let fields = variant_idents(v);
 
     match &v.fields {
         Fields::Named(_) => {
             token::Brace::default().surround(&mut token, |s| {
-                s.append_all(fields);
+                s.append_separated(fields, quote! {,});
             });
         }
         Fields::Unnamed(_) => {
             token::Paren::default().surround(&mut token, |s| {
-                s.append_all(fields);
+                s.append_separated(fields, quote! {,});
             });
         }
         Fields::Unit => {}
@@ -361,7 +312,14 @@ fn variant_match_branches(v: &Variant, attr: &Attr) -> proc_macro2::TokenStream
     token
 }
 
-fn field_header_name(f: &Field, attr: &Attr, index: usize) -> String {
+fn variant_name(variant: &Variant, attributes: &Attributes) -> String {
+    attributes
+        .name
+        .clone()
+        .unwrap_or_else(|| variant.ident.to_string())
+}
+
+fn field_header_name(f: &Field, attr: &Attributes, index: usize) -> String {
     match &attr.name {
         Some(name) => name.to_string(),
         None => match f.ident.as_ref() {
@@ -373,7 +331,7 @@ fn field_header_name(f: &Field, attr: &Attr, index: usize) -> String {
 
 // It would be cool to create a library for a parsing attributes
 #[derive(Debug)]
-struct Attr {
+struct Attributes {
     hidden: bool,
     inline: bool,
     inline_prefix: String,
@@ -381,7 +339,7 @@ struct Attr {
     display_with: Option<String>,
 }
 
-impl Attr {
+impl Attributes {
     fn parse(attrs: &[Attribute]) -> Self {
         let is_ignored = attrs_has_ignore_sign(attrs);
         let should_be_inlined = should_be_inlined(attrs);
@@ -389,7 +347,7 @@ impl Attr {
         let display_with = check_display_with_func(attrs);
         let override_header_name = override_header_name(attrs);
 
-        Attr {
+        Self {
             display_with,
             hidden: is_ignored,
             inline: should_be_inlined,


Test patch:
diff --git a/tests/alignment_test.rs b/tests/alignment_test.rs
index 54f977b..2e94b63 100644
--- a/tests/alignment_test.rs
+++ b/tests/alignment_test.rs
@@ -1,128 +1,67 @@
-use tabled::{Alignment, Column, Full, Head, Indent, Modify, Row, Style, Table, Tabled};
+use crate::util::create_vector;
+use tabled::{Alignment, Column, Full, Head, Indent, Modify, Row, Style, Table};
 
-#[derive(Tabled)]
-struct Linux {
-    id: u8,
-    destribution: &'static str,
-    link: &'static str,
-}
+mod util;
 
 #[test]
 fn full_alignment() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        " id | destribution | link                      \n",
-        "----+--------------+---------------------------\n",
-        " 0  | Fedora       | https://getfedora.org/    \n",
-        " 2  | OpenSUSE     | https://www.opensuse.org/ \n",
-        " 3  | Endeavouros  | https://endeavouros.com/  \n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(Modify::new(Full).with(Alignment::left()))
         .to_string();
 
+    let expected = concat!(
+        " N | column 0 | column 1 | column 2 \n",
+        "---+----------+----------+----------\n",
+        " 0 | 0-0      | 0-1      | 0-2      \n",
+        " 1 | 1-0      | 1-1      | 1-2      \n",
+        " 2 | 2-0      | 2-1      | 2-2      \n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn head_and_data_alignment() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "+----+--------------+---------------------------+\n",
-        "| id | destribution | link                      |\n",
-        "+----+--------------+---------------------------+\n",
-        "|  0 |       Fedora |    https://getfedora.org/ |\n",
-        "+----+--------------+---------------------------+\n",
-        "|  2 |     OpenSUSE | https://www.opensuse.org/ |\n",
-        "+----+--------------+---------------------------+\n",
-        "|  3 |  Endeavouros |  https://endeavouros.com/ |\n",
-        "+----+--------------+---------------------------+\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
-        .with(Style::default())
+        .with(Style::ascii())
         .with(Modify::new(Head).with(Alignment::left()))
         .with(Modify::new(Row(1..)).with(Alignment::right()))
         .to_string();
 
+    let expected = concat!(
+        "+---+----------+----------+----------+\n",
+        "| N | column 0 | column 1 | column 2 |\n",
+        "+---+----------+----------+----------+\n",
+        "| 0 |      0-0 |      0-1 |      0-2 |\n",
+        "+---+----------+----------+----------+\n",
+        "| 1 |      1-0 |      1-1 |      1-2 |\n",
+        "+---+----------+----------+----------+\n",
+        "| 2 |      2-0 |      2-1 |      2-2 |\n",
+        "+---+----------+----------+----------+\n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn full_alignment_multiline() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-        Linux {
-            id: 4,
-            destribution: "Red\nHat",
-            link: "https\n://\nwww\n.\nredhat\n.\ncom\n/en",
-        },
-    ];
+    let mut data = create_vector::<3, 3>();
+    data[2][2] = String::from("https://\nwww\n.\nredhat\n.com\n/en");
 
     let expected = concat!(
-        " id | destribution | link                      \n",
-        "----+--------------+---------------------------\n",
-        " 0  | Fedora       | https://getfedora.org/    \n",
-        " 2  | OpenSUSE     | https://www.opensuse.org/ \n",
-        " 3  | Endeavouros  | https://endeavouros.com/  \n",
-        " 4  | Red          | https                     \n",
-        "    | Hat          | ://                       \n",
-        "    |              | www                       \n",
-        "    |              | .                         \n",
-        "    |              | redhat                    \n",
-        "    |              | .                         \n",
-        "    |              | com                       \n",
-        "    |              | /en                       \n",
+        " N | column 0 | column 1 | column 2 \n",
+        "---+----------+----------+----------\n",
+        " 0 | 0-0      | 0-1      | 0-2      \n",
+        " 1 | 1-0      | 1-1      | 1-2      \n",
+        " 2 | 2-0      | https:// | 2-2      \n",
+        "   |          | www      |          \n",
+        "   |          | .        |          \n",
+        "   |          | redhat   |          \n",
+        "   |          | .com     |          \n",
+        "   |          | /en      |          \n",
     );
 
     let table = Table::new(&data)
@@ -135,28 +74,10 @@ fn full_alignment_multiline() {
 
 #[test]
 fn vertical_alignment_test() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "E\nnde\navou\nros",
-            link: "https://endeavouros.com/",
-        },
-        Linux {
-            id: 4,
-            destribution: "Red\nHat",
-            link: "https\n://\nwww\n.\nredhat\n.\ncom\n/en",
-        },
-    ];
+    let mut data = create_vector::<3, 3>();
+    data[1][2] = String::from("E\nnde\navou\nros");
+    data[2][2] = String::from("Red\nHat");
+    data[2][3] = String::from("https://\nwww\n.\nredhat\n.com\n/en");
 
     let table = Table::new(&data)
         .with(Style::psql())
@@ -164,22 +85,19 @@ fn vertical_alignment_test() {
         .to_string();
 
     let expected = concat!(
-        " id | destribution |           link            \n",
-        "----+--------------+---------------------------\n",
-        " 0  |    Fedora    |  https://getfedora.org/   \n",
-        " 2  |   OpenSUSE   | https://www.opensuse.org/ \n",
-        " 3  |      E       |                           \n",
-        "    |     nde      |                           \n",
-        "    |     avou     |                           \n",
-        "    |     ros      | https://endeavouros.com/  \n",
-        " 4  |              |           https           \n",
-        "    |              |            ://            \n",
-        "    |              |            www            \n",
-        "    |              |             .             \n",
-        "    |              |          redhat           \n",
-        "    |              |             .             \n",
-        "    |     Red      |            com            \n",
-        "    |     Hat      |            /en            \n",
+        " N | column 0 | column 1 | column 2 \n",
+        "---+----------+----------+----------\n",
+        " 0 |   0-0    |   0-1    |   0-2    \n",
+        " 1 |          |    E     |          \n",
+        "   |          |   nde    |          \n",
+        "   |          |   avou   |          \n",
+        "   |   1-0    |   ros    |   1-2    \n",
+        " 2 |          |          | https:// \n",
+        "   |          |          |   www    \n",
+        "   |          |          |    .     \n",
+        "   |          |          |  redhat  \n",
+        "   |          |   Red    |   .com   \n",
+        "   |   2-0    |   Hat    |   /en    \n",
     );
 
     assert_eq!(table, expected);
@@ -187,30 +105,14 @@ fn vertical_alignment_test() {
 
 #[test]
 fn alignment_doesnt_change_indent() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<3, 3>();
 
     let expected = concat!(
-        "   id|   destribution|   link                     \n",
-        "-----+---------------+----------------------------\n",
-        "   0 |   Fedora      |   https://getfedora.org/   \n",
-        "   2 |   OpenSUSE    |   https://www.opensuse.org/\n",
-        "   3 |   Endeavouros |   https://endeavouros.com/ \n",
+        "   N|   column 0|   column 1|   column 2\n",
+        "----+-----------+-----------+-----------\n",
+        "   0|   0-0     |   0-1     |   0-2     \n",
+        "   1|   1-0     |   1-1     |   1-2     \n",
+        "   2|   2-0     |   2-1     |   2-2     \n",
     );
 
     let table = Table::new(&data)
diff --git a/tests/disable_test.rs b/tests/disable_test.rs
index f1a9c87..39e839f 100644
--- a/tests/disable_test.rs
+++ b/tests/disable_test.rs
@@ -1,224 +1,107 @@
-use tabled::{Alignment, Disable, Full, Modify, Style, Table, Tabled};
+use crate::util::create_vector;
+use tabled::{Alignment, Disable, Full, Modify, Style, Table};
 
-#[derive(Tabled)]
-struct Linux {
-    id: u8,
-    destribution: &'static str,
-    link: &'static str,
-}
+mod util;
 
 #[test]
 fn disable_rows() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "+----+--------------+--------------------------+\n",
-        "| id | destribution | link                     |\n",
-        "+----+--------------+--------------------------+\n",
-        "| 3  | Endeavouros  | https://endeavouros.com/ |\n",
-        "+----+--------------+--------------------------+\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
-        .with(Style::default())
+        .with(Style::ascii())
         .with(Modify::new(Full).with(Alignment::left()))
         .with(Disable::Row(1..=2))
         .to_string();
 
-    println!("{}", table);
+    let expected = concat!(
+        "+---+----------+----------+----------+\n",
+        "| N | column 0 | column 1 | column 2 |\n",
+        "+---+----------+----------+----------+\n",
+        "| 2 | 2-0      | 2-1      | 2-2      |\n",
+        "+---+----------+----------+----------+\n",
+    );
 
     assert_eq!(table, expected);
 }
 
 #[test]
 fn disable_header() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "---+-------------+---------------------------\n",
-        " 0 | Fedora      | https://getfedora.org/    \n",
-        " 2 | OpenSUSE    | https://www.opensuse.org/ \n",
-        " 3 | Endeavouros | https://endeavouros.com/  \n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(Modify::new(Full).with(Alignment::left()))
         .with(Disable::Row(..1))
         .to_string();
 
-    println!("{}", table);
+    let expected = concat!(
+        "---+-----+-----+-----\n",
+        " 0 | 0-0 | 0-1 | 0-2 \n",
+        " 1 | 1-0 | 1-1 | 1-2 \n",
+        " 2 | 2-0 | 2-1 | 2-2 \n",
+    );
 
     assert_eq!(table, expected);
 }
 
 #[test]
 fn disable_all_table_via_rows() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = "";
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(Modify::new(Full).with(Alignment::left()))
         .with(Disable::Row(..))
         .to_string();
 
-    assert_eq!(table, expected);
+    assert_eq!(table, "");
 }
 
 #[test]
 fn disable_header_with_new_styling() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "┌───┬─────────────┬───────────────────────────┐\n",
-        "│ 0 │ Fedora      │ https://getfedora.org/    │\n",
-        "├───┼─────────────┼───────────────────────────┤\n",
-        "│ 2 │ OpenSUSE    │ https://www.opensuse.org/ │\n",
-        "│ 3 │ Endeavouros │ https://endeavouros.com/  │\n",
-        "└───┴─────────────┴───────────────────────────┘\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Modify::new(Full).with(Alignment::left()))
         .with(Disable::Row(..1))
         .with(Style::pseudo_clean())
         .to_string();
 
+    let expected = concat!(
+        "┌───┬─────┬─────┬─────┐\n",
+        "│ 0 │ 0-0 │ 0-1 │ 0-2 │\n",
+        "├───┼─────┼─────┼─────┤\n",
+        "│ 1 │ 1-0 │ 1-1 │ 1-2 │\n",
+        "│ 2 │ 2-0 │ 2-1 │ 2-2 │\n",
+        "└───┴─────┴─────┴─────┘\n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn disable_columns() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "| destribution | link                      \n",
-        "+--------------+---------------------------\n",
-        "| Fedora       | https://getfedora.org/    \n",
-        "| OpenSUSE     | https://www.opensuse.org/ \n",
-        "| Endeavouros  | https://endeavouros.com/  \n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
-        .with(Modify::new(Full).with(Alignment::left()))
         .with(Disable::Column(..1))
         .to_string();
 
-    println!("{}", table);
+    let expected = concat!(
+        "| column 0 | column 1 | column 2 \n",
+        "+----------+----------+----------\n",
+        "|   0-0    |   0-1    |   0-2    \n",
+        "|   1-0    |   1-1    |   1-2    \n",
+        "|   2-0    |   2-1    |   2-2    \n",
+    );
 
     assert_eq!(table, expected);
 }
 
 #[test]
 fn disable_all_table_via_columns() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = "";
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(Modify::new(Full).with(Alignment::left()))
         .with(Disable::Column(..))
         .to_string();
 
-    assert_eq!(table, expected);
+    assert_eq!(table, "");
 }
diff --git a/tests/expanded_display_test.rs b/tests/expanded_display_test.rs
index 27fc5fd..d993906 100644
--- a/tests/expanded_display_test.rs
+++ b/tests/expanded_display_test.rs
@@ -1,105 +1,71 @@
+use crate::util::create_vector;
 use tabled::{display::ExpandedDisplay, Tabled};
 
+#[cfg(feature = "color")]
+use owo_colors::{AnsiColors, OwoColorize};
+
+mod util;
+
 #[test]
 fn display() {
-    #[derive(Tabled)]
-    struct Linux {
-        id: u8,
-        destribution: &'static str,
-        link: &'static str,
-    }
-
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<3, 3>();
+    let table = ExpandedDisplay::new(&data).to_string();
 
     let expected = concat!(
-        "-[ RECORD 0 ]---------------------------\n",
-        "id           | 0\n",
-        "destribution | Fedora\n",
-        "link         | https://getfedora.org/\n",
-        "-[ RECORD 1 ]---------------------------\n",
-        "id           | 2\n",
-        "destribution | OpenSUSE\n",
-        "link         | https://www.opensuse.org/\n",
-        "-[ RECORD 2 ]---------------------------\n",
-        "id           | 3\n",
-        "destribution | Endeavouros\n",
-        "link         | https://endeavouros.com/\n",
+        "-[ RECORD 0 ]-\n",
+        "N        | 0\n",
+        "column 0 | 0-0\n",
+        "column 1 | 0-1\n",
+        "column 2 | 0-2\n",
+        "-[ RECORD 1 ]-\n",
+        "N        | 1\n",
+        "column 0 | 1-0\n",
+        "column 1 | 1-1\n",
+        "column 2 | 1-2\n",
+        "-[ RECORD 2 ]-\n",
+        "N        | 2\n",
+        "column 0 | 2-0\n",
+        "column 1 | 2-1\n",
+        "column 2 | 2-2\n",
     );
 
-    let table = ExpandedDisplay::new(&data).to_string();
-
     assert_eq!(table, expected);
 }
 
 #[cfg(feature = "color")]
 #[test]
 fn display_colored() {
-    use owo_colors::{AnsiColors, OwoColorize};
-
-    #[derive(Tabled)]
-    struct Linux {
-        id: u8,
-        destribution: &'static str,
-        link: String,
-    }
+    let mut data = create_vector::<3, 3>();
+    data[0][2] = "https://getfedora.org/"
+        .red()
+        .on_color(AnsiColors::Blue)
+        .to_string();
+    data[1][2] = "https://www.opensuse.org/"
+        .green()
+        .on_color(AnsiColors::Black)
+        .to_string();
+    data[2][2] = "https://endeavouros.com/".blue().underline().to_string();
 
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/"
-                .red()
-                .on_color(AnsiColors::Blue)
-                .to_string(),
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/"
-                .green()
-                .on_color(AnsiColors::Black)
-                .to_string(),
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/".blue().underline().to_string(),
-        },
-    ];
+    let table = ExpandedDisplay::new(&data).to_string();
 
     let expected = concat!(
-        "-[ RECORD 0 ]---------------------------\n",
-        "id           | 0\n",
-        "destribution | Fedora\n",
-        "link         | \u{1b}[44m\u{1b}[31mhttps://getfedora.org/\u{1b}[0m\u{1b}[0m\n",
-        "-[ RECORD 1 ]---------------------------\n",
-        "id           | 2\n",
-        "destribution | OpenSUSE\nlink         | \u{1b}[40m\u{1b}[32mhttps://www.opensuse.org/\u{1b}[0m\u{1b}[0m\n",
-        "-[ RECORD 2 ]---------------------------\n",
-        "id           | 3\ndestribution | Endeavouros\n",
-        "link         | \u{1b}[4m\u{1b}[34mhttps://endeavouros.com/\u{1b}[0m\u{1b}[0m\n",
+        "-[ RECORD 0 ]-----------------------\n",
+        "N        | 0\n",
+        "column 0 | 0-0\n",
+        "column 1 | \u{1b}[44m\u{1b}[31mhttps://getfedora.org/\u{1b}[0m\u{1b}[0m\n",
+        "column 2 | 0-2\n",
+        "-[ RECORD 1 ]-----------------------\n",
+        "N        | 1\n",
+        "column 0 | 1-0\n",
+        "column 1 | \u{1b}[40m\u{1b}[32mhttps://www.opensuse.org/\u{1b}[0m\u{1b}[0m\n",
+        "column 2 | 1-2\n",
+        "-[ RECORD 2 ]-----------------------\n",
+        "N        | 2\n",
+        "column 0 | 2-0\n",
+        "column 1 | \u{1b}[4m\u{1b}[34mhttps://endeavouros.com/\u{1b}[0m\u{1b}[0m\n",
+        "column 2 | 2-2\n",
     );
 
-    let table = ExpandedDisplay::new(&data).to_string();
-
-    println!("{}", table);
-
     assert_eq!(table, expected);
 }
 
@@ -318,16 +284,11 @@ fn display_dynamic_header_template() {
 
 #[test]
 fn display_multiline_field() {
-    #[allow(dead_code)]
-    struct Linux {
-        id: u8,
-        destribution: &'static str,
-        link: &'static str,
-    }
+    struct St;
 
-    impl Tabled for Linux {
+    impl Tabled for St {
         fn fields(&self) -> Vec<String> {
-            vec![String::new(), String::new(), String::new()]
+            vec!["1".to_string(), "2".to_string(), "3".to_string()]
         }
 
         fn headers() -> Vec<String> {
@@ -339,465 +300,265 @@ fn display_multiline_field() {
         }
     }
 
-    let data = vec![Linux {
-        id: 0,
-        destribution: "Fedora",
-        link: "https://getfedora.org/",
-    }];
+    let data = vec![St];
+    let table = ExpandedDisplay::new(&data).to_string();
 
     let expected = concat!(
-        "-[ RECORD 0 ]--\n",
-        "Hello\\nWorld | \n",
-        "123          | \n",
-        "asd          | \n",
+        "-[ RECORD 0 ]---\n",
+        "Hello\\nWorld | 1\n",
+        "123          | 2\n",
+        "asd          | 3\n",
     );
 
-    let table = ExpandedDisplay::new(&data).to_string();
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn display_multiline_record_value() {
-    #[allow(dead_code)]
-    struct Linux {
-        id: u8,
-        destribution: &'static str,
-        link: &'static str,
-    }
+    let mut data = create_vector::<2, 3>();
+    data[0][0] = "Hello\nWorld".to_string();
+    data[0][1] = "123".to_string();
+    data[0][2] = "asd".to_string();
 
-    impl Tabled for Linux {
-        fn fields(&self) -> Vec<String> {
-            vec![
-                "Hello\nWorld".to_string(),
-                "123".to_string(),
-                "asd".to_string(),
-            ]
-        }
-
-        fn headers() -> Vec<String> {
-            vec!["1".to_string(), "2".to_string(), "3".to_string()]
-        }
-    }
-
-    let data = vec![Linux {
-        id: 0,
-        destribution: "Fedora",
-        link: "https://getfedora.org/",
-    }];
+    let table = ExpandedDisplay::new(&data).to_string();
 
     let expected = concat!(
-        "-[ RECORD 0 ]-\n",
-        "1 | Hello\n",
-        "  | World\n",
-        "2 | 123\n",
-        "3 | asd\n",
+        "-[ RECORD 0 ]---\n",
+        "N        | Hello\n",
+        "         | World\n",
+        "column 0 | 123\n",
+        "column 1 | asd\n",
+        "column 2 | 0-2\n",
+        "-[ RECORD 1 ]---\n",
+        "N        | 1\n",
+        "column 0 | 1-0\n",
+        "column 1 | 1-1\n",
+        "column 2 | 1-2\n",
     );
 
-    let table = ExpandedDisplay::new(&data).to_string();
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn display_with_header_template() {
-    #[derive(Tabled)]
-    struct Linux {
-        id: u8,
-        destribution: &'static str,
-        link: &'static str,
-    }
-
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<2, 3>();
+    let table = ExpandedDisplay::new(&data)
+        .header_template(|i| format!("=== Record => {}", i))
+        .to_string();
 
     let expected = concat!(
         "=== Record => 0\n",
-        "id           | 0\n",
-        "destribution | Fedora\n",
-        "link         | https://getfedora.org/\n",
+        "N        | 0\n",
+        "column 0 | 0-0\n",
+        "column 1 | 0-1\n",
+        "column 2 | 0-2\n",
         "=== Record => 1\n",
-        "id           | 2\n",
-        "destribution | OpenSUSE\n",
-        "link         | https://www.opensuse.org/\n",
-        "=== Record => 2\n",
-        "id           | 3\n",
-        "destribution | Endeavouros\n",
-        "link         | https://endeavouros.com/\n",
+        "N        | 1\n",
+        "column 0 | 1-0\n",
+        "column 1 | 1-1\n",
+        "column 2 | 1-2\n",
     );
 
-    let table = ExpandedDisplay::new(&data)
-        .header_template(|i| format!("=== Record => {}", i))
-        .to_string();
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn display_with_formatter() {
-    #[derive(Tabled)]
-    struct Linux {
-        id: u8,
-        destribution: &'static str,
-        link: &'static str,
-    }
-
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fed\nora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "-[ RECORD 0 ]----------------------------\n",
-        "id           | 0!\n",
-        "             | \n",
-        "destribution | Fed\n",
-        "             | ora!\n",
-        "             | \n",
-        "link         | https://getfedora.org/!\n",
-        "             | \n",
-        "-[ RECORD 1 ]----------------------------\n",
-        "id           | 2!\n",
-        "             | \n",
-        "destribution | OpenSUSE!\n",
-        "             | \n",
-        "link         | https://www.opensuse.org/!\n",
-        "             | \n",
-        "-[ RECORD 2 ]----------------------------\n",
-        "id           | 3!\n",
-        "             | \n",
-        "destribution | Endeavouros!\n",
-        "             | \n",
-        "link         | https://endeavouros.com/!\n",
-        "             | \n",
-    );
+    let mut data = create_vector::<2, 3>();
+    data[0][1] = "123\n456".to_owned();
 
     let table = ExpandedDisplay::new(&data)
         .formatter(|s| format!("{}!\n\n", s))
         .to_string();
 
+    let expected = concat!(
+        "-[ RECORD 0 ]--\n",
+        "N        | 0!\n",
+        "         | \n",
+        "column 0 | 123\n",
+        "         | 456!\n",
+        "         | \n",
+        "column 1 | 0-1!\n",
+        "         | \n",
+        "column 2 | 0-2!\n",
+        "         | \n",
+        "-[ RECORD 1 ]--\n",
+        "N        | 1!\n",
+        "         | \n",
+        "column 0 | 1-0!\n",
+        "         | \n",
+        "column 1 | 1-1!\n",
+        "         | \n",
+        "column 2 | 1-2!\n",
+        "         | \n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn display_with_one_line_formatter() {
-    #[allow(dead_code)]
-    struct Linux {
-        id: u8,
-        destribution: &'static str,
-        link: &'static str,
-    }
-
-    impl Tabled for Linux {
-        fn fields(&self) -> Vec<String> {
-            vec![
-                "Hello\nWorld".to_string(),
-                "123".to_string(),
-                "asd".to_string(),
-            ]
-        }
-
-        fn headers() -> Vec<String> {
-            vec!["1".to_string(), "2".to_string(), "3".to_string()]
-        }
-    }
-
-    let data = vec![Linux {
-        id: 0,
-        destribution: "Fedora",
-        link: "https://getfedora.org/",
-    }];
-
-    let expected = concat!(
-        "-[ RECORD 0 ]---\n",
-        "1 | Hello\\nWorld\n",
-        "2 | 123\n",
-        "3 | asd\n",
-    );
+    let mut data = create_vector::<1, 3>();
+    data[0][0] = "Hello\nWorld".to_string();
+    data[0][1] = "123".to_string();
+    data[0][2] = "asd".to_string();
 
     let table = ExpandedDisplay::new(&data)
         .formatter(|s| s.escape_debug().to_string())
         .to_string();
 
+    let expected = concat!(
+        "-[ RECORD 0 ]----------\n",
+        "N        | Hello\\nWorld\n",
+        "column 0 | 123\n",
+        "column 1 | asd\n",
+        "column 2 | 0-2\n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn display_with_truncate() {
-    #[derive(Tabled)]
-    struct Linux {
-        id: u8,
-        destribution: &'static str,
-        link: &'static str,
-    }
-
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<3, 3>();
+    let table = ExpandedDisplay::new(&data).truncate(2, "").to_string();
 
     let expected = concat!(
-        "-[ RECORD 0 ]-----\n",
-        "id           | 0\n",
-        "destribution | Fed\n",
-        "link         | htt\n",
-        "-[ RECORD 1 ]-----\n",
-        "id           | 2\n",
-        "destribution | Ope\n",
-        "link         | htt\n",
-        "-[ RECORD 2 ]-----\n",
-        "id           | 3\n",
-        "destribution | End\n",
-        "link         | htt\n",
+        "-[ RECORD 0 ]-\n",
+        "N        | 0\n",
+        "column 0 | 0-\n",
+        "column 1 | 0-\n",
+        "column 2 | 0-\n",
+        "-[ RECORD 1 ]-\n",
+        "N        | 1\n",
+        "column 0 | 1-\n",
+        "column 1 | 1-\n",
+        "column 2 | 1-\n",
+        "-[ RECORD 2 ]-\n",
+        "N        | 2\n",
+        "column 0 | 2-\n",
+        "column 1 | 2-\n",
+        "column 2 | 2-\n",
     );
 
-    let table = ExpandedDisplay::new(&data).truncate(3, "").to_string();
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn display_with_truncate_with_tail() {
-    #[derive(Tabled)]
-    struct Linux {
-        id: u8,
-        destribution: &'static str,
-        link: &'static str,
-    }
-
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<2, 3>();
+    let table = ExpandedDisplay::new(&data).truncate(2, "...").to_string();
 
     let expected = concat!(
-        "-[ RECORD 0 ]--------\n",
-        "id           | 0\n",
-        "destribution | Fed...\n",
-        "link         | htt...\n",
-        "-[ RECORD 1 ]--------\n",
-        "id           | 2\n",
-        "destribution | Ope...\n",
-        "link         | htt...\n",
-        "-[ RECORD 2 ]--------\n",
-        "id           | 3\n",
-        "destribution | End...\n",
-        "link         | htt...\n",
+        "-[ RECORD 0 ]---\n",
+        "N        | 0\n",
+        "column 0 | 0-...\n",
+        "column 1 | 0-...\n",
+        "column 2 | 0-...\n",
+        "-[ RECORD 1 ]---\n",
+        "N        | 1\n",
+        "column 0 | 1-...\n",
+        "column 1 | 1-...\n",
+        "column 2 | 1-...\n",
     );
 
-    let table = ExpandedDisplay::new(&data).truncate(3, "...").to_string();
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn display_with_wrap() {
-    #[derive(Tabled)]
-    struct Linux {
-        id: u8,
-        destribution: &'static str,
-        link: &'static str,
-    }
-
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<2, 3>();
+    let table = ExpandedDisplay::new(&data).wrap(1).to_string();
 
     let expected = concat!(
-        "-[ RECORD 0 ]-----\n",
-        "id           | 0\n",
-        "destribution | Fed\n",
-        "             | ora\n",
-        "link         | htt\n",
-        "             | ps:\n",
-        "             | //g\n",
-        "             | etf\n",
-        "             | edo\n",
-        "             | ra.\n",
-        "             | org\n",
-        "             | /\n",
-        "-[ RECORD 1 ]-----\n",
-        "id           | 2\n",
-        "destribution | Ope\n",
-        "             | nSU\n",
-        "             | SE\n",
-        "link         | htt\n",
-        "             | ps:\n",
-        "             | //w\n",
-        "             | ww.\n",
-        "             | ope\n",
-        "             | nsu\n",
-        "             | se.\n",
-        "             | org\n",
-        "             | /\n",
-        "-[ RECORD 2 ]-----\n",
-        "id           | 3\n",
-        "destribution | End\n",
-        "             | eav\n",
-        "             | our\n",
-        "             | os\n",
-        "link         | htt\n",
-        "             | ps:\n",
-        "             | //e\n",
-        "             | nde\n",
-        "             | avo\n",
-        "             | uro\n",
-        "             | s.c\n",
-        "             | om/\n",
+        "-[ RECORD 0 ]-\n",
+        "N        | 0\n",
+        "column 0 | 0\n",
+        "         | -\n",
+        "         | 0\n",
+        "column 1 | 0\n",
+        "         | -\n",
+        "         | 1\n",
+        "column 2 | 0\n",
+        "         | -\n",
+        "         | 2\n",
+        "-[ RECORD 1 ]-\n",
+        "N        | 1\n",
+        "column 0 | 1\n",
+        "         | -\n",
+        "         | 0\n",
+        "column 1 | 1\n",
+        "         | -\n",
+        "         | 1\n",
+        "column 2 | 1\n",
+        "         | -\n",
+        "         | 2\n",
     );
 
-    let table = ExpandedDisplay::new(&data).wrap(3).to_string();
-
     assert_eq!(table, expected);
 }
 
 #[cfg(feature = "color")]
 #[test]
 fn display_with_wrap_colored() {
-    use owo_colors::{AnsiColors, OwoColorize};
-
-    #[derive(Tabled)]
-    struct Linux {
-        id: u8,
-        destribution: &'static str,
-        link: String,
-    }
+    let mut data = create_vector::<2, 3>();
+    data[0][2] = "https://getfedora.org/".red().to_string();
+    data[1][1] = "https://endeavouros.com/"
+        .white()
+        .on_color(AnsiColors::Black)
+        .to_string();
+    data[1][2] = "https://www.opensuse.org/".to_string();
 
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/".red().to_string(),
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/".to_string(),
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/"
-                .white()
-                .on_color(AnsiColors::Black)
-                .to_string(),
-        },
-    ];
+    let table = ExpandedDisplay::new(&data).wrap(2).to_string();
 
     let expected = concat!(
-        "-[ RECORD 0 ]-----\n",
-        "id           | 0\n",
-        "destribution | Fed",
-        "\n             | ora\n",
-        "link         | \u{1b}[31mhtt\u{1b}[0m\n",
-        "             | \u{1b}[31mps:\u{1b}[0m\n",
-        "             | \u{1b}[31m//g\u{1b}[0m\n",
-        "             | \u{1b}[31metf\u{1b}[0m\n",
-        "             | \u{1b}[31medo\u{1b}[0m\n",
-        "             | \u{1b}[31mra.\u{1b}[0m\n",
-        "             | \u{1b}[31morg\u{1b}[0m\n",
-        "             | \u{1b}[31m/\u{1b}[0m\n",
-        "-[ RECORD 1 ]-----\n",
-        "id           | 2\n",
-        "destribution | Ope\n",
-        "             | nSU\n",
-        "             | SE\n",
-        "link         | htt\n",
-        "             | ps:\n",
-        "             | //w\n",
-        "             | ww.\n",
-        "             | ope\n",
-        "             | nsu\n",
-        "             | se.\n",
-        "             | org\n",
-        "             | /\n",
-        "-[ RECORD 2 ]-----\n",
-        "id           | 3\n",
-        "destribution | End\n",
-        "             | eav\n",
-        "             | our\n",
-        "             | os\n",
-        "link         | \u{1b}[40m\u{1b}[37mhtt\u{1b}[0m\u{1b}[0m\n",
-        "             | \u{1b}[40m\u{1b}[37mps:\u{1b}[0m\u{1b}[0m\n",
-        "             | \u{1b}[40m\u{1b}[37m//e\u{1b}[0m\u{1b}[0m\n",
-        "             | \u{1b}[40m\u{1b}[37mnde\u{1b}[0m\u{1b}[0m\n",
-        "             | \u{1b}[40m\u{1b}[37mavo\u{1b}[0m\u{1b}[0m\n",
-        "             | \u{1b}[40m\u{1b}[37muro\u{1b}[0m\u{1b}[0m\n",
-        "             | \u{1b}[40m\u{1b}[37ms.c\u{1b}[0m\u{1b}[0m\n",
-        "             | \u{1b}[40m\u{1b}[37mom/\u{1b}[0m\u{1b}[0m\n",
+        "-[ RECORD 0 ]-\n",
+        "N        | 0\n",
+        "column 0 | 0-\n",
+        "         | 0\n",
+        "column 1 | \u{1b}[31mht\u{1b}[0m\n",
+        "         | \u{1b}[31mtp\u{1b}[0m\n",
+        "         | \u{1b}[31ms:\u{1b}[0m\n",
+        "         | \u{1b}[31m//\u{1b}[0m\n",
+        "         | \u{1b}[31mge\u{1b}[0m\n",
+        "         | \u{1b}[31mtf\u{1b}[0m\n",
+        "         | \u{1b}[31med\u{1b}[0m\n",
+        "         | \u{1b}[31mor\u{1b}[0m\n",
+        "         | \u{1b}[31ma.\u{1b}[0m\n",
+        "         | \u{1b}[31mor\u{1b}[0m\n",
+        "         | \u{1b}[31mg/\u{1b}[0m\n",
+        "column 2 | 0-\n",
+        "         | 2\n",
+        "-[ RECORD 1 ]-\n",
+        "N        | 1\n",
+        "column 0 | \u{1b}[40m\u{1b}[37mht\u{1b}[0m\u{1b}[0m\n",
+        "         | \u{1b}[40m\u{1b}[37mtp\u{1b}[0m\u{1b}[0m\n",
+        "         | \u{1b}[40m\u{1b}[37ms:\u{1b}[0m\u{1b}[0m\n",
+        "         | \u{1b}[40m\u{1b}[37m//\u{1b}[0m\u{1b}[0m\n",
+        "         | \u{1b}[40m\u{1b}[37men\u{1b}[0m\u{1b}[0m\n",
+        "         | \u{1b}[40m\u{1b}[37mde\u{1b}[0m\u{1b}[0m\n",
+        "         | \u{1b}[40m\u{1b}[37mav\u{1b}[0m\u{1b}[0m\n",
+        "         | \u{1b}[40m\u{1b}[37mou\u{1b}[0m\u{1b}[0m\n",
+        "         | \u{1b}[40m\u{1b}[37mro\u{1b}[0m\u{1b}[0m\n",
+        "         | \u{1b}[40m\u{1b}[37ms.\u{1b}[0m\u{1b}[0m\n",
+        "         | \u{1b}[40m\u{1b}[37mco\u{1b}[0m\u{1b}[0m\n",
+        "         | \u{1b}[40m\u{1b}[37mm/\u{1b}[0m\u{1b}[0m\n",
+        "column 1 | ht\n",
+        "         | tp\n",
+        "         | s:\n",
+        "         | //\n",
+        "         | ww\n",
+        "         | w.\n",
+        "         | op\n",
+        "         | en\n",
+        "         | su\n",
+        "         | se\n",
+        "         | .o\n",
+        "         | rg\n",
+        "         | /\n",
+        "column 2 | 1-\n",
+        "         | 2\n",
     );
 
-    let table = ExpandedDisplay::new(&data).wrap(3).to_string();
-
-    println!("{}", table);
-
     assert_eq!(table, expected);
 }
diff --git a/tests/format_test.rs b/tests/format_test.rs
index d51407e..cc176a7 100644
--- a/tests/format_test.rs
+++ b/tests/format_test.rs
@@ -1,236 +1,122 @@
+use crate::util::create_vector;
 use tabled::{
     multiline, Alignment, Cell, Column, Format, FormatFrom, FormatWithIndex, Full, Head, Indent,
-    Modify, Object, Row, Style, Table, Tabled,
+    Modify, Object, Row, Style, Table,
 };
 
-#[derive(Tabled)]
-struct Linux {
-    id: u8,
-    destribution: &'static str,
-    link: &'static str,
-}
+mod util;
 
 #[test]
 fn formatting_full_test() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "+------+----------------+-----------------------------+\n",
-        "| [id] | [destribution] |           [link]            |\n",
-        "+------+----------------+-----------------------------+\n",
-        "| [0]  |    [Fedora]    |  [https://getfedora.org/]   |\n",
-        "+------+----------------+-----------------------------+\n",
-        "| [2]  |   [OpenSUSE]   | [https://www.opensuse.org/] |\n",
-        "+------+----------------+-----------------------------+\n",
-        "| [3]  | [Endeavouros]  | [https://endeavouros.com/]  |\n",
-        "+------+----------------+-----------------------------+\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Modify::new(Full).with(Format(|s| format!("[{}]", s))))
         .to_string();
 
+    let expected = concat!(
+        "+-----+------------+------------+------------+\n",
+        "| [N] | [column 0] | [column 1] | [column 2] |\n",
+        "+-----+------------+------------+------------+\n",
+        "| [0] |   [0-0]    |   [0-1]    |   [0-2]    |\n",
+        "+-----+------------+------------+------------+\n",
+        "| [1] |   [1-0]    |   [1-1]    |   [1-2]    |\n",
+        "+-----+------------+------------+------------+\n",
+        "| [2] |   [2-0]    |   [2-1]    |   [2-2]    |\n",
+        "+-----+------------+------------+------------+\n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn formatting_head_test() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "| :id | :destribution |           :link           |\n",
-        "|-----+---------------+---------------------------|\n",
-        "|  0  |    Fedora     |  https://getfedora.org/   |\n",
-        "|  2  |   OpenSUSE    | https://www.opensuse.org/ |\n",
-        "|  3  |  Endeavouros  | https://endeavouros.com/  |\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::github_markdown())
         .with(Modify::new(Head).with(Format(|s| format!(":{}", s))))
         .to_string();
 
+    let expected = concat!(
+        "| :N | :column 0 | :column 1 | :column 2 |\n",
+        "|----+-----------+-----------+-----------|\n",
+        "| 0  |    0-0    |    0-1    |    0-2    |\n",
+        "| 1  |    1-0    |    1-1    |    1-2    |\n",
+        "| 2  |    2-0    |    2-1    |    2-2    |\n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn formatting_row_test() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        " id  | destribution  |            link             \n",
-        "-----+---------------+-----------------------------\n",
-        " <0> |   <Fedora>    |  <https://getfedora.org/>   \n",
-        " <2> |  <OpenSUSE>   | <https://www.opensuse.org/> \n",
-        " <3> | <Endeavouros> | <https://endeavouros.com/>  \n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(Modify::new(Row(1..)).with(Format(|s| format!("<{}>", s))))
         .to_string();
 
+    let expected = concat!(
+        "  N  | column 0 | column 1 | column 2 \n",
+        "-----+----------+----------+----------\n",
+        " <0> |  <0-0>   |  <0-1>   |  <0-2>   \n",
+        " <1> |  <1-0>   |  <1-1>   |  <1-2>   \n",
+        " <2> |  <2-0>   |  <2-1>   |  <2-2>   \n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn formatting_column_test() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        " (x) id | destribution |           link            \n",
-        "--------+--------------+---------------------------\n",
-        " (x) 0  |    Fedora    |  https://getfedora.org/   \n",
-        " (x) 2  |   OpenSUSE   | https://www.opensuse.org/ \n",
-        " (x) 3  | Endeavouros  | https://endeavouros.com/  \n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(Modify::new(Column(..1)).with(Format(|s| format!("(x) {}", s))))
         .to_string();
-
+    let expected = concat!(
+        " (x) N | column 0 | column 1 | column 2 \n",
+        "-------+----------+----------+----------\n",
+        " (x) 0 |   0-0    |   0-1    |   0-2    \n",
+        " (x) 1 |   1-0    |   1-1    |   1-2    \n",
+        " (x) 2 |   2-0    |   2-1    |   2-2    \n",
+    );
     assert_eq!(table, expected);
 }
 
 #[test]
 fn formatting_multiline_test() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 1,
-            destribution: "Open\nSUSE",
-            link: "https\n://\nwww.opensuse.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Red\nHat\nEnterprise",
-            link: "https://redhat.com/",
-        },
-    ];
-
-    let expected = concat!(
-        " (x) id | (x) destribution |           (x) link           \n",
-        "--------+------------------+------------------------------\n",
-        " (x) 0  |    (x) Fedora    |  (x) https://getfedora.org/  \n",
-        " (x) 1  |     (x) Open     |          (x) https           \n",
-        "        |     (x) SUSE     |           (x) ://            \n",
-        "        |                  |    (x) www.opensuse.org/     \n",
-        " (x) 2  | (x) Endeavouros  | (x) https://endeavouros.com/ \n",
-        " (x) 3  |     (x) Red      |   (x) https://redhat.com/    \n",
-        "        |     (x) Hat      |                              \n",
-        "        |  (x) Enterprise  |                              \n",
-    );
+    let mut data = create_vector::<3, 3>();
+    data[1][2] = String::from("E\nnde\navou\nros");
+    data[2][2] = String::from("Red\nHat");
+    data[2][3] = String::from("https://\nwww\n.\nredhat\n.com\n/en");
 
     let table = Table::new(&data)
         .with(Style::psql())
         .with(Modify::new(Full).with(Format(multiline(|s| format!("(x) {}", s)))))
         .to_string();
 
+    let expected = concat!(
+        " (x) N | (x) column 0 | (x) column 1 | (x) column 2 \n",
+        "-------+--------------+--------------+--------------\n",
+        " (x) 0 |   (x) 0-0    |   (x) 0-1    |   (x) 0-2    \n",
+        " (x) 1 |   (x) 1-0    |    (x) E     |   (x) 1-2    \n",
+        "       |              |   (x) nde    |              \n",
+        "       |              |   (x) avou   |              \n",
+        "       |              |   (x) ros    |              \n",
+        " (x) 2 |   (x) 2-0    |   (x) Red    | (x) https:// \n",
+        "       |              |   (x) Hat    |   (x) www    \n",
+        "       |              |              |    (x) .     \n",
+        "       |              |              |  (x) redhat  \n",
+        "       |              |              |   (x) .com   \n",
+        "       |              |              |   (x) /en    \n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn formatting_cell_test() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        " (x) id | (x) destribution |         (x) link          \n",
-        "--------+------------------+---------------------------\n",
-        "   0    |      Fedora      |  https://getfedora.org/   \n",
-        "   2    |     OpenSUSE     | https://www.opensuse.org/ \n",
-        "   3    |   Endeavouros    | https://endeavouros.com/  \n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(Modify::new(Cell(0, 0)).with(Format(|s| format!("(x) {}", s))))
@@ -238,73 +124,39 @@ fn formatting_cell_test() {
         .with(Modify::new(Cell(0, 2)).with(Format(|s| format!("(x) {}", s))))
         .to_string();
 
+    let expected = concat!(
+        " (x) N | (x) column 0 | (x) column 1 | column 2 \n",
+        "-------+--------------+--------------+----------\n",
+        "   0   |     0-0      |     0-1      |   0-2    \n",
+        "   1   |     1-0      |     1-1      |   1-2    \n",
+        "   2   |     2-0      |     2-1      |   2-2    \n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn formatting_and_combination_test() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        " (x) id | (x) destribution |         (x) link          \n",
-        "--------+------------------+---------------------------\n",
-        " (x) 0  |      Fedora      |  https://getfedora.org/   \n",
-        " (x) 2  |     OpenSUSE     | https://www.opensuse.org/ \n",
-        " (x) 3  |   Endeavouros    | https://endeavouros.com/  \n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(Modify::new(Column(..1).and(Row(..1))).with(Format(|s| format!("(x) {}", s))))
         .to_string();
 
+    let expected = concat!(
+        " (x) N | (x) column 0 | (x) column 1 | (x) column 2 \n",
+        "-------+--------------+--------------+--------------\n",
+        " (x) 0 |     0-0      |     0-1      |     0-2      \n",
+        " (x) 1 |     1-0      |     1-1      |     1-2      \n",
+        " (x) 2 |     2-0      |     2-1      |     2-2      \n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn formatting_not_combination_test() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "  id   | (x) destribution |         (x) link          \n",
-        "-------+------------------+---------------------------\n",
-        " (x) 0 |      Fedora      |  https://getfedora.org/   \n",
-        " (x) 2 |     OpenSUSE     | https://www.opensuse.org/ \n",
-        " (x) 3 |   Endeavouros    | https://endeavouros.com/  \n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(
@@ -313,101 +165,58 @@ fn formatting_not_combination_test() {
         )
         .to_string();
 
+    let expected = concat!(
+        "   N   | (x) column 0 | (x) column 1 | (x) column 2 \n",
+        "-------+--------------+--------------+--------------\n",
+        " (x) 0 |     0-0      |     0-1      |     0-2      \n",
+        " (x) 1 |     1-0      |     1-1      |     1-2      \n",
+        " (x) 2 |     2-0      |     2-1      |     2-2      \n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn formatting_using_lambda_test() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "| :id | :destribution |           :link           |\n",
-        "|-----+---------------+---------------------------|\n",
-        "|  0  |    Fedora     |  https://getfedora.org/   |\n",
-        "|  2  |   OpenSUSE    | https://www.opensuse.org/ |\n",
-        "|  3  |  Endeavouros  | https://endeavouros.com/  |\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::github_markdown())
         .with(Modify::new(Head).with(|s: &str| format!(":{}", s)))
         .to_string();
 
+    let expected = concat!(
+        "| :N | :column 0 | :column 1 | :column 2 |\n",
+        "|----+-----------+-----------+-----------|\n",
+        "| 0  |    0-0    |    0-1    |    0-2    |\n",
+        "| 1  |    1-0    |    1-1    |    1-2    |\n",
+        "| 2  |    2-0    |    2-1    |    2-2    |\n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn formatting_using_function_test() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "| ID | DESTRIBUTION |           LINK            |\n",
-        "|----+--------------+---------------------------|\n",
-        "| 0  |    Fedora    |  https://getfedora.org/   |\n",
-        "| 2  |   OpenSUSE   | https://www.opensuse.org/ |\n",
-        "| 3  | Endeavouros  | https://endeavouros.com/  |\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::github_markdown())
         .with(Modify::new(Head).with(str::to_uppercase))
         .to_string();
 
+    let expected = concat!(
+        "| N | COLUMN 0 | COLUMN 1 | COLUMN 2 |\n",
+        "|---+----------+----------+----------|\n",
+        "| 0 |   0-0    |   0-1    |   0-2    |\n",
+        "| 1 |   1-0    |   1-1    |   1-2    |\n",
+        "| 2 |   2-0    |   2-1    |   2-2    |\n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn format_from() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::github_markdown())
         .with(Modify::new(Head).with(FormatFrom(vec![
@@ -418,11 +227,11 @@ fn format_from() {
         .to_string();
 
     let expected = concat!(
-        "| Header Name 1 | Header Name 2 |       Header Name 3       |\n",
-        "|---------------+---------------+---------------------------|\n",
-        "|       0       |    Fedora     |  https://getfedora.org/   |\n",
-        "|       2       |   OpenSUSE    | https://www.opensuse.org/ |\n",
-        "|       3       |  Endeavouros  | https://endeavouros.com/  |\n",
+        "| Header Name 1 | Header Name 2 | Header Name 3 | column 2 |\n",
+        "|---------------+---------------+---------------+----------|\n",
+        "|       0       |      0-0      |      0-1      |   0-2    |\n",
+        "|       1       |      1-0      |      1-1      |   1-2    |\n",
+        "|       2       |      2-0      |      2-1      |   2-2    |\n",
     );
 
     assert_eq!(table, expected);
@@ -430,24 +239,7 @@ fn format_from() {
 
 #[test]
 fn format_with_index() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::github_markdown())
         .with(
@@ -461,11 +253,11 @@ fn format_with_index() {
         .to_string();
 
     let expected = concat!(
-        "| (0, 0) |   (0, 1)    |          (0, 2)           |\n",
-        "|--------+-------------+---------------------------|\n",
-        "|   0    |   Fedora    |  https://getfedora.org/   |\n",
-        "|   2    |  OpenSUSE   | https://www.opensuse.org/ |\n",
-        "|   3    | Endeavouros | https://endeavouros.com/  |\n",
+        "| (0, 0) | (0, 1) | (0, 2) | column 2 |\n",
+        "|--------+--------+--------+----------|\n",
+        "|   0    |  0-0   |  0-1   |   0-2    |\n",
+        "|   1    |  1-0   |  1-1   |   1-2    |\n",
+        "|   2    |  2-0   |  2-1   |   2-2    |\n",
     );
 
     assert_eq!(table, expected);
@@ -479,78 +271,30 @@ mod color {
 
     #[test]
     fn color_column_test() {
-        let data = vec![
-            Linux {
-                id: 0,
-                destribution: "Fedora",
-                link: "https://getfedora.org/",
-            },
-            Linux {
-                id: 2,
-                destribution: "OpenSUSE",
-                link: "https://www.opensuse.org/",
-            },
-            Linux {
-                id: 3,
-                destribution: "Endeavouros",
-                link: "https://endeavouros.com/",
-            },
-        ];
-
-        let expected = concat!(
-            " \u{1b}[31mid\u{1b}[0m | \u{1b}[34mdestribution\u{1b}[0m |           \u{1b}[31mlink\u{1b}[0m            \n",
-            "----+--------------+---------------------------\n",
-            " \u{1b}[31m0\u{1b}[0m  |    \u{1b}[34mFedora\u{1b}[0m    |  \u{1b}[31mhttps://getfedora.org/\u{1b}[0m   \n",
-            " \u{1b}[31m2\u{1b}[0m  |   \u{1b}[34mOpenSUSE\u{1b}[0m   | \u{1b}[31mhttps://www.opensuse.org/\u{1b}[0m \n",
-            " \u{1b}[31m3\u{1b}[0m  | \u{1b}[34mEndeavouros\u{1b}[0m  | \u{1b}[31mhttps://endeavouros.com/\u{1b}[0m  \n",
-        );
-
+        let data = create_vector::<3, 3>();
         let table = Table::new(&data)
             .with(Style::psql())
             .with(Modify::new(Column(..1).and(Column(2..))).with(Format(|s| s.red().to_string())))
             .with(Modify::new(Column(1..2)).with(Format(|s| s.blue().to_string())))
             .to_string();
 
-        println!("{}", table);
+        let expected = concat!(
+            " \u{1b}[31mN\u{1b}[0m | \u{1b}[34mcolumn 0\u{1b}[0m | \u{1b}[31mcolumn 1\u{1b}[0m | \u{1b}[31mcolumn 2\u{1b}[0m \n",
+            "---+----------+----------+----------\n",
+            " \u{1b}[31m0\u{1b}[0m |   \u{1b}[34m0-0\u{1b}[0m    |   \u{1b}[31m0-1\u{1b}[0m    |   \u{1b}[31m0-2\u{1b}[0m    \n",
+            " \u{1b}[31m1\u{1b}[0m |   \u{1b}[34m1-0\u{1b}[0m    |   \u{1b}[31m1-1\u{1b}[0m    |   \u{1b}[31m1-2\u{1b}[0m    \n",
+            " \u{1b}[31m2\u{1b}[0m |   \u{1b}[34m2-0\u{1b}[0m    |   \u{1b}[31m2-1\u{1b}[0m    |   \u{1b}[31m2-2\u{1b}[0m    \n",
+        );
 
         assert_eq!(table, expected);
     }
 
     #[test]
     fn color_multiline_test() {
-        let data = vec![
-            Linux {
-                id: 0,
-                destribution: "Fedora",
-                link: "https://getfedora.org/",
-            },
-            Linux {
-                id: 2,
-                destribution: "OpenSUSE",
-                link: "https://www.opensuse.org/",
-            },
-            Linux {
-                id: 3,
-                destribution: "Endeavouros",
-                link: "https://endeavouros.com/",
-            },
-            Linux {
-                id: 4,
-                destribution: "Red\nHat\nEnterprise",
-                link: "https://redhat.com/",
-            },
-        ];
-
-        let expected = concat!(
-            " \u{1b}[31mid\u{1b}[0m | \u{1b}[34mdestribution\u{1b}[0m |           \u{1b}[32mlink\u{1b}[0m            \n",
-            "----+--------------+---------------------------\n",
-            " \u{1b}[31m0\u{1b}[0m  |    \u{1b}[34mFedora\u{1b}[0m    |  \u{1b}[32mhttps://getfedora.org/\u{1b}[0m   \n",
-            " \u{1b}[31m2\u{1b}[0m  |   \u{1b}[34mOpenSUSE\u{1b}[0m   | \u{1b}[32mhttps://www.opensuse.org/\u{1b}[0m \n",
-            " \u{1b}[31m3\u{1b}[0m  | \u{1b}[34mEndeavouros\u{1b}[0m  | \u{1b}[32mhttps://endeavouros.com/\u{1b}[0m  \n",
-            " \u{1b}[31m4\u{1b}[0m  |     \u{1b}[34mRed\u{1b}[0m      |    \u{1b}[32mhttps://redhat.com/\u{1b}[0m    \n",
-            "    |     \u{1b}[34mHat\u{1b}[0m      |                           \n",
-            "    |  \u{1b}[34mEnterprise\u{1b}[0m  |                           \n",
-        );
+        let mut data = create_vector::<3, 3>();
+        data[1][2] = String::from("E\nnde\navou\nros");
+        data[2][2] = String::from("Red\nHat");
+        data[2][3] = String::from("https://\nwww\n.\nredhat\n.com\n/en");
 
         let table = Table::new(&data)
             .with(Style::psql())
@@ -559,7 +303,21 @@ mod color {
             .with(Modify::new(Column(2..)).with(Format(multiline(|s| s.green().to_string()))))
             .to_string();
 
-        println!("{}", table);
+        let expected = concat!(
+            " \u{1b}[31mN\u{1b}[0m | \u{1b}[34mcolumn 0\u{1b}[0m | \u{1b}[32mcolumn 1\u{1b}[0m | \u{1b}[32mcolumn 2\u{1b}[0m \n",
+            "---+----------+----------+----------\n",
+            " \u{1b}[31m0\u{1b}[0m |   \u{1b}[34m0-0\u{1b}[0m    |   \u{1b}[32m0-1\u{1b}[0m    |   \u{1b}[32m0-2\u{1b}[0m    \n",
+            " \u{1b}[31m1\u{1b}[0m |   \u{1b}[34m1-0\u{1b}[0m    |    \u{1b}[32mE\u{1b}[0m     |   \u{1b}[32m1-2\u{1b}[0m    \n",
+            "   |          |   \u{1b}[32mnde\u{1b}[0m    |          \n",
+            "   |          |   \u{1b}[32mavou\u{1b}[0m   |          \n",
+            "   |          |   \u{1b}[32mros\u{1b}[0m    |          \n",
+            " \u{1b}[31m2\u{1b}[0m |   \u{1b}[34m2-0\u{1b}[0m    |   \u{1b}[32mRed\u{1b}[0m    | \u{1b}[32mhttps://\u{1b}[0m \n",
+            "   |          |   \u{1b}[32mHat\u{1b}[0m    |   \u{1b}[32mwww\u{1b}[0m    \n",
+            "   |          |          |    \u{1b}[32m.\u{1b}[0m     \n",
+            "   |          |          |  \u{1b}[32mredhat\u{1b}[0m  \n",
+            "   |          |          |   \u{1b}[32m.com\u{1b}[0m   \n",
+            "   |          |          |   \u{1b}[32m/en\u{1b}[0m    \n",
+        );
 
         assert_eq!(table, expected);
     }
@@ -567,43 +325,24 @@ mod color {
 
 #[test]
 fn format_doesnt_change_indent() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "+--------+------------------+-------------------------------+\n",
-        "|   [id] |   [destribution] |   [link]                      |\n",
-        "+--------+------------------+-------------------------------+\n",
-        "|   [0]  |   [Fedora]       |   [https://getfedora.org/]    |\n",
-        "+--------+------------------+-------------------------------+\n",
-        "|   [2]  |   [OpenSUSE]     |   [https://www.opensuse.org/] |\n",
-        "+--------+------------------+-------------------------------+\n",
-        "|   [3]  |   [Endeavouros]  |   [https://endeavouros.com/]  |\n",
-        "+--------+------------------+-------------------------------+\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Modify::new(Full).with(Alignment::left()))
         .with(Modify::new(Full).with(Indent::new(3, 1, 0, 0)))
         .with(Modify::new(Full).with(Format(|s| format!("[{}]", s))))
         .to_string();
 
-    println!("{}", table);
+    let expected = concat!(
+        "+-------+--------------+--------------+--------------+\n",
+        "|   [N] |   [column 0] |   [column 1] |   [column 2] |\n",
+        "+-------+--------------+--------------+--------------+\n",
+        "|   [0] |   [0-0]      |   [0-1]      |   [0-2]      |\n",
+        "+-------+--------------+--------------+--------------+\n",
+        "|   [1] |   [1-0]      |   [1-1]      |   [1-2]      |\n",
+        "+-------+--------------+--------------+--------------+\n",
+        "|   [2] |   [2-0]      |   [2-1]      |   [2-2]      |\n",
+        "+-------+--------------+--------------+--------------+\n",
+    );
 
     assert_eq!(table, expected);
 }
diff --git a/tests/highlingt_test.rs b/tests/highlingt_test.rs
new file mode 100644
index 0000000..880fe8a
--- /dev/null
+++ b/tests/highlingt_test.rs
@@ -0,0 +1,175 @@
+use crate::util::create_vector;
+use tabled::{Border, Highlight, Style, Table};
+
+mod util;
+
+#[test]
+fn highlingt_cell() {
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data)
+        .with(Style::pseudo())
+        .with(Highlight::cell(
+            0,
+            0,
+            Border::full('+', '+', '+', '+', '+', '+', '+', '+'),
+        ))
+        .with(Highlight::cell(
+            1,
+            1,
+            Border::full('*', '*', '*', '*', '*', '*', '*', '*'),
+        ))
+        .to_string();
+
+    let expected = concat!(
+        "+++++──────────┬──────────┬──────────┐\n",
+        "+ N + column 0 │ column 1 │ column 2 │\n",
+        "++++************──────────┼──────────┤\n",
+        "│ 0 *   0-0    *   0-1    │   0-2    │\n",
+        "├───************──────────┼──────────┤\n",
+        "│ 1 │   1-0    │   1-1    │   1-2    │\n",
+        "├───┼──────────┼──────────┼──────────┤\n",
+        "│ 2 │   2-0    │   2-1    │   2-2    │\n",
+        "└───┴──────────┴──────────┴──────────┘\n",
+    );
+
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn highlingt_row() {
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data)
+        .with(Style::pseudo())
+        .with(Highlight::row(
+            0,
+            Border::full('+', '+', '+', '+', '+', '+', '+', '+'),
+        ))
+        .with(Highlight::row(
+            3,
+            Border::full('*', '*', '*', '*', '*', '*', '*', '*'),
+        ))
+        .to_string();
+
+    let expected = concat!(
+        "++++++++++++++++++++++++++++++++++++++\n",
+        "+ N │ column 0 │ column 1 │ column 2 +\n",
+        "++++++++++++++++++++++++++++++++++++++\n",
+        "│ 0 │   0-0    │   0-1    │   0-2    │\n",
+        "├───┼──────────┼──────────┼──────────┤\n",
+        "│ 1 │   1-0    │   1-1    │   1-2    │\n",
+        "**************************************\n",
+        "* 2 │   2-0    │   2-1    │   2-2    *\n",
+        "**************************************\n",
+    );
+
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn highlingt_column() {
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data)
+        .with(Style::pseudo())
+        .with(Highlight::column(
+            0,
+            Border::full('+', '+', '+', '+', '+', '+', '+', '+'),
+        ))
+        .with(Highlight::column(
+            2,
+            Border::full('*', '*', '*', '*', '*', '*', '*', '*'),
+        ))
+        .to_string();
+
+    let expected = concat!(
+        "+++++──────────************──────────┐\n",
+        "+ N + column 0 * column 1 * column 2 │\n",
+        "+───+──────────*──────────*──────────┤\n",
+        "+ 0 +   0-0    *   0-1    *   0-2    │\n",
+        "+───+──────────*──────────*──────────┤\n",
+        "+ 1 +   1-0    *   1-1    *   1-2    │\n",
+        "+───+──────────*──────────*──────────┤\n",
+        "+ 2 +   2-0    *   2-1    *   2-2    │\n",
+        "+++++──────────************──────────┘\n",
+    );
+
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn highlingt_row_range() {
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data)
+        .with(Style::pseudo())
+        .with(Highlight::row_range(
+            1,
+            3,
+            Border::full('+', '+', '+', '+', '+', '+', '+', '+'),
+        ))
+        .to_string();
+
+    let expected = concat!(
+        "┌───┬──────────┬──────────┬──────────┐\n",
+        "│ N │ column 0 │ column 1 │ column 2 │\n",
+        "++++++++++++++++++++++++++++++++++++++\n",
+        "+ 0 │   0-0    │   0-1    │   0-2    +\n",
+        "+───┼──────────┼──────────┼──────────+\n",
+        "+ 1 │   1-0    │   1-1    │   1-2    +\n",
+        "++++++++++++++++++++++++++++++++++++++\n",
+        "│ 2 │   2-0    │   2-1    │   2-2    │\n",
+        "└───┴──────────┴──────────┴──────────┘\n",
+    );
+
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn highlingt_column_range() {
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data)
+        .with(Style::pseudo())
+        .with(Highlight::column_range(
+            0,
+            2,
+            Border::full('+', '+', '+', '+', '+', '+', '+', '+'),
+        ))
+        .to_string();
+
+    let expected = concat!(
+        "++++++++++++++++──────────┬──────────┐\n",
+        "+ N │ column 0 + column 1 │ column 2 │\n",
+        "+───┼──────────+──────────┼──────────┤\n",
+        "+ 0 │   0-0    +   0-1    │   0-2    │\n",
+        "+───┼──────────+──────────┼──────────┤\n",
+        "+ 1 │   1-0    +   1-1    │   1-2    │\n",
+        "+───┼──────────+──────────┼──────────┤\n",
+        "+ 2 │   2-0    +   2-1    │   2-2    │\n",
+        "++++++++++++++++──────────┴──────────┘\n",
+    );
+
+    assert_eq!(table, expected);
+}
+
+#[test]
+fn highlingt_frame() {
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data)
+        .with(Style::pseudo())
+        .with(Highlight::frame(Border::full(
+            '+', '+', '+', '+', '+', '+', '+', '+',
+        )))
+        .to_string();
+
+    let expected = concat!(
+        "++++++++++++++++++++++++++++++++++++++\n",
+        "+ N │ column 0 │ column 1 │ column 2 +\n",
+        "+───┼──────────┼──────────┼──────────+\n",
+        "+ 0 │   0-0    │   0-1    │   0-2    +\n",
+        "+───┼──────────┼──────────┼──────────+\n",
+        "+ 1 │   1-0    │   1-1    │   1-2    +\n",
+        "+───┼──────────┼──────────┼──────────+\n",
+        "+ 2 │   2-0    │   2-1    │   2-2    +\n",
+        "++++++++++++++++++++++++++++++++++++++\n",
+    );
+
+    assert_eq!(table, expected);
+}
diff --git a/tests/indent_test.rs b/tests/indent_test.rs
index 7433e34..e3b76a4 100644
--- a/tests/indent_test.rs
+++ b/tests/indent_test.rs
@@ -1,119 +1,62 @@
-use tabled::{Alignment, Full, Indent, Modify, Row, Style, Table, Tabled};
+use crate::util::create_vector;
+use tabled::{Alignment, Full, Indent, Modify, Row, Style, Table};
 
-#[derive(Tabled)]
-struct Linux {
-    id: u8,
-    destribution: &'static str,
-    link: &'static str,
-}
+mod util;
 
 #[test]
 fn indent() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        " id | destribution | link                      \n",
-        "----+--------------+---------------------------\n",
-        " 0  | Fedora       | https://getfedora.org/    \n",
-        "    |              |                           \n",
-        "    |              |                           \n",
-        " 2  | OpenSUSE     | https://www.opensuse.org/ \n",
-        "    |              |                           \n",
-        "    |              |                           \n",
-        " 3  | Endeavouros  | https://endeavouros.com/  \n",
-        "    |              |                           \n",
-        "    |              |                           \n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(Modify::new(Full).with(Alignment::left()))
         .with(Modify::new(Row(1..)).with(Indent::new(1, 1, 0, 2)))
         .to_string();
 
+    let expected = concat!(
+        " N | column 0 | column 1 | column 2 \n",
+        "---+----------+----------+----------\n",
+        " 0 | 0-0      | 0-1      | 0-2      \n",
+        "   |          |          |          \n",
+        "   |          |          |          \n",
+        " 1 | 1-0      | 1-1      | 1-2      \n",
+        "   |          |          |          \n",
+        "   |          |          |          \n",
+        " 2 | 2-0      | 2-1      | 2-2      \n",
+        "   |          |          |          \n",
+        "   |          |          |          \n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn indent_multiline() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "Open\nSUSE",
-            link: "https://www.\nopensuse\n.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        " id | destribution |           link           \n",
-        "----+--------------+--------------------------\n",
-        "    |              |                          \n",
-        " 0  |    Fedora    |  https://getfedora.org/  \n",
-        "    |              |                          \n",
-        "    |              |                          \n",
-        " 2  |     Open     |       https://www.       \n",
-        "    |     SUSE     |         opensuse         \n",
-        "    |              |          .org/           \n",
-        "    |              |                          \n",
-        "    |              |                          \n",
-        " 3  | Endeavouros  | https://endeavouros.com/ \n",
-        "    |              |                          \n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(Modify::new(Row(1..)).with(Indent::new(1, 1, 1, 1)))
         .to_string();
 
+    let expected = concat!(
+        " N | column 0 | column 1 | column 2 \n",
+        "---+----------+----------+----------\n",
+        "   |          |          |          \n",
+        " 0 |   0-0    |   0-1    |   0-2    \n",
+        "   |          |          |          \n",
+        "   |          |          |          \n",
+        " 1 |   1-0    |   1-1    |   1-2    \n",
+        "   |          |          |          \n",
+        "   |          |          |          \n",
+        " 2 |   2-0    |   2-1    |   2-2    \n",
+        "   |          |          |          \n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn indent_multiline_with_vertical_alignment() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "Open\nSUSE",
-            link: "https://www.\nopensuse\n.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::psql())
         .with(
@@ -124,22 +67,18 @@ fn indent_multiline_with_vertical_alignment() {
         .with(Modify::new(Row(1..)).with(Indent::new(1, 1, 1, 1)))
         .to_string();
 
-    println!("{}", table);
-
     let expected = concat!(
-        " id | destribution |           link           \n",
-        "----+--------------+--------------------------\n",
-        "    |              |                          \n",
-        " 0  |    Fedora    |  https://getfedora.org/  \n",
-        "    |              |                          \n",
-        "    |              |                          \n",
-        "    |              |       https://www.       \n",
-        " 2  |     Open     |         opensuse         \n",
-        "    |     SUSE     |          .org/           \n",
-        "    |              |                          \n",
-        "    |              |                          \n",
-        " 3  | Endeavouros  | https://endeavouros.com/ \n",
-        "    |              |                          \n",
+        " N | column 0 | column 1 | column 2 \n",
+        "---+----------+----------+----------\n",
+        "   |          |          |          \n",
+        " 0 |   0-0    |   0-1    |   0-2    \n",
+        "   |          |          |          \n",
+        "   |          |          |          \n",
+        " 1 |   1-0    |   1-1    |   1-2    \n",
+        "   |          |          |          \n",
+        "   |          |          |          \n",
+        " 2 |   2-0    |   2-1    |   2-2    \n",
+        "   |          |          |          \n",
     );
 
     assert_eq!(table, expected);
diff --git a/tests/panel_test.rs b/tests/panel_test.rs
index a18370f..deda024 100644
--- a/tests/panel_test.rs
+++ b/tests/panel_test.rs
@@ -1,9 +1,13 @@
-use papergrid::{Border, Entity};
-use tabled::{Alignment, Footer, Full, Header, Modify, Object, Panel, Row, Style, Table, Tabled};
+use crate::util::create_vector;
+use tabled::{
+    Alignment, Border, Footer, Full, Header, Highlight, Modify, Object, Panel, Row, Style, Table,
+};
+
+mod util;
 
 #[test]
 fn panel_has_no_style_by_default() {
-    let table = Table::new(test_data())
+    let table = Table::new(create_vector::<3, 3>())
         .with(Style::psql())
         .with(Panel("Linux Distributions", 0))
         .to_string();
@@ -11,25 +15,25 @@ fn panel_has_no_style_by_default() {
     // todo: it would be better if vertical split was not set in panel line
     // it is because it has right border printed
     let expected = concat!(
-        "Linux Distributions                             \n",
-        " id | destribution |           link            \n",
-        "----+--------------+---------------------------\n",
-        " 0  |    Fedora    |  https://getfedora.org/   \n",
-        " 2  |   OpenSUSE   | https://www.opensuse.org/ \n",
-        " 3  | Endeavouros  | https://endeavouros.com/  \n",
+        "Linux Distributions                  \n",
+        " N | column 0 | column 1 | column 2 \n",
+        "---+----------+----------+----------\n",
+        " 0 |   0-0    |   0-1    |   0-2    \n",
+        " 1 |   1-0    |   1-1    |   1-2    \n",
+        " 2 |   2-0    |   2-1    |   2-2    \n",
     );
 
-    println!("{}", table);
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn highligt_panel() {
-    let table = Table::new(test_data())
+    let table = Table::new(create_vector::<3, 3>())
         .with(Panel("Linux Distributions", 0))
-        .with(Style::psql().highlight(
-            Entity::Cell(0, 0),
+        .with(Style::psql())
+        .with(Highlight::cell(
+            0,
+            0,
             Border::full('#', '#', '#', '#', '#', '#', '#', '#'),
         ))
         .to_string();
@@ -37,45 +41,41 @@ fn highligt_panel() {
     // todo: it would be better if vertical split was not set in panel line
     // it is because it has right border printed
     let expected = concat!(
-        "#################################################\n",
-        "#Linux Distributions                            #\n",
-        "#################################################\n",
-        "  id | destribution |           link            \n",
-        "  0  |    Fedora    |  https://getfedora.org/   \n",
-        "  2  |   OpenSUSE   | https://www.opensuse.org/ \n",
-        "  3  | Endeavouros  | https://endeavouros.com/  \n",
+        "######################################\n",
+        "#Linux Distributions                 #\n",
+        "######################################\n",
+        "  N | column 0 | column 1 | column 2 \n",
+        "  0 |   0-0    |   0-1    |   0-2    \n",
+        "  1 |   1-0    |   1-1    |   1-2    \n",
+        "  2 |   2-0    |   2-1    |   2-2    \n",
     );
 
-    println!("{}", table);
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn top_panel() {
-    let table = Table::new(test_data())
+    let table = Table::new(create_vector::<3, 3>())
         .with(Panel("Linux Distributions", 0))
         .with(Modify::new(Full).with(Alignment::center_horizontal()))
         .with(Style::psql())
         .to_string();
 
     let expected = concat!(
-        "              Linux Distributions              |\n",
-        "-----------------------------------------------+\n",
-        " id | destribution |           link            \n",
-        " 0  |    Fedora    |  https://getfedora.org/   \n",
-        " 2  |   OpenSUSE   | https://www.opensuse.org/ \n",
-        " 3  | Endeavouros  | https://endeavouros.com/  \n",
+        "        Linux Distributions         |\n",
+        "------------------------------------+\n",
+        " N | column 0 | column 1 | column 2 \n",
+        " 0 |   0-0    |   0-1    |   0-2    \n",
+        " 1 |   1-0    |   1-1    |   1-2    \n",
+        " 2 |   2-0    |   2-1    |   2-2    \n",
     );
 
-    println!("{}", table);
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn bottom_panel() {
-    let data = test_data();
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Panel("Linux Distributions", data.len() + 1))
         .with(Modify::new(Row(data.len() + 1..)).with(Alignment::center_horizontal()))
@@ -83,56 +83,52 @@ fn bottom_panel() {
         .to_string();
 
     let expected = concat!(
-        " id | destribution |           link            \n",
-        "----+--------------+---------------------------\n",
-        " 0  |    Fedora    |  https://getfedora.org/   \n",
-        " 2  |   OpenSUSE   | https://www.opensuse.org/ \n",
-        " 3  | Endeavouros  | https://endeavouros.com/  \n",
-        "              Linux Distributions              |\n",
+        " N | column 0 | column 1 | column 2 \n",
+        "---+----------+----------+----------\n",
+        " 0 |   0-0    |   0-1    |   0-2    \n",
+        " 1 |   1-0    |   1-1    |   1-2    \n",
+        " 2 |   2-0    |   2-1    |   2-2    \n",
+        "        Linux Distributions         |\n",
     );
 
-    println!("{}", table);
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn inner_panel() {
-    let table = Table::new(test_data())
+    let table = Table::new(create_vector::<3, 3>())
         .with(Panel("Linux Distributions", 2))
         .with(Modify::new(Row(2..)).with(Alignment::center_horizontal()))
         .with(Style::psql())
         .to_string();
 
     let expected = concat!(
-        " id | destribution |           link            \n",
-        "----+--------------+---------------------------\n",
-        " 0  |    Fedora    |  https://getfedora.org/   \n",
-        "              Linux Distributions              |\n",
-        " 2  |   OpenSUSE   | https://www.opensuse.org/ \n",
-        " 3  | Endeavouros  | https://endeavouros.com/  \n",
+        " N | column 0 | column 1 | column 2 \n",
+        "---+----------+----------+----------\n",
+        " 0 |   0-0    |   0-1    |   0-2    \n",
+        "        Linux Distributions         |\n",
+        " 1 |   1-0    |   1-1    |   1-2    \n",
+        " 2 |   2-0    |   2-1    |   2-2    \n",
     );
 
-    println!("{}", table);
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn header() {
-    let table = Table::new(test_data())
+    let table = Table::new(create_vector::<3, 3>())
         .with(Header("Linux Distributions"))
         .with(Style::psql())
         .with(Modify::new(Row(0..1)).with(Alignment::center_horizontal()))
         .to_string();
 
     let expected = concat!(
-        "              Linux Distributions              |\n",
-        "-----------------------------------------------+\n",
-        " id | destribution |           link            \n",
-        " 0  |    Fedora    |  https://getfedora.org/   \n",
-        " 2  |   OpenSUSE   | https://www.opensuse.org/ \n",
-        " 3  | Endeavouros  | https://endeavouros.com/  \n",
+        "        Linux Distributions         |\n",
+        "------------------------------------+\n",
+        " N | column 0 | column 1 | column 2 \n",
+        " 0 |   0-0    |   0-1    |   0-2    \n",
+        " 1 |   1-0    |   1-1    |   1-2    \n",
+        " 2 |   2-0    |   2-1    |   2-2    \n",
     );
 
     assert_eq!(table, expected);
@@ -140,7 +136,7 @@ fn header() {
 
 #[test]
 fn footer() {
-    let data = test_data();
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Header("Linux Distributions"))
         .with(Footer("The end"))
@@ -149,41 +145,14 @@ fn footer() {
         .to_string();
 
     let expected = concat!(
-        "              Linux Distributions              |\n",
-        "-----------------------------------------------+\n",
-        " id | destribution |           link            \n",
-        " 0  |    Fedora    |  https://getfedora.org/   \n",
-        " 2  |   OpenSUSE   | https://www.opensuse.org/ \n",
-        " 3  | Endeavouros  | https://endeavouros.com/  \n",
-        "                    The end                    |\n",
+        "        Linux Distributions         |\n",
+        "------------------------------------+\n",
+        " N | column 0 | column 1 | column 2 \n",
+        " 0 |   0-0    |   0-1    |   0-2    \n",
+        " 1 |   1-0    |   1-1    |   1-2    \n",
+        " 2 |   2-0    |   2-1    |   2-2    \n",
+        "              The end               |\n",
     );
 
     assert_eq!(table, expected);
 }
-
-#[derive(Tabled)]
-struct Linux {
-    id: u8,
-    destribution: &'static str,
-    link: &'static str,
-}
-
-fn test_data() -> Vec<Linux> {
-    vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ]
-}
diff --git a/tests/rotate_test.rs b/tests/rotate_test.rs
index 6399b19..699d92b 100644
--- a/tests/rotate_test.rs
+++ b/tests/rotate_test.rs
@@ -1,46 +1,196 @@
 // todo: add method for SPACING between cells.
 //       add MARGIN && PADDING instead of indent?
-use tabled::{Full, Indent, Modify, Rotate, Style, Table, Tabled};
+use tabled::{Border, Highlight, Rotate, Style, Table};
 
-#[derive(Tabled)]
-struct Linux {
-    id: u8,
-    destribution: &'static str,
-    link: &'static str,
+#[test]
+fn test_rotate() {
+    let table = || Table::new([(123, 456, 789), (234, 567, 891)]);
+
+    assert_eq!(
+        table()
+            .with(Rotate::Left)
+            .with(Rotate::Left)
+            .with(Rotate::Left)
+            .with(Rotate::Left)
+            .to_string(),
+        table().to_string()
+    );
+    assert_eq!(
+        table()
+            .with(Rotate::Right)
+            .with(Rotate::Right)
+            .with(Rotate::Right)
+            .with(Rotate::Right)
+            .to_string(),
+        table().to_string()
+    );
+    assert_eq!(
+        table().with(Rotate::Right).with(Rotate::Left).to_string(),
+        table().to_string()
+    );
+    assert_eq!(
+        table().with(Rotate::Left).with(Rotate::Right).to_string(),
+        table().to_string()
+    );
+    assert_eq!(
+        table().with(Rotate::Bottom).with(Rotate::Top).to_string(),
+        table().to_string()
+    );
+    assert_eq!(
+        table()
+            .with(Rotate::Bottom)
+            .with(Rotate::Bottom)
+            .to_string(),
+        table().to_string()
+    );
+    assert_eq!(
+        table().with(Rotate::Top).with(Rotate::Top).to_string(),
+        table().to_string()
+    );
 }
 
 #[test]
-fn rotate_left() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+fn test_3x3_box() {
+    let table = Table::new([(123, 456, 789), (234, 567, 891)]);
+
+    let table = table.with(Rotate::Left);
+    assert_eq!(
+        table.to_string(),
+        "+-----+-----+-----+\n\
+         | i32 | 789 | 891 |\n\
+         +-----+-----+-----+\n\
+         | i32 | 456 | 567 |\n\
+         +-----+-----+-----+\n\
+         | i32 | 123 | 234 |\n\
+         +-----+-----+-----+\n"
+    );
+
+    let table = table.with(Rotate::Right).with(Rotate::Right);
+    assert_eq!(
+        table.to_string(),
+        "+-----+-----+-----+\n\
+         | 234 | 123 | i32 |\n\
+         +-----+-----+-----+\n\
+         | 567 | 456 | i32 |\n\
+         +-----+-----+-----+\n\
+         | 891 | 789 | i32 |\n\
+         +-----+-----+-----+\n"
+    );
+}
+
+#[test]
+fn test_left_rotate() {
+    let table = Table::new([(123, 456, 789), (234, 567, 891), (111, 222, 333)]);
+
+    let table = table.with(Rotate::Left);
+    assert_eq!(
+        table.to_string(),
+        "+-----+-----+-----+-----+\n\
+         | i32 | 789 | 891 | 333 |\n\
+         +-----+-----+-----+-----+\n\
+         | i32 | 456 | 567 | 222 |\n\
+         +-----+-----+-----+-----+\n\
+         | i32 | 123 | 234 | 111 |\n\
+         +-----+-----+-----+-----+\n"
+    );
+}
+
+#[test]
+fn test_right_rotate() {
+    let table = Table::new([(123, 456, 789), (234, 567, 891), (111, 222, 333)]);
+
+    let table = table.with(Rotate::Right);
+    assert_eq!(
+        table.to_string(),
+        "+-----+-----+-----+-----+\n\
+         | 111 | 234 | 123 | i32 |\n\
+         +-----+-----+-----+-----+\n\
+         | 222 | 567 | 456 | i32 |\n\
+         +-----+-----+-----+-----+\n\
+         | 333 | 891 | 789 | i32 |\n\
+         +-----+-----+-----+-----+\n"
+    );
+}
+
+#[test]
+fn test_bottom_rotate() {
+    let table = Table::new([(123, 456, 789), (234, 567, 891), (111, 222, 333)]);
+
+    let table = table.with(Rotate::Bottom);
+    assert_eq!(
+        table.to_string(),
+        "+-----+-----+-----+\n\
+         | 111 | 222 | 333 |\n\
+         +-----+-----+-----+\n\
+         | 234 | 567 | 891 |\n\
+         +-----+-----+-----+\n\
+         | 123 | 456 | 789 |\n\
+         +-----+-----+-----+\n\
+         | i32 | i32 | i32 |\n\
+         +-----+-----+-----+\n"
+    );
+}
+
+#[test]
+fn test_top_rotate() {
+    let table = Table::new([(123, 456, 789), (234, 567, 891), (111, 222, 333)]);
+
+    let table = table.with(Rotate::Top);
+    assert_eq!(
+        table.to_string(),
+        "+-----+-----+-----+\n\
+         | 111 | 222 | 333 |\n\
+         +-----+-----+-----+\n\
+         | 234 | 567 | 891 |\n\
+         +-----+-----+-----+\n\
+         | 123 | 456 | 789 |\n\
+         +-----+-----+-----+\n\
+         | i32 | i32 | i32 |\n\
+         +-----+-----+-----+\n"
+    );
+}
+
+#[test]
+fn rotate_preserve_border_styles_test() {
+    let data = [(123, 456, 789), (234, 567, 891), (111, 222, 333)];
+
+    let table = Table::new(&data)
+        .with(Style::ascii())
+        .with(Highlight::row(0, Border::default().top('*')))
+        .with(Rotate::Left)
+        .to_string();
+
+    assert_eq!(
+        table,
+        concat!(
+            "******+-----+-----+-----+\n",
+            "| i32 | 789 | 891 | 333 |\n",
+            "+-----+-----+-----+-----+\n",
+            "| i32 | 456 | 567 | 222 |\n",
+            "+-----+-----+-----+-----+\n",
+            "| i32 | 123 | 234 | 111 |\n",
+            "+-----+-----+-----+-----+\n",
+        ),
+    );
 
     let table = Table::new(&data)
+        .with(Style::ascii())
+        .with(Highlight::cell(0, 2, Border::default().bottom('*')))
         .with(Rotate::Left)
-        .with(Style::noborder())
-        .with(Modify::new(Full).with(Indent::new(1, 1, 0, 0)))
         .to_string();
 
+    // it's a correct behaviour because
+    // when we sen bottom border of cell(0, 2) we also set top border of cell(1, 2)
     assert_eq!(
         table,
         concat!(
-            "     link       https://getfedora.org/   https://www.opensuse.org/   https://endeavouros.com/ \n",
-            " destribution           Fedora                   OpenSUSE                  Endeavouros        \n",
-            "      id                  0                          2                          3             \n"
+            "+-----+*****+-----+-----+\n",
+            "| i32 | 789 | 891 | 333 |\n",
+            "+*****+-----+-----+-----+\n",
+            "| i32 | 456 | 567 | 222 |\n",
+            "+-----+-----+-----+-----+\n",
+            "| i32 | 123 | 234 | 111 |\n",
+            "+-----+-----+-----+-----+\n",
         ),
     );
 }
diff --git a/tests/style_test.rs b/tests/style_test.rs
index ea9262b..c52dcf6 100644
--- a/tests/style_test.rs
+++ b/tests/style_test.rs
@@ -1,325 +1,154 @@
-use papergrid::{Border, Entity};
+use crate::util::create_vector;
 use tabled::style::Line;
-use tabled::{Style, Table, Tabled};
+use tabled::{Style, Table};
 
-#[derive(Tabled)]
-struct Linux {
-    id: u8,
-    destribution: &'static str,
-    link: &'static str,
-}
+mod util;
 
 #[test]
 fn default_style() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data).with(Style::ascii()).to_string();
 
     let expected = concat!(
-        "+----+--------------+---------------------------+\n",
-        "| id | destribution |           link            |\n",
-        "+----+--------------+---------------------------+\n",
-        "| 0  |    Fedora    |  https://getfedora.org/   |\n",
-        "+----+--------------+---------------------------+\n",
-        "| 2  |   OpenSUSE   | https://www.opensuse.org/ |\n",
-        "+----+--------------+---------------------------+\n",
-        "| 3  | Endeavouros  | https://endeavouros.com/  |\n",
-        "+----+--------------+---------------------------+\n",
+        "+---+----------+----------+----------+\n",
+        "| N | column 0 | column 1 | column 2 |\n",
+        "+---+----------+----------+----------+\n",
+        "| 0 |   0-0    |   0-1    |   0-2    |\n",
+        "+---+----------+----------+----------+\n",
+        "| 1 |   1-0    |   1-1    |   1-2    |\n",
+        "+---+----------+----------+----------+\n",
+        "| 2 |   2-0    |   2-1    |   2-2    |\n",
+        "+---+----------+----------+----------+\n",
     );
 
-    let table = Table::new(&data).with(Style::default()).to_string();
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn psql_style() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data).with(Style::psql()).to_string();
 
     let expected = concat!(
-        " id | destribution |           link            \n",
-        "----+--------------+---------------------------\n",
-        " 0  |    Fedora    |  https://getfedora.org/   \n",
-        " 2  |   OpenSUSE   | https://www.opensuse.org/ \n",
-        " 3  | Endeavouros  | https://endeavouros.com/  \n",
+        " N | column 0 | column 1 | column 2 \n",
+        "---+----------+----------+----------\n",
+        " 0 |   0-0    |   0-1    |   0-2    \n",
+        " 1 |   1-0    |   1-1    |   1-2    \n",
+        " 2 |   2-0    |   2-1    |   2-2    \n",
     );
 
-    let table = Table::new(&data).with(Style::psql()).to_string();
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn github_markdown_style() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data).with(Style::github_markdown()).to_string();
 
     let expected = concat!(
-        "| id | destribution |           link            |\n",
-        "|----+--------------+---------------------------|\n",
-        "| 0  |    Fedora    |  https://getfedora.org/   |\n",
-        "| 2  |   OpenSUSE   | https://www.opensuse.org/ |\n",
-        "| 3  | Endeavouros  | https://endeavouros.com/  |\n",
+        "| N | column 0 | column 1 | column 2 |\n",
+        "|---+----------+----------+----------|\n",
+        "| 0 |   0-0    |   0-1    |   0-2    |\n",
+        "| 1 |   1-0    |   1-1    |   1-2    |\n",
+        "| 2 |   2-0    |   2-1    |   2-2    |\n",
     );
 
-    let table = Table::new(&data).with(Style::github_markdown()).to_string();
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn pseudo_style() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data).with(Style::pseudo()).to_string();
 
     let expected = concat!(
-        "┌────┬──────────────┬───────────────────────────┐\n",
-        "│ id │ destribution │           link            │\n",
-        "├────┼──────────────┼───────────────────────────┤\n",
-        "│ 0  │    Fedora    │  https://getfedora.org/   │\n",
-        "├────┼──────────────┼───────────────────────────┤\n",
-        "│ 2  │   OpenSUSE   │ https://www.opensuse.org/ │\n",
-        "├────┼──────────────┼───────────────────────────┤\n",
-        "│ 3  │ Endeavouros  │ https://endeavouros.com/  │\n",
-        "└────┴──────────────┴───────────────────────────┘\n",
+        "┌───┬──────────┬──────────┬──────────┐\n",
+        "│ N │ column 0 │ column 1 │ column 2 │\n",
+        "├───┼──────────┼──────────┼──────────┤\n",
+        "│ 0 │   0-0    │   0-1    │   0-2    │\n",
+        "├───┼──────────┼──────────┼──────────┤\n",
+        "│ 1 │   1-0    │   1-1    │   1-2    │\n",
+        "├───┼──────────┼──────────┼──────────┤\n",
+        "│ 2 │   2-0    │   2-1    │   2-2    │\n",
+        "└───┴──────────┴──────────┴──────────┘\n",
     );
 
-    let table = Table::new(&data).with(Style::pseudo()).to_string();
-
-    println!("{}", table);
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn pseudo_clean_style() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data).with(Style::pseudo_clean()).to_string();
 
     let expected = concat!(
-        "┌────┬──────────────┬───────────────────────────┐\n",
-        "│ id │ destribution │           link            │\n",
-        "├────┼──────────────┼───────────────────────────┤\n",
-        "│ 0  │    Fedora    │  https://getfedora.org/   │\n",
-        "│ 2  │   OpenSUSE   │ https://www.opensuse.org/ │\n",
-        "│ 3  │ Endeavouros  │ https://endeavouros.com/  │\n",
-        "└────┴──────────────┴───────────────────────────┘\n",
+        "┌───┬──────────┬──────────┬──────────┐\n",
+        "│ N │ column 0 │ column 1 │ column 2 │\n",
+        "├───┼──────────┼──────────┼──────────┤\n",
+        "│ 0 │   0-0    │   0-1    │   0-2    │\n",
+        "│ 1 │   1-0    │   1-1    │   1-2    │\n",
+        "│ 2 │   2-0    │   2-1    │   2-2    │\n",
+        "└───┴──────────┴──────────┴──────────┘\n",
     );
 
-    let table = Table::new(&data).with(Style::pseudo_clean()).to_string();
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn noborder_style() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
+    let data = create_vector::<3, 3>();
+    let table = Table::new(&data).with(Style::noborder()).to_string();
 
     let expected = concat!(
-        " id   destribution             link            \n",
-        " 0       Fedora       https://getfedora.org/   \n",
-        " 2      OpenSUSE     https://www.opensuse.org/ \n",
-        " 3    Endeavouros    https://endeavouros.com/  \n",
+        " N   column 0   column 1   column 2 \n",
+        " 0     0-0        0-1        0-2    \n",
+        " 1     1-0        1-1        1-2    \n",
+        " 2     2-0        2-1        2-2    \n",
     );
 
-    let table = Table::new(&data).with(Style::noborder()).to_string();
-
     assert_eq!(table, expected);
 }
 
 #[test]
 fn style_head_changes() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "┌────┬──────────────┬───────────────────────────┐\n",
-        "│ id │ destribution │           link            │\n",
-        "│ 0  │    Fedora    │  https://getfedora.org/   │\n",
-        "│ 2  │   OpenSUSE   │ https://www.opensuse.org/ │\n",
-        "│ 3  │ Endeavouros  │ https://endeavouros.com/  │\n",
-        "└────┴──────────────┴───────────────────────────┘\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::pseudo_clean().header(None))
         .to_string();
 
+    let expected = concat!(
+        "┌───┬──────────┬──────────┬──────────┐\n",
+        "│ N │ column 0 │ column 1 │ column 2 │\n",
+        "│ 0 │   0-0    │   0-1    │   0-2    │\n",
+        "│ 1 │   1-0    │   1-1    │   1-2    │\n",
+        "│ 2 │   2-0    │   2-1    │   2-2    │\n",
+        "└───┴──────────┴──────────┴──────────┘\n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn style_frame_changes() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "│ id │ destribution │           link            │\n",
-        "├────┼──────────────┼───────────────────────────┤\n",
-        "│ 0  │    Fedora    │  https://getfedora.org/   │\n",
-        "│ 2  │   OpenSUSE   │ https://www.opensuse.org/ │\n",
-        "│ 3  │ Endeavouros  │ https://endeavouros.com/  │\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::pseudo_clean().frame_bottom(None).frame_top(None))
         .to_string();
 
+    let expected = concat!(
+        "│ N │ column 0 │ column 1 │ column 2 │\n",
+        "├───┼──────────┼──────────┼──────────┤\n",
+        "│ 0 │   0-0    │   0-1    │   0-2    │\n",
+        "│ 1 │   1-0    │   1-1    │   1-2    │\n",
+        "│ 2 │   2-0    │   2-1    │   2-2    │\n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn custom_style() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        " id \' destribution \'           link            \n",
-        "````\'``````````````\'```````````````````````````\n",
-        " 0  \'    Fedora    \'  https://getfedora.org/   \n",
-        "````\'``````````````\'```````````````````````````\n",
-        " 2  \'   OpenSUSE   \' https://www.opensuse.org/ \n",
-        "````\'``````````````\'```````````````````````````\n",
-        " 3  \' Endeavouros  \' https://endeavouros.com/  \n",
-        "****\'**************\'***************************\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(
             Style::noborder()
@@ -329,58 +158,16 @@ fn custom_style() {
         )
         .to_string();
 
-    println!("{}", table);
-
-    assert_eq!(table, expected);
-}
-
-#[test]
-fn style_highlingting() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
     let expected = concat!(
-        "++++++──────────────┬───────────────────────────┐\n",
-        "+ id + destribution │           link            │\n",
-        "+++++****************───────────────────────────┤\n",
-        "│ 0  *    Fedora    *  https://getfedora.org/   │\n",
-        "├────****************───────────────────────────┤\n",
-        "│ 2  │   OpenSUSE   │ https://www.opensuse.org/ │\n",
-        "├────┼──────────────┼───────────────────────────┤\n",
-        "│ 3  │ Endeavouros  │ https://endeavouros.com/  │\n",
-        "└────┴──────────────┴───────────────────────────┘\n",
+        " N ' column 0 ' column 1 ' column 2 \n",
+        "```'``````````'``````````'``````````\n",
+        " 0 '   0-0    '   0-1    '   0-2    \n",
+        "```'``````````'``````````'``````````\n",
+        " 1 '   1-0    '   1-1    '   1-2    \n",
+        "```'``````````'``````````'``````````\n",
+        " 2 '   2-0    '   2-1    '   2-2    \n",
+        "***'**********'**********'**********\n",
     );
 
-    let table = Table::new(&data)
-        .with(
-            Style::pseudo()
-                .highlight(
-                    Entity::Cell(0, 0),
-                    Border::full('+', '+', '+', '+', '+', '+', '+', '+'),
-                )
-                .highlight(
-                    Entity::Cell(1, 1),
-                    Border::full('*', '*', '*', '*', '*', '*', '*', '*'),
-                ),
-        )
-        .to_string();
-
-    println!("{}", table);
-
     assert_eq!(table, expected);
 }
diff --git a/tests/util.rs b/tests/util.rs
new file mode 100644
index 0000000..3487f42
--- /dev/null
+++ b/tests/util.rs
@@ -0,0 +1,57 @@
+use std::ops::{Index, IndexMut};
+
+use tabled::Tabled;
+
+#[derive(Debug)]
+pub struct Obj<const N: usize> {
+    data: Vec<String>,
+}
+
+impl<const N: usize> Obj<N> {
+    fn new(index: usize, mut data: Vec<String>) -> Self {
+        assert_eq!(data.len(), N);
+        data.insert(0, index.to_string());
+        Self { data }
+    }
+}
+
+impl<const N: usize> Index<usize> for Obj<N> {
+    type Output = String;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self.data[index]
+    }
+}
+
+impl<const N: usize> IndexMut<usize> for Obj<N> {
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        &mut self.data[index]
+    }
+}
+
+impl<const N: usize> Tabled for Obj<N> {
+    fn fields(&self) -> Vec<String> {
+        self.data.clone()
+    }
+
+    fn headers() -> Vec<String> {
+        std::iter::once("N".to_owned())
+            .chain((0..N).map(|n| format!("column {}", n)))
+            .collect()
+    }
+}
+
+pub fn create_vector<const ROWS: usize, const COLUMNS: usize>() -> Vec<Obj<COLUMNS>> {
+    let mut arr = Vec::with_capacity(ROWS);
+    for row in 0..ROWS {
+        let mut data = Vec::with_capacity(COLUMNS);
+        for column in 0..COLUMNS {
+            let text = format!("{}-{}", row, column);
+            data.push(text);
+        }
+
+        arr.push(Obj::new(row, data))
+    }
+
+    arr
+}
diff --git a/tests/width_test.rs b/tests/width_test.rs
index f6f6245..7a41121 100644
--- a/tests/width_test.rs
+++ b/tests/width_test.rs
@@ -1,87 +1,46 @@
-use tabled::{Column, Full, MaxWidth, Modify, Object, Row, Style, Table, Tabled};
+use crate::util::create_vector;
+use tabled::{Column, Full, MaxWidth, Modify, Object, Row, Style, Table};
 
-#[derive(Tabled)]
-struct Linux {
-    id: u8,
-    destribution: &'static str,
-    link: &'static str,
-}
+mod util;
 
 #[test]
 fn max_width() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "| id | destribution |  link  |\n",
-        "|----+--------------+--------|\n",
-        "| 0  |    Fed...    | htt... |\n",
-        "| 2  |    Ope...    | htt... |\n",
-        "| 3  |    End...    | htt... |\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::github_markdown())
-        .with(Modify::new(Column(1..).not(Row(..1))).with(MaxWidth::truncating(3, "...")))
+        .with(Modify::new(Column(1..).not(Row(..1))).with(MaxWidth::truncating(2, "...")))
         .to_string();
 
+    let expected = concat!(
+        "| N | column 0 | column 1 | column 2 |\n",
+        "|---+----------+----------+----------|\n",
+        "| 0 |  0-...   |  0-...   |  0-...   |\n",
+        "| 1 |  1-...   |  1-...   |  1-...   |\n",
+        "| 2 |  2-...   |  2-...   |  2-...   |\n",
+    );
+
     assert_eq!(table, expected);
 }
 
 #[test]
 fn max_width_wrapped() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "| id | destribution |    link    |\n",
-        "|----+--------------+------------|\n",
-        "| 0  |    Fedora    | https://ge |\n",
-        "|    |              | tfedora.or |\n",
-        "|    |              |     g/     |\n",
-        "| 2  |   OpenSUSE   | https://ww |\n",
-        "|    |              | w.opensuse |\n",
-        "|    |              |   .org/    |\n",
-        "| 3  |  Endeavouro  | https://en |\n",
-        "|    |      s       | deavouros. |\n",
-        "|    |              |    com/    |\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::github_markdown())
-        .with(Modify::new(Column(1..).not(Row(..1))).with(MaxWidth::wrapping(10)))
+        .with(Modify::new(Column(1..).not(Row(..1))).with(MaxWidth::wrapping(2)))
         .to_string();
 
+    let expected = concat!(
+        "| N | column 0 | column 1 | column 2 |\n",
+        "|---+----------+----------+----------|\n",
+        "| 0 |    0-    |    0-    |    0-    |\n",
+        "|   |    0     |    1     |    2     |\n",
+        "| 1 |    1-    |    1-    |    1-    |\n",
+        "|   |    0     |    1     |    2     |\n",
+        "| 2 |    2-    |    2-    |    2-    |\n",
+        "|   |    0     |    1     |    2     |\n",
+    );
+
     assert_eq!(table, expected);
 }
 
@@ -122,37 +81,20 @@ fn max_width_wrapped_collored() {
 
 #[test]
 fn dont_change_content_if_width_is_less_then_max_width() {
-    let data = vec![
-        Linux {
-            id: 0,
-            destribution: "Fedora",
-            link: "https://getfedora.org/",
-        },
-        Linux {
-            id: 2,
-            destribution: "OpenSUSE",
-            link: "https://www.opensuse.org/",
-        },
-        Linux {
-            id: 3,
-            destribution: "Endeavouros",
-            link: "https://endeavouros.com/",
-        },
-    ];
-
-    let expected = concat!(
-        "| id | destribution |           link            |\n",
-        "|----+--------------+---------------------------|\n",
-        "| 0  |    Fedora    |  https://getfedora.org/   |\n",
-        "| 2  |   OpenSUSE   | https://www.opensuse.org/ |\n",
-        "| 3  | Endeavouros  | https://endeavouros.com/  |\n",
-    );
-
+    let data = create_vector::<3, 3>();
     let table = Table::new(&data)
         .with(Style::github_markdown())
         .with(Modify::new(Full).with(MaxWidth::truncating(1000, "...")))
         .to_string();
 
+    let expected = concat!(
+        "| N | column 0 | column 1 | column 2 |\n",
+        "|---+----------+----------+----------|\n",
+        "| 0 |   0-0    |   0-1    |   0-2    |\n",
+        "| 1 |   1-0    |   1-1    |   1-2    |\n",
+        "| 2 |   2-0    |   2-1    |   2-2    |\n",
+    );
+
     assert_eq!(table, expected);
 }