Skip to content

Commit

Permalink
tests: extend capabilities of bot_helper.assert_sent() to allow more …
Browse files Browse the repository at this point in the history
…complex matching
  • Loading branch information
alanbriolat committed Feb 15, 2022
1 parent 4d736c6 commit 66c451d
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 46 deletions.
45 changes: 40 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,51 @@ def receive(self, lines):
lines = [lines]
return [self.client.line_received(line) for line in lines]

def assert_sent(self, lines):
def assert_sent(self, matchers, *, any_order=False, reset_mock=True):
"""Check that a list of (unicode) strings have been sent.
Resets the mock so the next call will not contain what was checked by
this call.
"""
if isinstance(lines, str):
lines = [lines]
self.client.send_line.assert_has_calls([mock.call(line) for line in lines])
self.client.send_line.reset_mock()
sent_lines = [args[0] for name, args, kwargs in self.client.send_line.mock_calls]

if callable(matchers) or isinstance(matchers, str):
matchers = [matchers]
matchers = [LineMatcher.equals(matcher) if not callable(matcher) else matcher
for matcher in matchers]

if not matchers:
pass
elif any_order:
for matcher in matchers:
assert any(matcher(line) for line in sent_lines), f"sent line not found: {matcher}"
else:
# Find the start of the matching run of sent messages
start = 0
while start < len(sent_lines) and not matchers[0](sent_lines[start]):
start += 1
for i, matcher in enumerate(matchers):
assert start + i < len(sent_lines), f"no line matching {matcher} in {sent_lines}"
assert matcher(sent_lines[start + i]), f"expected {sent_lines[start + i]!r} to match {matcher}"

if reset_mock:
self.client.send_line.reset_mock()


class LineMatcher:
def __init__(self, f, description):
self.f = f
self.description = description

def __call__(self, line):
return self.f(line)

def __repr__(self):
return self.description

@classmethod
def equals(cls, other):
return cls(lambda line: line == other, f"`line == {other!r}`")


@pytest.fixture
Expand Down
38 changes: 7 additions & 31 deletions tests/test_irc.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,62 +193,38 @@ async def test_client_PING(self, fast_forward, run_client):
run_client.client.send_line.assert_not_called()
# Advance time, test that a ping was sent
await fast_forward(4)
assert run_client.client.send_line.mock_calls == [
mock.call('PING 1'),
]
run_client.assert_sent(['PING 1'], reset_mock=False)
# Advance time again, test that the right number of pings was sent
await fast_forward(12)
assert run_client.client.send_line.mock_calls == [
mock.call('PING 1'),
mock.call('PING 2'),
mock.call('PING 3'),
mock.call('PING 4'),
mock.call('PING 5'),
]
run_client.assert_sent(['PING 1', 'PING 2', 'PING 3', 'PING 4', 'PING 5'], reset_mock=False)
# Disconnect, advance time, test that no more pings were sent
run_client.client.disconnect()
await run_client.client.disconnected.wait()
await fast_forward(12)
assert run_client.client.send_line.mock_calls == [
mock.call('PING 1'),
mock.call('PING 2'),
mock.call('PING 3'),
mock.call('PING 4'),
mock.call('PING 5'),
]
run_client.assert_sent(['PING 1', 'PING 2', 'PING 3', 'PING 4', 'PING 5'], reset_mock=False)

async def test_client_PING_only_when_needed(self, fast_forward, run_client):
"""Check that client PING commands are sent relative to the last received message."""
run_client.reset_mock()
run_client.client.send_line.assert_not_called()
# Advance time to just before the second PING, check that the first PING was sent
await fast_forward(5)
assert run_client.client.send_line.mock_calls == [
mock.call('PING 1'),
]
run_client.assert_sent(['PING 1'], reset_mock=False)
# Receive a message, this should reset the PING timer
run_client.receive(':nick!user@host PRIVMSG #channel :foo')
# Advance time to just after when the second PING would happen without any messages
# received, check that still only one PING was sent
await fast_forward(2)
assert run_client.client.send_line.mock_calls == [
mock.call('PING 1'),
]
run_client.assert_sent(['PING 1'], reset_mock=False)
# Advance time to 4 seconds after the last message was received, and check that another
# PING has now been sent
await fast_forward(2)
assert run_client.client.send_line.mock_calls == [
mock.call('PING 1'),
mock.call('PING 2'),
]
run_client.assert_sent(['PING 1', 'PING 2'], reset_mock=False)
# Disconnect, advance time, test that no more pings were sent
run_client.client.disconnect()
await run_client.client.disconnected.wait()
await fast_forward(12)
assert run_client.client.send_line.mock_calls == [
mock.call('PING 1'),
mock.call('PING 2'),
]
run_client.assert_sent(['PING 1', 'PING 2'], reset_mock=False)


def test_PING_PONG(irc_client_helper):
Expand Down
Empty file added tests/test_plugin_last.py
Empty file.
10 changes: 3 additions & 7 deletions tests/test_plugin_linkinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,7 @@ async def handler(url, **kwargs):
event.set()
await asyncio.wait(futures, timeout=0.1)
assert all(f.done() for f in futures)
bot_helper.client.send_line.assert_has_calls([
mock.call('NOTICE #channel :foo'),
])
bot_helper.assert_sent('NOTICE #channel :foo')

async def test_non_blocking_command(self, event_loop, bot_helper, aioresponses):
bot_helper.reset_mock()
Expand Down Expand Up @@ -281,7 +279,5 @@ async def handler(url, **kwargs):
event.set()
await asyncio.wait(futures, timeout=0.1)
assert all(f.done() for f in futures)
bot_helper.client.send_line.assert_has_calls([
mock.call('NOTICE #channel :Error: Content-Type not HTML-ish: '
'application/octet-stream (http://example.com/)'),
])
bot_helper.assert_sent('NOTICE #channel :Error: Content-Type not HTML-ish: '
'application/octet-stream (http://example.com/)')
4 changes: 1 addition & 3 deletions tests/test_plugin_xkcd.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,7 @@ async def test_command(self, bot_helper, num, url, content_type, fixture, expect
_, title, alt = expected
incoming = f":nick!user@host PRIVMSG #channel :!xkcd {num}"
await asyncio.wait(bot_helper.receive(incoming))
_, (outgoing,), _ = bot_helper.client.send_line.mock_calls[-1]
assert title in outgoing
assert alt in outgoing
bot_helper.assert_sent(lambda line: title in line and alt in line)

@pytest.mark.usefixtures("populate_responses")
async def test_integration_error(self, bot_helper):
Expand Down

0 comments on commit 66c451d

Please sign in to comment.