227 lines
7.3 KiB
Python
227 lines
7.3 KiB
Python
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from django.contrib.auth import get_user_model
|
|
|
|
from boardgames.models import BoardGame, BoardGameVariant
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_board_game_variant_creation():
|
|
game = BoardGame.objects.create(title="Test Game")
|
|
variant = BoardGameVariant.objects.create(
|
|
name="Test Variant",
|
|
board_game=game,
|
|
description="A test variant",
|
|
)
|
|
assert variant.name == "Test Variant"
|
|
assert variant.board_game == game
|
|
assert variant.description == "A test variant"
|
|
assert variant.uuid is not None
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_board_game_variant_str():
|
|
game = BoardGame.objects.create(title="Test Game")
|
|
variant = BoardGameVariant.objects.create(
|
|
name="Test Variant",
|
|
board_game=game,
|
|
)
|
|
assert str(variant) == "Test Variant (Test Game)"
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_board_game_variant_optional_description():
|
|
game = BoardGame.objects.create(title="Test Game")
|
|
variant = BoardGameVariant.objects.create(
|
|
name="Test Variant",
|
|
board_game=game,
|
|
)
|
|
assert variant.description is None
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_board_game_variant_related_name():
|
|
game = BoardGame.objects.create(title="Test Game")
|
|
variant1 = BoardGameVariant.objects.create(
|
|
name="Variant 1",
|
|
board_game=game,
|
|
)
|
|
variant2 = BoardGameVariant.objects.create(
|
|
name="Variant 2",
|
|
board_game=game,
|
|
)
|
|
assert list(game.variants.all()) == [variant1, variant2]
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_board_game_variant_cascade_delete():
|
|
game = BoardGame.objects.create(title="Test Game")
|
|
variant = BoardGameVariant.objects.create(
|
|
name="Test Variant",
|
|
board_game=game,
|
|
)
|
|
game.delete()
|
|
assert BoardGameVariant.objects.count() == 0
|
|
|
|
|
|
def _mock_bgg_game(bggeek_id, title, expansions=None):
|
|
"""Build a fake BGG game object shape used by lookup_boardgame_from_bgg."""
|
|
class FakeGame:
|
|
id = bggeek_id
|
|
name = title
|
|
description = f"Description of {title}"
|
|
yearpublished = 2020
|
|
image = "https://example.com/cover.jpg"
|
|
minplayers = 1
|
|
maxplayers = 4
|
|
minage = 8
|
|
rating_average = 7.5
|
|
bgg_rank = 100
|
|
playingtime = 60
|
|
mechanics = []
|
|
categories = []
|
|
families = []
|
|
designers = []
|
|
publishers = []
|
|
|
|
@property
|
|
def expansions(self):
|
|
if expansions is None:
|
|
return []
|
|
return expansions
|
|
|
|
return FakeGame()
|
|
|
|
|
|
def _mock_bgg_client(return_game):
|
|
"""Return a callable that creates a fake BGGClient instance."""
|
|
class FakeBGGClient:
|
|
def __init__(self, access_token=None):
|
|
pass
|
|
|
|
def game(self, game_id=None, name=None):
|
|
return return_game
|
|
|
|
return FakeBGGClient()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("boardgames.models.requests.get")
|
|
@patch("boardgames.sources.bgg.BGGClient")
|
|
def test_find_or_create_links_expansions(mock_bgg, mock_get):
|
|
exp1 = type("Thing", (), {"id": 200, "name": "Expansion 1"})()
|
|
exp2 = type("Thing", (), {"id": 201, "name": "Expansion 2"})()
|
|
base_game = _mock_bgg_game("100", "Base Game", expansions=[exp1, exp2])
|
|
exp1_game = _mock_bgg_game("200", "Expansion 1")
|
|
exp2_game = _mock_bgg_game("201", "Expansion 2")
|
|
mock_bgg.side_effect = [
|
|
_mock_bgg_client(base_game),
|
|
_mock_bgg_client(exp1_game),
|
|
_mock_bgg_client(exp2_game),
|
|
]
|
|
mock_get.return_value.status_code = 200
|
|
mock_get.return_value.content = b"fake_image_data"
|
|
|
|
game = BoardGame.find_or_create("100")
|
|
assert game.title == "Base Game"
|
|
|
|
expansions = BoardGame.objects.filter(expansion_for_boardgame=game)
|
|
assert expansions.count() == 2
|
|
assert {e.title for e in expansions} == {"Expansion 1", "Expansion 2"}
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("boardgames.sources.bgg.BGGClient")
|
|
def test_find_or_create_skips_expansions_for_existing_game(mock_bgg):
|
|
game = BoardGame.objects.create(title="Base Game", bggeek_id="100")
|
|
mock_bgg.assert_not_called()
|
|
|
|
result = BoardGame.find_or_create("100")
|
|
assert result == game
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("boardgames.models.requests.get")
|
|
@patch("boardgames.sources.bgg.BGGClient")
|
|
def test_fetch_and_link_expansions(mock_bgg, mock_get):
|
|
game = BoardGame.objects.create(title="Base Game", bggeek_id="100")
|
|
exp_game = _mock_bgg_game("200", "Expansion 1")
|
|
mock_bgg.side_effect = [_mock_bgg_client(exp_game)]
|
|
mock_get.return_value.status_code = 200
|
|
mock_get.return_value.content = b"fake_image_data"
|
|
|
|
from boardgames.utils import fetch_and_link_expansions
|
|
|
|
fetch_and_link_expansions(game, [{"id": 200, "name": "Expansion 1"}])
|
|
|
|
expansion = BoardGame.objects.get(bggeek_id="200")
|
|
assert expansion.expansion_for_boardgame == game
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("boardgames.models.requests.get")
|
|
@patch("boardgames.sources.bgg.BGGClient")
|
|
def test_fix_metadata_links_expansions(mock_bgg, mock_get):
|
|
game = BoardGame.objects.create(title="Base Game", bggeek_id="100")
|
|
exp_thing = type("Thing", (), {"id": 200, "name": "Expansion 1"})()
|
|
base_with_exp = _mock_bgg_game("100", "Base Game", expansions=[exp_thing])
|
|
exp_game = _mock_bgg_game("200", "Expansion 1")
|
|
# first call = fix_metadata -> lookup_boardgame_from_bgg(lookup_id='100')
|
|
# second call = find_or_create inside fetch_and_link_expansions for expansion
|
|
mock_bgg.side_effect = [
|
|
_mock_bgg_client(base_with_exp),
|
|
_mock_bgg_client(exp_game),
|
|
]
|
|
mock_get.return_value.status_code = 200
|
|
mock_get.return_value.content = b"fake_image_data"
|
|
|
|
game.fix_metadata(force_update=True)
|
|
|
|
expansion = BoardGame.objects.get(bggeek_id="200")
|
|
assert expansion.expansion_for_boardgame == game
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("boardgames.sources.bgg.BGGClient")
|
|
def test_management_command_fetch_expansions_dry_run(mock_bgg, capsys):
|
|
from django.core.management import call_command
|
|
|
|
game = BoardGame.objects.create(title="Base Game", bggeek_id="100")
|
|
exp_thing = type("Thing", (), {"id": 200, "name": "Expansion 1"})()
|
|
base_with_exp = _mock_bgg_game("100", "Base Game", expansions=[exp_thing])
|
|
mock_bgg.side_effect = [_mock_bgg_client(base_with_exp)]
|
|
|
|
call_command("fetch_expansions")
|
|
captured = capsys.readouterr()
|
|
assert "Would link 1 expansions" in captured.out
|
|
|
|
assert BoardGame.objects.filter(bggeek_id="200").count() == 0
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("boardgames.models.requests.get")
|
|
@patch("boardgames.sources.bgg.BGGClient")
|
|
def test_management_command_fetch_expansions_commit(mock_bgg, mock_get, capsys):
|
|
from django.core.management import call_command
|
|
|
|
game = BoardGame.objects.create(title="Base Game", bggeek_id="100")
|
|
exp_thing = type("Thing", (), {"id": 200, "name": "Expansion 1"})()
|
|
exp_game = _mock_bgg_game("200", "Expansion 1")
|
|
base_with_exp = _mock_bgg_game("100", "Base Game", expansions=[exp_thing])
|
|
mock_bgg.side_effect = [
|
|
_mock_bgg_client(base_with_exp),
|
|
_mock_bgg_client(exp_game),
|
|
]
|
|
mock_get.return_value.status_code = 200
|
|
mock_get.return_value.content = b"fake_image_data"
|
|
|
|
call_command("fetch_expansions", commit=True)
|
|
captured = capsys.readouterr()
|
|
assert "Updated 1 games" in captured.out
|
|
|
|
expansion = BoardGame.objects.get(bggeek_id="200")
|
|
assert expansion.expansion_for_boardgame == game
|