poker-ranking-service/tests/test_rank.py

443 lines
12 KiB
Python

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}