# -*- coding: utf-8 -*- """Test the generic output formatter interface.""" from __future__ import unicode_literals from decimal import Decimal from textwrap import dedent import pytest from cli_helpers.tabular_output import format_output, TabularOutputFormatter from cli_helpers.compat import binary_type, text_type from cli_helpers.utils import strip_ansi def test_tabular_output_formatter(): """Test the TabularOutputFormatter class.""" headers = ['text', 'numeric'] data = [ ["abc", Decimal(1)], ["defg", Decimal("11.1")], ["hi", Decimal("1.1")], ["Pablo\rß\n", 0], ] expected = dedent("""\ +------------+---------+ | text | numeric | +------------+---------+ | abc | 1 | | defg | 11.1 | | hi | 1.1 | | Pablo\\rß\\n | 0 | +------------+---------+""" ) print(expected) print("\n".join(TabularOutputFormatter().format_output( iter(data), headers, format_name='ascii'))) assert expected == "\n".join(TabularOutputFormatter().format_output( iter(data), headers, format_name='ascii')) def test_tabular_format_output_wrapper(): """Test the format_output wrapper.""" data = [['1', None], ['2', 'Sam'], ['3', 'Joe']] headers = ['id', 'name'] expected = dedent('''\ +----+------+ | id | name | +----+------+ | 1 | N/A | | 2 | Sam | | 3 | Joe | +----+------+''') assert expected == "\n".join(format_output(iter(data), headers, format_name='ascii', missing_value='N/A')) def test_additional_preprocessors(): """Test that additional preprocessors are run.""" def hello_world(data, headers, **_): def hello_world_data(data): for row in data: for i, value in enumerate(row): if value == 'hello': row[i] = "{}, world".format(value) yield row return hello_world_data(data), headers data = [['foo', None], ['hello!', 'hello']] headers = 'ab' expected = dedent('''\ +--------+--------------+ | a | b | +--------+--------------+ | foo | hello | | hello! | hello, world | +--------+--------------+''') assert expected == "\n".join(TabularOutputFormatter().format_output( iter(data), headers, format_name='ascii', preprocessors=(hello_world,), missing_value='hello')) def test_format_name_attribute(): """Test the the format_name attribute be set and retrieved.""" formatter = TabularOutputFormatter(format_name='plain') assert formatter.format_name == 'plain' formatter.format_name = 'simple' assert formatter.format_name == 'simple' with pytest.raises(ValueError): formatter.format_name = 'foobar' def test_unsupported_format(): """Test that TabularOutputFormatter rejects unknown formats.""" formatter = TabularOutputFormatter() with pytest.raises(ValueError): formatter.format_name = 'foobar' with pytest.raises(ValueError): formatter.format_output((), (), format_name='foobar') def test_tabulate_ansi_escape_in_default_value(): """Test that ANSI escape codes work with tabulate.""" data = [['1', None], ['2', 'Sam'], ['3', 'Joe']] headers = ['id', 'name'] styled = format_output(iter(data), headers, format_name='psql', missing_value='\x1b[38;5;10mNULL\x1b[39m') unstyled = format_output(iter(data), headers, format_name='psql', missing_value='NULL') stripped_styled = [strip_ansi(s) for s in styled] assert list(unstyled) == stripped_styled def test_get_type(): """Test that _get_type returns the expected type.""" formatter = TabularOutputFormatter() tests = ((1, int), (2.0, float), (b'binary', binary_type), ('text', text_type), (None, type(None)), ((), text_type)) for value, data_type in tests: assert data_type is formatter._get_type(value) def test_provide_column_types(): """Test that provided column types are passed to preprocessors.""" expected_column_types = (bool, float) data = ((1, 1.0), (0, 2)) headers = ('a', 'b') def preprocessor(data, headers, column_types=(), **_): assert expected_column_types == column_types return data, headers format_output(data, headers, 'csv', column_types=expected_column_types, preprocessors=(preprocessor,)) def test_enforce_iterable(): """Test that all output formatters accept iterable""" formatter = TabularOutputFormatter() loremipsum = 'lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod'.split(' ') for format_name in formatter.supported_formats: formatter.format_name = format_name try: formatted = next(formatter.format_output( zip(loremipsum), ['lorem'])) except TypeError: assert False, "{0} doesn't return iterable".format(format_name) def test_all_text_type(): """Test the TabularOutputFormatter class.""" data = [[1, u"", None, Decimal(2)]] headers = ['col1', 'col2', 'col3', 'col4'] output_formatter = TabularOutputFormatter() for format_name in output_formatter.supported_formats: for row in output_formatter.format_output(iter(data), headers, format_name=format_name): assert isinstance(row, text_type), "not unicode for {}".format(format_name)