"""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)