prettytable/
lib.rs

1#![warn(missing_docs,
2        unused_extern_crates,
3        unused_import_braces,
4        unused_qualifications)]
5//! A formatted and aligned table printer written in rust
6extern crate unicode_width;
7extern crate term;
8extern crate atty;
9#[macro_use]
10extern crate lazy_static;
11extern crate encode_unicode;
12
13use std::io::{self, Write, Error};
14use std::fmt;
15use std::iter::{FromIterator, IntoIterator};
16use std::slice::{Iter, IterMut};
17use std::ops::{Index, IndexMut};
18use std::mem::transmute;
19
20pub use term::{Attr, color};
21pub(crate) use term::{Terminal, stdout};
22
23mod cell;
24mod row;
25pub mod format;
26mod utils;
27
28#[cfg(feature = "csv")]
29pub mod csv;
30
31pub use row::Row;
32pub use cell::Cell;
33use format::{TableFormat, LinePosition, consts};
34use utils::StringWriter;
35
36/// An owned printable table
37#[derive(Clone, Debug, Hash, PartialEq, Eq)]
38pub struct Table {
39    format: Box<TableFormat>,
40    titles: Box<Option<Row>>,
41    rows: Vec<Row>,
42}
43
44/// A borrowed immutable `Table` slice
45/// A `TableSlice` is obtained by slicing a `Table` with the `Slice::slice` method.
46///
47/// # Examples
48/// ```rust
49/// # #[macro_use] extern crate prettytable;
50/// use prettytable::{Table, Slice};
51/// # fn main() {
52/// let table = table![[1, 2, 3], [4, 5, 6], [7, 8, 9]];
53/// let slice = table.slice(1..);
54/// slice.printstd(); // Prints only rows 1 and 2
55///
56/// //Also supports other syntax :
57/// table.slice(..);
58/// table.slice(..2);
59/// table.slice(1..3);
60/// # }
61/// ```
62///
63#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
64pub struct TableSlice<'a> {
65    format: &'a TableFormat,
66    titles: &'a Option<Row>,
67    rows: &'a [Row],
68}
69
70impl<'a> TableSlice<'a> {
71    /// Compute and return the number of column
72    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
73    pub fn get_column_num(&self) -> usize {
74        let mut cnum = 0;
75        for r in self.rows {
76            let l = r.column_count();
77            if l > cnum {
78                cnum = l;
79            }
80        }
81        cnum
82    }
83
84    /// Get the number of rows
85    pub fn len(&self) -> usize {
86        self.rows.len()
87    }
88
89    /// Check if the table slice is empty
90    pub fn is_empty(&self) -> bool {
91        self.rows.is_empty()
92    }
93
94    /// Get an immutable reference to a row
95    pub fn get_row(&self, row: usize) -> Option<&Row> {
96        self.rows.get(row)
97    }
98
99    /// Get the width of the column at position `col_idx`.
100    /// Return 0 if the column does not exists;
101    fn get_column_width(&self, col_idx: usize) -> usize {
102        let mut width = match *self.titles {
103            Some(ref t) => t.get_column_width(col_idx, self.format),
104            None => 0,
105        };
106        for r in self.rows {
107            let l = r.get_column_width(col_idx, self.format);
108            if l > width {
109                width = l;
110            }
111        }
112        width
113    }
114
115    /// Get the width of all columns, and return a slice
116    /// with the result for each column
117    fn get_all_column_width(&self) -> Vec<usize> {
118        let colnum = self.get_column_num();
119        let mut col_width = vec![0usize; colnum];
120        for i in 0..colnum {
121            // TODO: calling "get_column_width()" in a loop is inefficient
122            col_width[i] = self.get_column_width(i);
123        }
124        col_width
125    }
126
127    /// Returns an iterator over the immutable cells of the column specified by `column`
128    pub fn column_iter(&self, column: usize) -> ColumnIter {
129        ColumnIter(self.rows.iter(), column)
130    }
131
132    /// Returns an iterator over immutable rows
133    pub fn row_iter(&self) -> Iter<Row> {
134        self.rows.iter()
135    }
136
137    /// Internal only
138    fn __print<T: Write + ?Sized, F>(&self, out: &mut T, f: F) -> Result<usize, Error>
139        where F: Fn(&Row, &mut T, &TableFormat, &[usize]) -> Result<usize, Error>
140    {
141        let mut height = 0;
142        // Compute columns width
143        let col_width = self.get_all_column_width();
144        height += self.format
145            .print_line_separator(out, &col_width, LinePosition::Top)?;
146        if let Some(ref t) = *self.titles {
147            height += f(t, out, self.format, &col_width)?;
148            height += self.format
149                .print_line_separator(out, &col_width, LinePosition::Title)?;
150        }
151        // Print rows
152        let mut iter = self.rows.into_iter().peekable();
153        while let Some(r) = iter.next() {
154            height += f(r, out, self.format, &col_width)?;
155            if iter.peek().is_some() {
156                height += self.format
157                    .print_line_separator(out, &col_width, LinePosition::Intern)?;
158            }
159        }
160        height += self.format
161            .print_line_separator(out, &col_width, LinePosition::Bottom)?;
162        out.flush()?;
163        Ok(height)
164    }
165
166    /// Print the table to `out` and returns the number of
167    /// line printed, or an error
168    pub fn print<T: Write + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
169        self.__print(out, Row::print)
170    }
171
172    /// Print the table to terminal `out`, applying styles when needed and returns the number of
173    /// line printed, or an error
174    pub fn print_term<T: Terminal + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
175        self.__print(out, Row::print_term)
176    }
177
178    /// Print the table to standard output. Colors won't be displayed unless
179    /// stdout is a tty terminal, or `force_colorize` is set to `true`.
180    /// In ANSI terminals, colors are displayed using ANSI escape characters. When for example the
181    /// output is redirected to a file, or piped to another program, the output is considered
182    /// as not beeing tty, and ANSI escape characters won't be displayed unless `force colorize`
183    /// is set to `true`.
184    /// # Returns
185    /// The number of lines printed
186    /// # Panic
187    /// Panic if writing to standard output fails
188    pub fn print_tty(&self, force_colorize: bool) -> usize {
189        let r = match (stdout(), atty::is(atty::Stream::Stdout) || force_colorize) {
190            (Some(mut o), true) => self.print_term(&mut *o),
191            _ => self.print(&mut io::stdout()),
192        };
193        match r {
194            Err(e) => panic!("Cannot print table to standard output : {}", e),
195            Ok(height) => height
196        }
197    }
198
199    /// Print the table to standard output. Colors won't be displayed unless
200    /// stdout is a tty terminal. This means that if stdout is redirected to a file, or piped
201    /// to another program, no color will be displayed.
202    /// To force colors rendering, use `print_tty()` method.
203    /// Calling `printstd()` is equivalent to calling `print_tty(false)`
204    /// # Returns
205    /// The number of lines printed
206    /// # Panic
207    /// Panic if writing to standard output fails
208    pub fn printstd(&self) -> usize {
209        self.print_tty(false)
210    }
211}
212
213impl<'a> IntoIterator for &'a TableSlice<'a> {
214    type Item = &'a Row;
215    type IntoIter = Iter<'a, Row>;
216    fn into_iter(self) -> Self::IntoIter {
217        self.row_iter()
218    }
219}
220
221impl Table {
222    /// Create an empty table
223    pub fn new() -> Table {
224        Self::init(Vec::new())
225    }
226
227    /// Create a table initialized with `rows`
228    pub fn init(rows: Vec<Row>) -> Table {
229        Table {
230            rows: rows,
231            titles: Box::new(None),
232            format: Box::new(*consts::FORMAT_DEFAULT),
233        }
234    }
235
236    /// Change the table format. Eg : Separators
237    pub fn set_format(&mut self, format: TableFormat) {
238        *self.format = format;
239    }
240
241    /// Get a mutable reference to the internal format
242    pub fn get_format(&mut self) -> &mut TableFormat {
243        &mut self.format
244    }
245
246    /// Compute and return the number of column
247    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
248    pub fn get_column_num(&self) -> usize {
249        self.as_slice().get_column_num()
250    }
251
252    /// Get the number of rows
253    pub fn len(&self) -> usize {
254        self.rows.len()
255    }
256
257    /// Check if the table is empty
258    pub fn is_empty(&self) -> bool {
259        self.rows.is_empty()
260    }
261
262    /// Set the optional title lines
263    pub fn set_titles(&mut self, titles: Row) {
264        *self.titles = Some(titles);
265    }
266
267    /// Unset the title line
268    pub fn unset_titles(&mut self) {
269        *self.titles = None;
270    }
271
272    /// Get a mutable reference to a row
273    pub fn get_mut_row(&mut self, row: usize) -> Option<&mut Row> {
274        self.rows.get_mut(row)
275    }
276
277    /// Get an immutable reference to a row
278    pub fn get_row(&self, row: usize) -> Option<&Row> {
279        self.rows.get(row)
280    }
281
282    /// Append a row in the table, transferring ownership of this row to the table
283    /// and returning a mutable reference to the row
284    pub fn add_row(&mut self, row: Row) -> &mut Row {
285        self.rows.push(row);
286        let l = self.rows.len() - 1;
287        &mut self.rows[l]
288    }
289
290    /// Append an empty row in the table. Return a mutable reference to this new row.
291    pub fn add_empty_row(&mut self) -> &mut Row {
292        self.add_row(Row::default())
293    }
294
295    /// Insert `row` at the position `index`, and return a mutable reference to this row.
296    /// If index is higher than current numbers of rows, `row` is appended at the end of the table
297    pub fn insert_row(&mut self, index: usize, row: Row) -> &mut Row {
298        if index < self.rows.len() {
299            self.rows.insert(index, row);
300            &mut self.rows[index]
301        } else {
302            self.add_row(row)
303        }
304    }
305
306    /// Modify a single element in the table
307    pub fn set_element(&mut self, element: &str, column: usize, row: usize) -> Result<(), &str> {
308        let rowline = self.get_mut_row(row).ok_or("Cannot find row")?;
309        // TODO: If a cell already exist, copy it's alignment parameter
310        rowline.set_cell(Cell::new(element), column)
311    }
312
313    /// Remove the row at position `index`. Silently skip if the row does not exist
314    pub fn remove_row(&mut self, index: usize) {
315        if index < self.rows.len() {
316            self.rows.remove(index);
317        }
318    }
319
320    /// Return an iterator over the immutable cells of the column specified by `column`
321    pub fn column_iter(&self, column: usize) -> ColumnIter {
322        ColumnIter(self.rows.iter(), column)
323    }
324
325    /// Return an iterator over the mutable cells of the column specified by `column`
326    pub fn column_iter_mut(&mut self, column: usize) -> ColumnIterMut {
327        ColumnIterMut(self.rows.iter_mut(), column)
328    }
329
330    /// Returns an iterator over immutable rows
331    pub fn row_iter(&self) -> Iter<Row> {
332        self.rows.iter()
333    }
334
335    /// Returns an iterator over mutable rows
336    pub fn row_iter_mut(&mut self) -> IterMut<Row> {
337        self.rows.iter_mut()
338    }
339
340    /// Print the table to `out` and returns the number
341    /// of lines printed, or an error
342    pub fn print<T: Write + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
343        self.as_slice().print(out)
344    }
345
346    /// Print the table to terminal `out`, applying styles when needed and returns the number
347    /// of lines printed, or an error
348    pub fn print_term<T: Terminal + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
349        self.as_slice().print_term(out)
350    }
351
352    /// Print the table to standard output. Colors won't be displayed unless
353    /// stdout is a tty terminal, or `force_colorize` is set to `true`.
354    /// In ANSI terminals, colors are displayed using ANSI escape characters. When for example the
355    /// output is redirected to a file, or piped to another program, the output is considered
356    /// as not beeing tty, and ANSI escape characters won't be displayed unless `force colorize`
357    /// is set to `true`.
358    /// # Returns
359    /// The number of lines printed
360    /// # Panic
361    /// Panic if writing to standard output fails
362    pub fn print_tty(&self, force_colorize: bool) -> usize {
363        self.as_slice().print_tty(force_colorize)
364    }
365
366    /// Print the table to standard output. Colors won't be displayed unless
367    /// stdout is a tty terminal. This means that if stdout is redirected to a file, or piped
368    /// to another program, no color will be displayed.
369    /// To force colors rendering, use `print_tty()` method.
370    /// Calling `printstd()` is equivalent to calling `print_tty(false)`
371    /// # Returns
372    /// The number of lines printed
373    /// # Panic
374    /// Panic if writing to standard output fails
375    pub fn printstd(&self) -> usize {
376        self.as_slice().printstd()
377    }
378
379}
380
381trait AsTableSlice {
382    fn as_slice(&self) -> TableSlice<'_> ;
383}
384
385impl AsTableSlice for Table {
386    fn as_slice(&self) -> TableSlice<'_> {
387        TableSlice { format: &self.format, titles: &self.titles, rows: &self.rows }
388    }
389}
390
391impl <T> AsTableSlice for T where T: AsRef<Table> {
392    fn as_slice(&self) -> TableSlice<'_> {
393        self.as_ref().as_slice()
394    }
395}
396
397impl Index<usize> for Table {
398    type Output = Row;
399    fn index(&self, idx: usize) -> &Self::Output {
400        &self.rows[idx]
401    }
402}
403
404impl<'a> Index<usize> for TableSlice<'a> {
405    type Output = Row;
406    fn index(&self, idx: usize) -> &Self::Output {
407        &self.rows[idx]
408    }
409}
410
411impl IndexMut<usize> for Table {
412    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
413        &mut self.rows[idx]
414    }
415}
416
417impl fmt::Display for Table {
418    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
419        self.as_slice().fmt(fmt)
420    }
421}
422
423impl<'a> fmt::Display for TableSlice<'a> {
424    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
425        let mut writer = StringWriter::new();
426        if self.print(&mut writer).is_err() {
427            return Err(fmt::Error);
428        }
429        fmt.write_str(writer.as_string())
430    }
431}
432
433impl<B: ToString, A: IntoIterator<Item = B>> FromIterator<A> for Table {
434    fn from_iter<T>(iterator: T) -> Table
435        where T: IntoIterator<Item = A>
436    {
437        Self::init(iterator.into_iter().map(Row::from).collect())
438    }
439}
440
441impl FromIterator<Row> for Table {
442    fn from_iter<T>(iterator: T) -> Table
443        where T: IntoIterator<Item = Row>
444    {
445        Self::init(iterator.into_iter().collect())
446    }
447}
448
449impl<T, A, B> From<T> for Table
450    where B: ToString,
451          A: IntoIterator<Item = B>,
452          T: IntoIterator<Item = A>
453{
454    fn from(it: T) -> Table {
455        Self::from_iter(it)
456    }
457}
458
459impl<'a> IntoIterator for &'a Table {
460    type Item = &'a Row;
461    type IntoIter = Iter<'a, Row>;
462    fn into_iter(self) -> Self::IntoIter {
463        self.row_iter()
464    }
465}
466
467impl<'a> IntoIterator for &'a mut Table {
468    type Item = &'a mut Row;
469    type IntoIter = IterMut<'a, Row>;
470    fn into_iter(self) -> Self::IntoIter {
471        self.row_iter_mut()
472    }
473}
474
475// impl IntoIterator for Table {
476//     type Item = Row;
477//     type IntoIter = std::vec::IntoIter<Self::Item>;
478//     fn into_iter(self) -> Self::IntoIter {
479//         self.rows.into_iter()
480//     }
481// }
482
483impl <A: Into<Row>> Extend<A> for Table {
484    fn extend<T: IntoIterator<Item=A>>(&mut self, iter: T) {
485        self.rows.extend(iter.into_iter().map(|r| r.into()));
486    }
487}
488
489/// Iterator over immutable cells in a column
490pub struct ColumnIter<'a>(Iter<'a, Row>, usize);
491
492impl<'a> Iterator for ColumnIter<'a> {
493    type Item = &'a Cell;
494    fn next(&mut self) -> Option<&'a Cell> {
495        self.0.next().and_then(|row| row.get_cell(self.1))
496    }
497}
498
499/// Iterator over mutable cells in a column
500pub struct ColumnIterMut<'a>(IterMut<'a, Row>, usize);
501
502impl<'a> Iterator for ColumnIterMut<'a> {
503    type Item = &'a mut Cell;
504    fn next(&mut self) -> Option<&'a mut Cell> {
505        self.0.next().and_then(|row| row.get_mut_cell(self.1))
506    }
507}
508
509impl <'a> AsTableSlice for TableSlice<'a> {
510    fn as_slice(&self) -> TableSlice<'_> {
511        *self
512    }
513}
514
515impl<'a> AsRef<TableSlice<'a>> for TableSlice<'a> {
516    fn as_ref(&self) -> &TableSlice<'a> {
517        self
518    }
519}
520
521/// Trait implemented by types which can be sliced
522pub trait Slice<'a, E> {
523    /// Type output after slicing
524    type Output: 'a;
525    /// Get a slice from self
526    fn slice(&'a self, arg: E) -> Self::Output;
527}
528
529impl<'a, T, E> Slice<'a, E> for T
530    where T: AsTableSlice,
531          [Row]: Index<E, Output = [Row]>
532{
533    type Output = TableSlice<'a>;
534    fn slice(&'a self, arg: E) -> Self::Output {
535        let mut sl  = self.as_slice();
536        sl.rows = sl.rows.index(arg);
537        sl
538    }
539}
540
541/// Create a table filled with some values
542///
543/// All the arguments used for elements must implement the `std::string::ToString` trait
544/// # Syntax
545/// ```text
546/// table!([Element1_ row1, Element2_ row1, ...], [Element1_row2, ...], ...);
547/// ```
548///
549/// # Example
550/// ```
551/// # #[macro_use] extern crate prettytable;
552/// # fn main() {
553/// // Create a table initialized with some rows :
554/// let tab = table!(["Element1", "Element2", "Element3"],
555/// 				 [1, 2, 3],
556/// 				 ["A", "B", "C"]
557/// 				 );
558/// # drop(tab);
559/// # }
560/// ```
561///
562/// Some style can also be given in table creation
563///
564/// ```
565/// # #[macro_use] extern crate prettytable;
566/// # fn main() {
567/// let tab = table!([FrByl->"Element1", Fgc->"Element2", "Element3"],
568/// 				 [FrBy => 1, 2, 3],
569/// 				 ["A", "B", "C"]
570/// 				 );
571/// # drop(tab);
572/// # }
573/// ```
574///
575/// For details about style specifier syntax, check doc for [`Cell::style_spec`](cell/struct.Cell.html#method.style_spec) method
576#[macro_export]
577macro_rules! table {
578    ($([$($content:tt)*]), *) => (
579        $crate::Table::init(vec![$(row![$($content)*]), *])
580    );
581}
582
583/// Create a table with `table!` macro, print it to standard output, then return this table for future usage.
584///
585/// The syntax is the same that the one for the `table!` macro
586#[macro_export]
587macro_rules! ptable {
588    ($($content:tt)*) => (
589        {
590            let tab = table!($($content)*);
591            tab.printstd();
592            tab
593        }
594    );
595}
596
597#[cfg(test)]
598mod tests {
599    use Table;
600    use Slice;
601    use Row;
602    use Cell;
603    use format;
604    use format::consts::{FORMAT_DEFAULT, FORMAT_NO_LINESEP, FORMAT_NO_COLSEP, FORMAT_CLEAN, FORMAT_BOX_CHARS};
605    use utils::StringWriter;
606
607    #[test]
608    fn table() {
609        let mut table = Table::new();
610        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
611        table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
612        table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
613        let out = "\
614+-----+----+-----+
615| t1  | t2 | t3  |
616+=====+====+=====+
617| a   | bc | def |
618+-----+----+-----+
619| def | bc | a   |
620+-----+----+-----+
621";
622        assert_eq!(table.to_string().replace("\r\n", "\n"), out);
623        assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
624        table.unset_titles();
625        let out = "\
626+-----+----+-----+
627| a   | bc | def |
628+-----+----+-----+
629| def | bc | a   |
630+-----+----+-----+
631";
632        assert_eq!(table.to_string().replace("\r\n", "\n"), out);
633        assert_eq!(5, table.print(&mut StringWriter::new()).unwrap());
634    }
635
636    #[test]
637    fn index() {
638        let mut table = Table::new();
639        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
640        table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
641        table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
642        assert_eq!(table[1][1].get_content(), "bc");
643
644        table[1][1] = Cell::new("newval");
645        assert_eq!(table[1][1].get_content(), "newval");
646
647        let out = "\
648+-----+--------+-----+
649| t1  | t2     | t3  |
650+=====+========+=====+
651| a   | bc     | def |
652+-----+--------+-----+
653| def | newval | a   |
654+-----+--------+-----+
655";
656        assert_eq!(table.to_string().replace("\r\n", "\n"), out);
657        assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
658    }
659
660    #[test]
661    fn table_size() {
662        let mut table = Table::new();
663        assert!(table.is_empty());
664        assert!(table.as_ref().is_empty());
665        assert_eq!(table.len(), 0);
666        assert_eq!(table.as_ref().len(), 0);
667        assert_eq!(table.get_column_num(), 0);
668        assert_eq!(table.as_ref().get_column_num(), 0);
669        table.add_empty_row();
670        assert!(!table.is_empty());
671        assert!(!table.as_ref().is_empty());
672        assert_eq!(table.len(), 1);
673        assert_eq!(table.as_ref().len(), 1);
674        assert_eq!(table.get_column_num(), 0);
675        assert_eq!(table.as_ref().get_column_num(), 0);
676        table[0].add_cell(Cell::default());
677        assert_eq!(table.get_column_num(), 1);
678        assert_eq!(table.as_ref().get_column_num(), 1);
679    }
680
681    #[test]
682    fn get_row() {
683        let mut table = Table::new();
684        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
685        table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
686        assert!(table.get_row(12).is_none());
687        assert!(table.get_row(1).is_some());
688        assert_eq!(table.get_row(1).unwrap()[0].get_content(), "def");
689        assert!(table.get_mut_row(12).is_none());
690        assert!(table.get_mut_row(1).is_some());
691        table.get_mut_row(1).unwrap().add_cell(Cell::new("z"));
692        assert_eq!(table.get_row(1).unwrap()[3].get_content(), "z");
693    }
694
695    #[test]
696    fn add_empty_row() {
697        let mut table = Table::new();
698        assert_eq!(table.len(), 0);
699        table.add_empty_row();
700        assert_eq!(table.len(), 1);
701        assert_eq!(table[0].len(), 0);
702    }
703
704    #[test]
705    fn remove_row() {
706        let mut table = Table::new();
707        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
708        table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
709        table.remove_row(12);
710        assert_eq!(table.len(), 2);
711        table.remove_row(0);
712        assert_eq!(table.len(), 1);
713        assert_eq!(table[0][0].get_content(), "def");
714    }
715
716    #[test]
717    fn insert_row() {
718        let mut table = Table::new();
719        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
720        table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
721        table.insert_row(12,
722                         Row::new(vec![Cell::new("1"), Cell::new("2"), Cell::new("3")]));
723        assert_eq!(table.len(), 3);
724        assert_eq!(table[2][1].get_content(), "2");
725        table.insert_row(1,
726                         Row::new(vec![Cell::new("3"), Cell::new("4"), Cell::new("5")]));
727        assert_eq!(table.len(), 4);
728        assert_eq!(table[1][1].get_content(), "4");
729        assert_eq!(table[2][1].get_content(), "bc");
730    }
731
732    #[test]
733    fn set_element() {
734        let mut table = Table::new();
735        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
736        table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
737        assert!(table.set_element("foo", 12, 12).is_err());
738        assert!(table.set_element("foo", 1, 1).is_ok());
739        assert_eq!(table[1][1].get_content(), "foo");
740    }
741
742    #[test]
743    fn no_linesep() {
744        let mut table = Table::new();
745        table.set_format(*FORMAT_NO_LINESEP);
746        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
747        table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
748        table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
749        assert_eq!(table[1][1].get_content(), "bc");
750
751        table[1][1] = Cell::new("newval");
752        assert_eq!(table[1][1].get_content(), "newval");
753
754        let out = "\
755+-----+--------+-----+
756| t1  | t2     | t3  |
757| a   | bc     | def |
758| def | newval | a   |
759+-----+--------+-----+
760";
761        assert_eq!(table.to_string().replace("\r\n", "\n"), out);
762        assert_eq!(5, table.print(&mut StringWriter::new()).unwrap());
763    }
764
765    #[test]
766    fn no_colsep() {
767        let mut table = Table::new();
768        table.set_format(*FORMAT_NO_COLSEP);
769        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
770        table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
771        table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
772        assert_eq!(table[1][1].get_content(), "bc");
773
774        table[1][1] = Cell::new("newval");
775        assert_eq!(table[1][1].get_content(), "newval");
776
777        let out = "\
778------------------
779 t1   t2      t3 \n\
780==================
781 a    bc      def \n\
782------------------
783 def  newval  a \n\
784------------------
785";
786        println!("{}", out);
787        println!("____");
788        println!("{}", table.to_string().replace("\r\n", "\n"));
789        assert_eq!(table.to_string().replace("\r\n", "\n"), out);
790        assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
791    }
792
793    #[test]
794    fn clean() {
795        let mut table = Table::new();
796        table.set_format(*FORMAT_CLEAN);
797        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
798        table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
799        table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
800        assert_eq!(table[1][1].get_content(), "bc");
801
802        table[1][1] = Cell::new("newval");
803        assert_eq!(table[1][1].get_content(), "newval");
804
805        let out = "\
806\u{0020}t1   t2      t3 \n\
807\u{0020}a    bc      def \n\
808\u{0020}def  newval  a \n\
809";
810        println!("{}", out);
811        println!("____");
812        println!("{}", table.to_string().replace("\r\n", "\n"));
813        assert_eq!(out, table.to_string().replace("\r\n", "\n"));
814        assert_eq!(3, table.print(&mut StringWriter::new()).unwrap());
815    }
816
817    #[test]
818    fn padding() {
819        let mut table = Table::new();
820        let mut format = *FORMAT_DEFAULT;
821        format.padding(2, 2);
822        table.set_format(format);
823        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
824        table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
825        table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
826        assert_eq!(table[1][1].get_content(), "bc");
827
828        table[1][1] = Cell::new("newval");
829        assert_eq!(table[1][1].get_content(), "newval");
830
831        let out = "\
832+-------+----------+-------+
833|  t1   |  t2      |  t3   |
834+=======+==========+=======+
835|  a    |  bc      |  def  |
836+-------+----------+-------+
837|  def  |  newval  |  a    |
838+-------+----------+-------+
839";
840        println!("{}", out);
841        println!("____");
842        println!("{}", table.to_string().replace("\r\n", "\n"));
843        assert_eq!(out, table.to_string().replace("\r\n", "\n"));
844        assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
845    }
846
847    #[test]
848    fn indent() {
849        let mut table = Table::new();
850        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
851        table.add_row(Row::new(vec![Cell::new("def"), Cell::new("bc"), Cell::new("a")]));
852        table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
853        table.get_format().indent(8);
854        let out = "        +-----+----+-----+
855        | t1  | t2 | t3  |
856        +=====+====+=====+
857        | a   | bc | def |
858        +-----+----+-----+
859        | def | bc | a   |
860        +-----+----+-----+
861";
862        assert_eq!(table.to_string().replace("\r\n", "\n"), out);
863        assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
864    }
865
866    #[test]
867    fn slices() {
868        let mut table = Table::new();
869        table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
870        table.add_row(Row::new(vec![Cell::new("0"), Cell::new("0"), Cell::new("0")]));
871        table.add_row(Row::new(vec![Cell::new("1"), Cell::new("1"), Cell::new("1")]));
872        table.add_row(Row::new(vec![Cell::new("2"), Cell::new("2"), Cell::new("2")]));
873        table.add_row(Row::new(vec![Cell::new("3"), Cell::new("3"), Cell::new("3")]));
874        table.add_row(Row::new(vec![Cell::new("4"), Cell::new("4"), Cell::new("4")]));
875        table.add_row(Row::new(vec![Cell::new("5"), Cell::new("5"), Cell::new("5")]));
876        let out = "\
877+----+----+----+
878| t1 | t2 | t3 |
879+====+====+====+
880| 1  | 1  | 1  |
881+----+----+----+
882| 2  | 2  | 2  |
883+----+----+----+
884| 3  | 3  | 3  |
885+----+----+----+
886";
887        let slice = table.slice(..);
888        let slice = slice.slice(1..);
889        let slice = slice.slice(..3);
890        assert_eq!(out, slice.to_string().replace("\r\n", "\n"));
891        assert_eq!(9, slice.print(&mut StringWriter::new()).unwrap());
892        assert_eq!(out, table.slice(1..4).to_string().replace("\r\n", "\n"));
893        assert_eq!(9, table.slice(1..4).print(&mut StringWriter::new()).unwrap());
894    }
895
896    #[test]
897    fn test_unicode_separators() {
898        let mut table = Table::new();
899        table.set_format(*FORMAT_BOX_CHARS);
900        table.add_row(Row::new(vec![Cell::new("1"), Cell::new("1"), Cell::new("1")]));
901        table.add_row(Row::new(vec![Cell::new("2"), Cell::new("2"), Cell::new("2")]));
902        table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2"), Cell::new("t3")]));
903        let out = "\
904┌────┬────┬────┐
905│ t1 │ t2 │ t3 │
906├────┼────┼────┤
907│ 1  │ 1  │ 1  │
908├────┼────┼────┤
909│ 2  │ 2  │ 2  │
910└────┴────┴────┘
911";
912        println!("{}", out);
913        println!("____");
914        println!("{}", table.to_string().replace("\r\n", "\n"));
915        assert_eq!(out, table.to_string().replace("\r\n", "\n"));
916        assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
917    }
918
919    #[test]
920    fn test_readme_format() {
921
922        // The below is lifted from the README
923
924        let mut table = Table::new();
925        let format = format::FormatBuilder::new()
926            .column_separator('|')
927            .borders('|')
928            .separators(&[format::LinePosition::Top,
929                        format::LinePosition::Bottom],
930                        format::LineSeparator::new('-', '+', '+', '+'))
931            .padding(1, 1)
932            .build();
933        table.set_format(format);
934
935        table.set_titles(Row::new(vec![Cell::new("Title 1"), Cell::new("Title 2")]));
936        table.add_row(Row::new(vec![Cell::new("Value 1"), Cell::new("Value 2")]));
937        table.add_row(Row::new(vec![Cell::new("Value three"), Cell::new("Value four")]));
938
939        let out = "\
940+-------------+------------+
941| Title 1     | Title 2    |
942| Value 1     | Value 2    |
943| Value three | Value four |
944+-------------+------------+
945";
946
947        println!("{}", out);
948        println!("____");
949        println!("{}", table.to_string().replace("\r\n","\n"));
950        assert_eq!(out, table.to_string().replace("\r\n","\n"));
951        assert_eq!(5, table.print(&mut StringWriter::new()).unwrap());
952    }
953
954    #[test]
955    fn test_readme_format_with_title() {
956        let mut table = Table::new();
957        table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
958
959        table.set_titles(Row::new(vec![Cell::new("Title 1"), Cell::new("Title 2")]));
960        table.add_row(Row::new(vec![Cell::new("Value 1"), Cell::new("Value 2")]));
961        table.add_row(Row::new(vec![Cell::new("Value three"), Cell::new("Value four")]));
962
963        let out = "\
964+-------------+------------+
965| Title 1     | Title 2    |
966+-------------+------------+
967| Value 1     | Value 2    |
968| Value three | Value four |
969+-------------+------------+
970";
971        println!("{}", out);
972        println!("____");
973        println!("{}", table.to_string().replace("\r\n","\n"));
974        assert_eq!(out, table.to_string().replace("\r\n","\n"));
975        assert_eq!(6, table.print(&mut StringWriter::new()).unwrap());
976    }
977
978    #[test]
979    fn test_horizontal_span() {
980        let mut table = Table::new();
981        table.set_titles(Row::new(vec![Cell::new("t1"), Cell::new("t2").with_hspan(2)]));
982        table.add_row(Row::new(vec![Cell::new("a"), Cell::new("bc"), Cell::new("def")]));
983        table.add_row(Row::new(vec![Cell::new("def").style_spec("H02c"), Cell::new("a")]));
984        let out = "\
985+----+----+-----+
986| t1 | t2       |
987+====+====+=====+
988| a  | bc | def |
989+----+----+-----+
990|   def   | a   |
991+----+----+-----+
992";
993        println!("{}", out);
994        println!("____");
995        println!("{}", table.to_string().replace("\r\n","\n"));
996        assert_eq!(out, table.to_string().replace("\r\n","\n"));
997        assert_eq!(7, table.print(&mut StringWriter::new()).unwrap());
998    }
999}