mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-16 01:40:15 +08:00
334 lines
9.1 KiB
Python
334 lines
9.1 KiB
Python
"""
|
|
Tests for decorators.py - Handler decorator infrastructure.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
from astrbot_sdk.decorators import (
|
|
HANDLER_META_ATTR,
|
|
HandlerMeta,
|
|
get_handler_meta,
|
|
on_command,
|
|
on_event,
|
|
on_message,
|
|
on_schedule,
|
|
require_admin,
|
|
)
|
|
from astrbot_sdk.protocol.descriptors import (
|
|
CommandTrigger,
|
|
EventTrigger,
|
|
MessageTrigger,
|
|
Permissions,
|
|
ScheduleTrigger,
|
|
)
|
|
|
|
|
|
class TestHandlerMeta:
|
|
"""Tests for HandlerMeta dataclass."""
|
|
|
|
def test_default_values(self):
|
|
"""HandlerMeta should have default values."""
|
|
meta = HandlerMeta()
|
|
assert meta.trigger is None
|
|
assert meta.priority == 0
|
|
assert isinstance(meta.permissions, Permissions)
|
|
|
|
def test_trigger_assignment(self):
|
|
"""HandlerMeta should accept trigger assignment."""
|
|
trigger = CommandTrigger(command="test")
|
|
meta = HandlerMeta(trigger=trigger)
|
|
assert meta.trigger is trigger
|
|
|
|
def test_priority_assignment(self):
|
|
"""HandlerMeta should accept priority assignment."""
|
|
meta = HandlerMeta(priority=10)
|
|
assert meta.priority == 10
|
|
|
|
def test_permissions_assignment(self):
|
|
"""HandlerMeta should accept permissions assignment."""
|
|
permissions = Permissions(require_admin=True)
|
|
meta = HandlerMeta(permissions=permissions)
|
|
assert meta.permissions.require_admin is True
|
|
|
|
|
|
class TestGetHandlerMeta:
|
|
"""Tests for get_handler_meta function."""
|
|
|
|
def test_returns_none_for_undecorated_function(self):
|
|
"""get_handler_meta should return None for undecorated functions."""
|
|
|
|
async def plain_function():
|
|
pass
|
|
|
|
assert get_handler_meta(plain_function) is None
|
|
|
|
def test_returns_meta_for_decorated_function(self):
|
|
"""get_handler_meta should return meta for decorated functions."""
|
|
|
|
@on_command("test")
|
|
async def decorated():
|
|
pass
|
|
|
|
meta = get_handler_meta(decorated)
|
|
assert meta is not None
|
|
assert isinstance(meta, HandlerMeta)
|
|
|
|
|
|
class TestOnCommandDecorator:
|
|
"""Tests for @on_command decorator."""
|
|
|
|
def test_sets_handler_meta_attribute(self):
|
|
"""@on_command should set __astrbot_handler_meta__ attribute."""
|
|
|
|
@on_command("hello")
|
|
async def handler():
|
|
pass
|
|
|
|
assert hasattr(handler, HANDLER_META_ATTR)
|
|
|
|
def test_creates_command_trigger(self):
|
|
"""@on_command should create CommandTrigger."""
|
|
|
|
@on_command("hello")
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert isinstance(meta.trigger, CommandTrigger)
|
|
assert meta.trigger.command == "hello"
|
|
|
|
def test_supports_aliases(self):
|
|
"""@on_command should store aliases."""
|
|
|
|
@on_command("hello", aliases=["hi", "hey"])
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert meta.trigger.aliases == ["hi", "hey"]
|
|
|
|
def test_supports_description(self):
|
|
"""@on_command should store description."""
|
|
|
|
@on_command("hello", description="Say hello")
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert meta.trigger.description == "Say hello"
|
|
|
|
def test_default_empty_aliases(self):
|
|
"""@on_command should default to empty aliases."""
|
|
|
|
@on_command("test")
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert meta.trigger.aliases == []
|
|
|
|
def test_preserves_function(self):
|
|
"""@on_command should preserve the original function."""
|
|
|
|
@on_command("test")
|
|
async def handler():
|
|
return "result"
|
|
|
|
assert handler.__name__ == "handler"
|
|
|
|
|
|
class TestOnMessageDecorator:
|
|
"""Tests for @on_message decorator."""
|
|
|
|
def test_creates_message_trigger(self):
|
|
"""@on_message should create MessageTrigger."""
|
|
|
|
@on_message()
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert isinstance(meta.trigger, MessageTrigger)
|
|
|
|
def test_supports_regex(self):
|
|
"""@on_message should store regex pattern."""
|
|
|
|
@on_message(regex=r"\d+")
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert meta.trigger.regex == r"\d+"
|
|
|
|
def test_supports_keywords(self):
|
|
"""@on_message should store keywords."""
|
|
|
|
@on_message(keywords=["hello", "hi"])
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert meta.trigger.keywords == ["hello", "hi"]
|
|
|
|
def test_supports_platforms(self):
|
|
"""@on_message should store platforms."""
|
|
|
|
@on_message(platforms=["telegram", "discord"])
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert meta.trigger.platforms == ["telegram", "discord"]
|
|
|
|
def test_defaults_empty_lists(self):
|
|
"""@on_message should default to empty lists."""
|
|
|
|
@on_message()
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert meta.trigger.keywords == []
|
|
assert meta.trigger.platforms == []
|
|
|
|
|
|
class TestOnEventDecorator:
|
|
"""Tests for @on_event decorator."""
|
|
|
|
def test_creates_event_trigger(self):
|
|
"""@on_event should create EventTrigger."""
|
|
|
|
@on_event("message_received")
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert isinstance(meta.trigger, EventTrigger)
|
|
assert meta.trigger.event_type == "message_received"
|
|
|
|
def test_various_event_types(self):
|
|
"""@on_event should handle various event types."""
|
|
|
|
event_types = ["message_received", "user_joined", "custom_event"]
|
|
|
|
for event_type in event_types:
|
|
|
|
@on_event(event_type)
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert meta.trigger.event_type == event_type
|
|
|
|
|
|
class TestOnScheduleDecorator:
|
|
"""Tests for @on_schedule decorator."""
|
|
|
|
def test_creates_cron_trigger(self):
|
|
"""@on_schedule with cron should create ScheduleTrigger."""
|
|
|
|
@on_schedule(cron="* * * * *")
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert isinstance(meta.trigger, ScheduleTrigger)
|
|
assert meta.trigger.cron == "* * * * *"
|
|
|
|
def test_creates_interval_trigger(self):
|
|
"""@on_schedule with interval should create ScheduleTrigger."""
|
|
|
|
@on_schedule(interval_seconds=60)
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert meta.trigger.interval_seconds == 60
|
|
|
|
|
|
class TestRequireAdminDecorator:
|
|
"""Tests for @require_admin decorator."""
|
|
|
|
def test_sets_require_admin_permission(self):
|
|
"""@require_admin should set require_admin in permissions."""
|
|
|
|
@require_admin
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert meta.permissions.require_admin is True
|
|
|
|
def test_can_combine_with_other_decorators(self):
|
|
"""@require_admin can be combined with other decorators."""
|
|
|
|
@on_command("admin")
|
|
@require_admin
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert isinstance(meta.trigger, CommandTrigger)
|
|
assert meta.trigger.command == "admin"
|
|
assert meta.permissions.require_admin is True
|
|
|
|
def test_order_does_not_matter_for_permissions(self):
|
|
"""Decorator order should not affect permissions."""
|
|
|
|
@require_admin
|
|
@on_command("admin")
|
|
async def handler1():
|
|
pass
|
|
|
|
@on_command("admin")
|
|
@require_admin
|
|
async def handler2():
|
|
pass
|
|
|
|
meta1 = get_handler_meta(handler1)
|
|
meta2 = get_handler_meta(handler2)
|
|
|
|
assert meta1.permissions.require_admin is True
|
|
assert meta2.permissions.require_admin is True
|
|
|
|
|
|
class TestDecoratorChaining:
|
|
"""Tests for chaining multiple decorators."""
|
|
|
|
def test_multiple_decorators_share_meta(self):
|
|
"""Multiple decorators should share the same meta object."""
|
|
|
|
@on_command("test")
|
|
@require_admin
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert isinstance(meta.trigger, CommandTrigger)
|
|
assert meta.permissions.require_admin is True
|
|
|
|
def test_last_trigger_wins(self):
|
|
"""Last trigger decorator should override previous ones."""
|
|
|
|
# Decorators are applied bottom-up, so on_message wins
|
|
@on_message()
|
|
@on_command("override")
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
# on_message is applied last (outermost), so it wins
|
|
assert isinstance(meta.trigger, MessageTrigger)
|
|
|
|
def test_permissions_accumulate(self):
|
|
"""Permissions should accumulate across decorators."""
|
|
|
|
@require_admin
|
|
@on_command("test")
|
|
async def handler():
|
|
pass
|
|
|
|
meta = get_handler_meta(handler)
|
|
assert meta.permissions.require_admin is True
|