"""Tests for the commandant code that analyzes a function signature to determine the parameters to argparse.""" from unittest import TestCase from mock import ( patch, MagicMock, ANY, ) import json from pprint import pformat import yaml import csv from six import StringIO from charmhelpers import cli class SubCommandTest(TestCase): """Test creation of subcommands""" def setUp(self): super(SubCommandTest, self).setUp() self.cl = cli.CommandLine() @patch('sys.exit') def test_subcommand_wrapper(self, _sys_exit): """Test function name detection""" @self.cl.subcommand() def payload(): "A function that does work." pass args = self.cl.argument_parser.parse_args(['payload']) self.assertEqual(args.func, payload) self.assertEqual(_sys_exit.mock_calls, []) @patch('sys.exit') def test_subcommand_wrapper_bogus_arguments(self, _sys_exit): """Test function name detection""" @self.cl.subcommand() def payload(): "A function that does work." pass with self.assertRaises(TypeError): with patch("sys.argv", "tests deliberately bad input".split()): with patch("sys.stderr"): self.cl.argument_parser.parse_args() _sys_exit.assert_called_once_with(2) @patch('sys.exit') def test_subcommand_wrapper_cmdline_options(self, _sys_exit): """Test detection of positional arguments and optional parameters.""" @self.cl.subcommand() def payload(x, y=None): "A function that does work." return x args = self.cl.argument_parser.parse_args(['payload', 'positional', '--y=optional']) self.assertEqual(args.func, payload) self.assertEqual(args.x, 'positional') self.assertEqual(args.y, 'optional') self.assertEqual(_sys_exit.mock_calls, []) @patch('sys.exit') def test_subcommand_builder(self, _sys_exit): def noop(z): pass @self.cl.subcommand_builder('payload', description="A subcommand") def payload_command(subparser): subparser.add_argument('-z', action='store_true') return noop args = self.cl.argument_parser.parse_args(['payload', '-z']) self.assertEqual(args.func, noop) self.assertTrue(args.z) self.assertFalse(_sys_exit.called) def test_subcommand_builder_bogus_wrapped_args(self): with self.assertRaises(TypeError): @self.cl.subcommand_builder('payload', description="A subcommand") def payload_command(subparser, otherarg): pass def test_run(self): self.bar_called = False @self.cl.subcommand() def bar(x, y=None, *vargs): "A function that does work." self.assertEqual(x, 'baz') self.assertEqual(y, 'why') self.assertEqual(vargs, ('mux', 'zob')) self.bar_called = True return "qux" args = ['chlp', 'bar', '--y', 'why', 'baz', 'mux', 'zob'] self.cl.formatter = MagicMock() with patch("sys.argv", args): with patch("charmhelpers.core.unitdata._KV") as _KV: self.cl.run() assert _KV.flush.called self.assertTrue(self.bar_called) self.cl.formatter.format_output.assert_called_once_with('qux', ANY) def test_no_output(self): self.bar_called = False @self.cl.subcommand() @self.cl.no_output def bar(x, y=None, *vargs): "A function that does work." self.bar_called = True return "qux" args = ['foo', 'bar', 'baz'] self.cl.formatter = MagicMock() with patch("sys.argv", args): self.cl.run() self.assertTrue(self.bar_called) self.cl.formatter.format_output.assert_called_once_with('', ANY) def test_test_command(self): self.bar_called = False self.bar_result = True @self.cl.subcommand() @self.cl.test_command def bar(x, y=None, *vargs): "A function that does work." self.bar_called = True return self.bar_result args = ['foo', 'bar', 'baz'] self.cl.formatter = MagicMock() with patch("sys.argv", args): self.cl.run() self.assertTrue(self.bar_called) self.assertEqual(self.cl.exit_code, 0) self.cl.formatter.format_output.assert_called_once_with('', ANY) self.bar_result = False with patch("sys.argv", args): self.cl.run() self.assertEqual(self.cl.exit_code, 1) class OutputFormatterTest(TestCase): def setUp(self): super(OutputFormatterTest, self).setUp() self.expected_formats = ( "raw", "json", "py", "yaml", "csv", "tab", ) self.outfile = StringIO() self.of = cli.OutputFormatter(outfile=self.outfile) self.output_data = {"this": "is", "some": 1, "data": dict()} def test_supports_formats(self): self.assertEqual(sorted(self.expected_formats), sorted(self.of.supported_formats)) def test_adds_arguments(self): ap = MagicMock() arg_group = MagicMock() add_arg = MagicMock() arg_group.add_argument = add_arg ap.add_mutually_exclusive_group.return_value = arg_group self.of.add_arguments(ap) self.assertTrue(add_arg.called) for call_args in add_arg.call_args_list: if "--format" in call_args[0]: self.assertEqual(sorted(call_args[1]['choices']), sorted(self.expected_formats)) self.assertEqual(call_args[1]['default'], 'raw') break else: print(arg_group.call_args_list) self.fail("No --format argument was created") all_args = [c[0][0] for c in add_arg.call_args_list] all_args.extend([c[0][1] for c in add_arg.call_args_list if len(c[0]) > 1]) for fmt in self.expected_formats: self.assertIn("-{}".format(fmt[0]), all_args) self.assertIn("--{}".format(fmt), all_args) def test_outputs_raw(self): self.of.raw(self.output_data) self.outfile.seek(0) self.assertEqual(self.outfile.read(), str(self.output_data)) def test_outputs_json(self): self.of.json(self.output_data) self.outfile.seek(0) self.assertEqual(self.outfile.read(), json.dumps(self.output_data)) def test_outputs_py(self): self.of.py(self.output_data) self.outfile.seek(0) self.assertEqual(self.outfile.read(), pformat(self.output_data) + "\n") def test_outputs_yaml(self): self.of.yaml(self.output_data) self.outfile.seek(0) self.assertEqual(self.outfile.read(), yaml.dump(self.output_data)) def test_outputs_csv(self): sample = StringIO() writer = csv.writer(sample) writer.writerows(self.output_data) sample.seek(0) self.of.csv(self.output_data) self.outfile.seek(0) self.assertEqual(self.outfile.read(), sample.read()) def test_outputs_tab(self): sample = StringIO() writer = csv.writer(sample, dialect=csv.excel_tab) writer.writerows(self.output_data) sample.seek(0) self.of.tab(self.output_data) self.outfile.seek(0) self.assertEqual(self.outfile.read(), sample.read()) def test_formats_output(self): for format in self.expected_formats: mock_f = MagicMock() setattr(self.of, format, mock_f) self.of.format_output(self.output_data, format) mock_f.assert_called_with(self.output_data)