3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-11-24 03:29:28 +01:00

Many fixes to test API, utils.reverseModes stub

This commit is contained in:
James Lu 2015-08-28 19:27:38 -07:00
parent ab4cb4d895
commit ad5fc97e21
7 changed files with 120 additions and 38 deletions

View File

@ -311,29 +311,6 @@ class IrcChannel():
### FakeIRC classes, used for test cases ### FakeIRC classes, used for test cases
global testconf
testconf = {'bot':
{
'nick': 'PyLink',
'user': 'pylink',
'realname': 'PyLink Service Client',
'loglevel': 'DEBUG',
},
'servers':
{'unittest':
{
'ip': '0.0.0.0',
'port': 7000,
'recvpass': "abcd",
'sendpass': "abcd",
'protocol': "null",
'hostname': "pylink.unittest",
'sid': "9PY",
'channels': ["#pylink"],
},
},
}
class FakeIRC(Irc): class FakeIRC(Irc):
def connect(self): def connect(self):
self.messages = [] self.messages = []
@ -382,11 +359,16 @@ class FakeIRC(Irc):
@staticmethod @staticmethod
def dummyhook(irc, source, command, parsed_args): def dummyhook(irc, source, command, parsed_args):
"""Dummy function to bind to hooks.""" """Dummy function to bind to hooks. This is what allows takeHooks() to work."""
irc.hookmsgs.append(parsed_args) irc.hookmsgs.append(parsed_args)
class FakeProto(): class FakeProto():
"""Dummy protocol module for testing purposes.""" """Dummy protocol module for testing purposes."""
def __init__(self):
self.hook_map = {}
self.casemapping = 'rfc1459'
self.__name__ = 'FakeProto'
@staticmethod @staticmethod
def handle_events(irc, data): def handle_events(irc, data):
pass pass

37
conf.py
View File

@ -1,5 +1,8 @@
import yaml import yaml
import sys import sys
from collections import defaultdict
import world
global confname global confname
try: try:
@ -14,6 +17,40 @@ except IndexError:
confname = 'pylink' confname = 'pylink'
fname = 'config.yml' fname = 'config.yml'
global testconf
testconf = {'bot':
{
'nick': 'PyLink',
'user': 'pylink',
'realname': 'PyLink Service Client',
'loglevel': 'DEBUG',
'serverdesc': 'PyLink unit tests'
},
'servers':
# Wildcard defaultdict! This means that
# any network name you try will work and return
# this basic template:
defaultdict(lambda: {
'ip': '0.0.0.0',
'port': 7000,
'recvpass': "abcd",
'sendpass': "chucknorris",
'protocol': "null",
'hostname': "pylink.unittest",
'sid': "9PY",
'channels': ["#pylink"],
'maxnicklen': 20
})
}
with open(fname, 'r') as f: with open(fname, 'r') as f:
global conf global conf
try:
conf = yaml.load(f) conf = yaml.load(f)
except Exception as e:
if world.testing:
conf = testconf
confname = 'testconf'
else:
print('ERROR: Failed to load config from %r: %s: %s' % (fname, type(e).__name__, e))
sys.exit(4)

View File

@ -9,8 +9,10 @@ import conf
import classes import classes
import utils import utils
import coreplugin import coreplugin
import world
if __name__ == '__main__': if __name__ == '__main__':
world.testing = False
log.info('PyLink starting...') log.info('PyLink starting...')
if conf.conf['login']['password'] == 'changeme': if conf.conf['login']['password'] == 'changeme':
log.critical("You have not set the login details correctly! Exiting...") log.critical("You have not set the login details correctly! Exiting...")

View File

@ -7,34 +7,41 @@ import unittest
import utils import utils
import classes import classes
import relay import relay
import conf
def dummyf(): def dummyf():
pass pass
class TestRelay(unittest.TestCase): class TestRelay(unittest.TestCase):
def setUp(self): def setUp(self):
self.irc = classes.FakeIRC('unittest', classes.FakeProto(), classes.testconf) self.irc = classes.FakeIRC('unittest', classes.FakeProto(), conf.testconf)
self.irc.maxnicklen = 20 self.irc.maxnicklen = 20
self.irc.proto.__name__ = "test" self.f = lambda nick: relay.normalizeNick(self.irc, 'unittest', nick)
self.f = relay.normalizeNick # Fake our protocol name to something that supports slashes in nicks.
# relay uses a whitelist for this to prevent accidentally introducing
# bad nicks:
self.irc.proto.__name__ = "inspircd"
def testNormalizeNick(self): def testNormalizeNick(self):
# Second argument simply states the suffix. # Second argument simply states the suffix.
self.assertEqual(self.f(self.irc, 'unittest', 'helloworld'), 'helloworld/unittest') self.assertEqual(self.f('helloworld'), 'helloworld/unittest')
self.assertEqual(self.f(self.irc, 'unittest', 'ObnoxiouslyLongNick'), 'Obnoxiously/unittest') self.assertEqual(self.f('ObnoxiouslyLongNick'), 'Obnoxiously/unittest')
self.assertEqual(self.f(self.irc, 'unittest', '10XAAAAAA'), '_10XAAAAAA/unittest') self.assertEqual(self.f('10XAAAAAA'), '_10XAAAAAA/unittest')
def testNormalizeNickConflict(self): def testNormalizeNickConflict(self):
self.assertEqual(self.f(self.irc, 'unittest', 'helloworld'), 'helloworld/unittest') self.assertEqual(self.f('helloworld'), 'helloworld/unittest')
self.irc.users['10XAAAAAA'] = classes.IrcUser('helloworld/unittest', 1234, '10XAAAAAA') self.irc.users['10XAAAAAA'] = classes.IrcUser('helloworld/unittest', 1234, '10XAAAAAA')
# Increase amount of /'s by one # Increase amount of /'s by one
self.assertEqual(self.f(self.irc, 'unittest', 'helloworld'), 'helloworld//unittest') self.assertEqual(self.f('helloworld'), 'helloworld//unittest')
self.irc.users['10XAAAAAB'] = classes.IrcUser('helloworld//unittest', 1234, '10XAAAAAB') self.irc.users['10XAAAAAB'] = classes.IrcUser('helloworld//unittest', 1234, '10XAAAAAB')
# Cut off the nick, not the suffix if the result is too long. # Cut off the nick, not the suffix if the result is too long.
self.assertEqual(self.f(self.irc, 'unittest', 'helloworld'), 'helloworl///unittest') self.assertEqual(self.f('helloworld'), 'helloworl///unittest')
def testNormalizeNickRemovesSlashes(self): def testNormalizeNickRemovesSlashes(self):
self.irc.proto.__name__ = "charybdis" self.irc.proto.__name__ = "charybdis"
self.assertEqual(self.f(self.irc, 'unittest', 'helloworld'), 'helloworld|unittest') try:
self.assertEqual(self.f(self.irc, 'unittest', 'abcde/eJanus'), 'abcde|eJanu|unittest') self.assertEqual(self.f('helloworld'), 'helloworld|unittest')
self.assertEqual(self.f(self.irc, 'unittest', 'ObnoxiouslyLongNick'), 'Obnoxiously|unittest') self.assertEqual(self.f('abcde/eJanus'), 'abcde|eJanu|unittest')
self.assertEqual(self.f('ObnoxiouslyLongNick'), 'Obnoxiously|unittest')
finally:
self.irc.proto.__name__ = "inspircd"

View File

@ -5,11 +5,16 @@ import unittest
import itertools import itertools
import utils import utils
import classes
import conf
def dummyf(): def dummyf():
pass pass
class TestUtils(unittest.TestCase): class TestUtils(unittest.TestCase):
def setUp(self):
self.irc = classes.FakeIRC('fakeirc', classes.FakeProto(), conf.testconf)
def testTS6UIDGenerator(self): def testTS6UIDGenerator(self):
uidgen = utils.TS6UIDGenerator('9PY') uidgen = utils.TS6UIDGenerator('9PY')
self.assertEqual(uidgen.next_uid(), '9PYAAAAAA') self.assertEqual(uidgen.next_uid(), '9PYAAAAAA')
@ -96,5 +101,19 @@ class TestUtils(unittest.TestCase):
('+b', '*!*@*.badisp.net')]) ('+b', '*!*@*.badisp.net')])
self.assertEqual(res, '-o+l-nm+kb 9PYAAAAAA 50 hello *!*@*.badisp.net') self.assertEqual(res, '-o+l-nm+kb 9PYAAAAAA 50 hello *!*@*.badisp.net')
@unittest.skip('Wait, we need to work out the kinks first! (reversing changes of modes with arguments)')
def testReverseModes(self):
f = lambda x: utils.reverseModes(self.irc, '#test', x)
# Strings.
self.assertEqual(f("+nt-lk"), "-nt+lk")
self.assertEqual(f("nt-k"), "-nt+k")
# Lists.
self.assertEqual(f([('+m', None), ('+t', None), ('+l', '3'), ('-o', 'person')]),
[('-m', None), ('-t', None), ('-l', '3'), ('+o', 'person')])
# Sets.
self.assertEqual(f({('s', None), ('+o', 'whoever')}), {('-s', None), ('-o', 'whoever')})
# Combining modes with an initial + and those without
self.assertEqual(f({('s', None), ('+n', None)}), {('-s', None), ('-n', None)})
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -165,7 +165,7 @@ def isServerName(s):
return _isASCII(s) and '.' in s and not s.startswith('.') return _isASCII(s) and '.' in s and not s.startswith('.')
def parseModes(irc, target, args): def parseModes(irc, target, args):
"""Parses a mode string into a list of (mode, argument) tuples. """Parses a modestring list into a list of (mode, argument) tuples.
['+mitl-o', '3', 'person'] => [('+m', None), ('+i', None), ('+t', None), ('+l', '3'), ('-o', 'person')] ['+mitl-o', '3', 'person'] => [('+m', None), ('+i', None), ('+t', None), ('+l', '3'), ('-o', 'person')]
""" """
# http://www.irc.org/tech_docs/005.html # http://www.irc.org/tech_docs/005.html
@ -337,6 +337,34 @@ def joinModes(modes):
modelist += ' %s' % ' '.join(args) modelist += ' %s' % ' '.join(args)
return modelist return modelist
def reverseModes(irc, target, modes):
"""<mode string/mode list>
Reverses/Inverts the mode string or mode list given.
"+nt-lk" => "-nt+lk"
"nt-k" => "-nt+k"
[('+m', None), ('+t', None), ('+l', '3'), ('-o', 'person')] =>
[('-m', None), ('-t', None), ('-l', '3'), ('+o', 'person')]
[('s', None), ('+n', None)] => [('-s', None), ('-n', None)]
"""
origtype = type(modes)
# Operate on joined modestrings only; it's easier.
if origtype != str:
modes = joinModes(modes)
# Swap the +'s and -'s by replacing one with a dummy character, and then changing it back.
assert '\x00' not in modes, 'NUL cannot be in the mode list (it is a reserved character)!'
if not modes.startswith(('+', '-')):
modes = '+' + modes
newmodes = modes.replace('+', '\x00')
newmodes = newmodes.replace('-', '+')
newmodes = newmodes.replace('\x00', '-')
if origtype != str:
# If the original query isn't a string, send back the parseModes() output.
return parseModes(irc, target, newmodes.split(" "))
else:
return newmodes
def isInternalClient(irc, numeric): def isInternalClient(irc, numeric):
"""<irc object> <client numeric> """<irc object> <client numeric>

7
world.py Normal file
View File

@ -0,0 +1,7 @@
# world.py: global state variables go here
# Global variable to indicate whether we're being ran directly, or imported
# for a testcase.
testing = True