Async Python IRC bouncer with SOCKS5 proxy support, multi-network connections, password auth, and persistent SQLite backlog with replay. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
130 lines
4.4 KiB
Python
130 lines
4.4 KiB
Python
"""Tests for IRC message parsing and formatting."""
|
|
|
|
from bouncer.irc import IRCMessage, parse, parse_prefix
|
|
|
|
|
|
class TestParse:
|
|
def test_simple_command(self):
|
|
msg = parse(b"PING")
|
|
assert msg.command == "PING"
|
|
assert msg.params == []
|
|
assert msg.prefix is None
|
|
|
|
def test_command_with_param(self):
|
|
msg = parse(b"PING :server.example.com")
|
|
assert msg.command == "PING"
|
|
assert msg.params == ["server.example.com"]
|
|
|
|
def test_privmsg(self):
|
|
msg = parse(b":nick!user@host PRIVMSG #channel :Hello world")
|
|
assert msg.prefix == "nick!user@host"
|
|
assert msg.command == "PRIVMSG"
|
|
assert msg.params == ["#channel", "Hello world"]
|
|
|
|
def test_numeric_reply(self):
|
|
msg = parse(b":server 001 nick :Welcome to the network")
|
|
assert msg.prefix == "server"
|
|
assert msg.command == "001"
|
|
assert msg.params == ["nick", "Welcome to the network"]
|
|
|
|
def test_join(self):
|
|
msg = parse(b":nick!user@host JOIN #channel")
|
|
assert msg.command == "JOIN"
|
|
assert msg.params == ["#channel"]
|
|
|
|
def test_nick_user_registration(self):
|
|
msg = parse(b"NICK mynick")
|
|
assert msg.command == "NICK"
|
|
assert msg.params == ["mynick"]
|
|
|
|
def test_user_command(self):
|
|
msg = parse(b"USER myuser 0 * :Real Name")
|
|
assert msg.command == "USER"
|
|
assert msg.params == ["myuser", "0", "*", "Real Name"]
|
|
|
|
def test_pass_with_network(self):
|
|
msg = parse(b"PASS libera:secretpass")
|
|
assert msg.command == "PASS"
|
|
assert msg.params == ["libera:secretpass"]
|
|
|
|
def test_quit_with_message(self):
|
|
msg = parse(b":nick!user@host QUIT :Gone fishing")
|
|
assert msg.command == "QUIT"
|
|
assert msg.params == ["Gone fishing"]
|
|
|
|
def test_mode(self):
|
|
msg = parse(b":nick!user@host MODE #channel +o othernick")
|
|
assert msg.command == "MODE"
|
|
assert msg.params == ["#channel", "+o", "othernick"]
|
|
|
|
def test_crlf_stripped(self):
|
|
msg = parse(b"PING :test\r\n")
|
|
assert msg.command == "PING"
|
|
assert msg.params == ["test"]
|
|
|
|
def test_ircv3_tags(self):
|
|
msg = parse(b"@time=2024-01-01T00:00:00Z :nick!user@host PRIVMSG #ch :hi")
|
|
assert msg.tags == {"time": "2024-01-01T00:00:00Z"}
|
|
assert msg.command == "PRIVMSG"
|
|
|
|
def test_ircv3_tag_no_value(self):
|
|
msg = parse(b"@draft/reply;+example :nick PRIVMSG #ch :test")
|
|
assert msg.tags == {"draft/reply": None, "+example": None}
|
|
|
|
def test_latin1_fallback(self):
|
|
msg = parse(b":nick PRIVMSG #ch :\xe9\xe8\xea")
|
|
assert msg.params == ["#ch", "\xe9\xe8\xea"]
|
|
|
|
def test_trailing(self):
|
|
msg = parse(b":nick PRIVMSG #ch :hello world")
|
|
assert msg.trailing == "hello world"
|
|
|
|
def test_trailing_empty(self):
|
|
msg = parse(b"PING")
|
|
assert msg.trailing is None
|
|
|
|
|
|
class TestFormat:
|
|
def test_simple_command(self):
|
|
msg = IRCMessage(command="PING")
|
|
assert msg.format() == b"PING\r\n"
|
|
|
|
def test_with_params(self):
|
|
msg = IRCMessage(command="NICK", params=["mynick"])
|
|
assert msg.format() == b"NICK mynick\r\n"
|
|
|
|
def test_with_trailing(self):
|
|
msg = IRCMessage(command="PRIVMSG", params=["#channel", "Hello world"])
|
|
assert msg.format() == b"PRIVMSG #channel :Hello world\r\n"
|
|
|
|
def test_with_prefix(self):
|
|
msg = IRCMessage(command="PRIVMSG", params=["#ch", "hi"], prefix="nick!user@host")
|
|
assert msg.format() == b":nick!user@host PRIVMSG #ch hi\r\n"
|
|
|
|
def test_with_tags(self):
|
|
msg = IRCMessage(
|
|
command="PRIVMSG",
|
|
params=["#ch", "hi"],
|
|
tags={"time": "2024-01-01T00:00:00Z"},
|
|
)
|
|
assert msg.format() == b"@time=2024-01-01T00:00:00Z PRIVMSG #ch hi\r\n"
|
|
|
|
def test_roundtrip(self):
|
|
original = b":nick!user@host PRIVMSG #channel :Hello world"
|
|
msg = parse(original)
|
|
assert msg.format() == original + b"\r\n"
|
|
|
|
|
|
class TestParsePrefix:
|
|
def test_full(self):
|
|
assert parse_prefix("nick!user@host") == ("nick", "user", "host")
|
|
|
|
def test_nick_only(self):
|
|
assert parse_prefix("server.example.com") == ("server.example.com", None, None)
|
|
|
|
def test_nick_host(self):
|
|
assert parse_prefix("nick@host") == ("nick", None, "host")
|
|
|
|
def test_nick_user(self):
|
|
assert parse_prefix("nick!user") == ("nick", "user", None)
|