text: #!/usr/bin/python
  #
  # Copyright 2012 Google Inc. All Rights Reserved.
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #      http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  # implied. See the License for the specific language governing
  # permissions and limitations under the License.
  
  """Unittest for text table."""
  
  from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from __future__ import unicode_literals
  
  from builtins import range
  import unittest
  from io import StringIO
  from textfsm import terminal
  from textfsm import texttable
  
  
  def cmp(a, b):
    return (a > b) - (a < b)
  
  
  class UnitTestRow(unittest.TestCase):
    """Tests texttable.Row() class."""
  
    def setUp(self):
      super(UnitTestRow, self).setUp()
      self.row = texttable.Row()
      self.row._keys = ['a', 'b', 'c']
      self.row._values = ['1', '2', '3']
      self.row._BuildIndex()
  
    def testRowBasicMethods(self):
      row = texttable.Row()
      # Setting columns (__setitem__).
      row['a'] = 'one'
      row['b'] = 'two'
      row['c'] = 'three'
  
      # Access a single column (__getitem__).
      self.assertEqual('one', row['a'])
      self.assertEqual('two', row['b'])
      self.assertEqual('three', row['c'])
  
      # Access multiple columns (__getitem__).
      self.assertEqual(['one', 'three'], row[('a', 'c')])
      self.assertEqual(['two', 'three'], row[('b', 'c')])
  
      # Access integer indexes (__getitem__).
      self.assertEqual('one', row[0])
      self.assertEqual(['two', 'three'], row[1:])
  
      # Test "get".
      self.assertEqual('one', row.get('a'))
      self.assertEqual('one', row.get('a', 'four'))
      self.assertEqual('four', row.get('d', 'four'))
      self.assertIsNone(row.get('d'))
  
      self.assertEqual(['one', 'three'], row.get(('a', 'c'), 'four'))
      self.assertEqual(['one', 'four'], row.get(('a', 'd'), 'four'))
      self.assertEqual(['one', None], row.get(('a', 'd')))
  
      self.assertEqual('one', row.get(0, 'four'))
      self.assertEqual('four', row.get(3, 'four'))
      self.assertIsNone(row.get(3))
  
      # Change existing column value.
      row['b'] = 'Two'
      self.assertEqual('Two', row['b'])
  
      # Length.
      self.assertEqual(3, len(row))
  
      # Contains.
      self.assertTrue('two' not in row)
      self.assertTrue('Two' in row)
  
      # Iteration.
      self.assertEqual(['one', 'Two', 'three'], list(row))
  
    def testRowPublicMethods(self):
      self.row.header = ('x', 'y', 'z')
      # Header should be set, values initialised to None.
      self.assertEqual(['x', 'y', 'z'], self.row.header)
      self.assertEqual(['1', '2', '3'], self.row.values)
      row = texttable.Row()
      row.header = ('x', 'y', 'z')
      self.assertEqual(['x', 'y', 'z'], row.header)
      self.assertEqual([None, None, None], row.values)
  
    def testSetValues(self):
      """Tests setting row values from 'From' method."""
  
      # Set values from Dict.
      self.row._SetValues({'a': 'seven', 'b': 'eight', 'c': 'nine'})
      self.assertEqual(['seven', 'eight', 'nine'], self.row._values)
      self.row._SetValues({'b': '8', 'a': '7', 'c': '9'})
      self.assertEqual(['7', '8', '9'], self.row._values)
  
      # Converts integers to string equivalents.
      # Excess key/value pairs are ignored.
      self.row._SetValues({'a': 1, 'b': 2, 'c': 3, 'd': 4})
      self.assertEqual(['1', '2', '3'], self.row._values)
  
      # Values can come from a list of equal length the the keys.
      self.row._SetValues((7, '8', 9))
      self.assertEqual(['7', '8', '9'], self.row._values)
  
      # Or from a tuple of the same length.
      self.row._SetValues(('vb', 'coopers', 'squires'))
      self.assertEqual(['vb', 'coopers', 'squires'], self.row._values)
  
      # Raise error if list length is incorrect.
      self.assertRaises(TypeError, self.row._SetValues,
                        ['seven', 'eight', 'nine', 'ten'])
      # Raise error if row object has mismatched header.
      row = texttable.Row()
      self.row._keys = ['a']
      self.row._values = ['1']
      self.assertRaises(TypeError, self.row._SetValues, row)
      # Raise error if assigning wrong data type.
      self.assertRaises(TypeError, row._SetValues, 'abc')
  
    def testHeader(self):
      """Tests value property."""
      self.row.header = ('x', 'y', 'z')
      self.assertEqual(['x', 'y', 'z'], self.row.header)
      self.assertRaises(ValueError, self.row._SetHeader, ('a', 'b', 'c', 'd'))
  
    def testValue(self):
      """Tests value property."""
      self.row.values = {'a': 'seven', 'b': 'eight', 'c': 'nine'}
      self.assertEqual(['seven', 'eight', 'nine'], self.row.values)
      self.row.values = (7, '8', 9)
      self.assertEqual(['7', '8', '9'], self.row.values)
  
    def testIndex(self):
      """Tests Insert and Index methods."""
  
      self.assertEqual(1, self.row.index('b'))
      self.assertRaises(ValueError, self.row.index, 'bogus')
  
      # Insert element within row.
      self.row.Insert('black', 'white', 1)
      self.row.Insert('red', 'yellow', -1)
      self.assertEqual(['a', 'black', 'b', 'red', 'c'], self.row.header)
      self.assertEqual(['1', 'white', '2', 'yellow', '3'], self.row.values)
      self.assertEqual(1, self.row.index('black'))
      self.assertEqual(2, self.row.index('b'))
      self.assertRaises(IndexError, self.row.Insert, 'grey', 'gray', 6)
      self.assertRaises(IndexError, self.row.Insert, 'grey', 'gray', -7)
  
  
  class MyRow(texttable.Row):
    pass
  
  
  class UnitTestTextTable(unittest.TestCase):
  
    # pylint: disable=invalid-name
    def BasicTable(self):
      t = texttable.TextTable()
      t.header = ('a', 'b', 'c')
      t.Append(('1', '2', '3'))
      t.Append(('10', '20', '30'))
      return t
  
    def testFilter(self):
      old_table = self.BasicTable()
      filtered_table = old_table.Filter(
          function=lambda row: row['a'] == '10')
      self.assertEqual(1, filtered_table.size)
  
    def testFilterNone(self):
      t = texttable.TextTable()
      t.header = ('a', 'b', 'c')
      t.Append(('', '', []))
      filtered_table = t.Filter()
      self.assertEqual(0, filtered_table.size)
  
    def testMap(self):
      old_table = self.BasicTable()
      filtered_table = old_table.Map(
          function=lambda row: row['a'] == '10' and row)
      self.assertEqual(1, filtered_table.size)
  
    def testCustomRow(self):
      table = texttable.TextTable()
      table.header = ('a', 'b', 'c')
      self.assertEqual(type(texttable.Row()), type(table[0]))
      table = texttable.TextTable(row_class=MyRow)
      self.assertEqual(MyRow, table.row_class)
      table.header = ('a', 'b', 'c')
      self.assertEqual(type(MyRow()), type(table[0]))
  
    def testTableRepr(self):
      self.assertEqual(
          "TextTable('a, b, c\\n1, 2, 3\\n10, 20, 30\\n')",
          repr(self.BasicTable()))
  
    def testTableStr(self):
      self.assertEqual('a, b, c\n1, 2, 3\n10, 20, 30\n',
                       self.BasicTable().__str__())
  
    def testTableSetRow(self):
      t = self.BasicTable()
      t.Append(('one', 'two', 'three'))
      self.assertEqual(['one', 'two', 'three'], t[3].values)
      self.assertEqual(3, t.size)
  
    def testTableRowTypes(self):
      t = self.BasicTable()
      t.Append(('one', ['two', None], None))
      self.assertEqual(['one', ['two', 'None'], 'None'], t[3].values)
      self.assertEqual(3, t.size)
  
    def testTableRowDictWithInt(self):
      t = self.BasicTable()
      t.Append({'a': 1, 'b': 'two', 'c': 3})
      self.assertEqual(['1', 'two', '3'], t[3].values)
      self.assertEqual(3, t.size)
  
    def testTableRowListWithInt(self):
      t = self.BasicTable()
      t.Append([1, 'two', 3])
      self.assertEqual(['1', 'two', '3'], t[3].values)
      self.assertEqual(3, t.size)
  
    def testTableGetRow(self):
      t = self.BasicTable()
      self.assertEqual(['1', '2', '3'], t[1].values)
      self.assertEqual(['1', '3'], t[1][('a', 'c')])
      self.assertEqual('3', t[1][('c')])
      for rnum in range(t.size):
        self.assertEqual(rnum, t[rnum].row)
  
    def testTableRowWith(self):
      t = self.BasicTable()
      self.assertEqual(t.RowWith('a', '10'), t[2])
      self.assertRaises(IndexError, t.RowWith, 'g', '5')
  
    def testContains(self):
      t = self.BasicTable()
      self.assertTrue('a' in t)
      self.assertFalse('x' in t)
  
    def testIteration(self):
      t = self.BasicTable()
      index = 0
      for r in t:
        index += 1
        self.assertEqual(r, t[index])
        self.assertEqual(index, r.table._iterator)
  
      # Have we iterated over all entries.
      self.assertEqual(index, t.size)
      # The iterator count is reset.
      self.assertEqual(0, t._iterator)
  
      # Can we iterate repeatedly.
      index = 0
      for r in t:
        index += 1
        self.assertEqual(r, t[index])
  
      index1 = 0
      try:
        for r in t:
          index1 += 1
          index2 = 0
          self.assertEqual(index1, r.table._iterator)
          # Test nesting of iterations.
          for r2 in t:
            index2 += 1
            self.assertEqual(index2, r2.table._iterator)
            # Preservation of outer iterator after 'break'.
            if index1 == 2 and index2 == 2:
              break
          if index1 == 2:
            # Restoration of initial iterator after exception.
            raise IndexError
          self.assertEqual(index1, r.table._iterator)
      except IndexError:
        pass
  
      # Have we iterated over all entries - twice.
      self.assertEqual(index, t.size)
      self.assertEqual(index2, t.size)
      # The iterator count is reset.
      self.assertEqual(0, t._iterator)
  
    def testCsvToTable(self):
      buf = """
      # A comment
  a,b, c, d  # Trim comment
  # Inline comment
  # 1,2,3,4
  1,2,3,4
  5, 6, 7, 8
  10, 11
  # More comments.
  """
      f = StringIO(buf)
      t = texttable.TextTable()
      self.assertEqual(2, t.CsvToTable(f))
      # pylint: disable=E1101
      self.assertEqual(['a', 'b', 'c', 'd'], t.header.values)
      self.assertEqual(['1', '2', '3', '4'], t[1].values)
      self.assertEqual(['5', '6', '7', '8'], t[2].values)
      self.assertEqual(2, t.size)
  
    def testHeaderIndex(self):
      t = self.BasicTable()
      self.assertEqual('c', t.header[2])
      self.assertEqual('a', t.header[0])
  
    def testAppend(self):
      t = self.BasicTable()
      t.Append(['10', '20', '30'])
      self.assertEqual(3, t.size)
      self.assertEqual(['10', '20', '30'], t[3].values)
  
      t.Append(('100', '200', '300'))
      self.assertEqual(4, t.size)
      self.assertEqual(['100', '200', '300'], t[4].values)
  
      t.Append(t[1])
      self.assertEqual(5, t.size)
      self.assertEqual(['1', '2', '3'], t[5].values)
  
      t.Append({'a': '11', 'b': '12', 'c': '13'})
      self.assertEqual(6, t.size)
      self.assertEqual(['11', '12', '13'], t[6].values)
  
      # The row index and container table should be set on new rows.
      self.assertEqual(6, t[6].row)
      self.assertEqual(t[1].table, t[6].table)
  
      self.assertRaises(TypeError, t.Append, ['20', '30'])
      self.assertRaises(TypeError, t.Append, ('1', '2', '3', '4'))
      self.assertRaises(TypeError, t.Append,
                        {'a': '11', 'b': '12', 'd': '13'})
  
    def testDeleteRow(self):
      t = self.BasicTable()
      self.assertEqual(2, t.size)
      t.Remove(1)
      self.assertEqual(['10', '20', '30'], t[1].values)
      for row in t:
        self.assertEqual(row, t[row.row])
      t.Remove(1)
      self.assertFalse(t.size)
  
    def testRowNumberandParent(self):
      t = self.BasicTable()
      t.Append(['10', '20', '30'])
      t.Remove(1)
      for rownum, row in enumerate(t, start=1):
        self.assertEqual(row.row, rownum)
        self.assertEqual(row.table, t)
      t2 = self.BasicTable()
      t.table = t2
      for rownum, row in enumerate(t, start=1):
        self.assertEqual(row.row, rownum)
        self.assertEqual(row.table, t)
  
    def testAddColumn(self):
      t = self.BasicTable()
      t.AddColumn('Beer')
      # pylint: disable=E1101
      self.assertEqual(['a', 'b', 'c', 'Beer'], t.header.values)
      self.assertEqual(['10', '20', '30', ''], t[2].values)
  
      t.AddColumn('Wine', default='Merlot', col_index=1)
      self.assertEqual(['a', 'Wine', 'b', 'c', 'Beer'], t.header.values)
      self.assertEqual(['10', 'Merlot', '20', '30', ''], t[2].values)
  
      t.AddColumn('Spirits', col_index=-2)
      self.assertEqual(['a', 'Wine', 'b', 'Spirits', 'c', 'Beer'],
                       t.header.values)
      self.assertEqual(['10', 'Merlot', '20', '', '30', ''], t[2].values)
  
      self.assertRaises(IndexError, t.AddColumn, 'x', col_index=6)
      self.assertRaises(IndexError, t.AddColumn, 'x', col_index=-7)
      self.assertRaises(texttable.TableError, t.AddColumn, 'b')
  
    def testAddTable(self):
      t = self.BasicTable()
      t2 = self.BasicTable()
      t3 = t + t2
      # pylint: disable=E1101
      self.assertEqual(['a', 'b', 'c'], t3.header.values)
      self.assertEqual(['10', '20', '30'], t3[2].values)
      self.assertEqual(['10', '20', '30'], t3[4].values)
      self.assertEqual(4, t3.size)
  
    def testExtendTable(self):
      t2 = self.BasicTable()
      t2.AddColumn('Beer')
      t2[1]['Beer'] = 'Lager'
      t2[1]['three'] = 'three'
      t2.Append(('one', 'two', 'three', 'Stout'))
  
      t = self.BasicTable()
      # Explicit key, use first column.
      t.extend(t2, ('a',))
      # pylint: disable=E1101
      self.assertEqual(['a', 'b', 'c', 'Beer'], t.header.values)
      # Only new columns have updated values.
      self.assertEqual(['1', '2', '3', 'Lager'], t[1].values)
      # All rows are extended.
      self.assertEqual(['10', '20', '30', ''], t[2].values)
      # The third row of 't2', is not included as there is no matching
      # row with the same key in the first table 't'.
      self.assertEqual(2, t.size)
  
      # pylint: disable=E1101
      t = self.BasicTable()
      # If a Key is non-unique (which is a soft-error), then the first instance
      # on the RHS is used for and applied to all non-unique entries on the LHS.
      t.Append(('1', '2b', '3b'))
      t2.Append(('1', 'two', '', 'Ale'))
      t.extend(t2, ('a',))
      self.assertEqual(['1', '2', '3', 'Lager'], t[1].values)
      self.assertEqual(['1', '2b', '3b', 'Lager'], t[3].values)
  
      t = self.BasicTable()
      # No explicit key, row number is used as the key.
      t.extend(t2)
      self.assertEqual(['a', 'b', 'c', 'Beer'], t.header.values)
      # Since row is key we pick up new values from corresponding row number.
      self.assertEqual(['1', '2', '3', 'Lager'], t[1].values)
      # All rows are still extended.
      self.assertEqual(['10', '20', '30', ''], t[2].values)
      # The third/fourth row of 't2', is not included as there is no corresponding
      # row in the first table 't'.
      self.assertEqual(2, t.size)
  
      t = self.BasicTable()
      t.Append(('1', 'two', '3'))
      t.Append(('two', '1', 'three'))
      t2 = texttable.TextTable()
      t2.header = ('a', 'b', 'c', 'Beer')
      t2.Append(('1', 'two', 'three', 'Stout'))
      # Explicitly declare which columns constitute the key.
      # Sometimes more than one row is needed to define a unique key (superkey).
      t.extend(t2, ('a', 'b'))
  
      self.assertEqual(['a', 'b', 'c', 'Beer'], t.header.values)
      # key '1', '2' does not equal '1', 'two', so column unmatched.
      self.assertEqual(['1', '2', '3', ''], t[1].values)
      # '1', 'two' matches but 'two', '1' does not as order is important.
      self.assertEqual(['1', 'two', '3', 'Stout'], t[3].values)
      self.assertEqual(['two', '1', 'three', ''], t[4].values)
      self.assertEqual(4, t.size)
  
      # Expects a texttable as the argument.
      self.assertRaises(AttributeError, t.extend, ['a', 'list'])
      # All Key column Names must be valid.
      self.assertRaises(IndexError, t.extend, ['a', 'list'], ('a', 'bogus'))
  
    def testTableWithLabels(self):
      t = self.BasicTable()
      self.assertEqual(
          '# LABEL a\n1.b 2\n1.c 3\n10.b 20\n10.c 30\n',
          t.LabelValueTable())
      self.assertEqual(
          '# LABEL a\n1.b 2\n1.c 3\n10.b 20\n10.c 30\n',
          t.LabelValueTable(['a']))
      self.assertEqual(
          '# LABEL a.c\n1.3.b 2\n10.30.b 20\n',
          t.LabelValueTable(['a', 'c']))
      self.assertEqual(
          '# LABEL a.c\n1.3.b 2\n10.30.b 20\n',
          t.LabelValueTable(['c', 'a']))
      self.assertRaises(texttable.TableError, t.LabelValueTable, ['a', 'z'])
  
    def testTextJustify(self):
      t = texttable.TextTable()
      self.assertEqual([' a    '], t._TextJustify('a', 6))
      self.assertEqual([' a b  '], t._TextJustify('a b', 6))
      self.assertEqual([' a  b '], t._TextJustify('a  b', 6))
      self.assertEqual([' a ', ' b '], t._TextJustify('a b', 3))
      self.assertEqual([' a ', ' b '], t._TextJustify('a  b', 3))
      self.assertRaises(texttable.TableError, t._TextJustify, 'a', 2)
      self.assertRaises(texttable.TableError, t._TextJustify, 'a bb', 3)
      self.assertEqual([' a b  '], t._TextJustify('a\tb', 6))
      self.assertEqual([' a  b '], t._TextJustify('a\t\tb', 6))
      self.assertEqual([' a    ', ' b    '], t._TextJustify('a\nb\t', 6))
  
    def testSmallestColSize(self):
      t = texttable.TextTable()
      self.assertEqual(1, t._SmallestColSize('a'))
      self.assertEqual(2, t._SmallestColSize('a bb'))
      self.assertEqual(4, t._SmallestColSize('a cccc bb'))
      self.assertEqual(0, t._SmallestColSize(''))
      self.assertEqual(1, t._SmallestColSize('a\tb'))
      self.assertEqual(1, t._SmallestColSize('a\nb\tc'))
      self.assertEqual(3, t._SmallestColSize('a\nbbb\n\nc'))
      # Check if _SmallestColSize is not influenced by ANSI colors.
      self.assertEqual(
          3, t._SmallestColSize('bbb ' + terminal.AnsiText('bb', ['red'])))
  
    def testFormattedTableColor(self):
      # Test to sepcify the color defined in terminal.FG_COLOR_WORDS
      t = texttable.TextTable()
      t.header = ('LSP', 'Name')
      t.Append(('col1', 'col2'))
      for color_key in terminal.FG_COLOR_WORDS:
        t[0].color = terminal.FG_COLOR_WORDS[color_key]
        t.FormattedTable()
        self.assertEqual(sorted(t[0].color),
                         sorted(terminal.FG_COLOR_WORDS[color_key]))
      for color_key in terminal.BG_COLOR_WORDS:
        t[0].color = terminal.BG_COLOR_WORDS[color_key]
        t.FormattedTable()
        self.assertEqual(sorted(t[0].color),
                         sorted(terminal.BG_COLOR_WORDS[color_key]))
  
    def testFormattedTableColoredMultilineCells(self):
      t = texttable.TextTable()
      t.header = ('LSP', 'Name')
      t.Append((terminal.AnsiText('col1 boembabies', ['yellow']), 'col2'))
      t.Append(('col1', 'col2'))
      self.assertEqual(
          ' LSP           Name \n'
          '====================\n'
          ' \033[33mcol1          col2 \n'
          ' boembabies\033[0m         \n'
          '--------------------\n'
          ' col1          col2 \n',
          t.FormattedTable(width=20))
  
    def testFormattedTableColoredCells(self):
      t = texttable.TextTable()
      t.header = ('LSP', 'Name')
      t.Append((terminal.AnsiText('col1', ['yellow']), 'col2'))
      t.Append(('col1', 'col2'))
      self.assertEqual(
          ' LSP   Name \n'
          '============\n'
          ' \033[33mcol1\033[0m  col2 \n'
          ' col1  col2 \n',
          t.FormattedTable())
  
    def testFormattedTableColoredHeaders(self):
      t = texttable.TextTable()
      t.header = (terminal.AnsiText('LSP', ['yellow']), 'Name')
      t.Append(('col1', 'col2'))
      t.Append(('col1', 'col2'))
      self.assertEqual(
          ' \033[33mLSP\033[0m   Name \n'
          '============\n'
          ' col1  col2 \n'
          ' col1  col2 \n',
          t.FormattedTable())
  
      self.assertEqual(
          ' col1  col2 \n'
          ' col1  col2 \n',
          t.FormattedTable(display_header=False))
  
    def testFormattedTable(self):
      # Basic table has a single whitespace on each side of the max cell width.
      t = self.BasicTable()
      self.assertEqual(
          ' a   b   c  \n'
          '============\n'
          ' 1   2   3  \n'
          ' 10  20  30 \n',
          t.FormattedTable())
  
      # An increase in a cell size (or header), increases the side of that column.
      t.AddColumn('Beer')
      self.assertEqual(
          ' a   b   c   Beer \n'
          '==================\n'
          ' 1   2   3        \n'
          ' 10  20  30       \n',
          t.FormattedTable())
  
      self.assertEqual(
          ' 1   2   3        \n'
          ' 10  20  30       \n',
          t.FormattedTable(display_header=False))
  
      # Multiple words are on one line while space permits.
      t.Remove(1)
      t.Append(('', '', '', 'James Squire'))
      self.assertEqual(
          ' a   b   c   Beer         \n'
          '==========================\n'
          ' 10  20  30               \n'
          '             James Squire \n',
          t.FormattedTable())
  
      # Or split across rows if not enough space.
      # A '---' divider is inserted to give a delimiter for multiline data.
      self.assertEqual(
          ' a   b   c   Beer   \n'
          '====================\n'
          ' 10  20  30         \n'
          '--------------------\n'
          '             James  \n'
          '             Squire \n',
          t.FormattedTable(20))
  
      # Not needed below the data if last line, is needed otherwise.
      t.Append(('1', '2', '3', '4'))
      self.assertEqual(
          ' a   b   c   Beer   \n'
          '====================\n'
          ' 10  20  30         \n'
          '--------------------\n'
          '             James  \n'
          '             Squire \n'
          '--------------------\n'
          ' 1   2   3   4      \n',
          t.FormattedTable(20))
  
      # Multiple multi line columms.
      t.Remove(3)
      t.Append(('', 'A small essay with a longword here', '1', '2'))
      self.assertEqual(
          ' a   b         c   Beer   \n'
          '==========================\n'
          ' 10  20        30         \n'
          '--------------------------\n'
          '                   James  \n'
          '                   Squire \n'
          '--------------------------\n'
          '     A small   1   2      \n'
          '     essay                \n'
          '     with a               \n'
          '     longword             \n'
          '     here                 \n',
          t.FormattedTable(26))
  
      # Available space is added to multiline columns proportionaly
      # i.e. a column with twice as much text gets twice the space.
      self.assertEqual(
          ' a   b            c   Beer   \n'
          '=============================\n'
          ' 10  20           30         \n'
          '-----------------------------\n'
          '                      James  \n'
          '                      Squire \n'
          '-----------------------------\n'
          '     A small      1   2      \n'
          '     essay with              \n'
          '     a longword              \n'
          '     here                    \n',
          t.FormattedTable(29))
  
      # Display fails if the minimum size needed is not available.
      # These are both 1-char less than the minimum required.
      self.assertRaises(texttable.TableError, t.FormattedTable, 25)
      t.Remove(3)
      t.Remove(2)
      self.assertRaises(texttable.TableError, t.FormattedTable, 17)
      t.Append(('line\nwith\n\nbreaks', 'Line with\ttabs\t\t',
                'line with  lots of   spaces.', '4'))
      t[0].color = ['yellow']
      self.assertEqual(
          '\033[33m a       b     c         Beer \n'
          '==============================\033[0m\n'
          ' 10      20    30             \n'
          '------------------------------\n'
          ' line    Line  line      4    \n'
          ' with    with  with           \n'
          '         tabs  lots of        \n'
          ' breaks        spaces.        \n',
          t.FormattedTable(30))
  
      t[0].color = None
      self.assertEqual(
          ' a         b        c              Beer \n'
          '========================================\n'
          ' 10        20       30                  \n'
          '----------------------------------------\n'
          ' line      Line     line with      4    \n'
          ' with      with     lots of             \n'
          '           tabs     spaces.             \n'
          ' breaks                                 \n',
          t.FormattedTable(40))
  
    def testFormattedTable2(self):
      t = texttable.TextTable()
      t.header = ('Host', 'Interface', 'Admin', 'Oper', 'Proto', 'Address')
      t.Append(('DeviceA', 'lo0', 'up', 'up', '', []))
      t.Append(('DeviceA', 'lo0.0', 'up', 'up', 'inet',
                ['127.0.0.1', '10.100.100.1']))
      t.Append(('DeviceA', 'lo0.16384', 'up', 'up', 'inet', ['127.0.0.1']))
      t[-2].color = ['red']
  
      # pylint: disable=C6310
      self.assertEqual(
          ' Host     Interface  Admin  Oper  Proto  Address              \n'
          '==============================================================\n'
          ' DeviceA  lo0        up     up                                \n'
          '--------------------------------------------------------------\n'
          '\033[31m DeviceA  lo0.0      up     up    inet   127.0.0.1,           \n'
          '                                         10.100.100.1         \033[0m\n'
          '--------------------------------------------------------------\n'
          ' DeviceA  lo0.16384  up     up    inet   127.0.0.1            \n',
          t.FormattedTable(62))
  
      # Test with specific columns only
      self.assertEqual(
          ' Host     Interface  Admin  Oper  Address                 \n'
          '==========================================================\n'
          ' DeviceA  lo0        up     up                            \n'
          '\033[31m DeviceA  lo0.0      up     up    127.0.0.1, 10.100.100.1 \033[0m\n'
          ' DeviceA  lo0.16384  up     up    127.0.0.1               \n',
          t.FormattedTable(62, columns=['Host', 'Interface', 'Admin', 'Oper', 'Address']))
  
    def testSortTable(self):
      # pylint: disable=invalid-name
      def MakeTable():
        t = texttable.TextTable()
        t.header = ('Col1', 'Col2', 'Col3')
        t.Append(('lorem', 'ipsum', 'dolor'))
        t.Append(('ut', 'enim', 'ad'))
        t.Append(('duis', 'aute', 'irure'))
        return t
      # Test basic sort
      table = MakeTable()
      table.sort()
      self.assertEqual(['duis', 'aute', 'irure'], table[1].values)
      self.assertEqual(['lorem', 'ipsum', 'dolor'], table[2].values)
      self.assertEqual(['ut', 'enim', 'ad'], table[3].values)
  
      # Test with different key
      table = MakeTable()
      table.sort(key=lambda x: x['Col2'])
      self.assertEqual(['duis', 'aute', 'irure'], table[1].values)
      self.assertEqual(['ut', 'enim', 'ad'], table[2].values)
      self.assertEqual(['lorem', 'ipsum', 'dolor'], table[3].values)
  
      # Multiple keys.
      table = MakeTable()
      table.Append(('duis', 'aute', 'aute'))
      table.sort(key=lambda x: x['Col2', 'Col3'])
      self.assertEqual(['duis', 'aute', 'aute'], table[1].values)
      self.assertEqual(['duis', 'aute', 'irure'], table[2].values)
  
      # Test with custom compare
      # pylint: disable=C6409
      def compare(a, b):
        # Compare from 2nd char of 1st col
        return cmp(a[0][1:], b[0][1:])
      table = MakeTable()
      table.sort(cmp=compare)
      self.assertEqual(['lorem', 'ipsum', 'dolor'], table[1].values)
      self.assertEqual(['ut', 'enim', 'ad'], table[2].values)
      self.assertEqual(['duis', 'aute', 'irure'], table[3].values)
      # Set the key, so the 1st col compared is 'Col2'.
      table.sort(key=lambda x: x['Col2'], cmp=compare)
      self.assertEqual(['ut', 'enim', 'ad'], table[2].values)
      self.assertEqual(['lorem', 'ipsum', 'dolor'], table[1].values)
      self.assertEqual(['duis', 'aute', 'irure'], table[3].values)
  
      # Sort in reverse order.
      table.sort(key=lambda x: x['Col2'], reverse=True)
      self.assertEqual(['lorem', 'ipsum', 'dolor'], table[1].values)
      self.assertEqual(['ut', 'enim', 'ad'], table[2].values)
      self.assertEqual(['duis', 'aute', 'irure'], table[3].values)
  
  
  if __name__ == '__main__':
    unittest.main()
  