| """Test functions for matchmaking module."""
|
| from unittest.mock import Mock
|
| from lib.matchmaking import game_category, Matchmaking
|
| from lib.config import Configuration
|
| from lib.timer import Timer, seconds
|
| from lib.lichess_types import UserProfileType
|
|
|
|
|
| def test_game_category_standard_bullet() -> None:
|
| """Test bullet time control with config values."""
|
|
|
|
|
| assert game_category("standard", 60, 1, 0) == "bullet"
|
|
|
|
|
|
|
| assert game_category("standard", 60, 2, 0) == "bullet"
|
|
|
|
|
| def test_game_category_standard_blitz() -> None:
|
| """Test blitz time control with config values."""
|
|
|
|
|
| assert game_category("standard", 180, 1, 0) == "blitz"
|
|
|
|
|
|
|
| assert game_category("standard", 180, 2, 0) == "blitz"
|
|
|
|
|
| def test_game_category_standard_rapid() -> None:
|
| """Test rapid time control."""
|
|
|
|
|
| assert game_category("standard", 600, 5, 0) == "rapid"
|
|
|
|
|
|
|
| assert game_category("standard", 900, 0, 0) == "rapid"
|
|
|
|
|
| def test_game_category_standard_classical() -> None:
|
| """Test classical time control with max config values."""
|
|
|
|
|
| assert game_category("standard", 1800, 20, 0) == "classical"
|
|
|
|
|
|
|
| assert game_category("standard", 1500, 0, 0) == "classical"
|
|
|
|
|
| def test_game_category_correspondence() -> None:
|
| """Test correspondence games with config values."""
|
|
|
| assert game_category("standard", 0, 0, 1) == "correspondence"
|
|
|
|
|
| assert game_category("standard", 0, 0, 2) == "correspondence"
|
|
|
|
|
| assert game_category("standard", 0, 0, 14) == "correspondence"
|
|
|
|
|
| def test_game_category_variants() -> None:
|
| """Test chess variants from config."""
|
| assert game_category("atomic", 60, 1, 0) == "atomic"
|
| assert game_category("chess960", 180, 2, 0) == "chess960"
|
| assert game_category("crazyhouse", 600, 5, 0) == "crazyhouse"
|
| assert game_category("horde", 60, 0, 0) == "horde"
|
| assert game_category("kingOfTheHill", 180, 1, 0) == "kingOfTheHill"
|
| assert game_category("racingKings", 600, 0, 0) == "racingKings"
|
| assert game_category("threeCheck", 60, 1, 0) == "threeCheck"
|
| assert game_category("antichess", 180, 2, 0) == "antichess"
|
|
|
|
|
| def test_game_category_time_boundaries() -> None:
|
| """Test edge cases at time control boundaries."""
|
|
|
|
|
| assert game_category("standard", 179, 0, 0) == "blitz"
|
|
|
|
|
| assert game_category("standard", 178, 0, 0) == "bullet"
|
|
|
|
|
| assert game_category("standard", 479, 0, 0) == "rapid"
|
|
|
|
|
| assert game_category("standard", 478, 0, 0) == "blitz"
|
|
|
|
|
| assert game_category("standard", 1499, 0, 0) == "classical"
|
|
|
|
|
| assert game_category("standard", 1498, 0, 0) == "rapid"
|
|
|
|
|
| def test_game_category_min_config_values() -> None:
|
| """Test minimum config values."""
|
|
|
|
|
| assert game_category("standard", 0, 0, 0) == "bullet"
|
|
|
|
|
| assert game_category("standard", 0, 0, 1) == "correspondence"
|
|
|
|
|
| def test_game_category_correspondence_overrides_time() -> None:
|
| """Test that correspondence takes precedence over time controls."""
|
|
|
| assert game_category("standard", 1800, 20, 1) == "correspondence"
|
| assert game_category("standard", 60, 1, 2) == "correspondence"
|
|
|
|
|
| def test_game_category_variant_overrides_time() -> None:
|
| """Test that variants override time control categorization."""
|
|
|
|
|
| assert game_category("atomic", 1800, 20, 0) == "atomic"
|
| assert game_category("horde", 60, 1, 0) == "horde"
|
|
|
|
|
| assert game_category("chess960", 0, 0, 14) == "chess960"
|
|
|
|
|
| def test_game_category_negative_values() -> None:
|
| """Test edge case with negative values (should not happen in practice)."""
|
|
|
| assert game_category("standard", -100, 5, 0) == "bullet"
|
|
|
|
|
| result = game_category("standard", 100, -10, 0)
|
|
|
| assert result == "bullet"
|
|
|
|
|
| def test_game_category_realistic_scenarios() -> None:
|
| """Test realistic game scenarios from actual lichess games."""
|
|
|
| assert game_category("standard", 60, 0, 0) == "bullet"
|
|
|
|
|
| assert game_category("standard", 120, 1, 0) == "bullet"
|
|
|
|
|
| assert game_category("standard", 180, 0, 0) == "blitz"
|
|
|
|
|
| assert game_category("standard", 180, 2, 0) == "blitz"
|
|
|
|
|
| assert game_category("standard", 300, 0, 0) == "blitz"
|
|
|
|
|
| assert game_category("standard", 300, 3, 0) == "blitz"
|
|
|
|
|
| assert game_category("standard", 600, 0, 0) == "rapid"
|
|
|
|
|
| assert game_category("standard", 900, 5, 0) == "rapid"
|
|
|
|
|
| assert game_category("standard", 900, 10, 0) == "rapid"
|
|
|
|
|
| assert game_category("standard", 1800, 0, 0) == "classical"
|
|
|
|
|
| assert game_category("standard", 1800, 20, 0) == "classical"
|
|
|
|
|
| def test_get_random_config_value__returns_specific_value() -> None:
|
| """Test that get_random_config_value returns the config value when it's not 'random'."""
|
|
|
| mock_li = Mock()
|
| mock_config = Configuration({
|
| "challenge": {"variants": ["standard"]},
|
| "matchmaking": {
|
| "allow_matchmaking": False,
|
| "block_list": [],
|
| "online_block_list": [],
|
| "challenge_timeout": 30
|
| }
|
| })
|
| mock_user_profile: UserProfileType = {"username": "testbot", "perfs": {}}
|
|
|
|
|
| matchmaking = Matchmaking(mock_li, mock_config, mock_user_profile)
|
|
|
|
|
| test_config = Configuration({"challenge_variant": "atomic"})
|
|
|
|
|
| choices = ["standard", "chess960", "atomic", "horde"]
|
| result = matchmaking.get_random_config_value(test_config, "challenge_variant", choices)
|
|
|
| assert result == "atomic", f"Expected 'atomic' but got '{result}'"
|
|
|
|
|
| def test_should_create_challenge_respects_rate_limit_when_previous_challenge_expired() -> None:
|
| """An expired previous challenge should not bypass the challenge rate-limit timer."""
|
| mock_li = Mock()
|
| mock_config = Configuration({
|
| "challenge": {"variants": ["standard"]},
|
| "matchmaking": {
|
| "allow_matchmaking": True,
|
| "block_list": [],
|
| "online_block_list": [],
|
| "challenge_timeout": 0
|
| }
|
| })
|
| mock_user_profile: UserProfileType = {"username": "testbot", "perfs": {}}
|
| matchmaking = Matchmaking(mock_li, mock_config, mock_user_profile)
|
| matchmaking.challenge_id = "challenge-id"
|
| matchmaking.last_challenge_created_delay.starting_time -= 100
|
| matchmaking.rate_limit_timer = Timer(seconds(60))
|
|
|
| assert matchmaking.should_create_challenge() is False
|
|
|
|
|
| def test_get_random_config_value__returns_from_choices_when_random() -> None:
|
| """Test that get_random_config_value returns a value from choices when config value is 'random'."""
|
|
|
| mock_li = Mock()
|
| mock_config = Configuration({
|
| "challenge": {"variants": ["standard"]},
|
| "matchmaking": {
|
| "allow_matchmaking": False,
|
| "block_list": [],
|
| "online_block_list": [],
|
| "challenge_timeout": 30
|
| }
|
| })
|
| mock_user_profile: UserProfileType = {"username": "testbot", "perfs": {}}
|
|
|
|
|
| matchmaking = Matchmaking(mock_li, mock_config, mock_user_profile)
|
|
|
|
|
| test_config = Configuration({"challenge_mode": "random"})
|
|
|
|
|
| choices = ["casual", "rated"]
|
| result = matchmaking.get_random_config_value(test_config, "challenge_mode", choices)
|
|
|
| assert result in choices, f"Expected result to be in {choices} but got '{result}'"
|
|
|