| @@ -514,8 +514,7 @@ def encrypt(key, plaintext): | |||
| def decrypt(key, cyphertext): | |||
| """Decrypt the result of encrypt() using the original key, or raise | |||
| IncorrectKeyError(). If the cyphertext is malformed, raise | |||
| BadCyphertextError().""" | |||
| DecryptionError().""" | |||
| cypher = Blowfish(key) | |||
| try: | |||
| @@ -12,7 +12,7 @@ class Command(BaseCommand): | |||
| def process(self, data): | |||
| if not data.args: | |||
| self.connection.reply(data, "What do you want me to calculate?") | |||
| self.connection.reply(data, "what do you want me to calculate?") | |||
| return | |||
| query = ' '.join(data.args) | |||
| @@ -29,7 +29,7 @@ class Command(BaseCommand): | |||
| # Create a dummy message to test which commands pick up the user's | |||
| # input: | |||
| dummy = Data("PRIVMSG #fake-channel :Fake messsage!".split()) | |||
| dummy = Data(":foo!bar@example.com PRIVMSG #channel :msg!".split()) | |||
| dummy.command = command.lower() | |||
| dummy.is_command = True | |||
| @@ -0,0 +1,96 @@ | |||
| # -*- coding: utf-8 -*- | |||
| """ | |||
| EarwigBot's Unit Test Support | |||
| This module provides some support code for unit tests. | |||
| Importing this module will "fix" your path so that EarwigBot code from bot/ can | |||
| be imported normally. | |||
| CommandTestCase is a subclass of unittest.TestCase that provides setUp() for | |||
| creating a fake connection and some other helpful methods. It uses | |||
| FakeConnection, a subclass of classes.Connection, but with an internal string | |||
| instead of a socket for data. | |||
| """ | |||
| from os import path | |||
| import re | |||
| import sys | |||
| from unittest import TestCase | |||
| root_dir = path.split(path.dirname(path.abspath(__file__)))[0] | |||
| code_dir = path.join(root_dir, "bot") | |||
| sys.path.insert(0, code_dir) | |||
| from classes import Connection, Data | |||
| class CommandTestCase(TestCase): | |||
| re_sender = re.compile(":(.*?)!(.*?)@(.*?)\Z") | |||
| def setUp(self, command): | |||
| self.connection = FakeConnection() | |||
| self.connection.connect() | |||
| self.command = command(self.connection) | |||
| def get_single(self): | |||
| data = self.connection.get().split("\n") | |||
| line = data.pop(0) | |||
| for remaining in data[1:]: | |||
| self.connection.send(remaining) | |||
| return line | |||
| def assertSent(self, msg): | |||
| line = self.get_single() | |||
| self.assertEqual(line, msg) | |||
| def assertSentIn(self, msgs): | |||
| line = self.get_single() | |||
| self.assertIn(line, msgs) | |||
| def assertSaid(self, msg): | |||
| self.assertSent("PRIVMSG #channel :{0}".format(msg)) | |||
| def assertSaidIn(self, msgs): | |||
| msgs = ["PRIVMSG #channel :{0}".format(msg) for msg in msgs] | |||
| self.assertSentIn(msgs) | |||
| def assertReply(self, msg): | |||
| self.assertSaid("\x02Foo\x0F: {0}".format(msg)) | |||
| def assertReplyIn(self, msgs): | |||
| msgs = ["\x02Foo\x0F: {0}".format(msg) for msg in msgs] | |||
| self.assertSaidIn(msgs) | |||
| def maker(self, line, chan, msg=None): | |||
| data = Data(line) | |||
| data.nick, data.ident, data.host = self.re_sender.findall(line[0])[0] | |||
| if msg is not None: | |||
| data.msg = msg | |||
| data.chan = chan | |||
| data.parse_args() | |||
| return data | |||
| def make_msg(self, command, *args): | |||
| line = ":Foo!bar@example.com PRIVMSG #channel :!{0}".format(command) | |||
| line = line.strip().split() | |||
| line.extend(args) | |||
| return self.maker(line, line[2], " ".join(line[3:])[1:]) | |||
| def make_join(self): | |||
| line = ":Foo!bar@example.com JOIN :#channel".strip().split() | |||
| return self.maker(line, line[2][1:]) | |||
| class FakeConnection(Connection): | |||
| def connect(self): | |||
| self._buffer = "" | |||
| def close(self): | |||
| pass | |||
| def get(self, size=4096): | |||
| data, self._buffer = self._buffer, "" | |||
| return data | |||
| def send(self, msg): | |||
| self._buffer += msg + "\n" | |||
| @@ -0,0 +1,77 @@ | |||
| # -*- coding: utf-8 -*- | |||
| import unittest | |||
| import random | |||
| import string | |||
| import support | |||
| import blowfish | |||
| class TestBlowfish(unittest.TestCase): | |||
| def test_key_sizes(self): | |||
| b = blowfish.Blowfish | |||
| e = blowfish.KeyLengthError | |||
| self.assertRaisesRegexp(e, "no key given", b, None) | |||
| self.assertRaisesRegexp(e, "no key given", b, "") | |||
| self.assertRaisesRegexp(e, "at least", b, " " * 3) | |||
| self.assertRaisesRegexp(e, "at least", b, "1234567") | |||
| self.assertRaisesRegexp(e, "less than", b, " " * 57) | |||
| self.assertRaisesRegexp(e, "less than", b, "x" * 60) | |||
| self.assertRaisesRegexp(e, "less than", b, "1" * 128) | |||
| b("These keys should be valid!") | |||
| b("'!\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'") | |||
| b(" " * 8) | |||
| b(" " * 56) | |||
| def test_symmetry(self): | |||
| def _test_symmetry(): | |||
| key_length = random.randint(8, 56) | |||
| msg_length = random.randint(0, 4096) | |||
| key = "".join([random.choice(chars) for i in xrange(key_length)]) | |||
| msg = "".join([random.choice(chars) for i in xrange(msg_length)]) | |||
| enc = blowfish.encrypt(key, msg) | |||
| dec = blowfish.decrypt(key, enc) | |||
| self.assertEqual(dec, msg) | |||
| chars = string.letters + string.digits + string.punctuation | |||
| for i in xrange(8): | |||
| _test_symmetry() | |||
| def test_encryption(self): | |||
| tests = [ | |||
| ("example_key", "Hello, I'm a message!", "8411a21574431176cdff9a549d27962c616014a9fe2a1fe3b0c7a823e8a1e635"), | |||
| ("another random key", "Another random message! :(", "2cdcdf4e53145897ed9d4cc2433aa4bf59b087b14d0ac76a13eff12dec00e60c40857109da3c7bc4"), | |||
| ("HEY LET'S TRY |°|_J|\|C7|_J/-\\710|\|", "Yes, that was my fail attempt at 1337SP33K >_>", "d4901c7c0956da3b9507cd81cd3c880d7cda25ec6c5336deb9280ce67c099eeddf7c7e052f3a946afbd92c32ae0ab8dbdd875bc5a3f0d686") | |||
| ] | |||
| for test in tests: | |||
| self.assertEquals(blowfish.encrypt(test[0], test[1]), test[2]) | |||
| def test_decryption(self): | |||
| tests = [ | |||
| ("blah blah blah", "ab35274c66bb8b3b03c9bd26ab477f3de06857e1d369ad35", "Blah, blah, blah!"), | |||
| ("random key", "eb2fe950c5c12bca9534ffdd27631f33d3e4bcae53a634b4aaa09f9fe14c4386", "Random message as well!"), | |||
| ("Okay, now I'm just desperate", "0da74e1cec41e8323da93d0c05bcf3919084130cef93021991da174fd97f8e1c9b125ed5263b41a8", "Unit testing is SO FUN ISN'T IT.") | |||
| ] | |||
| for test in tests: | |||
| self.assertEquals(blowfish.decrypt(test[0], test[1]), test[2]) | |||
| def test_decryption_exceptions(self): | |||
| d = blowfish.decrypt | |||
| e = blowfish.BlowfishError | |||
| e1 = "could not be decoded" | |||
| e2 = "cannot be broken into 8-byte blocks" | |||
| e3 = "key is incorrect" | |||
| self.assertRaisesRegexp(e, e1, d, "some_key", "arr!") | |||
| self.assertRaisesRegexp(e, e2, d, "some_key", "abcd") | |||
| self.assertRaisesRegexp(e, e3, d, "some_key", "abcdabcdabcdabcd") | |||
| if __name__ == "__main__": | |||
| unittest.main(verbosity=2) | |||
| @@ -0,0 +1,39 @@ | |||
| # -*- coding: utf-8 -*- | |||
| import unittest | |||
| import support | |||
| from commands.calc import Command | |||
| class TestCalc(support.CommandTestCase): | |||
| def setUp(self): | |||
| super(TestCalc, self).setUp(Command) | |||
| def test_check(self): | |||
| self.assertFalse(self.command.check(self.make_msg("bloop"))) | |||
| self.assertFalse(self.command.check(self.make_join())) | |||
| self.assertTrue(self.command.check(self.make_msg("calc"))) | |||
| self.assertTrue(self.command.check(self.make_msg("CALC", "foo"))) | |||
| def test_ignore_empty(self): | |||
| self.command.process(self.make_msg("calc")) | |||
| self.assertReply("what do you want me to calculate?") | |||
| def test_maths(self): | |||
| tests = [ | |||
| ("2 + 2", "2 + 2 = 4"), | |||
| ("13 * 5", "13 * 5 = 65"), | |||
| ("80 / 42", "80 / 42 = 40/21 (approx. 1.9047619047619047)"), | |||
| ("2/0", "2/0 = undef"), | |||
| ("π", "π = 3.141592653589793238"), | |||
| ] | |||
| for test in tests: | |||
| q = test[0].strip().split() | |||
| self.command.process(self.make_msg("calc", *q)) | |||
| self.assertReply(test[1]) | |||
| if __name__ == "__main__": | |||
| unittest.main(verbosity=2) | |||
| @@ -0,0 +1,29 @@ | |||
| # -*- coding: utf-8 -*- | |||
| import unittest | |||
| import support | |||
| from commands.test import Command | |||
| class TestTest(support.CommandTestCase): | |||
| def setUp(self): | |||
| super(TestTest, self).setUp(Command) | |||
| def test_check(self): | |||
| self.assertFalse(self.command.check(self.make_msg("bloop"))) | |||
| self.assertFalse(self.command.check(self.make_join())) | |||
| self.assertTrue(self.command.check(self.make_msg("test"))) | |||
| self.assertTrue(self.command.check(self.make_msg("TEST", "foo"))) | |||
| def test_process(self): | |||
| def _test(): | |||
| self.command.process(self.make_msg("test")) | |||
| self.assertSaidIn(["Hey \x02Foo\x0F!", "'sup \x02Foo\x0F?"]) | |||
| for i in xrange(64): | |||
| _test() | |||
| if __name__ == "__main__": | |||
| unittest.main(verbosity=2) | |||