Move list_match to its own module, and prepare generalizing AnyStr

This commit is contained in:
2021-02-28 19:09:32 +01:00
committed by Valentin Lorentz
parent b8867cf4a2
commit e012c5248b
3 changed files with 65 additions and 37 deletions

View File

@ -24,7 +24,7 @@ import unittest
import pytest
from . import basecontrollers, client_mock, runner, tls
from . import basecontrollers, client_mock, patma, runner, tls
from .authentication import Authentication
from .basecontrollers import TestCaseControllerConfig
from .exceptions import ConnectionClosed
@ -65,13 +65,6 @@ TController = TypeVar("TController", bound=basecontrollers._BaseController)
T = TypeVar("T")
class AnyStr:
"""Used as a wildcard when matching message arguments
(see assertMessageMatch and listMatch)"""
pass
class ChannelJoinException(Exception):
def __init__(self, code: str, params: List[str]):
super().__init__(f"Failed to join channel ({code}): {params}")
@ -116,7 +109,7 @@ class _IrcTestCase(unittest.TestCase, Generic[TController]):
Takes the message as first arguments, and comparisons to be made
as keyword arguments.
Uses self.listMatch on the params argument.
Uses patma.list_match on the params argument.
"""
error = self.messageDiffers(msg, **kwargs)
if error:
@ -130,7 +123,7 @@ class _IrcTestCase(unittest.TestCase, Generic[TController]):
def messageDiffers(
self,
msg: Message,
params: Optional[List[Union[str, Type[AnyStr]]]] = None,
params: Optional[List[Union[str, patma.Operator]]] = None,
target: Optional[str] = None,
nick: Optional[str] = None,
fail_msg: Optional[str] = None,
@ -152,7 +145,7 @@ class _IrcTestCase(unittest.TestCase, Generic[TController]):
msg=msg,
)
if params and not self.listMatch(msg.params, params):
if params and not patma.list_match(msg.params, params):
fail_msg = fail_msg or "params to be {expects}, got {got}: {msg}"
return fail_msg.format(
*extra_format, got=msg.params, expects=params, msg=msg
@ -170,22 +163,6 @@ class _IrcTestCase(unittest.TestCase, Generic[TController]):
return None
def listMatch(
self, got: List[str], expected: List[Union[str, Type[AnyStr]]]
) -> bool:
"""Returns True iff the list are equal.
The ellipsis (aka. "..." aka triple dots) can be used on the 'expected'
side as a wildcard, matching any *single* value."""
if len(got) != len(expected):
return False
for (got_value, expected_value) in zip(got, expected):
if expected_value is AnyStr:
# wildcard
continue
if got_value != expected_value:
return False
return True
def assertIn(
self,
member: Any,

51
irctest/patma.py Normal file
View File

@ -0,0 +1,51 @@
"""Pattern-matching utilities"""
import dataclasses
import re
from typing import List, Union
class Operator:
"""Used as a wildcards and operators when matching message arguments
(see assertMessageMatch and match_list)"""
def __init__(self) -> None:
pass
class AnyStr(Operator):
"""Wildcard matching any string"""
def __repr__(self) -> str:
return "AnyStr"
@dataclasses.dataclass
class StrRe(Operator):
regexp: str
def __repr__(self) -> str:
return f"StrRe(r'{self.regexp}')"
ANYSTR = AnyStr()
"""Singleton, spares two characters"""
def match_list(got: List[str], expected: List[Union[str, Operator]]) -> bool:
"""Returns True iff the list are equal.
The ellipsis (aka. "..." aka triple dots) can be used on the 'expected'
side as a wildcard, matching any *single* value."""
if len(got) != len(expected):
return False
for (got_value, expected_value) in zip(got, expected):
if isinstance(expected_value, AnyStr):
# wildcard
continue
elif isinstance(expected_value, StrRe):
if not re.match(expected_value.regexp, got_value):
return False
else:
if got_value != expected_value:
return False
return True

View File

@ -1,5 +1,5 @@
from irctest import cases
from irctest.cases import AnyStr
from irctest.patma import ANYSTR
from irctest.runner import CapabilityNotSupported, ImplementationChoice
@ -40,7 +40,7 @@ class CapTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
self.assertMessageMatch(
m,
command="CAP",
params=[AnyStr, "NAK", "foo"],
params=[ANYSTR, "NAK", "foo"],
fail_msg="Expected CAP NAK after requesting non-existing "
"capability, got {msg}.",
)
@ -67,7 +67,7 @@ class CapTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
self.assertMessageMatch(
m,
command="CAP",
params=[AnyStr, "NAK", "foo qux bar baz qux quux"],
params=[ANYSTR, "NAK", "foo qux bar baz qux quux"],
fail_msg="Expected “CAP NAK :foo qux bar baz qux quux” after "
"sending “CAP REQ :foo qux bar baz qux quux”, but got {msg}.",
)
@ -86,7 +86,7 @@ class CapTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
self.assertMessageMatch(
m,
command="CAP",
params=[AnyStr, "NAK", "foo multi-prefix bar"],
params=[ANYSTR, "NAK", "foo multi-prefix bar"],
fail_msg="Expected “CAP NAK :foo multi-prefix bar” after "
"sending “CAP REQ :foo multi-prefix bar”, but got {msg}.",
)
@ -95,7 +95,7 @@ class CapTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
self.assertMessageMatch(
m,
command="CAP",
params=[AnyStr, "NAK", "multi-prefix bar"],
params=[ANYSTR, "NAK", "multi-prefix bar"],
fail_msg="Expected “CAP NAK :multi-prefix bar” after "
"sending “CAP REQ :multi-prefix bar”, but got {msg}.",
)
@ -104,7 +104,7 @@ class CapTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
self.assertMessageMatch(
m,
command="CAP",
params=[AnyStr, "NAK", "foo multi-prefix"],
params=[ANYSTR, "NAK", "foo multi-prefix"],
fail_msg="Expected “CAP NAK :foo multi-prefix” after "
"sending “CAP REQ :foo multi-prefix”, but got {msg}.",
)
@ -114,7 +114,7 @@ class CapTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
self.assertMessageMatch(
m,
command="CAP",
params=[AnyStr, "ACK", "multi-prefix"],
params=[ANYSTR, "ACK", "multi-prefix"],
fail_msg="Expected “CAP ACK :multi-prefix” after "
"sending “CAP REQ :multi-prefix”, but got {msg}.",
)
@ -134,7 +134,7 @@ class CapTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
self.sendLine(1, "user user 0 * realname")
self.sendLine(1, "CAP END")
m = self.getRegistrationMessage(1)
self.assertMessageMatch(m, command="CAP", params=[AnyStr, "ACK", AnyStr])
self.assertMessageMatch(m, command="CAP", params=[ANYSTR, "ACK", ANYSTR])
self.assertEqual(
set(m.params[2].split()), {cap1, cap2}, "Didn't ACK both REQed caps"
)
@ -152,9 +152,9 @@ class CapTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
self.sendLine(1, f"CAP REQ :-{cap2}")
m = self.getMessage(1)
# Must be either ACK or NAK
if self.messageDiffers(m, command="CAP", params=[AnyStr, "ACK", f"-{cap2}"]):
if self.messageDiffers(m, command="CAP", params=[ANYSTR, "ACK", f"-{cap2}"]):
self.assertMessageMatch(
m, command="CAP", params=[AnyStr, "NAK", f"-{cap2}"]
m, command="CAP", params=[ANYSTR, "NAK", f"-{cap2}"]
)
raise ImplementationChoice(f"Does not support CAP REQ -{cap2}")