示例#1
0
class CliUtilsTestCase(test.TestCase):
    def setUp(self):
        super(CliUtilsTestCase, self).setUp()
        self.categories = {
            "deployment": deployment.DeploymentCommands,
            "task": task.TaskCommands,
            "verify": verify.VerifyCommands
        }

    def tearDown(self):
        self._unregister_opts()
        super(CliUtilsTestCase, self).tearDown()

    def test_print_dict(self):
        out = six.StringIO()
        dict = {"key": "value"}
        cliutils.print_dict(dict, out=out)
        self.assertEqual(
            "+----------+-------+\n"
            "| Property | Value |\n"
            "+----------+-------+\n"
            "| key      | value |\n"
            "+----------+-------+\n", out.getvalue())

    def test_print_dict_wrap(self):
        out = six.StringIO()
        dict = {"key1": "not wrapped", "key2": "this will be wrapped"}
        cliutils.print_dict(dict, wrap=16, out=out)
        self.assertEqual(
            "+----------+--------------+\n"
            "| Property | Value        |\n"
            "+----------+--------------+\n"
            "| key1     | not wrapped  |\n"
            "| key2     | this will be |\n"
            "|          | wrapped      |\n"
            "+----------+--------------+\n", out.getvalue())

    def test_print_dict_formatters_and_fields(self):
        out = six.StringIO()
        dict = {"key1": "value", "key2": "Value", "key3": "vvv"}
        formatters = {"foo": lambda x: x["key1"], "bar": lambda x: x["key2"]}
        fields = ["foo", "bar"]
        cliutils.print_dict(dict,
                            formatters=formatters,
                            fields=fields,
                            out=out)
        self.assertEqual(
            "+----------+-------+\n"
            "| Property | Value |\n"
            "+----------+-------+\n"
            "| foo      | value |\n"
            "| bar      | Value |\n"
            "+----------+-------+\n", out.getvalue())

    def test_print_dict_header(self):
        out = six.StringIO()
        dict = {"key": "value"}
        cliutils.print_dict(dict,
                            table_label="Some Table",
                            print_header=False,
                            out=out)
        self.assertEqual(
            "+-------------+\n"
            "| Some Table  |\n"
            "+-----+-------+\n"
            "| key | value |\n"
            "+-----+-------+\n", out.getvalue())

    def test_print_dict_objects(self):
        class SomeStruct(object):
            def __init__(self, a, b):
                self.a = a
                self.b = b

            @property
            def c(self):
                return self.a + self.b

            def foo(self):
                pass

            @classmethod
            def bar(cls):
                pass

            @staticmethod
            def foobar():
                pass

        out = six.StringIO()
        formatters = {"c": lambda x: "a + b = %s" % x.c}
        cliutils.print_dict(SomeStruct(1, 2), formatters=formatters, out=out)
        self.assertEqual(
            "+----------+-----------+\n"
            "| Property | Value     |\n"
            "+----------+-----------+\n"
            "| a        | 1         |\n"
            "| b        | 2         |\n"
            "| c        | a + b = 3 |\n"
            "+----------+-----------+\n", out.getvalue())

    def test_print_dict_with_spec_chars(self):
        out = six.StringIO()
        dict = {"key": "line1\r\nline2"}
        cliutils.print_dict(dict, out=out)
        self.assertEqual(
            "+----------+-------+\n"
            "| Property | Value |\n"
            "+----------+-------+\n"
            "| key      | line1 |\n"
            "|          | line2 |\n"
            "+----------+-------+\n", out.getvalue())

    def test_make_header(self):
        h1 = cliutils.make_header("msg", size=4, symbol="=")
        self.assertEqual("====\nmsg\n====\n", h1)

    def test_make_table_header(self):
        actual = cliutils.make_table_header("Response Times (sec)", 40)
        expected = "\n".join((
            "+--------------------------------------+",
            "|         Response Times (sec)         |",
        ))
        self.assertEqual(expected, actual)

        actual = cliutils.make_table_header("Response Times (sec)", 39)
        expected = "\n".join((
            "+-------------------------------------+",
            "|        Response Times (sec)         |",
        ))
        self.assertEqual(expected, actual)

        self.assertRaises(ValueError, cliutils.make_table_header,
                          "Response Times (sec)", len("Response Times (sec)"))

    @ddt.data(
        {
            "obj": mock.Mock(foo=6.56565),
            "args": ["foo", 3],
            "expected": 6.566
        }, {
            "obj": mock.Mock(foo=6.56565),
            "args": ["foo"],
            "expected": 6.56565
        }, {
            "obj": mock.Mock(foo=None),
            "args": ["foo"],
            "expected": "n/a"
        }, {
            "obj": mock.Mock(foo="n/a"),
            "args": ["foo"],
            "expected": "n/a"
        }, {
            "obj": mock.Mock(foo="n/a"),
            "args": ["foo", 3],
            "expected": "n/a"
        }, {
            "obj": {
                "foo": 6.56565
            },
            "args": ["foo", 3],
            "expected": 6.566
        }, {
            "obj": {
                "foo": 6.56565
            },
            "args": ["foo"],
            "expected": 6.56565
        }, {
            "obj": {
                "foo": None
            },
            "args": ["foo"],
            "expected": "n/a"
        }, {
            "obj": {
                "foo": "n/a"
            },
            "args": ["foo"],
            "expected": "n/a"
        }, {
            "obj": {
                "foo": "n/a"
            },
            "args": ["foo", 3],
            "expected": "n/a"
        }, {
            "obj": object,
            "args": ["unexpected_field", 3],
            "expected": AttributeError
        }, {
            "obj": {
                "foo": 42
            },
            "args": ["unexpected_field", 3],
            "expected": KeyError
        })
    @ddt.unpack
    def test_pretty_float_formatter(self, obj, args, expected=None):
        formatter = cliutils.pretty_float_formatter(*args)
        if type(expected) == type and issubclass(expected, Exception):
            self.assertRaises(expected, formatter, obj)
        else:
            self.assertEqual(expected, formatter(obj))

    def test__methods_of_with_class(self):
        class fake_class(object):
            def public(self):
                pass

            def _private(self):
                pass

        result = cliutils._methods_of(fake_class)
        self.assertEqual(1, len(result))
        self.assertEqual("public", result[0][0])

    def test__methods_of_with_object(self):
        class fake_class(object):
            def public(self):
                pass

            def _private(self):
                pass

        mock_obj = fake_class()
        result = cliutils._methods_of(mock_obj)
        self.assertEqual(1, len(result))
        self.assertEqual("public", result[0][0])

    def test__methods_of_empty_result(self):
        class fake_class(object):
            def _private(self):
                pass

            def _private2(self):
                pass

        mock_obj = fake_class()
        result = cliutils._methods_of(mock_obj)
        self.assertEqual([], result)

    def _unregister_opts(self):
        CONF.reset()
        category_opt = cfg.SubCommandOpt("category",
                                         title="Command categories",
                                         help="Available categories")
        CONF.unregister_opt(category_opt)

    @mock.patch("rally.api.API",
                side_effect=exceptions.RallyException("config_file"))
    def test_run_fails(self, mock_rally_api_api):
        ret = cliutils.run(["rally", "task list"], self.categories)
        self.assertEqual(2, ret)
        mock_rally_api_api.assert_called_once_with(config_args=["task list"],
                                                   skip_db_check=True)

    @mock.patch("rally.api.API.check_db_revision")
    def test_run_version(self, mock_api_check_db_revision):
        ret = cliutils.run(["rally", "version"], self.categories)
        self.assertEqual(0, ret)

    @mock.patch("rally.api.API.check_db_revision")
    def test_run_bash_completion(self, mock_api_check_db_revision):
        ret = cliutils.run(["rally", "bash-completion"], self.categories)
        self.assertEqual(0, ret)

    @mock.patch("rally.api.API.check_db_revision")
    @mock.patch("rally.common.db.api.task_get",
                side_effect=exceptions.DBRecordNotFound(criteria="uuid: %s" %
                                                        FAKE_TASK_UUID,
                                                        table="tasks"))
    def test_run_task_not_found(self, mock_task_get,
                                mock_api_check_db_revision):
        ret = cliutils.run(["rally", "task", "status",
                            "%s" % FAKE_TASK_UUID], self.categories)
        self.assertTrue(mock_task_get.called)
        self.assertEqual(203, ret)

    @mock.patch("rally.api.API.check_db_revision")
    @mock.patch("rally.cli.cliutils.validate_args",
                side_effect=cliutils.MissingArgs("missing"))
    def test_run_task_failed(self, mock_validate_args,
                             mock_api_check_db_revision):
        ret = cliutils.run(["rally", "task", "status",
                            "%s" % FAKE_TASK_UUID], self.categories)
        self.assertTrue(mock_validate_args.called)
        self.assertEqual(1, ret)

    @mock.patch("rally.api.API.check_db_revision")
    def test_run_failed_to_open_file(self, mock_api_check_db_revision):
        class FailuresCommands(object):
            def failed_to_open_file(self):
                raise IOError("No such file")

        ret = cliutils.run(["rally", "failure", "failed-to-open-file"],
                           {"failure": FailuresCommands})
        self.assertEqual(1, ret)

    @mock.patch("rally.api.API.check_db_revision")
    def test_run_sqlalchmey_operational_failure(self,
                                                mock_api_check_db_revision):
        class SQLAlchemyCommands(object):
            def operational_failure(self):
                raise sqlalchemy.exc.OperationalError("Can't open DB file")

        ret = cliutils.run(["rally", "failure", "operational-failure"],
                           {"failure": SQLAlchemyCommands})
        self.assertEqual(1, ret)

    class TestObj(object):
        x = 1
        y = 2
        z = 3.142857142857143
        aOrB = 3  # mixed case field

    @ddt.data(
        {
            "args": [[TestObj()], ["x", "y"]],
            "kwargs": {
                "print_header": True,
                "print_border": True,
                "sortby_index": None
            },
            "expected": ("+---+---+\n"
                         "| x | y |\n"
                         "+---+---+\n"
                         "| 1 | 2 |\n"
                         "+---+---+")
        }, {
            "args": [[TestObj()], ["z"]],
            "kwargs": {
                "print_header": True,
                "print_border": True,
                "sortby_index": None,
                "formatters": {
                    "z": cliutils.pretty_float_formatter("z", 5)
                }
            },
            "expected": ("+---------+\n"
                         "| z       |\n"
                         "+---------+\n"
                         "| 3.14286 |\n"
                         "+---------+")
        }, {
            "args": [[TestObj()], ["x"]],
            "kwargs": {
                "print_header": True,
                "print_border": True
            },
            "expected": ("+---+\n"
                         "| x |\n"
                         "+---+\n"
                         "| 1 |\n"
                         "+---+")
        }, {
            "args": [[TestObj()], ["x", "y"]],
            "kwargs": {
                "print_header": True,
                "print_border": True
            },
            "expected": ("+---+---+\n"
                         "| x | y |\n"
                         "+---+---+\n"
                         "| 1 | 2 |\n"
                         "+---+---+")
        }, {
            "args": [[TestObj()], ["x"]],
            "kwargs": {
                "print_header": False,
                "print_border": False
            },
            "expected": "1"
        }, {
            "args": [[TestObj()], ["x", "y"]],
            "kwargs": {
                "print_header": False,
                "print_border": False
            },
            "expected": "1 2"
        }, {
            "args": [[TestObj()], ["x"]],
            "kwargs": {
                "print_header": True,
                "print_border": False
            },
            "expected": "x \n1"
        }, {
            "args": [[TestObj()], ["x", "y"]],
            "kwargs": {
                "print_header": True,
                "print_border": False
            },
            "expected": "x y \n1 2"
        }, {
            "args": [[TestObj()], ["x"]],
            "kwargs": {
                "print_header": False,
                "print_border": True
            },
            "expected": ("+--+\n"
                         "|1 |\n"
                         "+--+")
        }, {
            "args": [[TestObj()], ["x", "y"]],
            "kwargs": {
                "print_header": False,
                "print_border": True
            },
            "expected": ("+--+--+\n"
                         "|1 |2 |\n"
                         "+--+--+")
        }, {
            "args": [[TestObj()], ["aOrB"]],
            "kwargs": {
                "print_header": True,
                "print_border": True,
                "mixed_case_fields": ["aOrB"]
            },
            "expected": ("+------+\n"
                         "| aOrB |\n"
                         "+------+\n"
                         "| 3    |\n"
                         "+------+")
        }, {
            "args": [[TestObj()], ["aOrB"]],
            "kwargs": {
                "print_header": False,
                "print_border": True,
                "mixed_case_fields": ["aOrB"]
            },
            "expected": ("+--+\n"
                         "|3 |\n"
                         "+--+")
        }, {
            "args": [[TestObj()], ["aOrB"]],
            "kwargs": {
                "print_header": True,
                "print_border": False,
                "mixed_case_fields": ["aOrB"]
            },
            "expected": "aOrB \n3"
        }, {
            "args": [[TestObj()], ["aOrB"]],
            "kwargs": {
                "print_header": False,
                "print_border": False,
                "mixed_case_fields": ["aOrB"]
            },
            "expected": "3"
        }, {
            "args": [[{
                "x": 1,
                "y": 2
            }], ["x", "y"]],
            "kwargs": {
                "print_header": True,
                "print_border": True,
                "sortby_index": None
            },
            "expected": ("+---+---+\n"
                         "| x | y |\n"
                         "+---+---+\n"
                         "| 1 | 2 |\n"
                         "+---+---+")
        }, {
            "args": [[{
                "z": 3.142857142857143
            }], ["z"]],
            "kwargs": {
                "print_header": True,
                "print_border": True,
                "sortby_index": None,
                "formatters": {
                    "z": cliutils.pretty_float_formatter("z", 5)
                }
            },
            "expected": ("+---------+\n"
                         "| z       |\n"
                         "+---------+\n"
                         "| 3.14286 |\n"
                         "+---------+")
        }, {
            "args": [[{
                "x": 1
            }], ["x"]],
            "kwargs": {
                "print_header": True,
                "print_border": True
            },
            "expected": ("+---+\n"
                         "| x |\n"
                         "+---+\n"
                         "| 1 |\n"
                         "+---+")
        }, {
            "args": [[{
                "x": 1,
                "y": 2
            }], ["x", "y"]],
            "kwargs": {
                "print_header": True,
                "print_border": True
            },
            "expected": ("+---+---+\n"
                         "| x | y |\n"
                         "+---+---+\n"
                         "| 1 | 2 |\n"
                         "+---+---+")
        })
    @ddt.unpack
    def test_print_list(self, args, kwargs, expected):
        out = six.moves.StringIO()
        kwargs["out"] = out
        cliutils.print_list(*args, **kwargs)
        self.assertEqual(expected, out.getvalue().strip())

    def test_print_list_raises(self):
        out = six.moves.StringIO()
        self.assertRaisesRegex(ValueError,
                               "Field labels list.*has different number "
                               "of elements than fields list",
                               cliutils.print_list, [self.TestObj()], ["x"],
                               field_labels=["x", "y"],
                               sortby_index=None,
                               out=out)

    def test_help_for_grouped_methods(self):
        class SomeCommand(object):
            @cliutils.help_group("1_manage")
            def install(self):
                pass

            @cliutils.help_group("1_manage")
            def uninstall(self):
                pass

            @cliutils.help_group("1_manage")
            def reinstall(self):
                pass

            @cliutils.help_group("2_launch")
            def run(self):
                pass

            @cliutils.help_group("2_launch")
            def rerun(self):
                pass

            @cliutils.help_group("3_results")
            def show(self):
                pass

            @cliutils.help_group("3_results")
            def list(self):
                pass

            def do_do_has_do_has_mesh(self):
                pass

        self.assertEqual(
            "\n\nCommands:\n"
            "   do-do-has-do-has-mesh   \n"
            "\n"
            "   install                 \n"
            "   reinstall               \n"
            "   uninstall               \n"
            "\n"
            "   rerun                   \n"
            "   run                     \n"
            "\n"
            "   list                    \n"
            "   show                    \n",
            cliutils._compose_category_description(SomeCommand))
示例#2
0
class CliUtilsTestCase(test.TestCase):
    def setUp(self):
        super(CliUtilsTestCase, self).setUp()
        self.categories = {
            "deployment": deployment.DeploymentCommands,
            "show": show.ShowCommands,
            "task": task.TaskCommands,
            "verify": verify.VerifyCommands
        }

    def tearDown(self):
        self._unregister_opts()
        super(CliUtilsTestCase, self).tearDown()

    @mock.patch("rally.cli.cliutils.os.path")
    def test_find_config_files(self, mock_os_path):

        mock_os_path.expanduser.return_value = "expanduser"
        mock_os_path.abspath.return_value = "abspath"
        mock_os_path.isfile.return_value = True

        result = cliutils.find_config_files(["path1", "path2"])
        mock_os_path.expanduser.assert_called_once_with("path1")
        mock_os_path.abspath.assert_called_once_with(
            mock_os_path.expanduser.return_value)
        mock_os_path.isfile.assert_called_once_with(
            mock_os_path.abspath.return_value + "/rally.conf")
        self.assertEqual([mock_os_path.abspath.return_value + "/rally.conf"],
                         result)

        mock_os_path.isfile.return_value = False

        result = cliutils.find_config_files(["path1", "path2"])
        self.assertIsNone(result)

    def test_make_header(self):
        h1 = cliutils.make_header("msg", size=4, symbol="=")
        self.assertEqual(h1, "====\n msg\n====\n")

    def test_make_table_header(self):
        actual = cliutils.make_table_header("Response Times (sec)", 40)
        expected = "\n".join((
            "+--------------------------------------+",
            "|         Response Times (sec)         |",
        ))
        self.assertEqual(expected, actual)

        actual = cliutils.make_table_header("Response Times (sec)", 39)
        expected = "\n".join((
            "+-------------------------------------+",
            "|        Response Times (sec)         |",
        ))
        self.assertEqual(expected, actual)

        self.assertRaises(ValueError, cliutils.make_table_header,
                          "Response Times (sec)", len("Response Times (sec)"))

    def test_pretty_float_formatter_rounding(self):
        test_table_rows = {"test_header": 6.56565}
        self.__dict__.update(**test_table_rows)

        formatter = cliutils.pretty_float_formatter("test_header", 3)
        return_value = formatter(self)

        self.assertEqual(return_value, 6.566)

    def test_pretty_float_formatter_nonrounding(self):
        test_table_rows = {"test_header": 6.56565}
        self.__dict__.update(**test_table_rows)

        formatter = cliutils.pretty_float_formatter("test_header")
        return_value = formatter(self)

        self.assertEqual(return_value, 6.56565)

    def test_pretty_float_formatter_none_value(self):
        test_table_rows = {"test_header": None}
        self.__dict__.update(**test_table_rows)

        formatter = cliutils.pretty_float_formatter("test_header")
        return_value = formatter(self)

        self.assertEqual(return_value, "n/a")

    def test_process_keyestone_exc(self):
        @cliutils.process_keystone_exc
        def a(a):
            if a == 1:
                raise keystone_exc.Unauthorized()

            if a == 2:
                raise keystone_exc.AuthorizationFailure()

            if a == 3:
                raise keystone_exc.ConnectionRefused()

            return a

        self.assertEqual(1, a(1))
        self.assertEqual(1, a(2))
        self.assertEqual(1, a(3))
        self.assertEqual(4, a(4))

    def test__methods_of_with_class(self):
        class fake_class(object):
            def public(self):
                pass

            def _private(self):
                pass

        result = cliutils._methods_of(fake_class)
        self.assertEqual(1, len(result))
        self.assertEqual("public", result[0][0])

    def test__methods_of_with_object(self):
        class fake_class(object):
            def public(self):
                pass

            def _private(self):
                pass

        mock_obj = fake_class()
        result = cliutils._methods_of(mock_obj)
        self.assertEqual(1, len(result))
        self.assertEqual("public", result[0][0])

    def test__methods_of_empty_result(self):
        class fake_class(object):
            def _private(self):
                pass

            def _private2(self):
                pass

        mock_obj = fake_class()
        result = cliutils._methods_of(mock_obj)
        self.assertEqual(result, [])

    def _unregister_opts(self):
        CONF.reset()
        category_opt = cfg.SubCommandOpt("category",
                                         title="Command categories",
                                         help="Available categories")
        CONF.unregister_opt(category_opt)

    @mock.patch("rally.cli.cliutils.CONF",
                config_file=None,
                side_effect=cfg.ConfigFilesNotFoundError("config_file"))
    def test_run_fails(self, mock_cliutils_conf):
        ret = cliutils.run(["rally", "show", "flavors"], self.categories)
        self.assertEqual(ret, 2)

    def test_run_version(self):
        ret = cliutils.run(["rally", "version"], self.categories)
        self.assertEqual(ret, 0)

    def test_run_bash_completion(self):
        ret = cliutils.run(["rally", "bash-completion"], self.categories)
        self.assertEqual(ret, 0)

    def test_run_show(self):
        ret = cliutils.run(["rally", "show", "keypairs"], self.categories)
        self.assertEqual(ret, 1)

    @mock.patch("rally.common.db.task_get",
                side_effect=exceptions.TaskNotFound(uuid=FAKE_TASK_UUID))
    def test_run_task_not_found(self, mock_task_get):
        ret = cliutils.run(["rally", "task", "status",
                            "%s" % FAKE_TASK_UUID], self.categories)
        self.assertTrue(mock_task_get.called)
        self.assertEqual(ret, 1)

    @mock.patch("rally.cli.cliutils.validate_args",
                side_effect=cliutils.MissingArgs("missing"))
    def test_run_show_fails(self, mock_validate_args):
        ret = cliutils.run(["rally", "show", "keypairs"], self.categories)
        self.assertTrue(mock_validate_args.called)
        self.assertEqual(ret, 1)

    def test_run_failed_to_open_file(self):
        class FailuresCommands(object):
            def failed_to_open_file(self):
                raise IOError("No such file")

        ret = cliutils.run(["rally", "failure", "failed_to_open_file"],
                           {"failure": FailuresCommands})
        self.assertEqual(1, ret)

    def test_run_sqlalchmey_operational_failure(self):
        class SQLAlchemyCommands(object):
            def operational_failure(self):
                raise sqlalchemy.exc.OperationalError("Can't open DB file")

        ret = cliutils.run(["rally", "failure", "operational_failure"],
                           {"failure": SQLAlchemyCommands})
        self.assertEqual(1, ret)

    def test_print_list(self):
        class TestObj(object):
            x = 1
            y = 2
            z = 3.142857142857143
            aOrB = 3  # mixed case field

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["x", "y"],
                            print_header=True,
                            print_border=True,
                            sortby_index=None,
                            out=out)
        self.assertEqual(
            "+---+---+\n"
            "| x | y |\n"
            "+---+---+\n"
            "| 1 | 2 |\n"
            "+---+---+",
            out.getvalue().strip())

        out = moves.StringIO()
        formatter = cliutils.pretty_float_formatter("z", 5)
        cliutils.print_list([TestObj()], ["z"],
                            print_header=True,
                            print_border=True,
                            sortby_index=None,
                            formatters={"z": formatter},
                            out=out)
        self.assertEqual(
            "+---------+\n"
            "| z       |\n"
            "+---------+\n"
            "| 3.14286 |\n"
            "+---------+",
            out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["x"],
                            print_header=True,
                            print_border=True,
                            out=out)
        self.assertEqual("+---+\n"
                         "| x |\n"
                         "+---+\n"
                         "| 1 |\n"
                         "+---+",
                         out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["x", "y"],
                            print_header=True,
                            print_border=True,
                            out=out)
        self.assertEqual(
            "+---+---+\n"
            "| x | y |\n"
            "+---+---+\n"
            "| 1 | 2 |\n"
            "+---+---+",
            out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["x"],
                            print_header=False,
                            print_border=False,
                            out=out)
        self.assertEqual("1", out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["x", "y"],
                            print_header=False,
                            print_border=False,
                            out=out)
        self.assertEqual("1 2", out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["x"],
                            print_header=True,
                            print_border=False,
                            out=out)
        self.assertEqual("x \n1", out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["x", "y"],
                            print_header=True,
                            print_border=False,
                            out=out)
        self.assertEqual("x y \n1 2", out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["x"],
                            print_header=False,
                            print_border=True,
                            out=out)
        self.assertEqual("+--+\n" "|1 |\n" "+--+", out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["x", "y"],
                            print_header=False,
                            print_border=True,
                            out=out)
        self.assertEqual("+--+--+\n"
                         "|1 |2 |\n"
                         "+--+--+",
                         out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["aOrB"],
                            mixed_case_fields=["aOrB"],
                            print_header=True,
                            print_border=True,
                            out=out)
        self.assertEqual(
            "+------+\n"
            "| aOrB |\n"
            "+------+\n"
            "| 3    |\n"
            "+------+",
            out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["aOrB"],
                            mixed_case_fields=["aOrB"],
                            print_header=False,
                            print_border=True,
                            out=out)
        self.assertEqual("+--+\n" "|3 |\n" "+--+", out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["aOrB"],
                            mixed_case_fields=["aOrB"],
                            print_header=True,
                            print_border=False,
                            out=out)
        self.assertEqual("aOrB \n" "3", out.getvalue().strip())

        out = moves.StringIO()
        cliutils.print_list([TestObj()], ["aOrB"],
                            mixed_case_fields=["aOrB"],
                            print_header=False,
                            print_border=False,
                            out=out)
        self.assertEqual("3", out.getvalue().strip())

        out = moves.StringIO()
        self.assertRaisesRegexp(ValueError,
                                "Field labels list.*has different number "
                                "of elements than fields list",
                                cliutils.print_list, [TestObj()], ["x"],
                                field_labels=["x", "y"],
                                sortby_index=None,
                                out=out)