新增了Twitch、Telegram、Discord、Slack、Mattermost、WeChat、Zalo等多渠道的单元测试用例,覆盖了令牌处理、速率限制、消息去重、会话解析、格式转换、安全策略等模块 同时在测试配置中添加了测试用的OpenAI API密钥环境变量
172 lines
5.3 KiB
Python
172 lines
5.3 KiB
Python
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from yuxi.channels.adapters.twitch.irc_parser import (
|
|
ParsedIRCMessage,
|
|
build_identity_tags,
|
|
extract_nick,
|
|
make_irc_message_id,
|
|
parse_badges,
|
|
parse_emotes,
|
|
parse_irc_line,
|
|
parse_prefix,
|
|
)
|
|
|
|
PRIVMSG = (
|
|
"@badge-info=subscriber/1;badges=subscriber/0;color=#FF4500;"
|
|
"display-name=TestUser;emotes=;flags=;id=abc-123;mod=0;"
|
|
"room-id=123456;subscriber=1;tmi-sent-ts=1600000000000;"
|
|
"turbo=0;user-id=789;user-type= "
|
|
":testuser!testuser@testuser.tmi.twitch.tv PRIVMSG #channel :Hello world"
|
|
)
|
|
|
|
PRIVMSG_WITH_EMOTES = (
|
|
"@badges=;emotes=425618:0-7;user-id=789 "
|
|
":testuser!testuser@testuser.tmi.twitch.tv PRIVMSG #channel :Kreygasm hello"
|
|
)
|
|
|
|
PRIVMSG_WITH_BITS = (
|
|
"@badges=;bits=100;user-id=789 "
|
|
":testuser!testuser@testuser.tmi.twitch.tv PRIVMSG #channel :Cheer100 hello"
|
|
)
|
|
|
|
PING = "PING :tmi.twitch.tv"
|
|
|
|
NOTICE = (
|
|
"@msg-id=slow_off :tmi.twitch.tv NOTICE #channel :This room is no longer in slow mode."
|
|
)
|
|
|
|
USERNOTICE = (
|
|
"@badges=subscriber/6;color=#FF4500;display-name=SubUser;"
|
|
"emotes=;flags=;id=sub-msg-1;login=subuser;mod=0;"
|
|
"msg-id=sub;msg-param-cumulative-months=6;msg-param-months=0;"
|
|
"msg-param-should-share-streak=1;msg-param-sub-plan-name=Channel\\sSubscription;"
|
|
"msg-param-sub-plan=1000;room-id=123456;subscriber=1;"
|
|
"system-msg=SubUser\\ssubscribed\\sat\\sTier\\s1.;"
|
|
"tmi-sent-ts=1600000000000;user-id=789;user-type= "
|
|
":tmi.twitch.tv USERNOTICE #channel"
|
|
)
|
|
|
|
|
|
class TestParseIRCLine:
|
|
def test_parse_privmsg(self):
|
|
parsed = parse_irc_line(PRIVMSG)
|
|
assert parsed.command == "PRIVMSG"
|
|
assert parsed.prefix == "testuser!testuser@testuser.tmi.twitch.tv"
|
|
assert parsed.params == ["#channel"]
|
|
assert parsed.trailing == "Hello world"
|
|
assert parsed.tags["display-name"] == "TestUser"
|
|
assert parsed.tags["user-id"] == "789"
|
|
assert parsed.tags["mod"] == "0"
|
|
|
|
def test_parse_ping(self):
|
|
parsed = parse_irc_line(PING)
|
|
assert parsed.command == "PING"
|
|
assert "tmi.twitch.tv" in (parsed.trailing or " ".join(parsed.params))
|
|
|
|
def test_parse_notice(self):
|
|
parsed = parse_irc_line(NOTICE)
|
|
assert parsed.command == "NOTICE"
|
|
assert parsed.params == ["#channel"]
|
|
assert "slow_off" in parsed.tags.get("msg-id", "")
|
|
|
|
def test_parse_usernotice(self):
|
|
parsed = parse_irc_line(USERNOTICE)
|
|
assert parsed.command == "USERNOTICE"
|
|
assert parsed.tags["msg-id"] == "sub"
|
|
assert parsed.tags["msg-param-sub-plan"] == "1000"
|
|
|
|
def test_parse_empty_line(self):
|
|
parsed = parse_irc_line("")
|
|
assert parsed.command == ""
|
|
|
|
def test_parse_invalid_line(self):
|
|
parsed = parse_irc_line("garbage data without structure")
|
|
assert parsed.command == "GARBAGE"
|
|
|
|
def test_parse_cmd_only(self):
|
|
parsed = parse_irc_line("PING")
|
|
assert parsed.command == "PING"
|
|
|
|
|
|
class TestParsePrefix:
|
|
def test_full_prefix(self):
|
|
result = parse_prefix("user!user@host")
|
|
assert result["nick"] == "user"
|
|
assert result["user"] == "user"
|
|
assert result["host"] == "host"
|
|
|
|
def test_nick_only(self):
|
|
result = parse_prefix("justnick")
|
|
assert result["nick"] == "justnick"
|
|
|
|
def test_none_prefix(self):
|
|
result = parse_prefix(None)
|
|
assert result["nick"] is None
|
|
|
|
|
|
class TestExtractNick:
|
|
def test_extract_from_prefix(self):
|
|
assert extract_nick("testuser!testuser@host") == "testuser"
|
|
|
|
def test_extract_no_bang(self):
|
|
assert extract_nick("simplenick") == "simplenick"
|
|
|
|
def test_extract_none(self):
|
|
assert extract_nick(None) == "unknown"
|
|
|
|
|
|
class TestParseBadges:
|
|
def test_parse_badges(self):
|
|
badges = parse_badges("subscriber/6,moderator/1")
|
|
assert badges == {"subscriber": "6", "moderator": "1"}
|
|
|
|
def test_parse_empty(self):
|
|
assert parse_badges("") == {}
|
|
|
|
def test_parse_no_version(self):
|
|
badges = parse_badges("vip")
|
|
assert badges == {"vip": "1"}
|
|
|
|
|
|
class TestParseEmotes:
|
|
def test_parse_single_emote(self):
|
|
emotes = parse_emotes("425618:0-7", "Kreygasm hello")
|
|
assert len(emotes) == 1
|
|
assert emotes[0]["id"] == "425618"
|
|
assert emotes[0]["text"] == "Kreygasm"
|
|
assert emotes[0]["start"] == 0
|
|
assert emotes[0]["end"] == 7
|
|
|
|
def test_parse_no_emotes(self):
|
|
assert parse_emotes("", "hello") == []
|
|
|
|
def test_parse_multiple_positions(self):
|
|
emotes = parse_emotes("1:0-2,4-6", "abcabc")
|
|
assert len(emotes) == 2
|
|
|
|
def test_parse_emote_url(self):
|
|
emotes = parse_emotes("425618:0-7", "Kreygasm")
|
|
assert "static-cdn.jtvnw.net" in emotes[0]["url"]
|
|
|
|
|
|
class TestMakeIRCMessageId:
|
|
def test_with_ts(self):
|
|
msg_id = make_irc_message_id("789", "1600000000000")
|
|
assert msg_id == "789:1600000000000"
|
|
|
|
def test_without_ts(self):
|
|
msg_id = make_irc_message_id("789")
|
|
assert msg_id.startswith("789:")
|
|
|
|
|
|
class TestBuildIdentityTags:
|
|
def test_build_tags(self):
|
|
tags = build_identity_tags(user_id="789", color="#FF4500")
|
|
assert "user-id=789" in tags or "user_id=789" in tags
|
|
assert "color=#FF4500" in tags
|
|
|
|
def test_none_values_skipped(self):
|
|
tags = build_identity_tags(user_id="789", color=None)
|
|
assert "color" not in tags |