diff --git a/crm_5_implementation.py b/crm_5_implementation.py
index 36d5866..37fcfa0 100644
--- a/crm_5_implementation.py
+++ b/crm_5_implementation.py
@@ -1,759 +1,272 @@
-"""
-Tic Tac Toe Game Implementation
+import logging
+from flask import Flask, render_template_string
+from typing import Final
-This module provides a complete implementation of a Tic Tac Toe game
-with HTML, CSS, and JavaScript components. The game supports player
-turns, win detection, and game state persistence.
+# Configure logging for production readiness
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
-Classes:
- TicTacToe: Main game class handling game logic and state management
- GameBoard: Represents the game board and its state
- Player: Represents a player in the game
-
-Functions:
- main: Entry point for running the game
-"""
-
-import json
-import os
-from typing import List, Optional, Tuple, Dict, Any
-from enum import Enum
-from dataclasses import dataclass
-
-
-class PlayerSymbol(Enum):
- """Enumeration for player symbols."""
- X = "X"
- O = "O"
-
-
-class GameStatus(Enum):
- """Enumeration for game status states."""
- PLAYING = "playing"
- X_WINS = "x_wins"
- O_WINS = "o_wins"
- DRAW = "draw"
-
-
-@dataclass
-class Player:
- """Represents a player in the Tic Tac Toe game."""
- symbol: PlayerSymbol
- name: str
-
-
-class GameBoard:
- """Represents the game board and its state."""
-
- def __init__(self, size: int = 3):
- """
- Initialize the game board.
-
- Args:
- size: The size of the board (default 3 for 3x3)
- """
- self.size = size
- self.board: List[List[Optional[PlayerSymbol]]] = [
- [None for _ in range(size)] for _ in range(size)
- ]
-
- def make_move(self, row: int, col: int, symbol: PlayerSymbol) -> bool:
- """
- Make a move on the board.
-
- Args:
- row: Row index (0-based)
- col: Column index (0-based)
- symbol: Player symbol to place
-
- Returns:
- True if move was successful, False otherwise
-
- Raises:
- IndexError: If row or column is out of bounds
- """
- if not (0 <= row < self.size and 0 <= col < self.size):
- raise IndexError("Move coordinates are out of bounds")
-
- if self.board[row][col] is not None:
- return False
-
- self.board[row][col] = symbol
- return True
-
- def get_cell(self, row: int, col: int) -> Optional[PlayerSymbol]:
- """
- Get the symbol at a specific cell.
-
- Args:
- row: Row index (0-based)
- col: Column index (0-based)
-
- Returns:
- The symbol at the cell or None if empty
- """
- return self.board[row][col]
-
- def is_full(self) -> bool:
- """
- Check if the board is completely filled.
-
- Returns:
- True if board is full, False otherwise
- """
- for row in self.board:
- for cell in row:
- if cell is None:
- return False
- return True
-
- def get_empty_cells(self) -> List[Tuple[int, int]]:
- """
- Get list of all empty cells on the board.
-
- Returns:
- List of tuples containing (row, col) of empty cells
- """
- empty_cells = []
- for row in range(self.size):
- for col in range(self.size):
- if self.board[row][col] is None:
- empty_cells.append((row, col))
- return empty_cells
-
- def reset(self) -> None:
- """Reset the board to initial state."""
- self.board = [
- [None for _ in range(self.size)] for _ in range(self.size)
- ]
-
-
-class TicTacToe:
- """Main game class handling game logic and state management."""
-
- def __init__(self, player1: Player, player2: Player, board_size: int = 3):
- """
- Initialize the Tic Tac Toe game.
-
- Args:
- player1: First player
- player2: Second player
- board_size: Size of the game board (default 3)
- """
- self.player1 = player1
- self.player2 = player2
- self.current_player = player1
- self.board = GameBoard(board_size)
- self.status = GameStatus.PLAYING
- self.winner: Optional[Player] = None
- self.move_history: List[Tuple[int, int, PlayerSymbol]] = []
-
- def make_move(self, row: int, col: int) -> bool:
- """
- Make a move for the current player.
-
- Args:
- row: Row index (0-based)
- col: Column index (0-based)
-
- Returns:
- True if move was successful, False otherwise
-
- Raises:
- ValueError: If the game has already ended
- """
- if self.status != GameStatus.PLAYING:
- raise ValueError("Game has already ended")
-
- success = self.board.make_move(row, col, self.current_player.symbol)
-
- if success:
- # Record the move
- self.move_history.append((row, col, self.current_player.symbol))
-
- # Check win condition
- if self._check_win(row, col):
- self.status = GameStatus.X_WINS if self.current_player.symbol == PlayerSymbol.X else GameStatus.O_WINS
- self.winner = self.current_player
- elif self.board.is_full():
- self.status = GameStatus.DRAW
-
- # Switch player
- self.current_player = self.player2 if self.current_player == self.player1 else self.player1
-
- return success
-
- def _check_win(self, row: int, col: int) -> bool:
- """
- Check if the last move resulted in a win.
-
- Args:
- row: Last move row
- col: Last move column
-
- Returns:
- True if the move resulted in a win, False otherwise
- """
- symbol = self.board.get_cell(row, col)
-
- # Check row
- if all(self.board.get_cell(row, c) == symbol for c in range(self.board.size)):
- return True
-
- # Check column
- if all(self.board.get_cell(r, col) == symbol for r in range(self.board.size)):
- return True
-
- # Check diagonals
- if row == col:
- # Main diagonal
- if all(self.board.get_cell(i, i) == symbol for i in range(self.board.size)):
- return True
-
- if row + col == self.board.size - 1:
- # Anti-diagonal
- if all(self.board.get_cell(i, self.board.size - 1 - i) == symbol for i in range(self.board.size)):
- return True
-
- return False
-
- def get_game_state(self) -> Dict[str, Any]:
- """
- Get the current game state.
-
- Returns:
- Dictionary containing game state information
- """
- return {
- "status": self.status.value,
- "current_player_symbol": self.current_player.symbol.value,
- "board": [
- [cell.value if cell else None for cell in row]
- for row in self.board.board
- ],
- "winner": self.winner.symbol.value if self.winner else None,
- "move_history": self.move_history
- }
-
- def reset(self) -> None:
- """Reset the game to initial state."""
- self.board.reset()
- self.status = GameStatus.PLAYING
- self.winner = None
- self.current_player = self.player1
- self.move_history.clear()
-
- def get_winner(self) -> Optional[Player]:
- """
- Get the winner of the game.
-
- Returns:
- The winning player or None if no winner
- """
- return self.winner
-
- def get_current_player(self) -> Player:
- """
- Get the current player.
-
- Returns:
- The current player
- """
- return self.current_player
-
- def get_board(self) -> GameBoard:
- """
- Get the game board.
-
- Returns:
- The game board instance
- """
- return self.board
-
-
-def create_html_template(game_state: Dict[str, Any], game_id: str) -> str:
+class TicTacToeApp:
"""
- Create an HTML template for the Tic Tac Toe game.
+ A production-ready Flask application serving a Tic Tac Toe game.
- Args:
- game_state: Current game state dictionary
- game_id: Unique identifier for the game instance
-
- Returns:
- HTML string representing the game interface
+ This class encapsulates the web server logic and the frontend assets
+ (HTML, CSS, JS) required to run a client-side Tic Tac Toe game
+ following the specific architectural requirements provided.
"""
- # Create basic HTML structure with embedded CSS and JavaScript
- html_content = f"""
-
-
-
-
-
- Tic Tac Toe Game
-
-
-
-
-
Tic Tac Toe
-
Current Player: {game_state['current_player_symbol']}
-
- {"".join([
- f''
- for r in range(3) for c in range(3)
- ])}
-
-
-
-
-
-
-
-
-
-
-"""
-
- return html_content
-
-def save_game_state(game: TicTacToe, file_path: str) -> None:
- """
- Save the current game state to a JSON file.
-
- Args:
- game: The TicTacToe game instance to save
- file_path: Path to the file where game state should be saved
- """
- try:
- game_state = game.get_game_state()
-
- # Ensure directory exists
- os.makedirs(os.path.dirname(file_path), exist_ok=True)
-
- with open(file_path, 'w') as f:
- json.dump(game_state, f, indent=2)
+ # HTML/CSS/JS Content Template
+ # Following Architecture Design: HTML5, CSS3 (Grid/Flexbox), JS (ES6+ Module Pattern, Event Delegation)
+ TEMPLATE: Final[str] = """
+
+
+
+
+
+ CRM-5: Tic Tac Toe
+
+
+
+
+
+
Tic Tac Toe
+
Player X's Turn
- except Exception as e:
- raise IOError(f"Failed to save game state: {str(e)}")
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-def load_game_state(file_path: str) -> Dict[str, Any]:
+
+
+
"""
- Load game state from a JSON file.
-
- Args:
- file_path: Path to the file containing game state
-
- Returns:
- Dictionary containing loaded game state
-
- Raises:
- FileNotFoundError: If the file does not exist
- json.JSONDecodeError: If the file is not valid JSON
- """
- try:
- with open(file_path, 'r') as f:
- return json.load(f)
- except FileNotFoundError:
- raise FileNotFoundError(f"Game state file not found: {file_path}")
- except json.JSONDecodeError:
- raise json.JSONDecodeError("Invalid JSON in game state file", "", 0)
-
-
-def main() -> None:
- """Main function to demonstrate the Tic Tac Toe game."""
- # Create players
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- # Create game instance
- game = TicTacToe(player1, player2)
-
- # Display initial state
- print("Initial Game State:")
- state = game.get_game_state()
- print(json.dumps(state, indent=2))
-
- # Example moves
- try:
- game.make_move(0, 0) # X plays at (0,0)
- game.make_move(1, 1) # O plays at (1,1)
- game.make_move(0, 1) # X plays at (0,1)
- game.make_move(1, 0) # O plays at (1,0)
- game.make_move(0, 2) # X plays at (0,2) - wins
-
- print("\nAfter example moves:")
- state = game.get_game_state()
- print(json.dumps(state, indent=2))
-
- # Save the game state
- save_game_state(game, "games/tic_tac_toe_game.json")
- print("\nGame state saved successfully.")
-
- except Exception as e:
- print(f"Error during game execution: {e}")
-
-
-if __name__ == "__main__":
- main()
-Tic Tac Toe Game Implementation (Clean Version)
-
-Python backend game engine with optional HTML/CSS/JS generation.
-"""
-
-from typing import List, Optional, Dict, Any
-import json
-
-
-# -----------------------------
-# Player
-# -----------------------------
-class Player:
- """Represents a Tic Tac Toe player."""
-
- def __init__(self, symbol: str, name: str):
- if symbol not in ("X", "O"):
- raise ValueError("Symbol must be 'X' or 'O'")
- self.symbol = symbol
- self.name = name
-
-
-# -----------------------------
-# Game Board
-# -----------------------------
-class GameBoard:
- """3x3 Tic Tac Toe board."""
-
- def __init__(self):
- self.size = 3
- self.board = [["" for _ in range(3)] for _ in range(3)]
-
- def get_cell(self, row: int, col: int) -> str:
- self._validate_position(row, col)
- return self.board[row][col]
- def set_cell(self, row: int, col: int, symbol: str) -> None:
- self._validate_position(row, col)
-
- if symbol not in ("X", "O"):
- raise ValueError("Invalid symbol")
-
- if self.board[row][col] != "":
- raise ValueError("Cell already occupied")
-
- self.board[row][col] = symbol
-
- def clear_cell(self, row: int, col: int) -> None:
- self._validate_position(row, col)
- self.board[row][col] = ""
-
- def is_full(self) -> bool:
- return all(cell != "" for row in self.board for cell in row)
-
- def reset(self) -> None:
- self.board = [["" for _ in range(3)] for _ in range(3)]
-
- def to_dict(self) -> List[List[str]]:
- return [row[:] for row in self.board]
-
- def _validate_position(self, row: int, col: int) -> None:
- if not (0 <= row < 3 and 0 <= col < 3):
- raise IndexError("Row and column must be between 0 and 2")
-
-
-# -----------------------------
-# Win Checker
-# -----------------------------
-class WinChecker:
- """Utility class for win checking."""
-
- @staticmethod
- def check_winner(board: GameBoard) -> Optional[str]:
- b = board.board
-
- lines = (
- # rows
- b[0], b[1], b[2],
- # columns
- [b[0][0], b[1][0], b[2][0]],
- [b[0][1], b[1][1], b[2][1]],
- [b[0][2], b[1][2], b[2][2]],
- # diagonals
- [b[0][0], b[1][1], b[2][2]],
- [b[0][2], b[1][1], b[2][0]],
- )
-
- for line in lines:
- if line[0] and line.count(line[0]) == 3:
- return line[0]
-
- return None
-
-
-# -----------------------------
-# Game Engine
-# -----------------------------
-class GameEngine:
- """Main Tic Tac Toe game engine."""
-
- def __init__(self):
- self.players = [
- Player("X", "Player X"),
- Player("O", "Player O"),
- ]
- self.current_player_index = 0
- self.board = GameBoard()
- self.winner: Optional[str] = None
- self.game_over = False
- self.move_history: List[Dict[str, Any]] = []
-
- def current_player(self) -> Player:
- return self.players[self.current_player_index]
-
- def make_move(self, row: int, col: int) -> Dict[str, Any]:
- if self.game_over:
- return {"success": False, "error": "Game is already over"}
+ def __init__(self, host: str = '0.0.0.0', port: int = 5000, debug: bool = False):
+ """
+ Initializes the TicTacToe Server.
+ :param host: Network interface to bind to.
+ :param port: Port to listen on.
+ :param debug: Enable/Disable Flask debug mode.
+ """
+ self.app = Flask(__name__)
+ self.host = host
+ self.port = port
+ self.debug = debug
+ self._setup_routes()
+
+ def _setup_routes(self) -> None:
+ """Configures the Flask application routes."""
+ @self.app.route('/')
+ def index() -> str:
+ """Serves the main game page."""
+ try:
+ return render_template_string(self.TEMPLATE)
+ except Exception as e:
+ logger.error(f"Error rendering template: {e}")
+ return "Internal Server Error", 500
+
+ def run(self) -> None:
+ """Starts the Flask production server."""
try:
- symbol = self.current_player().symbol
- self.board.set_cell(row, col, symbol)
-
- self.move_history.append(
- {"row": row, "col": col, "symbol": symbol}
- )
-
- winner = WinChecker.check_winner(self.board)
- if winner:
- self.winner = winner
- self.game_over = True
- return self._response(f"{winner} wins!")
-
- if self.board.is_full():
- self.game_over = True
- return self._response("Game ended in a draw")
-
- self._switch_player()
- return self._response("Move successful")
-
+ logger.info(f"Starting Tic Tac Toe server on {self.host}:{self.port}")
+ self.app.run(host=self.host, port=self.port, debug=self.debug)
except Exception as e:
- return {"success": False, "error": str(e)}
-
- def undo_move(self) -> bool:
- if not self.move_history or self.game_over:
- return False
-
- last = self.move_history.pop()
- self.board.clear_cell(last["row"], last["col"])
- self._switch_player()
- return True
-
- def reset_game(self) -> None:
- self.board.reset()
- self.current_player_index = 0
- self.winner = None
- self.game_over = False
- self.move_history.clear()
-
- def get_game_state(self) -> Dict[str, Any]:
- return {
- "board": self.board.to_dict(),
- "current_player": self.current_player().name,
- "winner": self.winner,
- "game_over": self.game_over,
- "moves": self.move_history,
- }
-
- def _switch_player(self) -> None:
- self.current_player_index = (self.current_player_index + 1) % 2
-
- def _response(self, message: str) -> Dict[str, Any]:
- return {
- "success": True,
- "message": message,
- "state": self.get_game_state(),
- }
-
-
-# -----------------------------
-# Demo
-# -----------------------------
-def main() -> None:
- game = GameEngine()
- print("Tic Tac Toe started\n")
-
- print(json.dumps(game.make_move(0, 0), indent=2))
- print(json.dumps(game.make_move(1, 1), indent=2))
- print(json.dumps(game.make_move(0, 1), indent=2))
- print(json.dumps(game.make_move(2, 2), indent=2))
- print(json.dumps(game.make_move(0, 2), indent=2)) # X wins
-
+ logger.critical(f"Failed to start server: {e}")
if __name__ == "__main__":
- main()
+ # Production configuration
+ game_server = TicTacToeApp(
+ host='127.0.0.1',
+ port=8080,
+ debug=False
+ )
+ game_server.run()
\ No newline at end of file
diff --git a/test_crm_5_implementation.py b/test_crm_5_implementation.py
index 97d1bc5..ac32ef0 100644
--- a/test_crm_5_implementation.py
+++ b/test_crm_5_implementation.py
@@ -1,769 +1,157 @@
import pytest
from unittest.mock import patch, MagicMock
-import os
-import json
-
-from crm_5_implementation import (
- PlayerSymbol,
- GameStatus,
- Player,
- GameBoard,
- TicTacToe,
- create_html_template,
- save_game_state,
- load_game_state
-)
-
-
-class TestPlayerSymbol:
- """Test PlayerSymbol enumeration."""
-
- def test_player_symbol_values(self):
- """Test that PlayerSymbol has correct values."""
- assert PlayerSymbol.X.value == "X"
- assert PlayerSymbol.O.value == "O"
-
-
-class TestPlayer:
- """Test Player class."""
-
- def test_player_creation(self):
- """Test Player creation with valid parameters."""
- player = Player(PlayerSymbol.X, "Test Player")
- assert player.symbol == PlayerSymbol.X
- assert player.name == "Test Player"
-
- def test_player_equality(self):
- """Test Player equality comparison."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.X, "Player X")
- player3 = Player(PlayerSymbol.O, "Player O")
-
- assert player1 == player2
- assert player1 != player3
-
-
-class TestGameBoard:
- """Test GameBoard class."""
-
- def test_board_initialization(self):
- """Test board initialization with default size."""
- board = GameBoard()
- assert board.size == 3
- assert len(board.board) == 3
- assert all(len(row) == 3 for row in board.board)
- assert all(cell is None for row in board.board for cell in row)
-
- def test_board_initialization_custom_size(self):
- """Test board initialization with custom size."""
- board = GameBoard(5)
- assert board.size == 5
- assert len(board.board) == 5
- assert all(len(row) == 5 for row in board.board)
-
- def test_make_move_valid(self):
- """Test making a valid move."""
- board = GameBoard()
- result = board.make_move(0, 0, PlayerSymbol.X)
-
- assert result is True
- assert board.get_cell(0, 0) == PlayerSymbol.X
-
- def test_make_move_invalid_coordinates(self):
- """Test making a move with invalid coordinates."""
- board = GameBoard()
-
- with pytest.raises(IndexError):
- board.make_move(5, 5, PlayerSymbol.X)
-
- def test_make_move_occupied_cell(self):
- """Test making a move on an occupied cell."""
- board = GameBoard()
- board.make_move(0, 0, PlayerSymbol.X)
- result = board.make_move(0, 0, PlayerSymbol.O)
-
- assert result is False
- assert board.get_cell(0, 0) == PlayerSymbol.X
-
- def test_get_cell(self):
- """Test getting cell value."""
- board = GameBoard()
- board.make_move(1, 1, PlayerSymbol.O)
-
- assert board.get_cell(0, 0) is None
- assert board.get_cell(1, 1) == PlayerSymbol.O
-
- def test_is_full_empty_board(self):
- """Test is_full on empty board."""
- board = GameBoard()
- assert board.is_full() is False
-
- def test_is_full_full_board(self):
- """Test is_full on full board."""
- board = GameBoard()
- for i in range(3):
- for j in range(3):
- board.make_move(i, j, PlayerSymbol.X)
-
- assert board.is_full() is True
-
- def test_get_empty_cells(self):
- """Test getting empty cells."""
- board = GameBoard()
- board.make_move(0, 0, PlayerSymbol.X)
-
- empty_cells = board.get_empty_cells()
- assert len(empty_cells) == 8
- assert (0, 0) not in empty_cells
-
- def test_reset_board(self):
- """Test resetting the board."""
- board = GameBoard()
- board.make_move(0, 0, PlayerSymbol.X)
- board.reset()
-
- assert board.is_full() is False
- assert all(cell is None for row in board.board for cell in row)
-
-
-class TestTicTacToe:
- """Test TicTacToe class."""
-
- def test_game_initialization(self):
- """Test game initialization."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
-
- assert game.player1 == player1
- assert game.player2 == player2
- assert game.current_player == player1
- assert game.status == GameStatus.PLAYING
- assert game.winner is None
- assert len(game.move_history) == 0
-
- def test_game_initialization_custom_size(self):
- """Test game initialization with custom board size."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2, 5)
-
- assert game.board.size == 5
-
- def test_make_move_valid(self):
- """Test making a valid move."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
-
- result = game.make_move(0, 0)
-
- assert result is True
- assert game.current_player == player2
- assert len(game.move_history) == 1
- assert game.move_history[0] == (0, 0, PlayerSymbol.X)
-
- def test_make_move_invalid_game_ended(self):
- """Test making a move when game has ended."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
-
- # Make moves to end the game
- game.make_move(0, 0) # X plays at (0,0)
- game.make_move(1, 1) # O plays at (1,1)
- game.make_move(0, 1) # X plays at (0,1)
- game.make_move(1, 0) # O plays at (1,0)
- game.make_move(0, 2) # X plays at (0,2) - wins
-
- with pytest.raises(Exception): # Should raise an exception or handle properly
- game.make_move(2, 2)
-
- def test_check_win_row(self):
- """Test win condition checking for row."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
-
- # Make moves to create a winning row
- game.make_move(0, 0) # X plays at (0,0)
- game.make_move(1, 1) # O plays at (1,1)
- game.make_move(0, 1) # X plays at (0,1)
- game.make_move(1, 0) # O plays at (1,0)
- result = game.make_move(0, 2) # X plays at (0,2) - wins
-
- assert result is True
- assert game.status == GameStatus.PLAYING # Should still be playing until next move
-
- def test_check_win_column(self):
- """Test win condition checking for column."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
-
- # Make moves to create a winning column
- game.make_move(0, 0) # X plays at (0,0)
- game.make_move(1, 1) # O plays at (1,1)
- game.make_move(1, 0) # X plays at (1,0)
- game.make_move(2, 1) # O plays at (2,1)
- result = game.make_move(2, 0) # X plays at (2,0) - wins
-
- assert result is True
-
- def test_check_win_diagonal(self):
- """Test win condition checking for diagonal."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
-
- # Make moves to create a winning diagonal
- game.make_move(0, 0) # X plays at (0,0)
- game.make_move(1, 1) # O plays at (1,1)
- game.make_move(1, 0) # X plays at (1,0)
- game.make_move(2, 2) # O plays at (2,2)
- result = game.make_move(2, 0) # X plays at (2,0) - wins
-
- assert result is True
-
- def test_get_game_state(self):
- """Test getting game state."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
- state = game.get_game_state()
-
- assert isinstance(state, dict)
- assert "current_player_symbol" in state
- assert "board" in state
- assert "status" in state
- assert "winner" in state
-
- def test_reset_game(self):
- """Test resetting the game."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
- game.make_move(0, 0) # X plays at (0,0)
-
- # Reset the game
- # Note: There's no explicit reset method in the original code,
- # but we can simulate by creating a new game instance
-
- game2 = TicTacToe(player1, player2)
-
- assert game2.current_player == player1
- assert game2.status == GameStatus.PLAYING
- assert len(game2.move_history) == 0
-
- def test_draw_condition(self):
- """Test draw condition."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
-
- # Fill board with alternating moves to create a draw
- game.make_move(0, 0) # X plays at (0,0)
- game.make_move(0, 1) # O plays at (0,1)
- game.make_move(0, 2) # X plays at (0,2)
- game.make_move(1, 0) # O plays at (1,0)
- game.make_move(1, 1) # X plays at (1,1)
- game.make_move(1, 2) # O plays at (1,2)
- game.make_move(2, 0) # X plays at (2,0)
- game.make_move(2, 1) # O plays at (2,1)
- game.make_move(2, 2) # X plays at (2,2)
-
- # Check that game state is updated correctly
- state = game.get_game_state()
- assert state["status"] == "draw" or state["status"] == "o_wins" or state["status"] == "x_wins"
-
-
-class TestCreateHtmlTemplate:
- """Test create_html_template function."""
-
- def test_create_html_template(self):
- """Test creating HTML template with valid game state."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
- state = game.get_game_state()
-
- html_content = create_html_template(state, "test_game")
-
- assert isinstance(html_content, str)
- assert "Tic Tac Toe" in html_content
- assert "Current Player:" in html_content
- assert "resetGame()" in html_content
- assert "saveGame()" in html_content
-
-
-class TestSaveLoadGameState:
- """Test save_game_state and load_game_state functions."""
-
- def test_save_game_state(self, tmp_path):
- """Test saving game state to file."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
- game.make_move(0, 0) # X plays at (0,0)
-
- file_path = tmp_path / "test_game.json"
- save_game_state(game, str(file_path))
-
- assert file_path.exists()
-
- # Read and verify content
- with open(file_path, 'r') as f:
- saved_data = json.load(f)
-
- assert "current_player_symbol" in saved_data
- assert "board" in saved_data
- assert "status" in saved_data
-
- def test_save_game_state_error(self, tmp_path):
- """Test saving game state with invalid path."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
-
- # Try to save to a non-writable location
- with pytest.raises(IOError):
- save_game_state(game, "/nonexistent/directory/game.json")
-
- def test_load_game_state(self, tmp_path):
- """Test loading game state from file."""
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- game = TicTacToe(player1, player2)
- game.make_move(0, 0) # X plays at (0,0)
-
- file_path = tmp_path / "test_game.json"
- save_game_state(game, str(file_path))
-
- loaded_data = load_game_state(str(file_path))
-
- assert isinstance(loaded_data, dict)
- assert "current_player_symbol" in loaded_data
- assert "board" in loaded_data
-
- def test_load_game_state_file_not_found(self):
- """Test loading game state from non-existent file."""
- with pytest.raises(FileNotFoundError):
- load_game_state("nonexistent_file.json")
-
- def test_load_game_state_invalid_json(self, tmp_path):
- """Test loading game state from invalid JSON file."""
- file_path = tmp_path / "invalid.json"
- with open(file_path, 'w') as f:
- f.write("invalid json content")
-
- with pytest.raises(json.JSONDecodeError):
- load_game_state(str(file_path))
-
-
-class TestMainFunction:
- """Test main function."""
-
- @patch('sys.stdout', new_callable=MagicMock)
- def test_main_function(self, mock_stdout):
- """Test main function execution."""
- # This is a basic test - in real scenario, it would execute the full main function
- # We're just ensuring it doesn't crash
-
- try:
- # Import here to avoid circular imports in test setup
- from crm_5_implementation import main
-
- # We can't easily test the full main function without mocking more complex behavior
- # But we can at least ensure it doesn't crash on basic execution
- main()
-
- # If we get here without exception, the test passes
- assert True
-
- except Exception as e:
- # If there are exceptions, they should not be from basic functionality
- # This is just a smoke test
- assert "Error during game execution" not in str(e) or "main" in str(e)
-
-
-def test_edge_cases():
- """Test edge cases for all classes and functions."""
-
- # Test invalid board size
- with pytest.raises(Exception):
- GameBoard(-1) # This might raise an exception in real implementation
-
- # Test invalid player creation
- with pytest.raises(Exception):
- Player("invalid_symbol", "Player") # This might raise an exception in real implementation
-
- # Test multiple wins condition (should be handled by game logic)
-
- # Test large board size
- large_board = GameBoard(100)
- assert large_board.size == 100
-
- # Test negative board size
- with pytest.raises(Exception):
- GameBoard(-5)
-
- # Test zero board size
- with pytest.raises(Exception):
- GameBoard(0)
-
-
-def test_code_coverage():
- """Test that all code paths are covered."""
-
- # Test that all enums have proper values
- assert PlayerSymbol.X.value == "X"
- assert PlayerSymbol.O.value == "O"
-
- # Test that all game statuses are handled
- assert GameStatus.PLAYING.value == "playing"
- assert GameStatus.X_WINS.value == "x_wins"
- assert GameStatus.O_WINS.value == "o_wins"
- assert GameStatus.DRAW.value == "draw"
-
- # Test that the main function can be called without error
- try:
- from crm_5_implementation import main
- # We're not actually running main() here, just ensuring it exists
- assert callable(main)
- except Exception:
- # If there are import errors, the test should fail gracefully
- assert False
-
- # Test that all classes can be instantiated
- player1 = Player(PlayerSymbol.X, "Player X")
- player2 = Player(PlayerSymbol.O, "Player O")
-
- board = GameBoard()
- game = TicTacToe(player1, player2)
-
- assert isinstance(player1, Player)
- assert isinstance(board, GameBoard)
- assert isinstance(game, TicTacToe)
-
- # Test that all methods exist
- assert hasattr(board, 'make_move')
- assert hasattr(board, 'get_cell')
- assert hasattr(board, 'is_full')
- assert hasattr(board, 'get_empty_cells')
- assert hasattr(board, 'reset')
-
- assert hasattr(game, 'make_move')
- assert hasattr(game, 'get_game_state')
- assert hasattr(game, 'current_player')
- assert hasattr(game, 'status')
-
- # Test that all constants are accessible
- assert PlayerSymbol.X is not None
- assert PlayerSymbol.O is not None
- assert GameStatus.PLAYING is not None
- assert GameStatus.X_WINS is not None
- assert GameStatus.O_WINS is not None
- assert GameStatus.DRAW is not None
-"""
-Comprehensive unit tests for Tic Tac Toe game implementation.
-
-Tests all classes, methods, and edge cases for the Tic Tac Toe game.
-"""
-
-import pytest
-from crm_5_implementation import TicTacToeGame, TicTacToeUI, create_tic_tac_toe_game
-
-
-class TestTicTacToeGame:
- """Test cases for the TicTacToeGame class."""
-
- def test_initialization(self):
- """Test that game initializes correctly."""
- game = TicTacToeGame()
- assert game.board == [''] * 9
- assert game.current_player == 'X'
- assert game.game_over is False
- assert game.winner is None
- assert game.move_count == 0
-
- def test_make_move_valid_position(self):
- """Test making a valid move at position 0."""
- game = TicTacToeGame()
- result = game.make_move(0)
- assert result is True
- assert game.board[0] == 'X'
- assert game.current_player == 'O'
- assert game.move_count == 1
-
- def test_make_move_invalid_position_negative(self):
- """Test making a move at negative position."""
- game = TicTacToeGame()
- with pytest.raises(ValueError):
- game.make_move(-1)
-
- def test_make_move_invalid_position_too_high(self):
- """Test making a move at position 9."""
- game = TicTacToeGame()
- with pytest.raises(ValueError):
- game.make_move(9)
-
- def test_make_move_occupied_position(self):
- """Test making a move at already occupied position."""
- game = TicTacToeGame()
- game.make_move(0) # X at position 0
- with pytest.raises(IndexError):
- game.make_move(0) # Try to place O at same position
-
- def test_make_move_game_over(self):
- """Test making a move after game is already over."""
- game = TicTacToeGame()
- # Fill the board to make it full
- for i in range(9):
- game.make_move(i)
- # Try to make another move
- result = game.make_move(8)
- assert result is False
-
- def test_check_win_rows(self):
- """Test win detection for rows."""
- game = TicTacToeGame()
- # X wins with first row
- game.make_move(0)
- game.make_move(3)
- game.make_move(1)
- game.make_move(4)
- result = game.make_move(2)
- assert result is True
- assert game.game_over is True
- assert game.winner == 'X'
-
- def test_check_win_columns(self):
- """Test win detection for columns."""
- game = TicTacToeGame()
- # O wins with first column
- game.make_move(0)
- game.make_move(3)
- game.make_move(1)
- game.make_move(6)
- result = game.make_move(2)
- assert result is True
- assert game.game_over is True
- assert game.winner == 'X'
-
- def test_check_win_diagonals(self):
- """Test win detection for diagonals."""
- game = TicTacToeGame()
- # X wins with diagonal
- game.make_move(0)
- game.make_move(1)
- game.make_move(4)
- game.make_move(2)
- result = game.make_move(8)
- assert result is True
- assert game.game_over is True
- assert game.winner == 'X'
-
- def test_check_win_draw(self):
- """Test draw detection."""
- game = TicTacToeGame()
- # Fill board with alternating moves to create a draw
- game.make_move(0) # X
- game.make_move(1) # O
- game.make_move(2) # X
- game.make_move(4) # O
- game.make_move(3) # X
- game.make_move(5) # O
- game.make_move(7) # X
- game.make_move(6) # O
- result = game.make_move(8) # X - should end in draw
- assert result is True
- assert game.game_over is True
- assert game.winner == 'Draw'
-
- def test_reset_game(self):
- """Test resetting the game."""
- game = TicTacToeGame()
- game.make_move(0)
- game.make_move(1)
- game.reset_game()
- assert game.board == [''] * 9
- assert game.current_player == 'X'
- assert game.game_over is False
- assert game.winner is None
- assert game.move_count == 0
-
- def test_get_board_state(self):
- """Test getting board state."""
- game = TicTacToeGame()
- game.make_move(0)
- board_state = game.get_board_state()
- assert board_state[0] == 'X'
- assert board_state[1] == ''
- # Original board should be unchanged
- assert game.board[0] == 'X'
-
- def test_get_game_status(self):
- """Test getting game status."""
- game = TicTacToeGame()
- game.make_move(0)
- status = game.get_game_status()
- assert status['board'][0] == 'X'
- assert status['current_player'] == 'O'
- assert status['game_over'] is False
- assert status['winner'] is None
- assert status['move_count'] == 1
-
- def test_alternating_players(self):
- """Test that players alternate correctly."""
- game = TicTacToeGame()
- game.make_move(0)
- assert game.current_player == 'O'
- game.make_move(1)
- assert game.current_player == 'X'
- game.make_move(2)
- assert game.current_player == 'O'
-
-
-class TestTicTacToeUI:
- """Test cases for the TicTacToeUI class."""
-
- def test_ui_initialization(self):
- """Test UI initialization."""
- ui = TicTacToeUI()
- assert isinstance(ui.game, TicTacToeGame)
-
- def test_generate_html(self):
- """Test HTML generation."""
- ui = TicTacToeUI()
- html_content = ui.generate_html()
- assert '' in html_content
- assert 'Tic Tac Toe' in html_content
- assert '' in html_content
-
- def test_generate_css(self):
- """Test CSS generation."""
- ui = TicTacToeUI()
- css_content = ui.generate_css()
- assert 'body {' in css_content
- assert '.cell {' in css_content
- assert '@media' in css_content
-
- def test_generate_javascript(self):
- """Test JavaScript generation."""
- ui = TicTacToeUI()
- js_content = ui.generate_javascript()
- assert 'class TicTacToeGame' in js_content
- assert 'makeMove' in js_content
- assert 'updateUI' in js_content
-
-
-def test_create_tic_tac_toe_game():
- """Test creating complete game package."""
- result = create_tic_tac_toe_game()
- assert isinstance(result, dict)
- assert 'html' in result
- assert 'css' in result
- assert 'js' in result
- assert len(result['html']) > 0
- assert len(result['css']) > 0
- assert len(result['js']) > 0
-
-
-def test_main_function():
- """Test main function runs without errors."""
- # This is mainly for code coverage and to ensure the function can run
- # The actual content is tested in other tests
- pass
-
-
-class TestEdgeCases:
- """Test edge cases for the game."""
-
- def test_multiple_wins_same_row(self):
- """Test that win is detected correctly even with multiple moves."""
- game = TicTacToeGame()
- # Create a winning condition
- game.make_move(0) # X
- game.make_move(3) # O
- game.make_move(1) # X
- game.make_move(4) # O
- result = game.make_move(2) # X - should win
- assert result is True
- assert game.game_over is True
- assert game.winner == 'X'
-
- def test_full_board_draw(self):
- """Test draw with specific board arrangement."""
- game = TicTacToeGame()
- # Create a full board that should end in draw
- moves = [0, 1, 2, 4, 3, 5, 7, 6, 8] # X, O, X, O, X, O, X, O, X
- for i, move in enumerate(moves):
- game.make_move(move)
- assert game.game_over is True
- assert game.winner == 'Draw'
-
- def test_empty_board(self):
- """Test that initial board is empty."""
- game = TicTacToeGame()
- assert all(cell == '' for cell in game.board)
-
- def test_invalid_move_after_win(self):
- """Test making move after win."""
- game = TicTacToeGame()
- # Create a win condition
- game.make_move(0) # X
- game.make_move(3) # O
- game.make_move(1) # X
- game.make_move(4) # O
- game.make_move(2) # X - win
- # Try to make another move after win
- result = game.make_move(5)
- assert result is False
-
- def test_multiple_resets(self):
- """Test resetting multiple times."""
- game = TicTacToeGame()
- game.make_move(0)
- game.reset_game()
- game.reset_game() # Second reset
- assert game.board == [''] * 9
- assert game.current_player == 'X'
-
- def test_win_with_different_patterns(self):
- """Test win detection with different patterns."""
- game = TicTacToeGame()
-
- # Test column win
- game.make_move(0) # X
- game.make_move(1) # O
- game.make_move(3) # X
- game.make_move(4) # O
- result = game.make_move(6) # X - win column 0
- assert result is True
- assert game.game_over is True
- assert game.winner == 'X'
-
- # Reset and test diagonal win
- game.reset_game()
- game.make_move(0) # X
- game.make_move(1) # O
- game.make_move(4) # X
- game.make_move(2) # O
- result = game.make_move(8) # X - win diagonal
- assert result is True
- assert game.game_over is True
- assert game.winner == 'X'
+from flask import Flask
+from crm_5_implementation import TicTacToeApp
+
+@pytest.fixture
+def app_instance():
+ """Fixture to provide a TicTacToeApp instance for testing."""
+ return TicTacToeApp(host='127.0.0.1', port=8080, debug=False)
+
+@pytest.fixture
+def client(app_instance):
+ """Fixture to provide a Flask test client."""
+ app_instance.app.config['TESTING'] = True
+ with app_instance.app.test_client() as client:
+ yield client
+
+def test_initialization(app_instance):
+ """
+ Test that the TicTacToeApp initializes with correct attributes.
+ """
+ assert app_instance.host == '127.0.0.1'
+ assert app_instance.port == 8080
+ assert app_instance.debug is False
+ assert isinstance(app_instance.app, Flask)
+
+def test_index_route_success(client):
+ """
+ Test the index route ('/') to ensure it returns 200 OK and contains expected HTML content.
+ """
+ response = client.get('/')
+ assert response.status_code == 200
+ html_content = response.data.decode('utf-8')
+ assert 'CRM-5: Tic Tac Toe' in html_content
+ assert 'id="board"' in html_content
+ assert 'class="cell"' in html_content
+ assert 'id="reset-btn"' in html_content
+ assert 'const TicTacToe =' in html_content
+
+def test_index_route_template_rendering_failure(app_instance):
+ """
+ Test the index route error handling when template rendering fails.
+ """
+ with patch('crm_5_implementation.render_template_string') as mocked_render:
+ mocked_render.side_effect = Exception("Template Error")
+
+ with app_instance.app.test_client() as client:
+ response = client.get('/')
+ assert response.status_code == 500
+ assert b"Internal Server Error" in response.data
+
+def test_run_method_success(app_instance):
+ """
+ Test the run method to ensure it calls Flask's run with correct arguments.
+ """
+ with patch.object(app_instance.app, 'run') as mocked_run:
+ app_instance.run()
+ mocked_run.assert_called_once_with(
+ host='127.0.0.1',
+ port=8080,
+ debug=False
+ )
+
+def test_run_method_exception(app_instance):
+ """
+ Test the run method's exception handling when Flask fails to start.
+ """
+ with patch.object(app_instance.app, 'run') as mocked_run:
+ mocked_run.side_effect = Exception("Port already in use")
+ with patch('crm_5_implementation.logger.critical') as mocked_logger:
+ app_instance.run()
+ mocked_logger.assert_called_once()
+ assert "Failed to start server" in mocked_logger.call_args[0][0]
+
+def test_template_content_integrity(app_instance):
+ """
+ Test that the TEMPLATE constant contains essential game logic and styles.
+ """
+ template = app_instance.TEMPLATE
+ # Check CSS variables
+ assert '--x-color' in template
+ assert '--o-color' in template
+ # Check Grid layout
+ assert 'display: grid' in template
+ # Check JS Logic
+ assert 'winningConditions' in template
+ assert 'handleCellClick' in template
+ assert 'restartGame' in template
+ # Check Event Listeners
+ assert "addEventListener('click', TicTacToe.handleCellClick)" in template
+
+def test_custom_config_initialization():
+ """
+ Test initialization with non-default host and port.
+ """
+ custom_app = TicTacToeApp(host='192.168.1.1', port=9000, debug=True)
+ assert custom_app.host == '192.168.1.1'
+ assert custom_app.port == 9000
+ assert custom_app.debug is True
+
+def test_index_route_contains_all_cells(client):
+ """
+ Verify that the rendered HTML contains all 9 cells for the Tic Tac Toe board.
+ """
+ response = client.get('/')
+ html_content = response.data.decode('utf-8')
+ for i in range(9):
+ assert f'data-index="{i}"' in html_content
+
+@pytest.mark.parametrize("element", [
+ "status-indicator",
+ "game-board",
+ "cell",
+ "controls",
+ "reset-btn"
+])
+def test_ui_elements_presence(client, element):
+ """
+ Verify the presence of essential UI class names and IDs in the response.
+ """
+ response = client.get('/')
+ assert element.encode() in response.data
+
+def test_logger_info_on_run(app_instance):
+ """
+ Verify that the server logs an info message when starting.
+ """
+ with patch.object(app_instance.app, 'run'):
+ with patch('crm_5_implementation.logger.info') as mocked_info:
+ app_instance.run()
+ mocked_info.assert_called()
+ assert "Starting Tic Tac Toe server" in mocked_info.call_args[0][0]
+
+def test_route_registration(app_instance):
+ """
+ Verify that the '/' route is correctly registered in the Flask app.
+ """
+ rules = [rule.rule for rule in app_instance.app.url_map.iter_rules()]
+ assert '/' in rules
+
+def test_template_is_final_string(app_instance):
+ """
+ Ensure the TEMPLATE is a string and not empty.
+ """
+ assert isinstance(app_instance.TEMPLATE, str)
+ assert len(app_instance.TEMPLATE) > 0
+
+def test_internal_server_error_logging(app_instance):
+ """
+ Verify that template rendering errors are logged as errors.
+ """
+ with patch('crm_5_implementation.render_template_string', side_effect=Exception("Render fail")):
+ with patch('crm_5_implementation.logger.error') as mocked_error:
+ with app_instance.app.test_client() as client:
+ client.get('/')
+ mocked_error.assert_called_once()
+ assert "Error rendering template" in mocked_error.call_args[0][0]
\ No newline at end of file
diff --git a/test_integration.py b/test_integration.py
index 167927c..86a0718 100644
--- a/test_integration.py
+++ b/test_integration.py
@@ -1,279 +1,109 @@
-"""
-Integration tests for Tic Tac Toe Game Implementation
-
-This module contains integration tests that verify the complete
-functionality of the Tic Tac Toe game system, including
-component interactions, API endpoints, and database operations.
-"""
-
import pytest
-import json
-from unittest.mock import patch, MagicMock
-from crm_5_implementation import TicTacToe, GameBoard, Player
-
+from crm_5_implementation import TicTacToeApp
@pytest.fixture(scope="module")
-def game_instance():
- """Create a Tic Tac Toe game instance for testing."""
- return TicTacToe()
-
-
-@pytest.fixture(scope="function")
-def clean_game_board():
- """Create a fresh game board instance for each test."""
- return GameBoard()
-
-
-@pytest.fixture(scope="function")
-def player_x():
- """Create a player X instance."""
- return Player("X")
-
-
-@pytest.fixture(scope="function")
-def player_o():
- """Create a player O instance."""
- return Player("O")
-
-
-@pytest.fixture(autouse=True)
-def setup_and_teardown():
- """Setup and teardown for all tests."""
- # Setup
- yield
-
- # Teardown - clean up any test data if needed
- pass
-
-
-def test_game_initialization(game_instance):
- """Test that the game initializes correctly."""
- assert game_instance is not None
- assert hasattr(game_instance, 'board')
- assert hasattr(game_instance, 'current_player')
- assert hasattr(game_instance, 'players')
- assert len(game_instance.players) == 2
-
-
-def test_board_creation(clean_game_board):
- """Test that game board is created with correct dimensions."""
- assert clean_game_board is not None
- assert len(clean_game_board.board) == 3
- assert all(len(row) == 3 for row in clean_game_board.board)
- assert all(cell == '' for row in clean_game_board.board for cell in row)
-
-
-def test_player_creation(player_x, player_o):
- """Test that players are created with correct symbols."""
- assert player_x.symbol == "X"
- assert player_o.symbol == "O"
-
-
-def test_game_board_state_management(clean_game_board):
- """Test board state management operations."""
- # Test initial state
- assert clean_game_board.get_state() == [['', '', ''], ['', '', ''], ['', '', '']]
-
- # Test making a move
- clean_game_board.make_move(0, 0, "X")
- state = clean_game_board.get_state()
- assert state[0][0] == "X"
- assert state[0][1] == ""
- assert state[0][2] == ""
-
-
-def test_game_turn_management(game_instance, player_x, player_o):
- """Test that game manages turns correctly."""
- # Test initial player
- assert game_instance.current_player == player_x
-
- # Test turn switching
- game_instance.switch_player()
- assert game_instance.current_player == player_o
-
- # Test turn switching back
- game_instance.switch_player()
- assert game_instance.current_player == player_x
-
-
-def test_game_win_detection(clean_game_board):
- """Test win detection logic."""
- # Test horizontal win
- clean_game_board.board = [["X", "X", "X"], ["", "", ""], ["", "", ""]]
- assert clean_game_board.check_win() == "X"
-
- # Test vertical win
- clean_game_board.board = [["O", "", ""], ["O", "", ""], ["O", "", ""]]
- assert clean_game_board.check_win() == "O"
-
- # Test diagonal win
- clean_game_board.board = [["X", "", ""], ["", "X", ""], ["", "", "X"]]
- assert clean_game_board.check_win() == "X"
-
- # Test no win
- clean_game_board.board = [["X", "O", "X"], ["O", "X", "O"], ["O", "X", "O"]]
- assert clean_game_board.check_win() is None
-
-
-def test_game_draw_detection(clean_game_board):
- """Test draw detection logic."""
- # Test draw scenario
- clean_game_board.board = [["X", "O", "X"], ["O", "X", "O"], ["O", "X", "O"]]
- assert clean_game_board.check_draw() is True
-
- # Test ongoing game
- clean_game_board.board = [["X", "O", ""], ["O", "X", ""], ["O", "X", ""]]
- assert clean_game_board.check_draw() is False
-
-
-def test_game_reset_functionality(game_instance):
- """Test that game can be reset properly."""
- # Make some moves
- game_instance.board.make_move(0, 0, "X")
-
- # Reset game
- game_instance.reset_game()
-
- # Verify reset
- assert game_instance.current_player == game_instance.players[0]
- assert game_instance.board.get_state() == [['', '', ''], ['', '', ''], ['', '', '']]
-
-
-def test_player_symbol_assignment():
- """Test that players are assigned correct symbols."""
- game = TicTacToe()
-
- assert game.players[0].symbol == "X"
- assert game.players[1].symbol == "O"
-
-
-def test_complete_game_scenario():
- """Test a complete game scenario with multiple moves."""
- game = TicTacToe()
-
- # Player X makes first move
- game.make_move(0, 0, "X")
- assert game.current_player.symbol == "O"
-
- # Player O makes second move
- game.make_move(1, 1, "O")
- assert game.current_player.symbol == "X"
-
- # Player X makes third move
- game.make_move(0, 1, "X")
- assert game.current_player.symbol == "O"
-
- # Player O makes fourth move
- game.make_move(1, 0, "O")
- assert game.current_player.symbol == "X"
-
- # Player X makes fifth move (winning move)
- game.make_move(0, 2, "X")
-
- # Verify win condition
- assert game.check_game_status() == "X"
-
-
-def test_game_state_serialization():
- """Test that game state can be serialized and deserialized."""
- game = TicTacToe()
-
- # Make some moves
- game.make_move(0, 0, "X")
- game.make_move(1, 1, "O")
-
- # Serialize state
- state = game.serialize_state()
- assert isinstance(state, str)
-
- # Deserialize state
- new_game = TicTacToe()
- new_game.deserialize_state(state)
-
- # Verify state is restored
- assert new_game.board.get_state()[0][0] == "X"
- assert new_game.board.get_state()[1][1] == "O"
-
-
-def test_multiple_game_instances():
- """Test that multiple game instances can exist independently."""
- game1 = TicTacToe()
- game2 = TicTacToe()
-
- # Make moves in first game
- game1.make_move(0, 0, "X")
-
- # Verify second game is unaffected
- assert game2.board.get_state()[0][0] == ""
-
- # Verify first game state
- assert game1.board.get_state()[0][0] == "X"
-
-
-def test_invalid_move_handling(clean_game_board):
- """Test handling of invalid moves."""
- # Test move on occupied cell
- clean_game_board.make_move(0, 0, "X")
- result = clean_game_board.make_move(0, 0, "O")
-
- # Should not allow move on occupied cell
- assert result is False
-
- # Verify original move still there
- assert clean_game_board.board[0][0] == "X"
-
-
-def test_edge_cases():
- """Test edge cases in game logic."""
- game = TicTacToe()
-
- # Test moves outside board bounds
- assert game.make_move(-1, 0, "X") is False
- assert game.make_move(3, 0, "X") is False
- assert game.make_move(0, -1, "X") is False
- assert game.make_move(0, 3, "X") is False
-
- # Test invalid player symbols
- assert game.make_move(0, 0, "Invalid") is False
-
-
-def test_game_status_end_conditions():
- """Test various end game conditions."""
- # Test win condition
- game = TicTacToe()
- game.board.board = [["X", "X", "X"], ["", "", ""], ["", "", ""]]
- assert game.check_game_status() == "X"
-
- # Test draw condition
- game = TicTacToe()
- game.board.board = [["X", "O", "X"], ["O", "X", "O"], ["O", "X", "O"]]
- assert game.check_game_status() == "draw"
-
- # Test ongoing game
- game = TicTacToe()
- game.board.board = [["X", "", ""], ["", "", ""], ["", "", ""]]
- assert game.check_game_status() is None
-
-
-def test_concurrent_games():
- """Test that multiple concurrent games work correctly."""
- game1 = TicTacToe()
- game2 = TicTacToe()
-
- # Play first game to win
- game1.make_move(0, 0, "X")
- game1.make_move(0, 1, "X")
- game1.make_move(0, 2, "X")
-
- # Play second game to draw
- game2.make_move(0, 0, "X")
- game2.make_move(1, 1, "O")
- game2.make_move(0, 1, "O")
- game2.make_move(1, 0, "X")
- game2.make_move(2, 2, "O")
-
- # Verify first game has win
- assert game1.check_game_status() == "X"
-
- # Verify second game has draw
- assert game2.check_game_status() == "draw"
+def app_instance():
+ """
+ Setup fixture for the TicTacToeApp instance.
+ Ensures the Flask application is configured for testing mode.
+ """
+ # Initialize the application class
+ service = TicTacToeApp()
+ # Access the Flask app instance encapsulated within the class
+ flask_app = service.app
+ flask_app.config.update({
+ "TESTING": True,
+ })
+ return flask_app
+
+@pytest.fixture
+def client(app_instance):
+ """
+ Fixture to provide a test client for the Flask application.
+ Handles setup and teardown of the test client context.
+ """
+ with app_instance.test_client() as client:
+ yield client
+
+def test_index_route_integration(client):
+ """
+ Test the integration between the Flask route and the template rendering engine.
+ Verifies that the root endpoint returns a 200 OK status and serves the HTML content.
+ """
+ response = client.get('/')
+ assert response.status_code == 200
+
+ html_content = response.data.decode('utf-8')
+
+ # Verify core HTML structure is present
+ assert "" in html_content
+ assert "Tic Tac Toe" in html_content
+ assert "html" in html_content.lower()
+
+def test_frontend_assets_integration(client):
+ """
+ Verify that CSS and JavaScript components are correctly integrated into the response.
+ Since this is a client-side game, these assets should be embedded or linked.
+ """
+ response = client.get('/')
+ html_content = response.data.decode('utf-8')
+
+ # Check for CSS integration (style tags or links)
+ assert "