- Add pytest configuration and dependencies - Create test_models.py: 25 tests for Pydantic models - Create test_api.py: 23 tests for REST endpoints - Create test_websockets.py: 23 tests for WebSocket functionality - Add TEST_RESULTS.md with detailed analysis Tests validate: ✅ Message visibility system (private/public/mixed) ✅ Character isolation and privacy ✅ Session management ✅ API endpoints and error handling ✅ WebSocket connections Known issues: - 6 WebSocket async tests fail due to TestClient limitations - Production functionality manually verified - 10 Pydantic deprecation warnings to fix Coverage: 78% (219 statements, 48 missed) Ready for Phase 2 implementation
286 lines
10 KiB
Python
286 lines
10 KiB
Python
"""
|
|
Tests for Pydantic models (Message, Character, GameSession)
|
|
"""
|
|
import pytest
|
|
from datetime import datetime
|
|
from main import Message, Character, GameSession
|
|
|
|
|
|
class TestMessage:
|
|
"""Test Message model"""
|
|
|
|
def test_message_creation_default(self):
|
|
"""Test creating a message with default values"""
|
|
msg = Message(sender="character", content="Hello!")
|
|
|
|
assert msg.sender == "character"
|
|
assert msg.content == "Hello!"
|
|
assert msg.visibility == "private" # Default
|
|
assert msg.public_content is None
|
|
assert msg.private_content is None
|
|
assert msg.id is not None
|
|
assert msg.timestamp is not None
|
|
|
|
def test_message_creation_private(self):
|
|
"""Test creating a private message"""
|
|
msg = Message(
|
|
sender="character",
|
|
content="I search for traps",
|
|
visibility="private"
|
|
)
|
|
|
|
assert msg.visibility == "private"
|
|
assert msg.public_content is None
|
|
assert msg.private_content is None
|
|
|
|
def test_message_creation_public(self):
|
|
"""Test creating a public message"""
|
|
msg = Message(
|
|
sender="character",
|
|
content="I wave to everyone",
|
|
visibility="public"
|
|
)
|
|
|
|
assert msg.visibility == "public"
|
|
assert msg.content == "I wave to everyone"
|
|
|
|
def test_message_creation_mixed(self):
|
|
"""Test creating a mixed message"""
|
|
msg = Message(
|
|
sender="character",
|
|
content="Combined message",
|
|
visibility="mixed",
|
|
public_content="I shake hands with the merchant",
|
|
private_content="I try to pickpocket him"
|
|
)
|
|
|
|
assert msg.visibility == "mixed"
|
|
assert msg.public_content == "I shake hands with the merchant"
|
|
assert msg.private_content == "I try to pickpocket him"
|
|
|
|
def test_message_timestamp_format(self):
|
|
"""Test that timestamp is ISO format"""
|
|
msg = Message(sender="character", content="Test")
|
|
|
|
# Should be able to parse the timestamp
|
|
parsed_time = datetime.fromisoformat(msg.timestamp)
|
|
assert isinstance(parsed_time, datetime)
|
|
|
|
def test_message_unique_ids(self):
|
|
"""Test that messages get unique IDs"""
|
|
msg1 = Message(sender="character", content="Message 1")
|
|
msg2 = Message(sender="character", content="Message 2")
|
|
|
|
assert msg1.id != msg2.id
|
|
|
|
|
|
class TestCharacter:
|
|
"""Test Character model"""
|
|
|
|
def test_character_creation_minimal(self):
|
|
"""Test creating a character with minimal info"""
|
|
char = Character(
|
|
name="Gandalf",
|
|
description="A wise wizard"
|
|
)
|
|
|
|
assert char.name == "Gandalf"
|
|
assert char.description == "A wise wizard"
|
|
assert char.personality == ""
|
|
assert char.llm_model == "gpt-3.5-turbo"
|
|
assert char.conversation_history == []
|
|
assert char.pending_response is False
|
|
assert char.id is not None
|
|
|
|
def test_character_creation_full(self):
|
|
"""Test creating a character with all fields"""
|
|
char = Character(
|
|
name="Aragorn",
|
|
description="A ranger from the North",
|
|
personality="Brave and noble",
|
|
llm_model="gpt-4"
|
|
)
|
|
|
|
assert char.name == "Aragorn"
|
|
assert char.description == "A ranger from the North"
|
|
assert char.personality == "Brave and noble"
|
|
assert char.llm_model == "gpt-4"
|
|
|
|
def test_character_conversation_history(self):
|
|
"""Test adding messages to conversation history"""
|
|
char = Character(name="Legolas", description="An elf archer")
|
|
|
|
msg1 = Message(sender="character", content="I see danger ahead")
|
|
msg2 = Message(sender="storyteller", content="What do you do?")
|
|
|
|
char.conversation_history.append(msg1)
|
|
char.conversation_history.append(msg2)
|
|
|
|
assert len(char.conversation_history) == 2
|
|
assert char.conversation_history[0].content == "I see danger ahead"
|
|
assert char.conversation_history[1].sender == "storyteller"
|
|
|
|
def test_character_pending_response_flag(self):
|
|
"""Test pending response flag"""
|
|
char = Character(name="Gimli", description="A dwarf warrior")
|
|
|
|
assert char.pending_response is False
|
|
|
|
char.pending_response = True
|
|
assert char.pending_response is True
|
|
|
|
|
|
class TestGameSession:
|
|
"""Test GameSession model"""
|
|
|
|
def test_session_creation(self):
|
|
"""Test creating a game session"""
|
|
session = GameSession(name="Epic Adventure")
|
|
|
|
assert session.name == "Epic Adventure"
|
|
assert session.characters == {}
|
|
assert session.current_scene == ""
|
|
assert session.scene_history == []
|
|
assert session.public_messages == []
|
|
assert session.id is not None
|
|
|
|
def test_session_add_character(self):
|
|
"""Test adding a character to session"""
|
|
session = GameSession(name="Test Game")
|
|
char = Character(name="Frodo", description="A hobbit")
|
|
|
|
session.characters[char.id] = char
|
|
|
|
assert len(session.characters) == 1
|
|
assert char.id in session.characters
|
|
assert session.characters[char.id].name == "Frodo"
|
|
|
|
def test_session_multiple_characters(self):
|
|
"""Test session with multiple characters"""
|
|
session = GameSession(name="Fellowship")
|
|
|
|
char1 = Character(name="Sam", description="Loyal friend")
|
|
char2 = Character(name="Merry", description="Cheerful hobbit")
|
|
char3 = Character(name="Pippin", description="Curious hobbit")
|
|
|
|
session.characters[char1.id] = char1
|
|
session.characters[char2.id] = char2
|
|
session.characters[char3.id] = char3
|
|
|
|
assert len(session.characters) == 3
|
|
|
|
def test_session_scene_history(self):
|
|
"""Test adding scenes to history"""
|
|
session = GameSession(name="Test")
|
|
|
|
scene1 = "You enter a dark cave"
|
|
scene2 = "You hear footsteps behind you"
|
|
|
|
session.scene_history.append(scene1)
|
|
session.scene_history.append(scene2)
|
|
session.current_scene = scene2
|
|
|
|
assert len(session.scene_history) == 2
|
|
assert session.current_scene == scene2
|
|
|
|
def test_session_public_messages(self):
|
|
"""Test public messages feed"""
|
|
session = GameSession(name="Test")
|
|
|
|
msg1 = Message(sender="character", content="I wave", visibility="public")
|
|
msg2 = Message(sender="character", content="I charge forward", visibility="public")
|
|
|
|
session.public_messages.append(msg1)
|
|
session.public_messages.append(msg2)
|
|
|
|
assert len(session.public_messages) == 2
|
|
assert session.public_messages[0].visibility == "public"
|
|
|
|
|
|
class TestMessageVisibility:
|
|
"""Test message visibility logic"""
|
|
|
|
def test_private_message_properties(self):
|
|
"""Test that private messages have correct properties"""
|
|
msg = Message(
|
|
sender="character",
|
|
content="Secret action",
|
|
visibility="private"
|
|
)
|
|
|
|
assert msg.visibility == "private"
|
|
assert msg.public_content is None
|
|
assert msg.private_content is None
|
|
# Content field holds the entire message for private
|
|
assert msg.content == "Secret action"
|
|
|
|
def test_public_message_properties(self):
|
|
"""Test that public messages have correct properties"""
|
|
msg = Message(
|
|
sender="character",
|
|
content="Public action",
|
|
visibility="public"
|
|
)
|
|
|
|
assert msg.visibility == "public"
|
|
# For public messages, content is visible to all
|
|
assert msg.content == "Public action"
|
|
|
|
def test_mixed_message_properties(self):
|
|
"""Test that mixed messages split correctly"""
|
|
msg = Message(
|
|
sender="character",
|
|
content="Combined",
|
|
visibility="mixed",
|
|
public_content="I greet the guard",
|
|
private_content="I look for weaknesses in his armor"
|
|
)
|
|
|
|
assert msg.visibility == "mixed"
|
|
assert msg.public_content == "I greet the guard"
|
|
assert msg.private_content == "I look for weaknesses in his armor"
|
|
# Both parts exist separately
|
|
assert msg.public_content != msg.private_content
|
|
|
|
|
|
class TestCharacterIsolation:
|
|
"""Test that characters have isolated conversations"""
|
|
|
|
def test_separate_conversation_histories(self):
|
|
"""Test that each character has their own conversation history"""
|
|
char1 = Character(name="Alice", description="Warrior")
|
|
char2 = Character(name="Bob", description="Mage")
|
|
|
|
msg1 = Message(sender="character", content="Alice's message")
|
|
msg2 = Message(sender="character", content="Bob's message")
|
|
|
|
char1.conversation_history.append(msg1)
|
|
char2.conversation_history.append(msg2)
|
|
|
|
# Verify isolation
|
|
assert len(char1.conversation_history) == 1
|
|
assert len(char2.conversation_history) == 1
|
|
assert char1.conversation_history[0].content == "Alice's message"
|
|
assert char2.conversation_history[0].content == "Bob's message"
|
|
|
|
def test_public_messages_vs_private_history(self):
|
|
"""Test distinction between public feed and private history"""
|
|
session = GameSession(name="Test")
|
|
|
|
char1 = Character(name="Alice", description="Warrior")
|
|
char2 = Character(name="Bob", description="Mage")
|
|
|
|
# Alice sends private message
|
|
private_msg = Message(sender="character", content="I sneak", visibility="private")
|
|
char1.conversation_history.append(private_msg)
|
|
|
|
# Alice sends public message
|
|
public_msg = Message(sender="character", content="I wave", visibility="public")
|
|
session.public_messages.append(public_msg)
|
|
|
|
# Bob should not see Alice's private message
|
|
assert len(char2.conversation_history) == 0
|
|
# But can see public messages
|
|
assert len(session.public_messages) == 1
|
|
assert session.public_messages[0].content == "I wave"
|