diff --git a/test/test_Alias.py b/test/test_Alias.py new file mode 100644 index 000000000..3a1f42205 --- /dev/null +++ b/test/test_Alias.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from test import * + +import Alias + + +class FunctionsTest(unittest.TestCase): + def testFindAliasCommand(self): + s = 'command' + self.failIf(Alias.findAliasCommand(s, '')) + self.failIf(Alias.findAliasCommand(s, 'foo')) + self.failIf(Alias.findAliasCommand(s, 'foo bar [ baz]')) + self.failIf(Alias.findAliasCommand(s, 'foo bar [baz]')) + self.failUnless(Alias.findAliasCommand(s, s)) + self.failUnless(Alias.findAliasCommand(s, ' %s' % s)) + self.failUnless(Alias.findAliasCommand(s, '[%s]' % s)) + self.failUnless(Alias.findAliasCommand(s, '[ %s]' % s)) + self.failUnless(Alias.findAliasCommand(s, 'foo bar [%s]' % s)) + self.failUnless(Alias.findAliasCommand(s, 'foo bar [ %s]' % s)) + + def testFindBiggestDollar(self): + self.assertEqual(Alias.findBiggestDollar(''), None) + self.assertEqual(Alias.findBiggestDollar('foo'), None) + self.assertEqual(Alias.findBiggestDollar('$0'), 0) + self.assertEqual(Alias.findBiggestDollar('$1'), 1) + self.assertEqual(Alias.findBiggestDollar('$2'), 2) + self.assertEqual(Alias.findBiggestDollar('$3'), 3) + self.assertEqual(Alias.findBiggestDollar('foo bar $1'), 1) + self.assertEqual(Alias.findBiggestDollar('foo $2 $1'), 2) + self.assertEqual(Alias.findBiggestDollar('foo $0 $1'), 1) + self.assertEqual(Alias.findBiggestDollar('foo $1 $3'), 3) + self.assertEqual(Alias.findBiggestDollar('$10 bar $1'), 10) diff --git a/test/test_callbacks.py b/test/test_callbacks.py new file mode 100644 index 000000000..582deb874 --- /dev/null +++ b/test/test_callbacks.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from test import * + +import conf +import ircmsgs +import callbacks + +tokenize = callbacks.tokenize + + +class TokenizerTestCase(unittest.TestCase): + def testEmpty(self): + self.assertEqual(tokenize(''), []) + + def testSingleWord(self): + self.assertEqual(tokenize('foo'), ['foo']) + + def testMultipleSimpleWords(self): + words = 'one two three four five six seven eight'.split() + for i in range(len(words)): + self.assertEqual(tokenize(' '.join(words[:i])), words[:i]) + + def testSingleQuotesNotQuotes(self): + self.assertEqual(tokenize("it's"), ["it's"]) + + def testQuotedWords(self): + self.assertEqual(tokenize('"foo bar"'), ['foo bar']) + self.assertEqual(tokenize('""'), ['']) + self.assertEqual(tokenize('foo "" bar'), ['foo', '', 'bar']) + self.assertEqual(tokenize('foo "bar baz" quux'), + ['foo', 'bar baz', 'quux']) + + def testNesting(self): + self.assertEqual(tokenize('[]'), [[]]) + self.assertEqual(tokenize('[foo]'), [['foo']]) + self.assertEqual(tokenize('foo [bar]'), ['foo', ['bar']]) + self.assertEqual(tokenize('foo bar [baz quux]'), + ['foo', 'bar', ['baz', 'quux']]) + + def testError(self): + self.assertRaises(SyntaxError, tokenize, '[foo') #] + self.assertRaises(SyntaxError, tokenize, '"foo') #" + + +class FunctionsTestCase(unittest.TestCase): + def testCanonicalName(self): + self.assertEqual('foo', callbacks.canonicalName('foo')) + self.assertEqual('foobar', callbacks.canonicalName('foo-bar')) + self.assertEqual('foobar', callbacks.canonicalName('foo_bar')) + self.assertEqual('foobar', callbacks.canonicalName('FOO-bar')) + self.assertEqual('foobar', callbacks.canonicalName('FOOBAR')) + self.assertEqual('foobar', callbacks.canonicalName('foo___bar')) + self.assertEqual('foobar', callbacks.canonicalName('_f_o_o-b_a_r_')) + + def testAddressed(self): + oldprefixchars = conf.prefixChars + nick = 'supybot' + conf.prefixChars = '~!@' + inChannel = ['~foo', '@foo', '!foo', + '%s: foo' % nick, '%s foo' % nick] + inChannel = [ircmsgs.privmsg('#foo', s) for s in inChannel] + badmsg = ircmsgs.privmsg('#foo', '%s:foo' % nick) + self.failIf(callbacks.addressed(nick, badmsg)) + for msg in inChannel: + self.assertEqual('foo', callbacks.addressed(nick, msg), msg) + msg = ircmsgs.privmsg(nick, 'foo') + self.assertEqual('foo', callbacks.addressed(nick, msg)) + conf.prefixChars = oldprefixchars + + def testReply(self): + prefix = 'foo!bar@baz' + channelMsg = ircmsgs.privmsg('#foo', 'bar baz', prefix=prefix) + nonChannelMsg = ircmsgs.privmsg('supybot', 'bar baz', prefix=prefix) + self.assertEqual(ircmsgs.privmsg(nonChannelMsg.nick, 'foo'), + callbacks.reply(nonChannelMsg, 'foo')) + self.assertEqual(ircmsgs.privmsg(channelMsg.args[0], + '%s: foo' % channelMsg.nick), + callbacks.reply(channelMsg, 'foo')) diff --git a/test/test_fix.py b/test/test_fix.py new file mode 100644 index 000000000..d247811c7 --- /dev/null +++ b/test/test_fix.py @@ -0,0 +1,281 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from __future__ import generators + +from test import * + +import pickle + +class QueueTest(unittest.TestCase): + def testGetitem(self): + q = queue() + n = 10 + for i in xrange(n): + q.enqueue(i) + for i in xrange(n): + self.assertEqual(q[i], i) + for i in xrange(n, 0, -1): + self.assertEqual(q[-i], n-i) + self.assertRaises(IndexError, q.__getitem__, -(n+1)) + self.assertRaises(IndexError, q.__getitem__, n) + #self.assertEqual(q[3:7], queue([3, 4, 5, 6])) + + def testSetitem(self): + q1 = queue() + for i in xrange(10): + q1.enqueue(i) + q2 = eval(repr(q1)) + for (i, elt) in enumerate(q2): + q2[i] = elt*2 + self.assertEqual([x*2 for x in q1], list(q2)) + + def testNonzero(self): + q = queue() + self.failIf(q, 'queue not zero after initialization') + q.enqueue(1) + self.failUnless(q, 'queue zero after adding element') + q.dequeue() + self.failIf(q, 'queue not zero after dequeue of only element') + + def testLen(self): + q = queue() + self.assertEqual(0, len(q), 'queue len not 0 after initialization') + q.enqueue(1) + self.assertEqual(1, len(q), 'queue len not 1 after enqueue') + q.enqueue(2) + self.assertEqual(2, len(q), 'queue len not 2 after enqueue') + q.dequeue() + self.assertEqual(1, len(q), 'queue len not 1 after dequeue') + q.dequeue() + self.assertEqual(0, len(q), 'queue len not 0 after dequeue') + for i in range(10): + L = range(i) + q = queue(L) + self.assertEqual(len(q), i) + + def testEq(self): + q1 = queue() + q2 = queue() + self.failUnless(q1 == q1, 'queue not equal to itself') + self.failUnless(q2 == q2, 'queue not equal to itself') + self.failUnless(q1 == q2, 'initialized queues not equal') + q1.enqueue(1) + self.failUnless(q1 == q1, 'queue not equal to itself') + self.failUnless(q2 == q2, 'queue not equal to itself') + q2.enqueue(1) + self.failUnless(q1 == q1, 'queue not equal to itself') + self.failUnless(q2 == q2, 'queue not equal to itself') + self.failUnless(q1 == q2, 'queues not equal after identical enqueue') + q1.dequeue() + self.failUnless(q1 == q1, 'queue not equal to itself') + self.failUnless(q2 == q2, 'queue not equal to itself') + self.failIf(q1 == q2, 'queues equal after one dequeue') + q2.dequeue() + self.failUnless(q1 == q2, 'queues not equal after both are dequeued') + self.failUnless(q1 == q1, 'queue not equal to itself') + self.failUnless(q2 == q2, 'queue not equal to itself') + + def testInit(self): + self.assertEqual(len(queue()), 0, 'queue len not 0 after init') + q = queue() + q.enqueue(1) + q.enqueue(2) + q.enqueue(3) + self.assertEqual(queue((1, 2, 3)),q, 'init not equivalent to enqueues') + q = queue((1, 2, 3)) + self.assertEqual(q.dequeue(), 1, 'values not returned in proper order') + self.assertEqual(q.dequeue(), 2, 'values not returned in proper order') + self.assertEqual(q.dequeue(), 3, 'values not returned in proper order') + + def testRepr(self): + q = queue() + q.enqueue(1) + self.assertEqual(q, eval(repr(q)), 'repr doesn\'t eval to same queue') + q.enqueue('foo') + self.assertEqual(q, eval(repr(q)), 'repr doesn\'t eval to same queue') + q.enqueue(None) + self.assertEqual(q, eval(repr(q)), 'repr doesn\'t eval to same queue') + q.enqueue(1.0) + self.assertEqual(q, eval(repr(q)), 'repr doesn\'t eval to same queue') + q.enqueue([]) + self.assertEqual(q, eval(repr(q)), 'repr doesn\'t eval to same queue') + q.enqueue(()) + self.assertEqual(q, eval(repr(q)), 'repr doesn\'t eval to same queue') + q.enqueue([1]) + self.assertEqual(q, eval(repr(q)), 'repr doesn\'t eval to same queue') + q.enqueue((1,)) + self.assertEqual(q, eval(repr(q)), 'repr doesn\'t eval to same queue') + + def testEnqueueDequeue(self): + q = queue() + self.assertRaises(IndexError, q.dequeue) + q.enqueue(1) + self.assertEqual(q.dequeue(), 1, + 'first dequeue didn\'t return same as first enqueue') + q.enqueue(1) + q.enqueue(2) + q.enqueue(3) + self.assertEqual(q.dequeue(), 1) + self.assertEqual(q.dequeue(), 2) + self.assertEqual(q.dequeue(), 3) + + def testPeek(self): + q = queue() + self.assertRaises(IndexError, q.peek) + q.enqueue(1) + self.assertEqual(q.peek(), 1, 'peek didn\'t return first enqueue') + q.enqueue(2) + self.assertEqual(q.peek(), 1, 'peek didn\'t return first enqueue') + q.dequeue() + self.assertEqual(q.peek(), 2, 'peek didn\'t return second enqueue') + q.dequeue() + self.assertRaises(IndexError, q.peek) + + def testContains(self): + q = queue() + self.failIf(1 in q, 'empty queue cannot have elements') + q.enqueue(1) + self.failUnless(1 in q, 'recent enqueued element not in q') + q.enqueue(2) + self.failUnless(1 in q, 'original enqueued element not in q') + self.failUnless(2 in q, 'second enqueued element not in q') + q.dequeue() + self.failIf(1 in q, 'dequeued element in q') + self.failUnless(2 in q, 'not dequeued element not in q') + q.dequeue() + self.failIf(2 in q, 'dequeued element in q') + + def testIter(self): + q1 = queue((1, 2, 3)) + q2 = queue() + for i in q1: + q2.enqueue(i) + self.assertEqual(q1, q2, 'iterate didn\'t return all elements') + for _ in queue(): + self.fail('no elements should be in empty queue') + + def testPickleCopy(self): + q = queue(range(10)) + self.assertEqual(q, pickle.loads(pickle.dumps(q))) + + +class MaxLengthQueueTestCase(unittest.TestCase): + def testMaxLength(self): + q = MaxLengthQueue(3) + q.enqueue(1) + self.assertEqual(len(q), 1) + q.enqueue(2) + self.assertEqual(len(q), 2) + q.enqueue(3) + self.assertEqual(len(q), 3) + q.enqueue(4) + self.assertEqual(len(q), 3) + self.assertEqual(q.peek(), 2) + q.enqueue(5) + self.assertEqual(len(q), 3) + self.assertEqual(q[0], 3) + +class FunctionsTest(unittest.TestCase): + def testCatch(self): + def f(): + raise Exception + catch(f) + + def testReviter(self): + L = range(10) + revL = list(reviter(L)) + L.reverse() + self.assertEqual(L, revL, 'reviter didn\'t return reversed list') + for elt in reviter([]): + self.fail('reviter caused iteration over empty sequence') + + def testWindow(self): + L = range(10) + def wwindow(*args): + return list(window(*args)) + self.assertEqual(wwindow([], 1), [], 'Empty sequence, empty window') + self.assertEqual(wwindow([], 2), [], 'Empty sequence, empty window') + self.assertEqual(wwindow([], 5), [], 'Empty sequence, empty window') + self.assertEqual(wwindow([], 100), [], 'Empty sequence, empty window') + self.assertEqual(wwindow(L, 1), [[x] for x in L], 'Window length 1') + self.assertRaises(ValueError, wwindow, [], 0) + self.assertRaises(ValueError, wwindow, [], -1) + + def testItersplit(self): + L = [1, 2, 3] * 3 + s = 'foo bar baz' + self.assertEqual(list(itersplit(L, lambda x: x == 3)), + [[1, 2], [1, 2], [1, 2]]) + self.assertEqual(list(itersplit(L, lambda x: x == 3, True)), + [[1, 2], [1, 2], [1, 2], []]) + self.assertEqual(list(itersplit([], lambda x: x)), []) + self.assertEqual(list(itersplit(s, lambda c: c.isspace())), + map(list, s.split())) + + def testIterableMap(self): + class alist(IterableMap): + def __init__(self): + self.L = [] + + def __setitem__(self, key, value): + self.L.append((key, value)) + + def iteritems(self): + for (k, v) in self.L: + yield (k, v) + AL = alist() + self.failIf(AL) + AL[1] = 2 + AL[2] = 3 + AL[3] = 4 + self.failUnless(AL) + self.assertEqual(AL.items(), [(1, 2), (2, 3), (3, 4)]) + self.assertEqual(list(AL.iteritems()), [(1, 2), (2, 3), (3, 4)]) + self.assertEqual(AL.keys(), [1, 2, 3]) + self.assertEqual(list(AL.iterkeys()), [1, 2, 3]) + self.assertEqual(AL.values(), [2, 3, 4]) + self.assertEqual(list(AL.itervalues()), [2, 3, 4]) + self.assertEqual(len(AL), 3) + + def testFlatten(self): + def lflatten(seq): + return list(flatten(seq)) + self.assertEqual(lflatten([]), []) + self.assertEqual(lflatten([1]), [1]) + self.assertEqual(lflatten(range(10)), range(10)) + twoRanges = range(10)*2 + twoRanges.sort() + self.assertEqual(lflatten(zip(range(10), range(10))), twoRanges) + self.assertEqual(lflatten([1, [2, 3], 4]), [1, 2, 3, 4]) + self.assertEqual(lflatten([[[[[[[[[[]]]]]]]]]]), []) + self.assertEqual(lflatten([1, [2, [3, 4], 5], 6]), [1, 2, 3, 4, 5, 6]) + self.assertRaises(TypeError, lflatten, 1) diff --git a/test/test_ircdb.py b/test/test_ircdb.py new file mode 100644 index 000000000..1de359177 --- /dev/null +++ b/test/test_ircdb.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from test import * + +import os +import unittest + +import debug +import ircdb +import ircutils + +class FunctionsTestCase(unittest.TestCase): + def testIsAntiCapability(self): + self.failIf(ircdb.isAntiCapability('foo')) + self.failIf(ircdb.isAntiCapability('#foo.bar')) + self.failUnless(ircdb.isAntiCapability('!foo')) + self.failUnless(ircdb.isAntiCapability('#foo.!bar')) + + def testIsChannelCapability(self): + self.failIf(ircdb.isChannelCapability('foo')) + self.failUnless(ircdb.isChannelCapability('#foo.bar')) + + def testMakeAntiCapability(self): + self.assertEqual(ircdb.makeAntiCapability('foo'), '!foo') + self.assertEqual(ircdb.makeAntiCapability('#foo.bar'), '#foo.!bar') + + def testMakeChannelCapability(self): + self.assertEqual(ircdb.makeChannelCapability('#f', 'b'), '#f.b') + self.assertEqual(ircdb.makeChannelCapability('#f', '!b'), '#f.!b') + + def testUnAntiCapability(self): + self.assertEqual(ircdb.unAntiCapability('!bar'), 'bar') + self.assertEqual(ircdb.unAntiCapability('#foo.!bar'), '#foo.bar') + + def testInvertCapability(self): + self.assertEqual(ircdb.invertCapability('bar'), '!bar') + self.assertEqual(ircdb.invertCapability('!bar'), 'bar') + self.assertEqual(ircdb.invertCapability('#foo.bar'), '#foo.!bar') + self.assertEqual(ircdb.invertCapability('#foo.!bar'), '#foo.bar') + + +class CapabilitySetTestCase(unittest.TestCase): + def test(self): + d = ircdb.CapabilitySet() + self.assertRaises(KeyError, d.check, 'foo') + d = ircdb.CapabilitySet(('foo',)) + self.failUnless(d.check('foo')) + self.failIf(d.check('!foo')) + d.add('bar') + self.failUnless(d.check('bar')) + self.failIf(d.check('!bar')) + d.add('!baz') + self.failIf(d.check('baz')) + self.failUnless(d.check('!baz')) + d.add('!bar') + self.failIf(d.check('bar')) + self.failUnless(d.check('!bar')) + d.remove('!bar') + self.assertRaises(KeyError, d.check, '!bar') + self.assertRaises(KeyError, d.check, 'bar') + + +class UserCapabilitySetTestCase(unittest.TestCase): + def test(self): + d = ircdb.UserCapabilitySet(('owner',)) + self.failIf(d.check('!foo')) + self.failUnless(d.check('foo')) + + +class CapabilitySetTestCase(unittest.TestCase): + def test(self): + s = ircdb.CapabilitySet() + s.add('foo') + self.failUnless('foo' in s) + self.failIf('!foo' in s) + s.add('!bar') + self.failUnless('!bar' in s) + self.failIf('bar' in s) + self.assertRaises(KeyError, s.check, 'baz') + self.assertRaises(KeyError, s.check, '!baz') + s.remove('!bar') + self.assertRaises(KeyError, s.check, '!bar') + self.assertRaises(KeyError, s.check, 'bar') + s.remove('foo') + self.assertRaises(KeyError, s.check, 'foo') + self.assertRaises(KeyError, s.check, '!foo') + +class UserCapabilitySetTestCase(unittest.TestCase): + def test(self): + s = ircdb.UserCapabilitySet() + s.add('owner') + self.failUnless(s.check('owner')) + self.failIf(s.check('!owner')) + self.failIf(s.check('!foo')) + self.failUnless(s.check('foo')) + +class IrcUserTestCase(unittest.TestCase): + def testCapabilities(self): + u = ircdb.IrcUser() + u.addCapability('foo') + self.failUnless(u.checkCapability('foo')) + self.failIf(u.checkCapability('!foo')) + u.addCapability('!bar') + self.failUnless(u.checkCapability('!bar')) + self.failIf(u.checkCapability('bar')) + u.removeCapability('foo') + u.removeCapability('!bar') + self.assertRaises(KeyError, u.checkCapability, 'foo') + self.assertRaises(KeyError, u.checkCapability, '!bar') + + def testOwner(self): + u = ircdb.IrcUser() + u.addCapability('owner') + self.failUnless(u.checkCapability('foo')) + self.failIf(u.checkCapability('!foo')) + + def testInitCapabilities(self): + u = ircdb.IrcUser(capabilities=['foo']) + self.failUnless(u.checkCapability('foo')) + + def testPassword(self): + u = ircdb.IrcUser() + u.setPassword('foobar') + self.failUnless(u.checkPassword('foobar')) + self.failIf(u.checkPassword('somethingelse')) + + def testHostmasks(self): + prefix = 'foo!bar@baz' + hostmasks = ['*!bar@baz', 'foo!*@*'] + u = ircdb.IrcUser() + self.failIf(u.checkHostmask(prefix)) + for hostmask in hostmasks: + u.addHostmask(hostmask) + self.failUnless(u.checkHostmask(prefix)) + + def testAuth(self): + prefix = 'foo!bar@baz' + u = ircdb.IrcUser() + u.setAuth(prefix) + self.failUnless(u.checkAuth(prefix)) + u.unsetAuth() + self.failIf(u.checkAuth(prefix)) + + def testIgnore(self): + u = ircdb.IrcUser(ignore=True) + self.failIf(u.checkCapability('foo')) + self.failUnless(u.checkCapability('!foo')) + +class IrcChannelTestCase(unittest.TestCase): + def testInit(self): + c = ircdb.IrcChannel() + self.failIf(c.checkCapability('op')) + self.failIf(c.checkCapability('voice')) + self.failIf(c.checkCapability('halfop')) + self.failIf(c.checkCapability('protected')) + + def testCapabilities(self): + c = ircdb.IrcChannel(defaultAllow=False) + self.failIf(c.checkCapability('foo')) + c.addCapability('foo') + self.failUnless(c.checkCapability('foo')) + c.removeCapability('foo') + self.failIf(c.checkCapability('foo')) + + def testDefaultCapability(self): + c = ircdb.IrcChannel() + c.setDefaultCapability(False) + self.failIf(c.checkCapability('foo')) + self.failUnless(c.checkCapability('!foo')) + c.setDefaultCapability(True) + self.failUnless(c.checkCapability('foo')) + self.failIf(c.checkCapability('!foo')) + + def testLobotomized(self): + c = ircdb.IrcChannel(lobotomized=True) + self.failUnless(c.checkIgnored('')) + + def testIgnored(self): + prefix = 'foo!bar@baz' + banmask = ircutils.banmask(prefix) + c = ircdb.IrcChannel() + self.failIf(c.checkIgnored(prefix)) + c.addIgnore(banmask) + self.failUnless(c.checkIgnored(prefix)) + c.removeIgnore(banmask) + self.failIf(c.checkIgnored(prefix)) + c.addBan(banmask) + self.failUnless(c.checkIgnored(prefix)) + c.removeBan(banmask) + self.failIf(c.checkIgnored(prefix)) + +class UsersDictionaryTestCase(unittest.TestCase): + filename = 'UsersDictionaryTestCase.conf' + def setUp(self): + fd = file(self.filename, 'w') + fd.write('{}\n') + fd.close() + self.users = ircdb.UsersDictionary(self.filename) + + def tearDown(self): + os.remove(self.filename) + + def testGetSetDelUser(self): + self.assertRaises(KeyError, self.users.getUser, 'foo') + self.assertRaises(KeyError, self.users.getUser, 'foo!bar@baz') + u = ircdb.IrcUser() + hostmask = 'foo!bar@baz' + banmask = ircutils.banmask(hostmask) + u.addHostmask(banmask) + self.users.setUser('foo', u) + self.assertEqual(self.users.getUser('foo'), u) + self.assertEqual(self.users.getUser(hostmask), u) + self.assertEqual(self.users.getUser(banmask), u) + # The UsersDictionary shouldn't allow users to be added whose hostmasks + # match another user's already in the database. + self.assertRaises(ValueError, self.users.setUser, 'bar', u) + u.removeHostmask(banmask) + u.addHostmask('*!*@*') + self.assertRaises(ValueError, self.users.setUser, 'biff', u) + + +class CheckCapabilityTestCase(unittest.TestCase): + filename = 'CheckCapabilityTestCase.conf' + owner = 'owner!owner@owner' + nothing = 'nothing!nothing@nothing' + justfoo = 'justfoo!justfoo@justfoo' + antifoo = 'antifoo!antifoo@antifoo' + justchanfoo = 'justchanfoo!justchanfoo@justchanfoo' + antichanfoo = 'antichanfoo!antichanfoo@antichanfoo' + channel = '#channel' + cap = 'foo' + anticap = ircdb.makeAntiCapability(cap) + chancap = ircdb.makeChannelCapability(channel, cap) + antichancap = ircdb.makeAntiCapability(chancap) + channelnothing = ircdb.IrcChannel() + channelcap = ircdb.IrcChannel() + channelcap.addCapability(cap) + channelanticap = ircdb.IrcChannel() + channelanticap.addCapability(anticap) + def setUp(self): + fd = file(self.filename, 'w') + fd.write('{}\n') + fd.close() + self.users = ircdb.UsersDictionary(self.filename) + self.channels = ircdb.ChannelsDictionary(self.filename) + owner = ircdb.IrcUser() + owner.addCapability('owner') + owner.addHostmask(self.owner) + self.users.setUser('owner', owner) + nothing = ircdb.IrcUser() + nothing.addHostmask(self.nothing) + self.users.setUser('nothing', nothing) + justfoo = ircdb.IrcUser() + justfoo.addCapability(self.cap) + justfoo.addHostmask(self.justfoo) + self.users.setUser('justfoo', justfoo) + antifoo = ircdb.IrcUser() + antifoo.addCapability(self.anticap) + antifoo.addHostmask(self.antifoo) + self.users.setUser('antifoo', antifoo) + justchanfoo = ircdb.IrcUser() + justchanfoo.addCapability(self.chancap) + justchanfoo.addHostmask(self.justchanfoo) + self.users.setUser('justchanfoo', justchanfoo) + antichanfoo = ircdb.IrcUser() + antichanfoo.addCapability(self.antichancap) + antichanfoo.addHostmask(self.antichanfoo) + self.users.setUser('antichanfoo', antichanfoo) + channel = ircdb.IrcChannel() + self.channels.setChannel(self.channel, channel) + + def tearDown(self): + os.remove(self.filename) + + def checkCapability(self, hostmask, capability): + return ircdb.checkCapability(hostmask, capability, + self.users, self.channels) + + def testOwner(self): + self.failUnless(self.checkCapability(self.owner, self.cap)) + self.failIf(self.checkCapability(self.owner, self.anticap)) + self.failUnless(self.checkCapability(self.owner, self.chancap)) + self.failIf(self.checkCapability(self.owner, self.antichancap)) + self.channels.setChannel(self.channel, self.channelanticap) + self.failUnless(self.checkCapability(self.owner, self.cap)) + self.failIf(self.checkCapability(self.owner, self.anticap)) + + def testNothingAgainstChannel(self): + self.channels.setChannel(self.channel, self.channelnothing) + self.assertEqual(self.checkCapability(self.nothing, self.chancap), + self.channelnothing.defaultAllow) + self.channelnothing.defaultAllow = not self.channelnothing.defaultAllow + self.channels.setChannel(self.channel, self.channelnothing) + self.assertEqual(self.checkCapability(self.nothing, self.chancap), + self.channelnothing.defaultAllow) + self.channels.setChannel(self.channel, self.channelcap) + self.failUnless(self.checkCapability(self.nothing, self.chancap)) + self.failIf(self.checkCapability(self.nothing, self.antichancap)) + self.channels.setChannel(self.channel, self.channelanticap) + self.failIf(self.checkCapability(self.nothing, self.chancap)) + self.failUnless(self.checkCapability(self.nothing, self.antichancap)) + + def testNothing(self): + self.failIf(self.checkCapability(self.nothing, self.cap)) + self.failIf(self.checkCapability(self.nothing, self.anticap)) + + def testJustFoo(self): + self.failUnless(self.checkCapability(self.justfoo, self.cap)) + self.failIf(self.checkCapability(self.justfoo, self.anticap)) + + def testAntiFoo(self): + self.failUnless(self.checkCapability(self.antifoo, self.anticap)) + self.failIf(self.checkCapability(self.antifoo, self.cap)) + + def testJustChanFoo(self): + self.channels.setChannel(self.channel, self.channelnothing) + self.failUnless(self.checkCapability(self.justchanfoo, self.chancap)) + self.failIf(self.checkCapability(self.justchanfoo, self.antichancap)) + self.channelnothing.defaultAllow = not self.channelnothing.defaultAllow + self.failUnless(self.checkCapability(self.justchanfoo, self.chancap)) + self.failIf(self.checkCapability(self.justchanfoo, self.antichancap)) + self.channels.setChannel(self.channel, self.channelanticap) + self.failUnless(self.checkCapability(self.justchanfoo, self.chancap)) + self.failIf(self.checkCapability(self.justchanfoo, self.antichancap)) + + def testAntiChanFoo(self): + self.channels.setChannel(self.channel, self.channelnothing) + self.failIf(self.checkCapability(self.antichanfoo, self.chancap)) + self.failUnless(self.checkCapability(self.antichanfoo, + self.antichancap)) diff --git a/test/test_irclib.py b/test/test_irclib.py new file mode 100644 index 000000000..b9d693c14 --- /dev/null +++ b/test/test_irclib.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from test import * + +import copy + +import conf +import irclib +import ircmsgs + +class IrcMsgQueueTestCase(unittest.TestCase): + mode = ircmsgs.op('#foo', 'jemfinch') + msg = ircmsgs.privmsg('#foo', 'hey, you') + msgs = [ircmsgs.privmsg('#foo', str(i)) for i in range(10)] + kick = ircmsgs.kick('#foo', 'PeterB') + pong = ircmsgs.pong('123') + ping = ircmsgs.ping('123') + notice = ircmsgs.notice('jemfinch', 'supybot here') + + def testEmpty(self): + q = irclib.IrcMsgQueue() + self.failIf(q) + + def testEnqueueDequeue(self): + q = irclib.IrcMsgQueue() + q.enqueue(self.msg) + self.failUnless(q) + self.assertEqual(self.msg, q.dequeue()) + self.failIf(q) + q.enqueue(self.msg) + q.enqueue(self.notice) + self.assertEqual(self.msg, q.dequeue()) + self.assertEqual(self.notice, q.dequeue()) + for msg in self.msgs: + q.enqueue(msg) + for msg in self.msgs: + self.assertEqual(msg, q.dequeue()) + + def testPrioritizing(self): + q = irclib.IrcMsgQueue() + q.enqueue(self.msg) + q.enqueue(self.mode) + self.assertEqual(self.mode, q.dequeue()) + self.assertEqual(self.msg, q.dequeue()) + q.enqueue(self.msg) + q.enqueue(self.kick) + self.assertEqual(self.kick, q.dequeue()) + q.enqueue(self.ping) + q.enqueue(self.msg) + self.assertEqual(self.msg, q.dequeue()) + self.assertEqual(self.ping, q.dequeue()) + q.enqueue(self.ping) + q.enqueue(self.msgs[0]) + q.enqueue(self.kick) + q.enqueue(self.msgs[1]) + q.enqueue(self.mode) + self.assertEqual(self.kick, q.dequeue()) + self.assertEqual(self.mode, q.dequeue()) + self.assertEqual(self.msgs[0], q.dequeue()) + self.assertEqual(self.msgs[1], q.dequeue()) + self.assertEqual(self.ping, q.dequeue()) + + def testNoIdenticals(self): + q = irclib.IrcMsgQueue() + q.enqueue(self.msg) + q.enqueue(self.msg) + self.assertEqual(self.msg, q.dequeue()) + self.failIf(q) + + +class IrcStateTestCase(unittest.TestCase): + class FakeIrc: + nick = 'nick' + irc = FakeIrc() + def testHistory(self): + oldconfmaxhistory = conf.maxHistory + conf.maxHistory = 10 + state = irclib.IrcState() + for msg in msgs: + try: + state.addMsg(self.irc, msg) + except Exception: + pass + self.failIf(len(state.history) > conf.maxHistory) + self.assertEqual(len(state.history), conf.maxHistory) + self.assertEqual(list(state.history), msgs[len(msgs)-conf.maxHistory:]) + conf.maxHistory = oldconfmaxhistory + + """ + def testChannels(self): + channel = + state = irclib.IrcState() + state.addMsg(self.irc, ircmsgs.join('#foo')) + """ + +class IrcTestCase(unittest.TestCase): + irc = irclib.Irc('nick') + def testPingResponse(self): + self.irc.feedMsg(ircmsgs.ping('123')) + self.assertEqual(ircmsgs.pong('123'), self.irc.takeMsg()) + + def test433Response(self): + self.irc.feedMsg(ircmsgs.IrcMsg('433 * %s :Nickname already in use.' %\ + self.irc.nick)) + msg = self.irc.takeMsg() + self.failUnless(msg.command == 'NICK' and msg.args[0] != self.irc.nick) + + def testReset(self): + for msg in msgs: + try: + self.irc.feedMsg(msg) + except: + pass + self.irc.reset() + self.failIf(self.irc.fastqueue) + self.failIf(self.irc.state.history) + self.failIf(self.irc.state.channels) + self.failIf(self.irc.outstandingPongs) + self.assertEqual(self.irc._nickmods, conf.nickmods) + + def testHistory(self): + self.irc.reset() + msg1 = ircmsgs.IrcMsg('PRIVMSG #linux :foo bar baz!') + self.irc.feedMsg(msg1) + self.assertEqual(self.irc.state.history[0], msg1) + msg2 = ircmsgs.IrcMsg('JOIN #sourcereview') + self.irc.feedMsg(msg2) + self.assertEqual(list(self.irc.state.history), [msg1, msg2]) + + +class IrcCallbackTestCase(unittest.TestCase): + class FakeIrc: + pass + irc = FakeIrc() + def testName(self): + class UnnamedIrcCallback(irclib.IrcCallback): + pass + unnamed = UnnamedIrcCallback() + + class NamedIrcCallback(irclib.IrcCallback): + myName = 'foobar' + def name(self): + return self.myName + named = NamedIrcCallback() + self.assertEqual(unnamed.name(), unnamed.__class__.__name__) + self.assertEqual(named.name(), named.myName) + + def testDoCommand(self): + def makeCommand(msg): + return 'do' + msg.command.capitalize() + class DoCommandCatcher(irclib.IrcCallback): + def __init__(self): + self.L = [] + def __getattr__(self, attr): + self.L.append(attr) + return lambda *args: None + doCommandCatcher = DoCommandCatcher() + for msg in msgs: + doCommandCatcher(self.irc, msg) + commands = map(makeCommand, msgs) + self.assertEqual(doCommandCatcher.L, + list(flatten(zip(commands, commands)))) + + def testFirstCommands(self): + oldconfthrottle = conf.throttleTime + conf.throttleTime = 0 + nick = 'nick' + user = 'user any user' + password = 'password' + expected = [ircmsgs.nick(nick), ircmsgs.user(nick, user)] + irc = irclib.Irc(nick, user) + msgs = [irc.takeMsg()] + while msgs[-1] != None: + msgs.append(irc.takeMsg()) + msgs.pop() + self.assertEqual(msgs, expected) + irc = irclib.Irc(nick, user, password=password) + msgs = [irc.takeMsg()] + while msgs[-1] != None: + msgs.append(irc.takeMsg()) + msgs.pop() + expected.insert(0, ircmsgs.password(password)) + self.assertEqual(msgs, expected) + conf.throttleTime = oldconfthrottle diff --git a/test/test_ircmsgs.py b/test/test_ircmsgs.py new file mode 100644 index 000000000..6f4177e07 --- /dev/null +++ b/test/test_ircmsgs.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from test import * + +import copy +import pickle + +import ircmsgs +import ircutils + + +class IrcMsgTestCase(unittest.TestCase): + def testLen(self): + for msg in msgs: + if msg.prefix: + strmsg = str(msg) + self.failIf(len(msg) != len(strmsg) and \ + strmsg.replace(':', '') == strmsg) + + def testRepr(self): + from ircmsgs import IrcMsg + for msg in msgs: + self.assertEqual(msg, eval(repr(msg))) + + def testStr(self): + for (rawmsg, msg) in zip(rawmsgs, msgs): + strmsg = str(msg).strip() + self.failIf(rawmsg != strmsg and \ + strmsg.replace(':', '') == strmsg) + + def testEq(self): + for msg in msgs: + self.assertEqual(msg, msg) + + def testNe(self): + for msg in msgs: + self.failIf(msg != msg) + + def testImmutability(self): + s = 'something else' + t = ('foo', 'bar', 'baz') + for msg in msgs: + self.assertRaises(AttributeError, setattr, msg, 'prefix', s) + self.assertRaises(AttributeError, setattr, msg, 'nick', s) + self.assertRaises(AttributeError, setattr, msg, 'user', s) + self.assertRaises(AttributeError, setattr, msg, 'host', s) + self.assertRaises(AttributeError, setattr, msg, 'command', s) + self.assertRaises(AttributeError, setattr, msg, 'args', t) + if msg.args: + def setArgs(msg): + msg.args[0] = s + self.assertRaises(TypeError, setArgs, msg) + + def testInit(self): + for msg in msgs: + self.assertEqual(msg, ircmsgs.IrcMsg(prefix=msg.prefix, + command=msg.command, + args=msg.args)) + self.assertEqual(msg, ircmsgs.IrcMsg(msg=msg)) + self.assertRaises(ValueError, + ircmsgs.IrcMsg, + args=('foo', 'bar'), + prefix='foo!bar@baz') + + def testPickleCopy(self): + for msg in msgs: + self.assertEqual(msg, pickle.loads(pickle.dumps(msg))) + self.assertEqual(msg, copy.copy(msg)) + +class FunctionsTestCase(unittest.TestCase): + def testIsAction(self): + L = [':jemfinch!~jfincher@ts26-2.homenet.ohio-state.edu PRIVMSG' + ' #sourcereview :ACTION does something', + ':supybot!~supybot@underthemain.net PRIVMSG #sourcereview ' + ':ACTION beats angryman senseless with a Unix manual (#2)', + ':supybot!~supybot@underthemain.net PRIVMSG #sourcereview ' + ':ACTION beats ang senseless with a 50lb Unix manual (#2)', + ':supybot!~supybot@underthemain.net PRIVMSG #sourcereview ' + ':ACTION resizes angryman\'s terminal to 40x24 (#16)'] + msgs = map(ircmsgs.IrcMsg, L) + for msg in msgs: + self.failUnless(ircmsgs.isAction(msg)) + + def testUnAction(self): + s = 'foo bar baz' + msg = ircmsgs.action('#foo', s) + self.assertEqual(ircmsgs.unAction(msg), s) + + def testBan(self): + channel = '#osu' + ban = '*!*@*.edu' + exception = '*!*@*ohio-state.edu' + noException = ircmsgs.ban(channel, ban) + self.assertEqual(ircutils.separateModes(noException.args[1:]), + [('+b', ban)]) + withException = ircmsgs.ban(channel, ban, exception) + self.assertEqual(ircutils.separateModes(withException.args[1:]), + [('+b', ban), ('+e', exception)]) + + def testBans(self): + channel = '#osu' + bans = ['*!*@*', 'jemfinch!*@*'] + exceptions = ['*!*@*ohio-state.edu'] + noException = ircmsgs.bans(channel, bans) + self.assertEqual(ircutils.separateModes(noException.args[1:]), + [('+b', bans[0]), ('+b', bans[1])]) + withExceptions = ircmsgs.bans(channel, bans, exceptions) + self.assertEqual(ircutils.separateModes(withExceptions.args[1:]), + [('+b', bans[0]), ('+b', bans[1]), + ('+e', exceptions[0])]) + + def testJoin(self): + channel = '#osu' + key = 'michiganSucks' + self.assertEqual(ircmsgs.join(channel).args, ('#osu',)) + self.assertEqual(ircmsgs.join(channel, key).args, + ('#osu', 'michiganSucks')) + + def testJoins(self): + channels = ['#osu', '#umich'] + keys = ['michiganSucks', 'osuSucks'] + self.assertEqual(ircmsgs.joins(channels).args, ('#osu,#umich',)) + self.assertEqual(ircmsgs.joins(channels, keys).args, + ('#osu,#umich', 'michiganSucks,osuSucks')) + keys.pop() + self.assertEqual(ircmsgs.joins(channels, keys).args, + ('#osu,#umich', 'michiganSucks')) diff --git a/test/test_ircutils.py b/test/test_ircutils.py new file mode 100644 index 000000000..414d6136a --- /dev/null +++ b/test/test_ircutils.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + + +from test import * + +import ircmsgs +import ircutils + +class FunctionsTestCase(unittest.TestCase): + hostmask = 'foo!bar@baz' + def testIsUserHostmask(self): + self.failUnless(ircutils.isUserHostmask(self.hostmask)) + self.failUnless(ircutils.isUserHostmask('a!b@c')) + self.failIf(ircutils.isUserHostmask('!bar@baz')) + self.failIf(ircutils.isUserHostmask('!@baz')) + self.failIf(ircutils.isUserHostmask('!bar@')) + self.failIf(ircutils.isUserHostmask('!@')) + self.failIf(ircutils.isUserHostmask('foo!@baz')) + self.failIf(ircutils.isUserHostmask('foo!bar@')) + self.failIf(ircutils.isUserHostmask('')) + self.failIf(ircutils.isUserHostmask('!')) + self.failIf(ircutils.isUserHostmask('@')) + self.failIf(ircutils.isUserHostmask('!bar@baz')) + + def testIsChannel(self): + self.failUnless(ircutils.isChannel('#')) + self.failUnless(ircutils.isChannel('&')) + self.failUnless(ircutils.isChannel('+')) + self.failUnless(ircutils.isChannel('!')) + self.failUnless(ircutils.isChannel('#foo')) + self.failUnless(ircutils.isChannel('&foo')) + self.failUnless(ircutils.isChannel('+foo')) + self.failUnless(ircutils.isChannel('!foo')) + self.failIf(ircutils.isChannel('#foo bar')) + self.failIf(ircutils.isChannel('#foo,bar')) + self.failIf(ircutils.isChannel('#foobar\x07')) + self.failIf(ircutils.isChannel('foo')) + self.failIf(ircutils.isChannel('')) + + def testBold(self): + s = ircutils.bold('foo') + self.assertEqual(s[0], '\x02') + self.assertEqual(s[-1], '\x02') + + def testSafeArgument(self): + s = 'I have been running for 9 seconds' + bolds = ircutils.bold(s) + self.assertEqual(s, ircutils.safeArgument(s)) + self.assertEqual(bolds, ircutils.safeArgument(bolds)) + + def testIsIP(self): + self.failIf(ircutils.isIP('a.b.c')) + self.failIf(ircutils.isIP('256.0.0.0')) + self.failUnless(ircutils.isIP('127.1')) + self.failUnless(ircutils.isIP('0.0.0.0')) + self.failUnless(ircutils.isIP('100.100.100.100')) + self.failUnless(ircutils.isIP('255.255.255.255')) + + def testIsNick(self): + self.failUnless(ircutils.isNick('jemfinch')) + self.failUnless(ircutils.isNick('jemfinch0')) + self.failUnless(ircutils.isNick('[0]')) + self.failUnless(ircutils.isNick('{jemfinch}')) + self.failUnless(ircutils.isNick('\\```')) + self.failIf(ircutils.isNick('')) + self.failIf(ircutils.isNick('8foo')) + self.failIf(ircutils.isNick('10')) + + def banmask(self): + for msg in msgs: + if ircutils.isUserHostmask(msg.prefix): + self.failUnless(ircutils.hostmaskPatternEqual + (ircutils.banmask(msg.prefix), + msg.prefix)) + + def testSeparateModes(self): + self.assertEqual(ircutils.separateModes(['+ooo', 'x', 'y', 'z']), + [('+o', 'x'), ('+o', 'y'), ('+o', 'z')]) + self.assertEqual(ircutils.separateModes(['+o-o', 'x', 'y']), + [('+o', 'x'), ('-o', 'y')]) + self.assertEqual(ircutils.separateModes(['+s-o', 'x']), + [('+s', None), ('-o', 'x')]) + self.assertEqual(ircutils.separateModes(['+sntl', '100']), + [('+s', None),('+n', None),('+t', None),('+l', '100')]) + + def testToLower(self): + self.assertEqual('jemfinch', ircutils.toLower('jemfinch')) + self.assertEqual('{}|^', ircutils.toLower('[]\\~')) + + def testNick(self): + nicks = ['jemfinch', 'jemfinch\\[]~'] + for nick in nicks: + self.assertEqual(str(ircutils.nick(nick)), str(nick)) + self.assertEqual(ircutils.nick(nick), nick) + self.assertEqual(ircutils.nick(nick), ircutils.toLower(nick)) + + def testReplyTo(self): + prefix = 'foo!bar@baz' + channel = ircmsgs.privmsg('#foo', 'bar baz', prefix=prefix) + private = ircmsgs.privmsg('jemfinch', 'bar baz', prefix=prefix) + self.assertEqual(ircutils.replyTo(channel), channel.args[0]) + self.assertEqual(ircutils.replyTo(private), private.nick) + + def testJoinModes(self): + plusE = ('+e', '*!*@*ohio-state.edu') + plusB = ('+b', '*!*@*umich.edu') + minusL = ('-l', None) + modes = [plusB, plusE, minusL] + self.assertEqual(ircutils.joinModes(modes), + ['+be-l', plusB[1], plusE[1]]) +class IrcDictTestCase(unittest.TestCase): + def test(self): + d = ircutils.IrcDict() + d['#FOO'] = 'bar' + self.assertEqual(d['#FOO'], 'bar') + self.assertEqual(d['#Foo'], 'bar') + self.assertEqual(d['#foo'], 'bar') + del d['#fOO'] + d['jemfinch{}'] = 'bar' + self.assertEqual(d['jemfinch{}'], 'bar') + self.assertEqual(d['jemfinch[]'], 'bar') + self.assertEqual(d['JEMFINCH[]'], 'bar') + + def testContains(self): + d = ircutils.IrcDict() + d['#FOO'] = None + self.failUnless('#foo' in d) + d['#fOOBAR[]'] = None + self.failUnless('#foobar{}' in d) + + def testGetSetItem(self): + d = ircutils.IrcDict() + d['#FOO'] = 12 + self.assertEqual(12, d['#foo']) + d['#fOOBAR[]'] = 'blah' + self.assertEqual('blah', d['#foobar{}']) diff --git a/test/test_privmsgs.py b/test/test_privmsgs.py new file mode 100644 index 000000000..1638ca126 --- /dev/null +++ b/test/test_privmsgs.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from test import * + +import ircmsgs +import privmsgs +import callbacks + +class FunctionsTest(unittest.TestCase): + def testGetChannel(self): + channel = '#foo' + msg = ircmsgs.privmsg(channel, 'foo bar baz') + args = msg.args[1].split() + originalArgs = args[:] + self.assertEqual(privmsgs.getChannel(msg, args), channel) + self.assertEqual(args, originalArgs) + msg = ircmsgs.privmsg('nick', '%s bar baz' % channel) + args = msg.args[1].split() + originalArgs = args[:] + self.assertEqual(privmsgs.getChannel(msg, args), channel) + self.assertEqual(args, originalArgs[1:]) + + def testGetArgs(self): + args = ['foo', 'bar', 'baz'] + self.assertEqual(privmsgs.getArgs(args), ' '.join(args)) + self.assertEqual(privmsgs.getArgs(args, needed=2), + [args[0], ' '.join(args[1:])]) + self.assertEqual(privmsgs.getArgs(args, needed=3), args) + self.assertRaises(callbacks.ArgumentError, + privmsgs.getArgs, args, needed=4) + self.assertEqual(privmsgs.getArgs(args, needed=3, optional=1), + args + ['']) + self.assertEqual(privmsgs.getArgs(args, needed=0, optional=1), + ' '.join(args)) diff --git a/test/test_utils.py b/test/test_utils.py new file mode 100644 index 000000000..d074694fa --- /dev/null +++ b/test/test_utils.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from test import * + +import utils + + +class UtilsTest(unittest.TestCase): + def testTimeElapsed(self): + self.assertRaises(ValueError, utils.timeElapsed, 0, 0, seconds=False) + then = 0 + now = 0 + for now, expected in [(0, '0 seconds'), + (1, '1 second'), + (60, '1 minute and 0 seconds'), + (61, '1 minute and 1 second'), + (62, '1 minute and 2 seconds'), + (122, '2 minutes and 2 seconds'), + (3722, '1 hour, 2 minutes and 2 seconds'), + (7322, '2 hours, 2 minutes and 2 seconds')]: + self.assertEqual(utils.timeElapsed(now, then), expected) + + def testEachSubstring(self): + s = 'foobar' + L = ['f', 'fo', 'foo', 'foob', 'fooba', 'foobar'] + self.assertEqual(list(utils.eachSubstring(s)), L) + + def testDistance(self): + self.assertEqual(utils.distance('', ''), 0) + self.assertEqual(utils.distance('a', 'b'), 1) + self.assertEqual(utils.distance('a', 'a'), 0) + self.assertEqual(utils.distance('foobar', 'jemfinch'), 8) + self.assertEqual(utils.distance('a', 'ab'), 1) + self.assertEqual(utils.distance('foo', ''), 3) + self.assertEqual(utils.distance('', 'foo'), 3) + self.assertEqual(utils.distance('appel', 'nappe'), 2) + self.assertEqual(utils.distance('nappe', 'appel'), 2) + + def testAbbrev(self): + L = ['abc', 'bcd', 'bbe', 'foo', 'fool'] + d = utils.abbrev(L) + def getItem(s): + return d[s] + self.assertRaises(KeyError, getItem, 'f') + self.assertRaises(KeyError, getItem, 'fo') + self.assertRaises(KeyError, getItem, 'b') + self.assertEqual(d['bb'], 'bbe') + self.assertEqual(d['bc'], 'bcd') + self.assertEqual(d['a'], 'abc') + self.assertEqual(d['ab'], 'abc') + self.assertEqual(d['fool'], 'fool') + self.assertEqual(d['foo'], 'foo') + + def testSoundex(self): + L = [('Euler', 'E460'), + ('Ellery', 'E460'), + ('Gauss', 'G200'), + ('Ghosh', 'G200'), + ('Hilbert', 'H416'), + ('Heilbronn', 'H416'), + ('Knuth', 'K530'), + ('Kant', 'K530'), + ('Lloyd', 'L300'), + ('Ladd', 'L300'), + ('Lukasiewicz', 'L222'), + ('Lissajous', 'L222')] + for (name, key) in L: + soundex = utils.soundex(name) + self.assertEqual(soundex, key, + '%s was %s, not %s' % (name, soundex, key)) + + def testDQRepr(self): + L = [('foo', '"foo"'), + ('foo\'bar', '"foo\'bar"'), + ('foo"bar', '"foo\\"bar"'), + ('"', '"\\""'), + ('', '""'), + ('\x00', '"\\x00"')] + for (s, r) in L: + self.assertEqual(r, utils.dqrepr(s)) + self.assertEqual(s, eval(utils.dqrepr(s))) + + def testPerlReToPythonRe(self): + r = utils.perlReToPythonRe('m/foo/') + self.failUnless(r.search('foo')) + r = utils.perlReToPythonRe('/foo/') + self.failUnless(r.search('foo')) + r = utils.perlReToPythonRe('m/\\//') + self.failUnless(r.search('/')) + + def testPerlReToReplacer(self): + f = utils.perlReToReplacer('s/foo/bar/') + self.assertEqual(f('foobarbaz'), 'barbarbaz') + f = utils.perlReToReplacer('s/fool/bar/') + self.assertEqual(f('foobarbaz'), 'foobarbaz') + f = utils.perlReToReplacer('s/foo//') + self.assertEqual(f('foobarbaz'), 'barbaz') + f = utils.perlReToReplacer('s/ba//') + self.assertEqual(f('foobarbaz'), 'foorbaz') + f = utils.perlReToReplacer('s/ba//g') + self.assertEqual(f('foobarbaz'), 'foorz') + f = utils.perlReToReplacer('s/ba\\///g') + self.assertEqual(f('fooba/rba/z'), 'foorz') +