From 6d68a497ac7a264e4b726f615da628197db90f00 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Sat, 19 Dec 2015 09:30:50 +0100 Subject: [PATCH] Add --show-io, improve I/O commands, and add test case for empty CAP LS. --- irctest/__main__.py | 3 ++ irctest/cases.py | 51 +++++++++++++++++++++++------ irctest/clienttests/test_cap.py | 8 ++++- irctest/irc_utils/message_parser.py | 7 +--- 4 files changed, 52 insertions(+), 17 deletions(-) diff --git a/irctest/__main__.py b/irctest/__main__.py index c53feef..1fa86b5 100644 --- a/irctest/__main__.py +++ b/irctest/__main__.py @@ -26,6 +26,7 @@ def main(args): file=sys.stderr) exit(1) _IrcTestCase.controllerClass = controller_class + _IrcTestCase.show_io = args.show_io unittest.main(module=module, argv=[sys.argv[0], 'discover']) @@ -33,6 +34,8 @@ parser = argparse.ArgumentParser( description='A script to test interoperability of IRC software.') parser.add_argument('module', type=str, help='The module used to run the tested program.') +parser.add_argument('--show-io', action='store_true', + help='Show input/outputs with the tested program.') args = parser.parse_args() main(args) diff --git a/irctest/cases.py b/irctest/cases.py index 6d00d0e..bb0a4ce 100644 --- a/irctest/cases.py +++ b/irctest/cases.py @@ -6,6 +6,17 @@ from .irc_utils import message_parser class _IrcTestCase(unittest.TestCase): controllerClass = None # Will be set by __main__.py + def getLine(self): + raise NotImplementedError() + def getMessage(self, filter_pred=None): + """Gets a message and returns it. If a filter predicate is given, + fetches messages until the predicate returns a False on a message, + and returns this message.""" + while True: + msg = message_parser.parse_message(self.getLine()) + if not filter_pred or filter_pred(msg): + return msg + class BaseClientTestCase(_IrcTestCase): """Basic class for client tests. Handles spawning a client and getting messages from it.""" @@ -26,14 +37,21 @@ class BaseClientTestCase(_IrcTestCase): def acceptClient(self): """Make the server accept a client connection. Blocking.""" (self.conn, addr) = self.server.accept() - self.conn_file = self.conn.makefile(newline='\r\n') + self.conn_file = self.conn.makefile(newline='\r\n', + encoding='utf8') def getLine(self): - return self.conn_file.readline().strip() - def getMessage(self): - return message_parser.parse_message(self.conn_file.readline()) + line = self.conn_file.readline() + if self.show_io: + print('C: {}'.format(line.strip())) + return line + def sendLine(self, line): + assert self.conn.sendall(line.encode()) is None + if not line.endswith('\r\n'): + assert self.conn.sendall(b'\r\n') is None + print('S: {}'.format(line.strip())) -class NegociationHelper: +class ClientNegociationHelper: """Helper class for tests handling capabilities negociation.""" def readCapLs(self): (hostname, port) = self.server.getsockname() @@ -46,12 +64,25 @@ class NegociationHelper: m = self.getMessage() self.assertEqual(m.command, 'CAP', 'First message is not CAP LS.') - self.assertEqual(m.subcommand, 'LS', - 'First message is not CAP LS.') - if m.params == []: + if m.params == ['LS']: self.protocol_version = 301 - elif m.params == ['302']: + elif m.params == ['LS', '302']: self.protocol_version = 302 else: - raise AssertionError('Unknown protocol version {}' + raise AssertionError('Unknown CAP params: {}' .format(m.params)) + + def userNickPredicate(self, msg): + """Predicate to be used with getMessage to handle NICK/USER + transparently.""" + if msg.command == 'NICK': + self.assertEqual(len(msg.params), 1, msg) + self.nick = msg.params[0] + return False + elif msg.command == 'USER': + self.assertEqual(len(msg.params), 4, msg) + self.nick = msg.params + return False + else: + return True + diff --git a/irctest/clienttests/test_cap.py b/irctest/clienttests/test_cap.py index 5577ce5..2a6f1bc 100644 --- a/irctest/clienttests/test_cap.py +++ b/irctest/clienttests/test_cap.py @@ -1,6 +1,12 @@ from irctest import cases from irctest.irc_utils.message_parser import Message -class CapTestCase(cases.BaseClientTestCase, cases.NegociationHelper): +class CapTestCase(cases.BaseClientTestCase, cases.ClientNegociationHelper): def testSendCap(self): self.readCapLs() + + def testEmptyCapLs(self): + self.readCapLs() + self.sendLine('CAP * LS :') + m = self.getMessage(filter_pred=self.userNickPredicate) + self.assertEqual(m, Message([], None, 'CAP', ['END'])) diff --git a/irctest/irc_utils/message_parser.py b/irctest/irc_utils/message_parser.py index a33e7f8..343a174 100644 --- a/irctest/irc_utils/message_parser.py +++ b/irctest/irc_utils/message_parser.py @@ -29,7 +29,7 @@ def parse_tags(s): return tags Message = collections.namedtuple('Message', - 'tags prefix command subcommand params') + 'tags prefix command params') def parse_message(s): """Parse a message according to @@ -52,15 +52,10 @@ def parse_message(s): else: prefix = None command = tokens.pop(0) - if command == 'CAP': - subcommand = tokens.pop(0) - else: - subcommand = None params = tokens return Message( tags=tags, prefix=prefix, command=command, - subcommand=subcommand, params=params, )