2024-08-09 23:14:42 +01:00
|
|
|
"""
|
|
|
|
Test functions for Matchy
|
|
|
|
"""
|
|
|
|
import discord
|
|
|
|
import pytest
|
2024-08-10 09:44:22 +01:00
|
|
|
import matching
|
2024-08-10 15:12:14 +01:00
|
|
|
import history
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
|
|
|
|
|
|
|
|
def test_protocols():
|
|
|
|
"""Verify the protocols we're using match the discord ones"""
|
|
|
|
assert isinstance(discord.Member, matching.Member)
|
|
|
|
assert isinstance(discord.Guild, matching.Guild)
|
|
|
|
assert isinstance(discord.Role, matching.Role)
|
|
|
|
|
|
|
|
|
|
|
|
class TestMember():
|
|
|
|
def __init__(self, id: int):
|
|
|
|
self._id = id
|
|
|
|
|
|
|
|
@property
|
|
|
|
def mention(self) -> str:
|
|
|
|
return f"<@{self._id}>"
|
|
|
|
|
|
|
|
@property
|
|
|
|
def id(self) -> int:
|
|
|
|
return self._id
|
|
|
|
|
|
|
|
@id.setter
|
|
|
|
def id(self, value):
|
|
|
|
self._id = value
|
2024-08-09 23:14:42 +01:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("matchees, per_group", [
|
2024-08-10 15:12:14 +01:00
|
|
|
# Simplest test possible
|
|
|
|
([TestMember(1)], 1),
|
|
|
|
|
|
|
|
# More requested than we have
|
|
|
|
([TestMember(1)], 2),
|
|
|
|
|
|
|
|
# A selection of hyper-simple checks to validate core functionality
|
|
|
|
([TestMember(1)] * 100, 3),
|
|
|
|
([TestMember(1)] * 12, 5),
|
|
|
|
([TestMember(1)] * 11, 2),
|
|
|
|
([TestMember(1)] * 356, 8),
|
|
|
|
])
|
|
|
|
def test_matchees_to_groups_no_history(matchees, per_group):
|
|
|
|
"""Test simple group matching works"""
|
|
|
|
hist = history.History()
|
|
|
|
core_validate_members_to_groups(matchees, hist, per_group)
|
|
|
|
|
|
|
|
|
|
|
|
def items_found_in_lists(list_of_lists, items):
|
|
|
|
"""validates if any sets of items are found in individual lists"""
|
|
|
|
for sublist in list_of_lists:
|
|
|
|
if all(item in sublist for item in items):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("history_data, matchees, per_group, checks", [
|
|
|
|
# Slightly more difficult test
|
|
|
|
# Describe a history where we previously matched up some people and ensure they don't get rematched
|
|
|
|
(
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"ts": datetime.now() - timedelta(days=1),
|
|
|
|
"groups": [
|
|
|
|
[TestMember(1), TestMember(2)],
|
|
|
|
[TestMember(3), TestMember(4)],
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
[
|
|
|
|
TestMember(1),
|
|
|
|
TestMember(2),
|
|
|
|
TestMember(3),
|
|
|
|
TestMember(4),
|
|
|
|
],
|
|
|
|
2,
|
|
|
|
[
|
|
|
|
lambda groups: not items_found_in_lists(
|
|
|
|
groups, [TestMember(1), TestMember(2)]),
|
|
|
|
lambda groups: not items_found_in_lists(
|
|
|
|
groups, [TestMember(3), TestMember(4)])
|
|
|
|
]
|
|
|
|
),
|
|
|
|
# Feed the system an "impossible" test
|
|
|
|
# The function should fall back to ignoring history and still give us something
|
|
|
|
(
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"ts": datetime.now() - timedelta(days=1),
|
|
|
|
"groups": [
|
|
|
|
[TestMember(1), TestMember(2), TestMember(3)],
|
|
|
|
[TestMember(4), TestMember(5), TestMember(6)],
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
[
|
|
|
|
TestMember(1),
|
|
|
|
TestMember(2),
|
|
|
|
TestMember(3),
|
|
|
|
TestMember(4),
|
|
|
|
TestMember(5),
|
|
|
|
TestMember(6),
|
|
|
|
],
|
|
|
|
3,
|
|
|
|
[
|
|
|
|
# Nothing specific to validate
|
|
|
|
]
|
|
|
|
),
|
|
|
|
|
2024-08-09 23:14:42 +01:00
|
|
|
])
|
2024-08-10 15:12:14 +01:00
|
|
|
def test_matchees_to_groups_with_history(history_data, matchees, per_group, checks):
|
2024-08-09 23:14:42 +01:00
|
|
|
"""Test simple group matching works"""
|
2024-08-10 15:12:14 +01:00
|
|
|
hist = history.History()
|
|
|
|
|
|
|
|
# Replay the history
|
|
|
|
for d in history_data:
|
|
|
|
hist.log_groups_to_history(d["groups"], d["ts"])
|
|
|
|
|
|
|
|
groups = core_validate_members_to_groups(matchees, hist, per_group)
|
|
|
|
|
|
|
|
# Run the custom validate functions
|
|
|
|
for check in checks:
|
|
|
|
assert check(groups)
|
|
|
|
|
|
|
|
|
|
|
|
def core_validate_members_to_groups(matchees: list[TestMember], hist: history.History, per_group: int):
|
|
|
|
# Convert members to groups
|
|
|
|
groups = matching.members_to_groups(matchees, hist, per_group)
|
|
|
|
|
|
|
|
# We should always have one group
|
|
|
|
assert len(groups)
|
|
|
|
|
|
|
|
# Log the groups to history
|
|
|
|
# This will validate the internals
|
|
|
|
hist.log_groups_to_history(groups)
|
|
|
|
|
|
|
|
# Ensure each group contains within the bounds of expected members
|
2024-08-09 23:14:42 +01:00
|
|
|
for group in groups:
|
2024-08-10 15:12:14 +01:00
|
|
|
if len(matchees) >= per_group:
|
|
|
|
assert len(group) >= per_group
|
|
|
|
else:
|
|
|
|
assert len(group) == len(matchees)
|
|
|
|
assert len(group) < per_group*2 # TODO: We could be more strict here
|
|
|
|
|
|
|
|
return groups
|