mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-27 22:34:51 +00:00
* feat: add simplex-support-bot-light * feat: package simplex-support-bot-light for docker * docs: document simplex-support-bot-light * fix: make a missing config actionable and bounded * docs: note the attached compose Ctrl+C behaviour * refactor: use the library for startup and custom data * refactor: drop the display-name workaround * style: shorten the startup comment * build: build the core and the library into the image * docs: correct where the image type rule comes from * fix: log what the core said a command got wrong * build: run the container as the operator's uid * docs: keep the container uid in .env * docs: tighten the README
86 lines
3.0 KiB
Python
86 lines
3.0 KiB
Python
from support_bot_light import messages
|
|
from support_bot_light.roster import RosterEntry
|
|
|
|
|
|
def entry(name, state, since="2026-08-13T09:00:00+00:00", reachable=True):
|
|
return RosterEntry(contact_id=1, name=name, state=state, since=since, reachable=reachable)
|
|
|
|
|
|
def test_render_roster_lists_active_and_pending():
|
|
out = messages.render_roster([entry("sh", "active"), entry("Alex", "pending")])
|
|
assert "On the roster (1):" in out
|
|
assert "• sh — since 2026-08-13" in out
|
|
assert "Contact request not accepted (1):" in out
|
|
assert "• Alex — asked 2026-08-13" in out
|
|
|
|
|
|
def test_render_roster_empty():
|
|
assert messages.render_roster([]) == messages.ROSTER_EMPTY
|
|
|
|
|
|
def test_render_roster_omits_pending_section_when_none():
|
|
out = messages.render_roster([entry("sh", "active")])
|
|
assert "Waiting" not in out
|
|
|
|
|
|
def test_render_roster_omits_date_suffix_when_since_is_empty():
|
|
out = messages.render_roster([entry("sh", "active", since="")])
|
|
assert out == "On the roster (1):\n • sh"
|
|
assert "since" not in out
|
|
|
|
|
|
def test_render_roster_formats_date_suffix():
|
|
out = messages.render_roster([entry("sh", "active")])
|
|
assert out == "On the roster (1):\n • sh — since 2026-08-13"
|
|
|
|
|
|
def test_invite_log_lists_added_names():
|
|
assert messages.invite_log("Alex", ["sh", "Narasimha"], []) == (
|
|
"Connected: Alex → added sh, Narasimha"
|
|
)
|
|
|
|
|
|
def test_invite_log_reports_failures():
|
|
line = messages.invite_log("Alex", ["sh"], ["Narasimha"])
|
|
assert line == "Connected: Alex → added sh (failed: Narasimha)"
|
|
|
|
|
|
def test_help_mentions_every_command():
|
|
for keyword in ("dm", "list", "leave"):
|
|
assert f"/{keyword}" in messages.HELP
|
|
|
|
|
|
def test_render_roster_separates_unreachable_members():
|
|
out = messages.render_roster(
|
|
[entry("live", "active"), entry("dead", "active", reachable=False)]
|
|
)
|
|
assert "On the roster (1):" in out
|
|
assert "Not reachable, not being added (1):" in out
|
|
assert "• dead" in out
|
|
|
|
|
|
def test_render_roster_caps_long_sections():
|
|
entries = [entry(f"n{i}", "active") for i in range(messages.MAX_LISTED + 12)]
|
|
out = messages.render_roster(entries)
|
|
assert f"On the roster ({messages.MAX_LISTED + 12}):" in out
|
|
assert "… and 12 more" in out
|
|
assert out.count("•") == messages.MAX_LISTED
|
|
assert len(out.encode()) < 15000
|
|
|
|
|
|
def test_render_roster_bounds_the_whole_reply_in_bytes():
|
|
# Names are capped in characters, so CJK can overrun a byte limit even with
|
|
# every section capped.
|
|
entries = [entry("漢" * 50, "active") for _ in range(messages.MAX_LISTED)]
|
|
entries += [entry("漢" * 50, "pending") for _ in range(messages.MAX_LISTED)]
|
|
out = messages.render_roster(entries)
|
|
assert len(out.encode()) <= messages.MAX_REPLY_BYTES
|
|
assert out.endswith(messages.TRUNCATED)
|
|
|
|
|
|
def test_invite_log_is_bounded_in_bytes():
|
|
names = ["漢" * 50 for _ in range(100)]
|
|
out = messages.invite_log("Alex", names, [])
|
|
assert len(out.encode()) <= messages.MAX_REPLY_BYTES
|
|
assert out.endswith(messages.TRUNCATED)
|