"""
Pytest configuration and fixtures for the City Builder test suite.
This provides clean test isolation by resetting the server state before each test.
"""
import pytest
import asyncio
import tempfile
import os
import time
from pathlib import Path
# Import server components
from server.main import initialize_components, game_state, ws_manager, economy_engine, database
from server.game_state import GameState
from server.economy import EconomyEngine
from server.database import Database
@pytest.fixture(scope="function")
async def fresh_server_state():
"""
Fixture that provides fresh server state for each test.
This resets the global server components with a clean test database.
"""
# Create temporary database for this test
temp_fd, temp_db_path = tempfile.mkstemp(suffix=".db")
os.close(temp_fd)
try:
# Initialize server components with test database
test_game_state, test_ws_manager, test_economy_engine, test_database = initialize_components(temp_db_path)
# Initialize the test database
test_database.init_db()
# Yield the components for the test
yield {
'game_state': test_game_state,
'ws_manager': test_ws_manager,
'economy_engine': test_economy_engine,
'database': test_database,
'db_path': temp_db_path
}
finally:
# Clean up temporary database
if os.path.exists(temp_db_path):
os.unlink(temp_db_path)
@pytest.fixture(scope="function")
def isolated_game_components():
"""
Fixture providing completely isolated game components for unit tests.
These are separate from the server's global state.
"""
# Create temporary database for this test
temp_fd, temp_db_path = tempfile.mkstemp(suffix=".db")
os.close(temp_fd)
try:
# Create fresh, isolated components
game_state = GameState()
economy_engine = EconomyEngine(game_state)
database = Database(temp_db_path)
database.init_db()
yield game_state, economy_engine, database
finally:
# Clean up temporary database
if os.path.exists(temp_db_path):
os.unlink(temp_db_path)
@pytest.fixture(scope="function")
def unique_coordinates():
"""
Fixture that provides unique coordinates for each test to avoid conflicts.
Uses timestamp-based coordinates to ensure uniqueness.
"""
base_time = int(time.time() * 1000) % 10000 # Get last 4 digits of timestamp
def get_coords(offset=0):
"""Get unique coordinates with optional offset"""
x = (base_time + offset) % 100
y = (base_time + offset * 2) % 100
return x, y
return get_coords
# Configure asyncio mode for all tests
pytest_plugins = ('pytest_asyncio',)