poker-ranking-service/tests/test_rank.py

443 lines
12 KiB
Python
Raw Permalink Normal View History

from itertools import cycle
from typing import Optional, Union
import pytest
from poker.constants import Suit, Value
from poker.models import Card, Hand
from poker.rank.hands import (
_is_flush,
_is_straight,
flush,
four_of_a_kind,
full_house,
high_card,
pair,
royal_flush,
straight,
straight_flush,
three_of_a_kind,
two_pair,
)
from tests.conftest import Factory
@pytest.mark.parametrize(
"suits,expected",
[
([Suit.CLUBS, Suit.DIAMONDS, Suit.SPADES, Suit.HEARTS, Suit.CLUBS], False),
([Suit.CLUBS, Suit.CLUBS, Suit.CLUBS, Suit.CLUBS, Suit.CLUBS], True),
],
ids=[
"non-unique",
"unique",
],
)
def test__is_flush(
card_factory: Factory[Card], suits: list[Suit], expected: dict[str, Union[str, int]]
) -> None:
result = _is_flush([card_factory(suit=suit) for suit in suits])
if expected:
assert result
else:
assert not result
@pytest.mark.parametrize(
"values,expected",
[
([Value.TWO, Value.TWO, Value.THREE, Value.FOUR, Value.FIVE], None),
([Value.THREE, Value.TWO, Value.ACE, Value.TEN, Value.KING], None),
([Value.ACE, Value.TWO, Value.THREE, Value.FOUR, Value.FIVE], Value.FIVE),
([Value.ACE, Value.KING, Value.TEN, Value.JACK, Value.QUEEN], Value.ACE),
([Value.THREE, Value.FIVE, Value.TWO, Value.FOUR, Value.SIX], Value.SIX),
],
ids=[
"non-unique",
"not-flush",
"low-ace",
"high-ace",
"middle-flush",
],
)
def test__is_straight(
card_factory: Factory[Card], values: list[Value], expected: Optional[Value]
) -> None:
suits = cycle(Suit)
result = _is_straight(
[card_factory(suit=suit, value=value) for suit, value in zip(suits, values)]
)
assert result == expected
@pytest.mark.parametrize(
"values,different_suits,expected",
[
([Value.TWO, Value.TEN, Value.THREE, Value.FOUR, Value.FIVE], False, {}),
(
[Value.ACE, Value.KING, Value.TEN, Value.JACK, Value.QUEEN],
False,
{"suit": Suit.CLUBS},
),
([Value.ACE, Value.KING, Value.TEN, Value.JACK, Value.QUEEN], True, {}),
],
ids=[
"not-flush",
"royal-flush",
"flush-not-royal",
],
)
def test_is_royal_flush(
card_factory: Factory[Card],
values: list[Value],
different_suits: bool,
expected: dict[str, Union[str, int]],
) -> None:
suits = cycle(Suit)
if different_suits:
result = royal_flush(
Hand(
cards=[
card_factory(suit=suit, value=value)
for suit, value in zip(suits, values)
]
)
)
else:
result = royal_flush(
Hand(cards=[card_factory(value=value) for value in values])
)
assert result == expected
@pytest.mark.parametrize(
"values,different_suits,expected",
[
([Value.TWO, Value.THREE, Value.FOUR, Value.FIVE, Value.SIX], True, {}),
([Value.TWO, Value.THREE, Value.FIVE, Value.SIX, Value.TEN], False, {}),
(
[Value.TWO, Value.THREE, Value.FOUR, Value.FIVE, Value.SIX],
False,
{"high": Value.SIX, "suit": Suit.CLUBS},
),
],
ids=[
"straight-only",
"flush-only",
"straight-flush",
],
)
def test_is_straight_flush(
card_factory: Factory[Card],
values: list[Value],
different_suits: bool,
expected: dict[str, Union[str, int]],
) -> None:
suits = cycle(Suit)
if different_suits:
result = straight_flush(
Hand(
cards=[
card_factory(suit=suit, value=value)
for suit, value in zip(suits, values)
]
)
)
else:
result = straight_flush(
Hand(cards=[card_factory(value=value) for value in values])
)
assert result == expected
@pytest.mark.parametrize(
"cards,expected",
[
(
[
Card(suit=Suit.CLUBS, value=Value.TWO),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.TWO),
Card(suit=Suit.SPADES, value=Value.TWO),
Card(suit=Suit.CLUBS, value=Value.THREE),
],
{"value": Value.TWO},
),
(
[
Card(suit=Suit.CLUBS, value=Value.TEN),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.TWO),
Card(suit=Suit.SPADES, value=Value.TWO),
Card(suit=Suit.CLUBS, value=Value.THREE),
],
{},
),
],
ids=[
"four-of-a-kind",
"not-four-of-a-kind",
],
)
def test_is_four_of_a_kind(
cards: list[Card], expected: dict[str, Union[str, int]]
) -> None:
result = four_of_a_kind(Hand(cards=cards))
assert result == expected
@pytest.mark.parametrize(
"cards,expected",
[
(
[
Card(suit=Suit.CLUBS, value=Value.THREE),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.TWO),
Card(suit=Suit.SPADES, value=Value.TWO),
Card(suit=Suit.SPADES, value=Value.THREE),
],
{"trips": Value.TWO, "pair": Value.THREE},
),
(
[
Card(suit=Suit.CLUBS, value=Value.TWO),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.TWO),
Card(suit=Suit.SPADES, value=Value.TWO),
Card(suit=Suit.CLUBS, value=Value.THREE),
],
{},
),
],
ids=[
"full-house",
"not-full-house",
],
)
def test_is_full_house(cards: list[Card], expected: dict[str, Union[str, int]]) -> None:
result = full_house(Hand(cards=cards))
assert result == expected
@pytest.mark.parametrize(
"values,different_suits,expected",
[
([Value.TWO, Value.THREE, Value.FOUR, Value.FIVE, Value.SIX], True, {}),
(
[Value.TWO, Value.THREE, Value.FIVE, Value.SIX, Value.TEN],
False,
{"suit": Suit.CLUBS},
),
([Value.TWO, Value.THREE, Value.FOUR, Value.FIVE, Value.SIX], False, {}),
],
ids=[
"straight-only",
"flush-only",
"straight-flush",
],
)
def test_is_flush(
card_factory: Factory[Card],
values: list[Value],
different_suits: bool,
expected: dict[str, Union[str, int]],
) -> None:
suits = cycle(Suit)
if different_suits:
result = flush(
Hand(
cards=[
card_factory(suit=suit, value=value)
for suit, value in zip(suits, values)
]
)
)
else:
result = flush(Hand(cards=[card_factory(value=value) for value in values]))
assert result == expected
@pytest.mark.parametrize(
"values,different_suits,expected",
[
(
[Value.TWO, Value.THREE, Value.FOUR, Value.FIVE, Value.SIX],
True,
{"high": Value.SIX},
),
([Value.TWO, Value.THREE, Value.FIVE, Value.SIX, Value.TEN], False, {}),
([Value.TWO, Value.THREE, Value.FOUR, Value.FIVE, Value.SIX], False, {}),
],
ids=[
"straight-only",
"flush-only",
"straight-flush",
],
)
def test_is_straight(
card_factory: Factory[Card],
values: list[Value],
different_suits: bool,
expected: dict[str, Union[str, int]],
) -> None:
suits = cycle(Suit)
if different_suits:
result = straight(
Hand(
cards=[
card_factory(suit=suit, value=value)
for suit, value in zip(suits, values)
]
)
)
else:
result = straight(Hand(cards=[card_factory(value=value) for value in values]))
assert result == expected
@pytest.mark.parametrize(
"cards,expected",
[
(
[
Card(suit=Suit.CLUBS, value=Value.THREE),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.TWO),
Card(suit=Suit.SPADES, value=Value.TWO),
Card(suit=Suit.SPADES, value=Value.THREE),
],
{},
),
(
[
Card(suit=Suit.CLUBS, value=Value.TWO),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.TWO),
Card(suit=Suit.SPADES, value=Value.ACE),
Card(suit=Suit.CLUBS, value=Value.THREE),
],
{"value": Value.TWO},
),
(
[
Card(suit=Suit.CLUBS, value=Value.TWO),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.TEN),
Card(suit=Suit.SPADES, value=Value.ACE),
Card(suit=Suit.CLUBS, value=Value.THREE),
],
{},
),
],
ids=["full-house", "three-of-a-kind", "not-three-of-a-kind"],
)
def test_is_three_of_a_kind(
cards: list[Card], expected: dict[str, Union[str, int]]
) -> None:
result = three_of_a_kind(Hand(cards=cards))
assert result == expected
@pytest.mark.parametrize(
"cards,expected",
[
(
[
Card(suit=Suit.CLUBS, value=Value.TWO),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.TWO),
Card(suit=Suit.SPADES, value=Value.THREE),
Card(suit=Suit.DIAMONDS, value=Value.THREE),
],
{},
),
(
[
Card(suit=Suit.CLUBS, value=Value.TWO),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.ACE),
Card(suit=Suit.SPADES, value=Value.ACE),
Card(suit=Suit.CLUBS, value=Value.THREE),
],
{"high": Value.ACE, "low": Value.TWO},
),
(
[
Card(suit=Suit.CLUBS, value=Value.TWO),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.TWO),
Card(suit=Suit.SPADES, value=Value.ACE),
Card(suit=Suit.CLUBS, value=Value.THREE),
],
{},
),
],
ids=["full-house", "two-pair", "three-of-a-kind"],
)
def test_is_two_pair(cards: list[Card], expected: dict[str, Union[str, int]]) -> None:
result = two_pair(Hand(cards=cards))
assert result == expected
@pytest.mark.parametrize(
"cards,expected",
[
(
[
Card(suit=Suit.CLUBS, value=Value.TWO),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.TWO),
Card(suit=Suit.SPADES, value=Value.THREE),
Card(suit=Suit.DIAMONDS, value=Value.THREE),
],
{},
),
(
[
Card(suit=Suit.CLUBS, value=Value.TWO),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.ACE),
Card(suit=Suit.SPADES, value=Value.ACE),
Card(suit=Suit.CLUBS, value=Value.THREE),
],
{},
),
(
[
Card(suit=Suit.CLUBS, value=Value.TWO),
Card(suit=Suit.DIAMONDS, value=Value.TWO),
Card(suit=Suit.HEARTS, value=Value.KING),
Card(suit=Suit.SPADES, value=Value.ACE),
Card(suit=Suit.CLUBS, value=Value.THREE),
],
{"value": Value.TWO},
),
],
ids=["full-house", "two-pair", "pair"],
)
def test_is_pair(cards: list[Card], expected: dict[str, Union[str, int]]) -> None:
result = pair(Hand(cards=cards))
assert result == expected
def test_high_card(card_factory: Factory[Card]) -> None:
values = [Value.TWO, Value.THREE, Value.FIVE, Value.SIX, Value.TEN]
result = high_card(Hand(cards=[card_factory(value=value) for value in values]))
assert result == {"value": Value.TEN}