Files
python-fun/tests/test_classified_ad.py

434 lines
13 KiB
Python

from decimal import Decimal
from uuid import uuid4
import pytest
from domain.framework.entity import Entity
from domain.marketplace.classified_ad import ClassifiedAd
from domain.marketplace.classified_ad_id import ClassifiedAdId
from domain.marketplace.classified_ad_state import ClassifiedAdState
from domain.marketplace.classified_ad_text import ClassifiedAdText
from domain.marketplace.classified_ad_title import ClassifiedAdTitle
from domain.marketplace.domain_event import (
ClassifiedAdPriceUpdated,
ClassifiedAdSentForReview,
ClassifiedAdTextUpdated,
ClassifiedAdTitleChanged,
)
from domain.marketplace.invalid_entity_state_exception import (
InvalidEntityStateException,
)
from domain.marketplace.price import Price
from domain.marketplace.user_id import UserId
def test_classified_ad_creation():
ad_id = ClassifiedAdId(value=uuid4())
owner_id = UserId(value=uuid4())
ad = ClassifiedAd(
id=ad_id,
_ownerId=owner_id,
title=ClassifiedAdTitle(title="Test Title"),
text=ClassifiedAdText(text="Test text content"),
price=Price(amount=Decimal("99.99")),
)
assert ad.id == ad_id
assert ad._ownerId == owner_id
assert ad.title == ClassifiedAdTitle(title="Test Title")
assert ad.text == ClassifiedAdText(text="Test text content")
assert ad.price == Price(amount=Decimal("99.99"))
def test_classified_ad_can_not_be_created_without_id():
with pytest.raises(TypeError):
ClassifiedAd(
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
def test_classified_ad_can_not_be_created_without_owner_id():
with pytest.raises(TypeError):
ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
def test_classified_ad_can_be_created_without_price():
ad_id = ClassifiedAdId(value=uuid4())
owner_id = UserId(value=uuid4())
ad = ClassifiedAd(
id=ad_id,
_ownerId=owner_id,
title=ClassifiedAdTitle(title="Test Title"),
text=ClassifiedAdText(text="Test text content"),
)
assert ad.id == ad_id
assert ad._ownerId == owner_id
assert ad.title == ClassifiedAdTitle(title="Test Title")
assert ad.text == ClassifiedAdText(text="Test text content")
assert ad.price == Price(amount=Decimal("0.00"))
def test_classified_ad_can_not_have_negative_price():
with pytest.raises(ValueError):
ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("-10.00")),
)
def test_classified_ad_is_immutable():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
try:
ad.title = "New Title" # type: ignore
assert False, "Should have raised FrozenInstanceError"
except AttributeError:
pass
def test_classified_ad_equality():
ad_id = ClassifiedAdId(value=uuid4())
owner_id = UserId(value=uuid4())
ad1 = ClassifiedAd(
id=ad_id,
_ownerId=owner_id,
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
ad2 = ClassifiedAd(
id=ad_id,
_ownerId=owner_id,
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
assert ad1 == ad2
def test_classified_ad_title_validation():
long_title = "a" * 101
with pytest.raises(ValueError):
ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title=long_title),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
def test_request_to_publish_sets_state_to_pending_review():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
published = ad.request_to_publish()
assert published.state == ClassifiedAdState.PendingReview
changes = published.get_changes()
assert len(changes) == 1
event = changes[0]
assert isinstance(event, ClassifiedAdSentForReview)
assert event.id == ad.id.value
def test_request_to_publish_fails_when_title_empty():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title=""),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
with pytest.raises(InvalidEntityStateException) as exc_info:
ad.request_to_publish()
assert "title" in str(exc_info.value)
def test_request_to_publish_fails_when_text_empty():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text=""),
price=Price(amount=Decimal("10.00")),
)
with pytest.raises(InvalidEntityStateException) as exc_info:
ad.request_to_publish()
assert "text" in str(exc_info.value)
def test_request_to_publish_fails_when_price_is_zero():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
)
with pytest.raises(InvalidEntityStateException) as exc_info:
ad.request_to_publish()
assert "price" in str(exc_info.value)
def test_request_to_publish_reports_all_errors():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title=""),
text=ClassifiedAdText(text=""),
)
with pytest.raises(InvalidEntityStateException) as exc_info:
ad.request_to_publish()
assert "title" in str(exc_info.value)
assert "text" in str(exc_info.value)
assert "price" in str(exc_info.value)
def test_request_to_publish_does_not_mutate_original():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
ad.request_to_publish()
assert ad.state is None
def test_classified_ad_is_instance_of_entity():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
assert isinstance(ad, Entity)
def test_classified_ad_can_use_entity_raise_event():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
event = ClassifiedAdSentForReview(id=ad.id.value)
updated_ad = ad.raise_event(event)
assert updated_ad.get_changes() == (event,)
assert ad.get_changes() == ()
def test_set_title_updates_title():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Old Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
new_title = ClassifiedAdTitle(title="New Title")
updated = ad.set_title(new_title)
assert updated.title == new_title
assert ad.title == ClassifiedAdTitle(title="Old Title")
def test_set_title_preserves_other_fields():
ad_id = ClassifiedAdId(value=uuid4())
owner_id = UserId(value=uuid4())
text = ClassifiedAdText(text="Text")
price = Price(amount=Decimal("10.00"))
ad = ClassifiedAd(
id=ad_id,
_ownerId=owner_id,
title=ClassifiedAdTitle(title="Old Title"),
text=text,
price=price,
)
updated = ad.set_title(ClassifiedAdTitle(title="New Title"))
assert updated.id == ad_id
assert updated._ownerId == owner_id
assert updated.text == text
assert updated.price == price
def test_set_title_fails_when_new_title_empty():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
with pytest.raises(InvalidEntityStateException) as exc_info:
ad.set_title(ClassifiedAdTitle(title=""))
assert "title" in str(exc_info.value)
def test_set_title_raises_classified_ad_title_changed_event():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Old Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
updated = ad.set_title(ClassifiedAdTitle(title="New Title"))
changes = updated.get_changes()
assert len(changes) == 1
event = changes[0]
assert isinstance(event, ClassifiedAdTitleChanged)
assert event.id == ad.id.value
assert event.title == "New Title"
def test_update_text_updates_text():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Old text"),
price=Price(amount=Decimal("10.00")),
)
new_text = ClassifiedAdText(text="New text")
updated = ad.update_text(new_text)
assert updated.text == new_text
assert ad.text == ClassifiedAdText(text="Old text")
def test_update_text_fails_when_new_text_empty():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
with pytest.raises(InvalidEntityStateException) as exc_info:
ad.update_text(ClassifiedAdText(text=""))
assert "text" in str(exc_info.value)
def test_update_text_raises_classified_ad_text_updated_event():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Old text"),
price=Price(amount=Decimal("10.00")),
)
updated = ad.update_text(ClassifiedAdText(text="New text"))
changes = updated.get_changes()
assert len(changes) == 1
event = changes[0]
assert isinstance(event, ClassifiedAdTextUpdated)
assert event.id == ad.id.value
assert event.ad_text == "New text"
def test_update_price_updates_price():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
new_price = Price(amount=Decimal("25.00"))
updated = ad.update_price(new_price)
assert updated.price == new_price
assert ad.price == Price(amount=Decimal("10.00"))
def test_update_price_fails_when_price_zero():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
with pytest.raises(InvalidEntityStateException) as exc_info:
ad.update_price(Price(amount=Decimal("0.00")))
assert "price" in str(exc_info.value)
def test_update_price_raises_classified_ad_price_updated_event():
ad = ClassifiedAd(
id=ClassifiedAdId(value=uuid4()),
_ownerId=UserId(value=uuid4()),
title=ClassifiedAdTitle(title="Title"),
text=ClassifiedAdText(text="Text"),
price=Price(amount=Decimal("10.00")),
)
updated = ad.update_price(Price(amount=Decimal("25.00")))
changes = updated.get_changes()
assert len(changes) == 1
event = changes[0]
assert isinstance(event, ClassifiedAdPriceUpdated)
assert event.id == ad.id.value
assert event.price == Decimal("25.00")