244 lines
7.7 KiB
Python
244 lines
7.7 KiB
Python
"""Unit tests for croxy.py.
|
|
|
|
Usage: python3 test.py
|
|
"""
|
|
|
|
import unittest
|
|
import io
|
|
import sys
|
|
|
|
import croxy
|
|
|
|
|
|
class TestClientServer(unittest.TestCase):
|
|
"""Test the ClientServer class which extends socketserver.TCPServer.
|
|
"""
|
|
def test_init(self):
|
|
addr = ("127.0.0.1", 1234)
|
|
cs = croxy.ClientServer(addr, None, 'localhost', 6697, 's3cret')
|
|
self.assertTrue(cs)
|
|
cs.socket.close()
|
|
|
|
def test_handle_client_line(self):
|
|
|
|
old = suppress_stdout()
|
|
|
|
msg = "This is a test"
|
|
line = "PRIVMSG #test :" + msg
|
|
password = "secret"
|
|
remote_f = io.BytesIO()
|
|
croxy.handle_client_line(line, password, remote_f)
|
|
|
|
output = remote_f.getvalue()
|
|
ciphertext = output.decode('utf8').split(":")[1]
|
|
clear = croxy.croxy_decrypt(ciphertext, password)
|
|
self.assertEqual(clear, msg)
|
|
|
|
restore_stdout(old)
|
|
|
|
|
|
class TestServerWorker(unittest.TestCase):
|
|
"""Test the ServerWorker class which is a thread.
|
|
"""
|
|
|
|
def test_handle_server_line(self):
|
|
|
|
old = suppress_stdout()
|
|
|
|
msg = "Test"
|
|
password = "secret"
|
|
ciphertext = croxy.croxy_encrypt(msg, password)
|
|
line = ":gk3!~gk3@example.net PRIVMSG #secure :" + ciphertext
|
|
|
|
local_f = io.BytesIO()
|
|
croxy.handle_server_line(line, password, local_f)
|
|
|
|
output = local_f.getvalue()
|
|
clear = output.decode('utf8').split(":")[2].strip()
|
|
self.assertEqual(clear, msg)
|
|
|
|
restore_stdout(old)
|
|
|
|
def test_handle_not_encrypted(self):
|
|
"""Make sure not encrypted messages get clearly marked.
|
|
"""
|
|
|
|
old = suppress_stdout()
|
|
|
|
password = "test"
|
|
line = ":gk!~gk@example.net PRIVMSG #sectest :test"
|
|
local_f = io.BytesIO()
|
|
croxy.handle_server_line(line, password, local_f)
|
|
|
|
output = local_f.getvalue()
|
|
clear = output.decode('utf8').split(":")[2].strip()
|
|
self.assertEqual(clear, "(I) test")
|
|
|
|
restore_stdout(old)
|
|
|
|
|
|
class TestUtil(unittest.TestCase):
|
|
"""Test various utility functions.
|
|
"""
|
|
|
|
def test_mpad(self):
|
|
"""Test the mpad function which pads a string.
|
|
"""
|
|
self.assertEqual(len(croxy.mpad(b"Test", 32)), 32)
|
|
self.assertEqual(len(croxy.mpad(b"123456789", 8)), 16)
|
|
|
|
u1 = "Федерация"
|
|
self.assertEqual(len(croxy.mpad(u1.encode("utf8"), 16)), 32)
|
|
|
|
def test_decode_unicode_unchanged(self):
|
|
"""Test 'decode' returns unicode unchanged
|
|
"""
|
|
u8 = "Καλώς ήλθατε στην Ελλάδα"
|
|
self.assertEqual(croxy.decode(u8), u8)
|
|
|
|
def test_decode_utf8(self):
|
|
"""Test decode can handle utf8"""
|
|
u8 = "Καλώς ήλθατε στην Ελλάδα"
|
|
self.assertEqual(croxy.decode(u8.encode("utf8")), u8)
|
|
|
|
def test_decode_latin1(self):
|
|
"""Test decode can handle iso-8859-1 aka latin-1."""
|
|
l1 = "On s'était dit..."
|
|
self.assertEqual(croxy.decode(l1.encode("latin-1")), l1)
|
|
|
|
def test_main_no_args(self):
|
|
old_stdout = sys.stdout
|
|
sys.stdout = buf = io.StringIO()
|
|
|
|
self.assertEqual(croxy.main([]), 1)
|
|
self.assertTrue(len(buf.getvalue()) > 0)
|
|
|
|
restore_stdout(old_stdout)
|
|
|
|
def test_parse_args_default_port(self):
|
|
|
|
h1, p1 = croxy.parse_args(["localhost"])
|
|
self.assertEqual(h1, "localhost")
|
|
self.assertEqual(p1, 6697)
|
|
|
|
def test_parse_args(self):
|
|
h2, p2 = croxy.parse_args(["localhost", 7000])
|
|
self.assertEqual(h2, "localhost")
|
|
self.assertEqual(p2, 7000)
|
|
|
|
|
|
class TestParse(unittest.TestCase):
|
|
"""Test parsing lines."""
|
|
|
|
def test_parse_out(self):
|
|
prefix, body = croxy.parse_out("PRIVMSG #test :bob: How's it going?")
|
|
self.assertEqual(prefix, "PRIVMSG #test ")
|
|
self.assertEqual(body, "bob: How's it going?")
|
|
|
|
def test_parse_in_welcome(self):
|
|
line = ":barjavel.freenode.net 001 graham_king :Welcome to the freenode Internet Relay Chat Network graham_king"
|
|
prefix, command, args = croxy.parse_in(line)
|
|
self.assertEqual(prefix, "barjavel.freenode.net")
|
|
self.assertEqual(command, "001")
|
|
self.assertEqual(args, ["graham_king", "Welcome to the freenode Internet Relay Chat Network graham_king"])
|
|
|
|
def test_parse_in_privmsg(self):
|
|
line = ":rnowak!~rnowak@q.ovron.com PRIVMSG #linode :totally"
|
|
prefix, command, args = croxy.parse_in(line)
|
|
self.assertEqual(prefix, "rnowak!~rnowak@q.ovron.com")
|
|
self.assertEqual(command, "PRIVMSG")
|
|
self.assertEqual(args, ["#linode", "totally"])
|
|
|
|
def test_parse_in_andbang(self):
|
|
line = ":alan!223@irc.andbang.com PRIVMSG #ab :hello @graham"
|
|
prefix, command, args = croxy.parse_in(line)
|
|
self.assertEqual(prefix, "alan!223@irc.andbang.com")
|
|
self.assertEqual(command, "PRIVMSG")
|
|
self.assertEqual(args, ["#ab", "hello @graham"])
|
|
|
|
def test_parse_in_away(self):
|
|
line = ":hybrid7.debian.local 301 graham_king graham :Not here"
|
|
prefix, command, args = croxy.parse_in(line)
|
|
self.assertEqual(prefix, "hybrid7.debian.local")
|
|
self.assertEqual(command, "301")
|
|
self.assertEqual(args, ["graham_king", "graham", "Not here"])
|
|
|
|
def test_parse_in_list(self):
|
|
line = ":oxygen.oftc.net 322 graham_king #linode 412 :Linode Community Support | http://www.linode.com/ | Linodes in Asia-Pacific! - http://bit.ly/ooBzhV"
|
|
prefix, command, args = croxy.parse_in(line)
|
|
self.assertEqual(prefix, "oxygen.oftc.net")
|
|
self.assertEqual(command, "322")
|
|
|
|
def test_parse_in_url(self):
|
|
line = ":bob!~bob@example.com PRIVMSG #test :https://botbot.me"
|
|
prefix, command, args = croxy.parse_in(line)
|
|
self.assertEqual(prefix, "bob!~bob@example.com")
|
|
self.assertEqual(command, "PRIVMSG")
|
|
self.assertEqual(args, ["#test", "https://botbot.me"])
|
|
|
|
|
|
|
|
class TestCrypto(unittest.TestCase):
|
|
"""Test the crypto methods.
|
|
"""
|
|
|
|
def setUp(self):
|
|
self.key = "s3cret"
|
|
|
|
def test_pbkdf2(self):
|
|
"""Test croxy_pbkdf2.
|
|
"""
|
|
derived = b'n\x9aar\x97j\xb2\\\xeb\x04K\xce\xd3lM\xd4\x97p\xd1\xe36\xfa\x1a@d,\xced\xb8\xb6\xfb\xd7'
|
|
self.assertEqual(
|
|
croxy.croxy_pbkdf2(self.key, iterations=1000, salt=b'CROXYSALT'),
|
|
derived)
|
|
|
|
def test_not_encrypted(self):
|
|
"""Test trying to decrypt an unecrypted string.
|
|
"""
|
|
try:
|
|
croxy.croxy_decrypt("But I'm not encrypted!", self.key)
|
|
self.fail("Decrypting cleartext should raise an exception")
|
|
except croxy.NotEncrypted:
|
|
pass
|
|
|
|
def test_roundtrip(self):
|
|
"""Test decrypt(encrypt(clear)) == clear.
|
|
"""
|
|
def rt(cleartext):
|
|
ciphertext = croxy.croxy_encrypt(cleartext, self.key)
|
|
cleartext2 = croxy.croxy_decrypt(ciphertext, self.key)
|
|
self.assertEqual(cleartext, cleartext2)
|
|
|
|
rt("Test")
|
|
rt("Björk Guðmundsdóttir")
|
|
rt("فُصْحَى")
|
|
|
|
def test_does_something(self):
|
|
"""Because the IV for AES is random, we can't check the exact
|
|
output of croxy_encrypt, so we test_roundtrip (above) to
|
|
makes sure it works.
|
|
Here we just makes sure encrypt doesn't return the cleartext.
|
|
"""
|
|
self.assertTrue(croxy.croxy_encrypt('xyz', self.key) != 'xyz')
|
|
|
|
def test_rijndael(self):
|
|
"""The rijndael code from tlslite has a 'test' function, so
|
|
what the hell let's call it.
|
|
"""
|
|
croxy.test()
|
|
|
|
|
|
def suppress_stdout():
|
|
"""Turn off write to screen, for pretty test output."""
|
|
old_stdout = sys.stdout
|
|
sys.stdout = io.StringIO()
|
|
return old_stdout
|
|
|
|
def restore_stdout(old_stdout):
|
|
"""Turn stdout back on."""
|
|
sys.stdout = old_stdout
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|