vibe-praying/test_pairing.py

234 lines
9.2 KiB
Python

#!/usr/bin/env python3
"""
Unit tests for the pairing algorithm using pytest
"""
import pytest
import random
from app import create_pairs
class TestPairingAlgorithm:
"""Test class for the pairing algorithm"""
def test_minimum_names_requirement(self):
"""Test that at least 3 names are required"""
with pytest.raises(ValueError, match="Need at least 3 names"):
create_pairs([])
with pytest.raises(ValueError, match="Need at least 3 names"):
create_pairs(["Alice"])
with pytest.raises(ValueError, match="Need at least 3 names"):
create_pairs(["Alice", "Bob"])
def test_basic_pairing_4_people(self):
"""Test pairing with 4 people"""
names = ["Alice", "Bob", "Charlie", "Diana"]
pairs = create_pairs(names)
# Should have exactly 4 pairs (4 people * 2 pairs each / 2 = 4 total pairs)
assert len(pairs) == 4
# Each person should have exactly 2 pairs
person_pair_counts = self._count_pairs_per_person(pairs)
for person in names:
assert person_pair_counts[person] == 2, f"{person} has {person_pair_counts[person]} pairs, expected 2"
# No duplicate pairs
self._assert_no_duplicate_pairs(pairs)
def test_pairing_5_people(self):
"""Test pairing with 5 people"""
names = ["Alice", "Bob", "Charlie", "Diana", "Eve"]
pairs = create_pairs(names)
# Should have exactly 5 pairs
assert len(pairs) == 5
# Each person should have exactly 2 pairs
person_pair_counts = self._count_pairs_per_person(pairs)
for person in names:
assert person_pair_counts[person] == 2, f"{person} has {person_pair_counts[person]} pairs, expected 2"
# No duplicate pairs
self._assert_no_duplicate_pairs(pairs)
def test_pairing_6_people(self):
"""Test pairing with 6 people"""
names = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank"]
pairs = create_pairs(names)
# Should have exactly 6 pairs
assert len(pairs) == 6
# Each person should have exactly 2 pairs
person_pair_counts = self._count_pairs_per_person(pairs)
for person in names:
assert person_pair_counts[person] == 2, f"{person} has {person_pair_counts[person]} pairs, expected 2"
# No duplicate pairs
self._assert_no_duplicate_pairs(pairs)
def test_pairing_7_people(self):
"""Test pairing with 7 people"""
names = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace"]
pairs = create_pairs(names)
# Should have exactly 7 pairs
assert len(pairs) == 7
# Each person should have exactly 2 pairs
person_pair_counts = self._count_pairs_per_person(pairs)
for person in names:
assert person_pair_counts[person] == 2, f"{person} has {person_pair_counts[person]} pairs, expected 2"
# No duplicate pairs
self._assert_no_duplicate_pairs(pairs)
def test_no_self_pairing(self):
"""Test that no person is paired with themselves"""
names = ["Alice", "Bob", "Charlie", "Diana"]
pairs = create_pairs(names)
for pair in pairs:
assert pair["person1"] != pair["person2"], f"Self-pairing found: {pair}"
def test_pair_structure(self):
"""Test that pairs have the correct structure"""
names = ["Alice", "Bob", "Charlie"]
pairs = create_pairs(names)
for pair in pairs:
assert "person1" in pair, "Pair missing person1 key"
assert "person2" in pair, "Pair missing person2 key"
assert isinstance(pair["person1"], str), "person1 should be a string"
assert isinstance(pair["person2"], str), "person2 should be a string"
def test_randomness(self):
"""Test that the algorithm produces different results on multiple runs"""
names = ["Alice", "Bob", "Charlie", "Diana", "Eve"]
# Run multiple times and collect results
results = []
for _ in range(10):
pairs = create_pairs(names)
# Convert to set of tuples for comparison
pair_set = {(p["person1"], p["person2"]) for p in pairs}
results.append(pair_set)
# Check that we get at least 2 different results (indicating randomness)
unique_results = set()
for result in results:
unique_results.add(tuple(sorted(result)))
assert len(unique_results) >= 2, "Algorithm doesn't seem to be random"
def test_edge_case_odd_number(self):
"""Test with odd number of people"""
names = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace"]
pairs = create_pairs(names)
# Should have exactly 7 pairs
assert len(pairs) == 7
# Each person should have exactly 2 pairs
person_pair_counts = self._count_pairs_per_person(pairs)
for person in names:
assert person_pair_counts[person] == 2, f"{person} has {person_pair_counts[person]} pairs, expected 2"
def test_edge_case_even_number(self):
"""Test with even number of people"""
names = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank"]
pairs = create_pairs(names)
# Should have exactly 6 pairs
assert len(pairs) == 6
# Each person should have exactly 2 pairs
person_pair_counts = self._count_pairs_per_person(pairs)
for person in names:
assert person_pair_counts[person] == 2, f"{person} has {person_pair_counts[person]} pairs, expected 2"
def test_large_group(self):
"""Test with a larger group"""
names = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace", "Henry", "Ivy", "Jack"]
pairs = create_pairs(names)
# Should have exactly 10 pairs
assert len(pairs) == 10
# Each person should have exactly 2 pairs
person_pair_counts = self._count_pairs_per_person(pairs)
for person in names:
assert person_pair_counts[person] == 2, f"{person} has {person_pair_counts[person]} pairs, expected 2"
# No duplicate pairs
self._assert_no_duplicate_pairs(pairs)
def test_special_characters_in_names(self):
"""Test with names containing special characters"""
names = ["José", "Mary-Jane", "O'Connor", "李小明"]
pairs = create_pairs(names)
# Should have exactly 4 pairs
assert len(pairs) == 4
# Each person should have exactly 2 pairs
person_pair_counts = self._count_pairs_per_person(pairs)
for person in names:
assert person_pair_counts[person] == 2, f"{person} has {person_pair_counts[person]} pairs, expected 2"
def _count_pairs_per_person(self, pairs):
"""Helper method to count how many pairs each person has"""
person_pair_counts = {}
for pair in pairs:
person1, person2 = pair["person1"], pair["person2"]
person_pair_counts[person1] = person_pair_counts.get(person1, 0) + 1
person_pair_counts[person2] = person_pair_counts.get(person2, 0) + 1
return person_pair_counts
def _assert_no_duplicate_pairs(self, pairs):
"""Helper method to assert no duplicate pairs exist"""
pair_strings = set()
for pair in pairs:
pair_str = f"{pair['person1']}-{pair['person2']}"
reverse_str = f"{pair['person2']}-{pair['person1']}"
assert pair_str not in pair_strings, f"Duplicate pair found: {pair}"
assert reverse_str not in pair_strings, f"Duplicate pair found (reverse): {pair}"
pair_strings.add(pair_str)
class TestPairingProperties:
"""Test class for mathematical properties of pairing"""
def test_total_pairs_formula(self):
"""Test that total pairs = number of people"""
for n in range(3, 11): # Test with 3 to 10 people
names = [f"Person{i}" for i in range(n)]
pairs = create_pairs(names)
# Total pairs should equal number of people
assert len(pairs) == n, f"Expected {n} pairs for {n} people, got {len(pairs)}"
def test_each_person_has_exactly_two_pairs(self):
"""Test that each person has exactly 2 pairs"""
for n in range(3, 11): # Test with 3 to 10 people
names = [f"Person{i}" for i in range(n)]
pairs = create_pairs(names)
person_pair_counts = {}
for pair in pairs:
person1, person2 = pair["person1"], pair["person2"]
person_pair_counts[person1] = person_pair_counts.get(person1, 0) + 1
person_pair_counts[person2] = person_pair_counts.get(person2, 0) + 1
for person in names:
assert person_pair_counts[person] == 2, f"{person} has {person_pair_counts[person]} pairs, expected 2"
if __name__ == "__main__":
# Run tests with pytest
pytest.main([__file__, "-v"])