Files
bouncer/tests/test_namespace.py
user 3c6f0bcf19 fix: use client nick for synthetic JOINs and own-nick rewriting
irssi (and other IRC clients) only open a channel window when they see
a JOIN from their own nick. The synthetic JOINs were using the network
nick (e.g. pagumowa) but the client registered as tester -- mismatch.

Three changes:
- Synthetic JOIN prefix is now client_nick!user@bouncer
- 001 welcome uses the client's registered nick
- encode_nick/encode_message accept client_nick param to rewrite own
  nicks from any network to the client's nick, so irssi recognizes
  all self-actions consistently

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 19:42:10 +01:00

169 lines
5.3 KiB
Python

"""Tests for network namespace encoding/decoding."""
from bouncer.irc import IRCMessage
from bouncer.namespace import (
decode_channel,
decode_target,
encode_channel,
encode_message,
encode_nick,
encode_prefix,
)
OWN = {"libera": "mybot", "oftc": "mybot2"}
class TestEncodeChannel:
def test_basic(self):
assert encode_channel("#libera", "libera") == "#libera/libera"
def test_preserves_prefix(self):
assert encode_channel("&local", "net") == "&local/net"
class TestDecodeChannel:
def test_basic(self):
assert decode_channel("#libera/libera") == ("#libera", "libera")
def test_no_separator(self):
assert decode_channel("#libera") == ("#libera", None)
def test_channel_with_slash_in_name(self):
# Edge: channel name itself contains slash -- rfind picks the last one
assert decode_channel("#a/b/net") == ("#a/b", "net")
class TestEncodeNick:
def test_foreign_nick(self):
assert encode_nick("user123", "libera", OWN) == "user123/libera"
def test_own_nick_bare(self):
assert encode_nick("mybot", "libera", OWN) == "mybot"
def test_own_nick_other_network(self):
# Own nick on another network still shown bare
assert encode_nick("mybot2", "libera", OWN) == "mybot2"
def test_own_nick_rewritten_to_client_nick(self):
assert encode_nick("mybot", "libera", OWN, client_nick="tester") == "tester"
def test_foreign_nick_unaffected_by_client_nick(self):
assert encode_nick("user123", "libera", OWN, client_nick="tester") == "user123/libera"
class TestEncodePrefix:
def test_full_prefix(self):
result = encode_prefix("user!ident@host", "libera", OWN)
assert result == "user/libera!ident@host"
def test_own_prefix(self):
result = encode_prefix("mybot!ident@host", "libera", OWN)
assert result == "mybot!ident@host"
def test_nick_only(self):
result = encode_prefix("server.example.com", "libera", OWN)
assert result == "server.example.com/libera"
class TestDecodeTarget:
def test_channel(self):
assert decode_target("#libera/libera") == ("#libera", "libera")
def test_nick(self):
assert decode_target("user123/libera") == ("user123", "libera")
def test_bare(self):
assert decode_target("#libera") == ("#libera", None)
class TestEncodeMessage:
def test_privmsg_channel(self):
msg = IRCMessage(
command="PRIVMSG",
params=["#test", "hello"],
prefix="user!ident@host",
)
out = encode_message(msg, "libera", OWN)
assert out.params[0] == "#test/libera"
assert out.prefix == "user/libera!ident@host"
def test_privmsg_own_prefix(self):
msg = IRCMessage(
command="PRIVMSG",
params=["#test", "hello"],
prefix="mybot!ident@host",
)
out = encode_message(msg, "libera", OWN)
assert out.prefix == "mybot!ident@host"
def test_namreply(self):
msg = IRCMessage(
command="353",
params=["mybot", "=", "#test", "@op +voice regular mybot"],
)
out = encode_message(msg, "libera", OWN)
assert out.params[2] == "#test/libera"
names = out.params[3].split()
assert names[0] == "@op/libera"
assert names[1] == "+voice/libera"
assert names[2] == "regular/libera"
assert names[3] == "mybot" # own nick stays bare
def test_nick_change(self):
msg = IRCMessage(
command="NICK",
params=["newnick"],
prefix="oldnick!user@host",
)
out = encode_message(msg, "libera", OWN)
assert out.params[0] == "newnick/libera"
assert out.prefix == "oldnick/libera!user@host"
def test_join(self):
msg = IRCMessage(
command="JOIN",
params=["#test"],
prefix="user!ident@host",
)
out = encode_message(msg, "libera", OWN)
assert out.params[0] == "#test/libera"
def test_non_channel_target_untouched(self):
msg = IRCMessage(
command="PRIVMSG",
params=["someuser", "hi"],
prefix="other!ident@host",
)
out = encode_message(msg, "libera", OWN)
# Private message to a nick -- params[0] is not a channel, left as-is
assert out.params[0] == "someuser"
def test_no_raw_preserved(self):
msg = IRCMessage(
command="PRIVMSG",
params=["#test", "hello"],
prefix="user!ident@host",
raw=b":user!ident@host PRIVMSG #test :hello\r\n",
)
out = encode_message(msg, "libera", OWN)
assert out.raw is None # raw must not carry over
def test_own_prefix_rewritten_to_client_nick(self):
msg = IRCMessage(
command="PRIVMSG",
params=["#test", "hello"],
prefix="mybot!ident@host",
)
out = encode_message(msg, "libera", OWN, client_nick="tester")
assert out.prefix == "tester!ident@host"
def test_namreply_own_nick_rewritten(self):
msg = IRCMessage(
command="353",
params=["mybot", "=", "#test", "@op mybot"],
)
out = encode_message(msg, "libera", OWN, client_nick="tester")
names = out.params[3].split()
assert names[0] == "@op/libera"
assert names[1] == "tester"