266 lines
7.3 KiB
Python
266 lines
7.3 KiB
Python
"""Tests for Pydantic models in finn_eiendom.models."""
|
|
|
|
import json
|
|
from datetime import UTC, datetime
|
|
|
|
from finn_eiendom.models import (
|
|
EiendomUnit,
|
|
FinnAd,
|
|
FinnSearchCard,
|
|
SimilarUnit,
|
|
UnitVector,
|
|
)
|
|
|
|
|
|
def test_finn_search_card_json_roundtrip():
|
|
"""Test JSON roundtrip for FinnSearchCard model."""
|
|
data = {
|
|
"finnkode": "123456789",
|
|
"url": "https://www.finn.no/realestate/homes/ad.html?finnkode=123456789",
|
|
"title": "Beautiful apartment in Oslo",
|
|
"address": "Karl Johans gate 1",
|
|
"area_m2": 80,
|
|
"asking_price": 5000000,
|
|
"total_price": 5200000,
|
|
"common_costs": 2000,
|
|
"property_type": "APARTMENT",
|
|
"ownership_type": "FREEHOLD",
|
|
"bedrooms": 2,
|
|
"floor": "3/5",
|
|
"broker_company": "Estate AS",
|
|
}
|
|
|
|
# Create model instance
|
|
model = FinnSearchCard(**data)
|
|
|
|
# Convert to JSON
|
|
json_str = model.model_dump_json()
|
|
|
|
# Parse JSON back to dict
|
|
parsed_data = json.loads(json_str)
|
|
|
|
# Create new instance from parsed data
|
|
model_from_json = FinnSearchCard(**parsed_data)
|
|
|
|
# Assert they're equal
|
|
assert model == model_from_json
|
|
|
|
|
|
def test_finn_ad_json_roundtrip():
|
|
"""Test JSON roundtrip for FinnAd model."""
|
|
now = datetime.now(UTC)
|
|
data = {
|
|
"finnkode": "123456789",
|
|
"url": "https://www.finn.no/realestate/homes/ad.html?finnkode=123456789",
|
|
"title": "Beautiful apartment in Oslo",
|
|
"address": "Karl Johans gate 1",
|
|
"postal_area": "0150",
|
|
"district": "Sentrum",
|
|
"property_type": "APARTMENT",
|
|
"ownership_type": "FREEHOLD",
|
|
"asking_price": 5000000,
|
|
"total_price": 5200000,
|
|
"shared_debt": 100000,
|
|
"common_costs": 2000,
|
|
"municipal_fee": 500,
|
|
"other_fees": 300,
|
|
"area_m2": 80,
|
|
"rooms": 3,
|
|
"bedrooms": 2,
|
|
"floor": "3/5",
|
|
"construction_year": 2000,
|
|
"energy_rating": "C",
|
|
"heating": "FJERNVARME",
|
|
"has_balcony": True,
|
|
"has_terrace": False,
|
|
"has_elevator": True,
|
|
"has_parking": False,
|
|
"has_garage": False,
|
|
"listing_description": "A lovely apartment with great views",
|
|
"broker_name": "John Doe",
|
|
"broker_company": "Estate AS",
|
|
"first_seen_at": now,
|
|
"last_seen_at": now,
|
|
"detail_fetched_at": now,
|
|
"eiendom_unit_code": "EI-987654321",
|
|
}
|
|
|
|
# Create model instance
|
|
model = FinnAd(**data)
|
|
|
|
# Convert to JSON
|
|
json_str = model.model_dump_json()
|
|
|
|
# Parse JSON back to dict
|
|
parsed_data = json.loads(json_str)
|
|
|
|
# Create new instance from parsed data
|
|
model_from_json = FinnAd(**parsed_data)
|
|
|
|
# Assert they're equal
|
|
assert model == model_from_json
|
|
|
|
|
|
def test_eiendom_unit_json_roundtrip():
|
|
"""Test JSON roundtrip for EiendomUnit model."""
|
|
now = datetime.now(UTC)
|
|
data = {
|
|
"unit_code": "EI-987654321",
|
|
"address": "Karl Johans gate 1",
|
|
"lat": 59.9139,
|
|
"lng": 10.7522,
|
|
"property_type": "APARTMENT",
|
|
"floor": 3,
|
|
"rooms": 3,
|
|
"construction_year": 2000,
|
|
"usable_area": 80,
|
|
"estimated_selling_price": 5500000,
|
|
"estimated_selling_price_lower": 5200000,
|
|
"estimated_selling_price_upper": 5800000,
|
|
"listing_price": 5000000,
|
|
"listing_sqm_price": 62500,
|
|
"common_costs": 2000,
|
|
"days_on_market": 45,
|
|
"sale_status": "FOR_SALE",
|
|
"market_placement_score": "GOOD",
|
|
"unit_vector": "base64encodedvector===",
|
|
"fetched_at": now,
|
|
}
|
|
|
|
# Create model instance
|
|
model = EiendomUnit(**data)
|
|
|
|
# Convert to JSON
|
|
json_str = model.model_dump_json()
|
|
|
|
# Parse JSON back to dict
|
|
parsed_data = json.loads(json_str)
|
|
|
|
# Create new instance from parsed data
|
|
model_from_json = EiendomUnit(**parsed_data)
|
|
|
|
# Assert they're equal
|
|
assert model == model_from_json
|
|
|
|
|
|
def test_similar_unit_json_roundtrip():
|
|
"""Test JSON roundtrip for SimilarUnit model."""
|
|
data = {
|
|
"unit_code": "EI-123456789",
|
|
"address": "Karl Johans gate 2",
|
|
"lat": 59.9140,
|
|
"lng": 10.7523,
|
|
"property_type": "APARTMENT",
|
|
"floor": 4,
|
|
"rooms": 3,
|
|
"construction_year": 2005,
|
|
"usable_area": 90,
|
|
"listing_price": 5800000,
|
|
"selling_price": 5700000,
|
|
"shared_debt": 120000,
|
|
"common_costs": 2200,
|
|
"sqm_price": 63333,
|
|
"days_on_market": 30,
|
|
"sale_status": "SOLD",
|
|
"finalized_at": datetime.now(UTC),
|
|
"listing_status": "RECENTLY_SOLD",
|
|
}
|
|
|
|
# Create model instance
|
|
model = SimilarUnit(**data)
|
|
|
|
# Convert to JSON
|
|
json_str = model.model_dump_json()
|
|
|
|
# Parse JSON back to dict
|
|
parsed_data = json.loads(json_str)
|
|
|
|
# Create new instance from parsed data
|
|
model_from_json = SimilarUnit(**parsed_data)
|
|
|
|
# Assert they're equal
|
|
assert model == model_from_json
|
|
|
|
|
|
def test_unit_vector_json_roundtrip():
|
|
"""Test JSON roundtrip for UnitVector model."""
|
|
data = {
|
|
"lon": 10.7522,
|
|
"lat": 59.9139,
|
|
"ptype": "APARTMENT",
|
|
"floor": 3,
|
|
"rooms": 3,
|
|
"built": 2000,
|
|
"area": 80,
|
|
"price": 5000000,
|
|
}
|
|
|
|
# Create model instance
|
|
model = UnitVector(**data)
|
|
|
|
# Convert to JSON
|
|
json_str = model.model_dump_json()
|
|
|
|
# Parse JSON back to dict
|
|
parsed_data = json.loads(json_str)
|
|
|
|
# Create new instance from parsed data
|
|
model_from_json = UnitVector(**parsed_data)
|
|
|
|
# Assert they're equal
|
|
assert model == model_from_json
|
|
|
|
|
|
def test_finn_ad_serializer_datetime():
|
|
"""Test that FinnAd datetime serialization works correctly."""
|
|
now = datetime.now(UTC)
|
|
data = {
|
|
"finnkode": "123456789",
|
|
"url": "https://www.finn.no/realestate/homes/ad.html?finnkode=123456789",
|
|
"first_seen_at": now,
|
|
"last_seen_at": now,
|
|
}
|
|
|
|
model = FinnAd(**data)
|
|
json_str = model.model_dump_json()
|
|
parsed_data = json.loads(json_str)
|
|
|
|
# Check that datetimes are serialized as ISO strings
|
|
assert isinstance(parsed_data["first_seen_at"], str)
|
|
assert isinstance(parsed_data["last_seen_at"], str)
|
|
assert "T" in parsed_data["first_seen_at"] # ISO format contains T
|
|
assert "Z" in parsed_data["first_seen_at"] or "+" in parsed_data["first_seen_at"] # TZ info
|
|
|
|
|
|
def test_eiendom_unit_serializer_datetime():
|
|
"""Test that EiendomUnit datetime serialization works correctly."""
|
|
now = datetime.now(UTC)
|
|
data = {
|
|
"unit_code": "EI-987654321",
|
|
"fetched_at": now,
|
|
}
|
|
|
|
model = EiendomUnit(**data)
|
|
json_str = model.model_dump_json()
|
|
parsed_data = json.loads(json_str)
|
|
|
|
# Check that datetimes are serialized as ISO strings
|
|
assert isinstance(parsed_data["fetched_at"], str)
|
|
assert "T" in parsed_data["fetched_at"] # ISO format contains T
|
|
assert "Z" in parsed_data["fetched_at"] or "+" in parsed_data["fetched_at"] # Timezone info
|
|
|
|
|
|
def test_similar_unit_serializer_datetime():
|
|
"""Test that SimilarUnit datetime serialization works correctly (handles None)."""
|
|
data = {
|
|
"unit_code": "EI-123456789",
|
|
"finalized_at": None, # This should serialize to null
|
|
}
|
|
|
|
model = SimilarUnit(**data)
|
|
json_str = model.model_dump_json()
|
|
parsed_data = json.loads(json_str)
|
|
|
|
# Check that None datetimes serialize to null
|
|
assert parsed_data["finalized_at"] is None
|