nordabiz/tests/unit/test_conversation_models.py
Maciej Pienczyn bca1decf97
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
test(messages): add unit tests for conversation models and link preview
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 13:31:44 +01:00

243 lines
8.0 KiB
Python

"""
Unit Tests — Conversation Models
=================================
Tests for the new SQLAlchemy conversation models (mock-based, no DB required):
- Conversation.display_name
- Conversation.member_count
- ConversationMember.is_owner
- ConvMessage.__repr__
- MessageReaction unique constraint
- Model imports
"""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
import pytest
from unittest.mock import MagicMock
from sqlalchemy import UniqueConstraint
# ============================================================
# Import Tests
# ============================================================
class TestModelImports:
"""Verify all 5 conversation models can be imported from database."""
def test_import_conversation(self):
from database import Conversation
assert Conversation is not None
def test_import_conversation_member(self):
from database import ConversationMember
assert ConversationMember is not None
def test_import_conv_message(self):
from database import ConvMessage
assert ConvMessage is not None
def test_import_message_reaction(self):
from database import MessageReaction
assert MessageReaction is not None
def test_import_message_attachment(self):
from database import MessageAttachment
assert MessageAttachment is not None
# ============================================================
# Helpers
# ============================================================
def _make_mock_member(name=None, email='user@example.com'):
"""Create a MagicMock simulating a ConversationMember with a User."""
member = MagicMock()
user = MagicMock()
user.name = name
user.email = email
member.user = user
return member
def _make_conversation(name=None, members=None):
"""Create a MagicMock simulating a Conversation instance."""
from database import Conversation
conv = MagicMock(spec=Conversation)
# Attach the real property logic by calling it on the mock
conv.name = name
conv.members = members or []
# Bind the real display_name property to this mock
conv.display_name = Conversation.display_name.fget(conv)
conv.member_count = Conversation.member_count.fget(conv)
return conv
# ============================================================
# Conversation.display_name Tests
# ============================================================
class TestConversationDisplayName:
"""Test Conversation.display_name property."""
def test_display_name_returns_name_when_set(self):
from database import Conversation
conv = MagicMock()
conv.name = 'Projekt Alpha'
conv.members = []
result = Conversation.display_name.fget(conv)
assert result == 'Projekt Alpha'
def test_display_name_joins_member_names_when_no_name(self):
from database import Conversation
conv = MagicMock()
conv.name = None
conv.members = [
_make_mock_member(name='Anna'),
_make_mock_member(name='Bob'),
]
result = Conversation.display_name.fget(conv)
assert 'Anna' in result
assert 'Bob' in result
def test_display_name_uses_email_prefix_when_user_has_no_name(self):
from database import Conversation
conv = MagicMock()
conv.name = None
conv.members = [
_make_mock_member(name=None, email='jan.kowalski@example.com'),
]
result = Conversation.display_name.fget(conv)
assert 'jan.kowalski' in result
def test_display_name_truncates_beyond_four_members(self):
from database import Conversation
conv = MagicMock()
conv.name = None
conv.members = [
_make_mock_member(name=f'User{i}', email=f'user{i}@example.com')
for i in range(6)
]
result = Conversation.display_name.fget(conv)
assert '+2' in result
def test_display_name_no_suffix_for_four_or_fewer_members(self):
from database import Conversation
conv = MagicMock()
conv.name = None
conv.members = [
_make_mock_member(name=f'User{i}', email=f'user{i}@example.com')
for i in range(4)
]
result = Conversation.display_name.fget(conv)
assert '+' not in result
# ============================================================
# Conversation.member_count Tests
# ============================================================
class TestConversationMemberCount:
"""Test Conversation.member_count property."""
def test_member_count_returns_length_of_members(self):
from database import Conversation
conv = MagicMock()
conv.members = [MagicMock(), MagicMock(), MagicMock()]
assert Conversation.member_count.fget(conv) == 3
def test_member_count_zero_when_no_members(self):
from database import Conversation
conv = MagicMock()
conv.members = []
assert Conversation.member_count.fget(conv) == 0
# ============================================================
# ConversationMember.is_owner Tests
# ============================================================
class TestConversationMemberIsOwner:
"""Test ConversationMember.is_owner property."""
def test_is_owner_true_when_role_is_owner(self):
from database import ConversationMember
cm = MagicMock()
cm.role = 'owner'
assert ConversationMember.is_owner.fget(cm) is True
def test_is_owner_false_when_role_is_member(self):
from database import ConversationMember
cm = MagicMock()
cm.role = 'member'
assert ConversationMember.is_owner.fget(cm) is False
def test_is_owner_false_when_role_is_admin(self):
from database import ConversationMember
cm = MagicMock()
cm.role = 'admin'
assert ConversationMember.is_owner.fget(cm) is False
def test_is_owner_false_when_role_is_empty(self):
from database import ConversationMember
cm = MagicMock()
cm.role = ''
assert ConversationMember.is_owner.fget(cm) is False
# ============================================================
# ConvMessage.__repr__ Tests
# ============================================================
class TestConvMessageRepr:
"""Test ConvMessage.__repr__ returns expected format."""
def test_repr_format(self):
from database import ConvMessage
msg = MagicMock()
msg.id = 42
msg.conversation_id = 7
msg.sender_id = 13
# Call the actual __repr__ method on the mock instance
result = ConvMessage.__repr__(msg)
assert '42' in result
assert '7' in result
assert '13' in result
def test_repr_contains_class_indicator(self):
from database import ConvMessage
msg = MagicMock()
msg.id = 1
msg.conversation_id = 2
msg.sender_id = 3
assert 'ConvMessage' in ConvMessage.__repr__(msg)
# ============================================================
# MessageReaction UniqueConstraint Tests
# ============================================================
class TestMessageReactionUniqueConstraint:
"""Verify MessageReaction __table_args__ contains UniqueConstraint."""
def test_table_args_contains_unique_constraint(self):
from database import MessageReaction
table_args = MessageReaction.__table_args__
assert table_args is not None
constraint_types = [type(a) for a in table_args]
assert UniqueConstraint in constraint_types
def test_unique_constraint_covers_message_user_emoji(self):
from database import MessageReaction
table_args = MessageReaction.__table_args__
unique_constraints = [a for a in table_args if isinstance(a, UniqueConstraint)]
assert len(unique_constraints) >= 1
constraint = unique_constraints[0]
col_names = [col.key for col in constraint.columns]
assert 'message_id' in col_names
assert 'user_id' in col_names
assert 'emoji' in col_names