import random import pytest from konabot.plugins.trpg_roll.core import RollError, roll_expression class FakeRandom: def __init__(self, randint_values: list[int] | None = None, choice_values: list[int] | None = None): self._randint_values = list(randint_values or []) self._choice_values = list(choice_values or []) def randint(self, _a: int, _b: int) -> int: assert self._randint_values return self._randint_values.pop(0) def choice(self, _seq): assert self._choice_values return self._choice_values.pop(0) def test_roll_expression_basic(): rng = FakeRandom(randint_values=[2, 4, 5]) result = roll_expression("3d6", rng=rng) assert result.total == 11 assert result.format() == "3d6 = 11\n+3d6=[2, 4, 5]" def test_roll_expression_multiple_terms(): rng = FakeRandom(randint_values=[14, 3, 1]) result = roll_expression("d20+1d4-2", rng=rng) assert result.total == 15 assert result.format() == "d20+1d4-2 = 15\n+1d20=[14] +1d4=[3] -2=2" def test_roll_expression_df(): rng = FakeRandom(choice_values=[-1, 0, 1, 1]) result = roll_expression("4dF", rng=rng) assert result.total == 1 assert result.format() == "4dF = 1\n+4dF=[-1, +0, +1, +1]" @pytest.mark.parametrize( ("expr", "message"), [ ("", "请提供要掷的表达式"), ("abc", "无法解析表达式"), ("1d0", "骰子面数必须大于 0"), ("0d6", "骰子个数必须大于 0"), ("101d6", "单项最多只能掷 100 个骰子"), ("1d1001", "骰子面数不能超过 1000"), ("201d1", "单项最多只能掷 100 个骰子"), ("1d6*2", "表达式中含有无法识别的内容"), ], ) def test_roll_expression_invalid(expr: str, message: str): with pytest.raises(RollError, match=message): roll_expression(expr, rng=random.Random(0)) def test_roll_expression_total_roll_limit(): with pytest.raises(RollError, match="一次最多只能实际掷 200 个骰子"): roll_expression("100d6+100d6+1d6", rng=random.Random(0))