generated from daniil-berg/boilerplate-py
Fixed Python 3.8 compatibility bugs; classmethod+property workaround; control session buffer
This commit is contained in:
@ -38,7 +38,7 @@ class CLITestCase(IsolatedAsyncioTestCase):
|
||||
mock_client = MagicMock(start=mock_client_start)
|
||||
mock_client_cls = MagicMock(return_value=mock_client)
|
||||
mock_client_kwargs = {'foo': 123, 'bar': 456, 'baz': 789}
|
||||
mock_parse_cli.return_value = {module.CLIENT_CLASS: mock_client_cls} | mock_client_kwargs
|
||||
mock_parse_cli.return_value = {module.CLIENT_CLASS: mock_client_cls, **mock_client_kwargs}
|
||||
self.assertIsNone(await module.main())
|
||||
mock_parse_cli.assert_called_once_with()
|
||||
mock_client_cls.assert_called_once_with(**mock_client_kwargs)
|
||||
|
@ -41,9 +41,9 @@ class ControlParserTestCase(TestCase):
|
||||
self.help_formatter_factory_patcher = patch.object(parser.ControlParser, 'help_formatter_factory')
|
||||
self.mock_help_formatter_factory = self.help_formatter_factory_patcher.start()
|
||||
self.mock_help_formatter_factory.return_value = RawTextHelpFormatter
|
||||
self.stream_writer, self.terminal_width = MagicMock(), 420
|
||||
self.stream, self.terminal_width = MagicMock(), 420
|
||||
self.kwargs = {
|
||||
'stream_writer': self.stream_writer,
|
||||
'stream': self.stream,
|
||||
'terminal_width': self.terminal_width,
|
||||
'formatter_class': FOO
|
||||
}
|
||||
@ -72,10 +72,9 @@ class ControlParserTestCase(TestCase):
|
||||
|
||||
def test_init(self):
|
||||
self.assertIsInstance(self.parser, ArgumentParser)
|
||||
self.assertEqual(self.stream_writer, self.parser._stream_writer)
|
||||
self.assertEqual(self.stream, self.parser._stream)
|
||||
self.assertEqual(self.terminal_width, self.parser._terminal_width)
|
||||
self.mock_help_formatter_factory.assert_called_once_with(self.terminal_width, FOO)
|
||||
self.assertFalse(getattr(self.parser, 'exit_on_error'))
|
||||
self.assertEqual(RawTextHelpFormatter, getattr(self.parser, 'formatter_class'))
|
||||
self.assertSetEqual(set(), self.parser._flags)
|
||||
self.assertIsNone(self.parser._commands)
|
||||
@ -89,7 +88,7 @@ class ControlParserTestCase(TestCase):
|
||||
mock_get_first_doc_line.return_value = mock_help = 'help 123'
|
||||
kwargs = {FOO: 1, BAR: 2, parser.DESCRIPTION: FOO + BAR}
|
||||
expected_name = 'foo-bar'
|
||||
expected_kwargs = {parser.NAME: expected_name, parser.PROG: expected_name, parser.HELP: mock_help} | kwargs
|
||||
expected_kwargs = {parser.NAME: expected_name, parser.PROG: expected_name, parser.HELP: mock_help, **kwargs}
|
||||
to_omit = ['abc', 'xyz']
|
||||
output = self.parser.add_function_command(foo_bar, omit_params=to_omit, **kwargs)
|
||||
self.assertEqual(mock_subparser, output)
|
||||
@ -107,7 +106,7 @@ class ControlParserTestCase(TestCase):
|
||||
mock_get_first_doc_line.return_value = mock_help = 'help 123'
|
||||
kwargs = {FOO: 1, BAR: 2, parser.DESCRIPTION: FOO + BAR}
|
||||
expected_name = 'get-prop'
|
||||
expected_kwargs = {parser.NAME: expected_name, parser.PROG: expected_name, parser.HELP: mock_help} | kwargs
|
||||
expected_kwargs = {parser.NAME: expected_name, parser.PROG: expected_name, parser.HELP: mock_help, **kwargs}
|
||||
output = self.parser.add_property_command(prop, **kwargs)
|
||||
self.assertEqual(mock_subparser, output)
|
||||
mock_get_first_doc_line.assert_called_once_with(get_prop)
|
||||
@ -119,7 +118,7 @@ class ControlParserTestCase(TestCase):
|
||||
|
||||
prop = property(get_prop, set_prop)
|
||||
expected_help = f"Get/set the `.{expected_name}` property"
|
||||
expected_kwargs = {parser.NAME: expected_name, parser.PROG: expected_name, parser.HELP: expected_help} | kwargs
|
||||
expected_kwargs = {parser.NAME: expected_name, parser.PROG: expected_name, parser.HELP: expected_help, **kwargs}
|
||||
output = self.parser.add_property_command(prop, **kwargs)
|
||||
self.assertEqual(mock_subparser, output)
|
||||
mock_get_first_doc_line.assert_has_calls([call(get_prop), call(set_prop)])
|
||||
@ -152,8 +151,7 @@ class ControlParserTestCase(TestCase):
|
||||
mock_subparser = MagicMock(set_defaults=mock_set_defaults)
|
||||
mock_add_function_command.return_value = mock_add_property_command.return_value = mock_subparser
|
||||
x = 'x'
|
||||
common_kwargs = {parser.STREAM_WRITER: self.parser._stream_writer,
|
||||
parser.CLIENT_INFO.TERMINAL_WIDTH: self.parser._terminal_width}
|
||||
common_kwargs = {'stream': self.parser._stream, parser.CLIENT_INFO.TERMINAL_WIDTH: self.parser._terminal_width}
|
||||
expected_output = {'method': mock_subparser, 'prop': mock_subparser}
|
||||
output = self.parser.add_class_commands(FooBar, public_only=True, omit_members=['to_omit'], member_arg_name=x)
|
||||
self.assertDictEqual(expected_output, output)
|
||||
@ -170,12 +168,12 @@ class ControlParserTestCase(TestCase):
|
||||
mock_base_add_subparsers.assert_called_once_with(*args, **kwargs)
|
||||
|
||||
def test__print_message(self):
|
||||
self.stream_writer.write = MagicMock()
|
||||
self.stream.write = MagicMock()
|
||||
self.assertIsNone(self.parser._print_message(''))
|
||||
self.stream_writer.write.assert_not_called()
|
||||
self.stream.write.assert_not_called()
|
||||
msg = 'foo bar baz'
|
||||
self.assertIsNone(self.parser._print_message(msg))
|
||||
self.stream_writer.write.assert_called_once_with(msg.encode())
|
||||
self.stream.write.assert_called_once_with(msg)
|
||||
|
||||
@patch.object(parser.ControlParser, '_print_message')
|
||||
def test_exit(self, mock__print_message: MagicMock):
|
||||
|
@ -21,11 +21,12 @@ Unittests for the `asyncio_taskpool.session` module.
|
||||
|
||||
import json
|
||||
from argparse import ArgumentError, Namespace
|
||||
from io import StringIO
|
||||
from unittest import IsolatedAsyncioTestCase
|
||||
from unittest.mock import AsyncMock, MagicMock, patch, call
|
||||
|
||||
from asyncio_taskpool.control import session
|
||||
from asyncio_taskpool.internals.constants import CLIENT_INFO, CMD, SESSION_MSG_BYTES, STREAM_WRITER
|
||||
from asyncio_taskpool.internals.constants import CLIENT_INFO, CMD, SESSION_MSG_BYTES
|
||||
from asyncio_taskpool.exceptions import HelpRequested
|
||||
from asyncio_taskpool.pool import SimpleTaskPool
|
||||
|
||||
@ -61,14 +62,15 @@ class ControlServerTestCase(IsolatedAsyncioTestCase):
|
||||
self.assertEqual(self.mock_reader, self.session._reader)
|
||||
self.assertEqual(self.mock_writer, self.session._writer)
|
||||
self.assertIsNone(self.session._parser)
|
||||
self.assertIsInstance(self.session._response_buffer, StringIO)
|
||||
|
||||
@patch.object(session, 'return_or_exception')
|
||||
async def test__exec_method_and_respond(self, mock_return_or_exception: AsyncMock):
|
||||
def method(self, arg1, arg2, *var_args, **rest): pass
|
||||
test_arg1, test_arg2, test_var_args, test_rest = 123, 'xyz', [0.1, 0.2, 0.3], {'aaa': 1, 'bbb': 11}
|
||||
kwargs = {'arg1': test_arg1, 'arg2': test_arg2, 'var_args': test_var_args} | test_rest
|
||||
kwargs = {'arg1': test_arg1, 'arg2': test_arg2, 'var_args': test_var_args}
|
||||
mock_return_or_exception.return_value = None
|
||||
self.assertIsNone(await self.session._exec_method_and_respond(method, **kwargs))
|
||||
self.assertIsNone(await self.session._exec_method_and_respond(method, **kwargs, **test_rest))
|
||||
mock_return_or_exception.assert_awaited_once_with(
|
||||
method, self.mock_pool, test_arg1, test_arg2, *test_var_args, **test_rest
|
||||
)
|
||||
@ -104,7 +106,7 @@ class ControlServerTestCase(IsolatedAsyncioTestCase):
|
||||
self.mock_reader.read = mock_read
|
||||
self.mock_writer.drain = AsyncMock()
|
||||
expected_parser_kwargs = {
|
||||
STREAM_WRITER: self.mock_writer,
|
||||
'stream': self.session._response_buffer,
|
||||
CLIENT_INFO.TERMINAL_WIDTH: width,
|
||||
'prog': '',
|
||||
'usage': f'[-h] [{CMD}] ...'
|
||||
@ -132,10 +134,9 @@ class ControlServerTestCase(IsolatedAsyncioTestCase):
|
||||
kwargs = {FOO: BAR, 'hello': 'python'}
|
||||
mock_parse_args = MagicMock(return_value=Namespace(**{CMD: method}, **kwargs))
|
||||
self.session._parser = MagicMock(parse_args=mock_parse_args)
|
||||
self.mock_writer.write = MagicMock()
|
||||
self.assertIsNone(await self.session._parse_command(msg))
|
||||
mock_parse_args.assert_called_once_with(msg.split(' '))
|
||||
self.mock_writer.write.assert_not_called()
|
||||
self.assertEqual('', self.session._response_buffer.getvalue())
|
||||
mock__exec_method_and_respond.assert_awaited_once_with(method, **kwargs)
|
||||
mock__exec_property_and_respond.assert_not_called()
|
||||
|
||||
@ -145,7 +146,7 @@ class ControlServerTestCase(IsolatedAsyncioTestCase):
|
||||
mock_parse_args.return_value = Namespace(**{CMD: prop}, **kwargs)
|
||||
self.assertIsNone(await self.session._parse_command(msg))
|
||||
mock_parse_args.assert_called_once_with(msg.split(' '))
|
||||
self.mock_writer.write.assert_not_called()
|
||||
self.assertEqual('', self.session._response_buffer.getvalue())
|
||||
mock__exec_method_and_respond.assert_not_called()
|
||||
mock__exec_property_and_respond.assert_awaited_once_with(prop, **kwargs)
|
||||
|
||||
@ -161,26 +162,28 @@ class ControlServerTestCase(IsolatedAsyncioTestCase):
|
||||
mock_parse_args.assert_called_once_with(msg.split(' '))
|
||||
mock__exec_method_and_respond.assert_not_called()
|
||||
mock__exec_property_and_respond.assert_not_called()
|
||||
self.mock_writer.write.assert_called_once_with(str(exc).encode())
|
||||
self.assertEqual(str(exc), self.session._response_buffer.getvalue())
|
||||
|
||||
mock__exec_property_and_respond.reset_mock()
|
||||
mock_parse_args.reset_mock()
|
||||
self.mock_writer.write.reset_mock()
|
||||
self.session._response_buffer.seek(0)
|
||||
self.session._response_buffer.truncate()
|
||||
|
||||
mock_parse_args.side_effect = exc = ArgumentError(MagicMock(), "oops")
|
||||
self.assertIsNone(await self.session._parse_command(msg))
|
||||
mock_parse_args.assert_called_once_with(msg.split(' '))
|
||||
self.mock_writer.write.assert_called_once_with(str(exc).encode())
|
||||
self.assertEqual(str(exc), self.session._response_buffer.getvalue())
|
||||
mock__exec_method_and_respond.assert_not_awaited()
|
||||
mock__exec_property_and_respond.assert_not_awaited()
|
||||
|
||||
self.mock_writer.write.reset_mock()
|
||||
mock_parse_args.reset_mock()
|
||||
self.session._response_buffer.seek(0)
|
||||
self.session._response_buffer.truncate()
|
||||
|
||||
mock_parse_args.side_effect = HelpRequested()
|
||||
self.assertIsNone(await self.session._parse_command(msg))
|
||||
mock_parse_args.assert_called_once_with(msg.split(' '))
|
||||
self.mock_writer.write.assert_not_called()
|
||||
self.assertEqual('', self.session._response_buffer.getvalue())
|
||||
mock__exec_method_and_respond.assert_not_awaited()
|
||||
mock__exec_property_and_respond.assert_not_awaited()
|
||||
|
||||
@ -191,17 +194,23 @@ class ControlServerTestCase(IsolatedAsyncioTestCase):
|
||||
self.mock_writer.drain = AsyncMock(side_effect=make_reader_return_empty)
|
||||
msg = "fascinating"
|
||||
self.mock_reader.read = AsyncMock(return_value=f' {msg} '.encode())
|
||||
response = FOO + BAR + FOO
|
||||
self.session._response_buffer.write(response)
|
||||
self.assertIsNone(await self.session.listen())
|
||||
self.mock_reader.read.assert_has_awaits([call(SESSION_MSG_BYTES), call(SESSION_MSG_BYTES)])
|
||||
mock__parse_command.assert_awaited_once_with(msg)
|
||||
self.assertEqual('', self.session._response_buffer.getvalue())
|
||||
self.mock_writer.write.assert_called_once_with(response.encode())
|
||||
self.mock_writer.drain.assert_awaited_once_with()
|
||||
|
||||
self.mock_reader.read.reset_mock()
|
||||
mock__parse_command.reset_mock()
|
||||
self.mock_writer.write.reset_mock()
|
||||
self.mock_writer.drain.reset_mock()
|
||||
|
||||
self.mock_server.is_serving = MagicMock(return_value=False)
|
||||
self.assertIsNone(await self.session.listen())
|
||||
self.mock_reader.read.assert_not_awaited()
|
||||
mock__parse_command.assert_not_awaited()
|
||||
self.mock_writer.write.assert_not_called()
|
||||
self.mock_writer.drain.assert_not_awaited()
|
||||
|
Reference in New Issue
Block a user