"""Unit tests for ListingRepository.""" from datetime import datetime, timedelta import pytest from sqlalchemy import Engine from models.listing import ( FurnishType, ListingType, QueryParameters, RentListing, ) from repositories.listing_repository import ListingRepository class TestListingRepository: """Tests for ListingRepository methods.""" async def test_get_listings_empty_db( self, listing_repository: ListingRepository ) -> None: """Test that get_listings returns empty list for empty database.""" listings = await listing_repository.get_listings() assert listings == [] async def test_get_listings_returns_inserted_listings( self, listing_repository: ListingRepository, sample_rent_listing: RentListing, ) -> None: """Test that get_listings returns listings that were inserted.""" await listing_repository.upsert_listings([sample_rent_listing]) listings = await listing_repository.get_listings() assert len(listings) == 1 assert listings[0].id == sample_rent_listing.id async def test_upsert_listings_creates_new( self, listing_repository: ListingRepository, sample_rent_listing: RentListing, ) -> None: """Test that upsert_listings creates new listings.""" result = await listing_repository.upsert_listings([sample_rent_listing]) assert len(result) == 1 assert result[0].id == sample_rent_listing.id # Verify it's in the database listings = await listing_repository.get_listings() assert len(listings) == 1 async def test_upsert_listings_updates_existing( self, listing_repository: ListingRepository, sample_rent_listing: RentListing, ) -> None: """Test that upsert_listings updates existing listings.""" # Insert initial listing await listing_repository.upsert_listings([sample_rent_listing]) # Update the listing sample_rent_listing.price = 3000.0 await listing_repository.upsert_listings([sample_rent_listing]) # Verify update listings = await listing_repository.get_listings() assert len(listings) == 1 assert listings[0].price == 3000.0 async def test_mark_seen_updates_timestamp( self, listing_repository: ListingRepository, sample_rent_listing: RentListing, ) -> None: """Test that mark_seen updates the last_seen timestamp.""" # Set an old timestamp old_time = datetime.now() - timedelta(days=7) sample_rent_listing.last_seen = old_time await listing_repository.upsert_listings([sample_rent_listing]) # Mark as seen await listing_repository.mark_seen(sample_rent_listing.id) # Verify timestamp was updated listings = await listing_repository.get_listings() assert len(listings) == 1 assert listings[0].last_seen > old_time async def test_mark_seen_nonexistent_listing( self, listing_repository: ListingRepository ) -> None: """Test that mark_seen handles nonexistent listings gracefully.""" # Should not raise an exception await listing_repository.mark_seen(999999) async def test_get_listings_with_only_ids( self, listing_repository: ListingRepository, sample_rent_listings: list[RentListing], ) -> None: """Test that get_listings filters by only_ids.""" await listing_repository.upsert_listings(sample_rent_listings) # Request only specific IDs listings = await listing_repository.get_listings(only_ids=[1, 3]) assert len(listings) == 2 listing_ids = [l.id for l in listings] assert 1 in listing_ids assert 3 in listing_ids assert 2 not in listing_ids async def test_get_listings_with_limit( self, listing_repository: ListingRepository, sample_rent_listings: list[RentListing], ) -> None: """Test that get_listings respects limit parameter.""" await listing_repository.upsert_listings(sample_rent_listings) listings = await listing_repository.get_listings(limit=2) assert len(listings) == 2 class TestListingRepositoryFilters: """Tests for ListingRepository query parameter filtering.""" async def test_filter_by_bedrooms( self, listing_repository: ListingRepository, sample_rent_listings: list[RentListing], ) -> None: """Test filtering by bedroom count.""" await listing_repository.upsert_listings(sample_rent_listings) query_params = QueryParameters( listing_type=ListingType.RENT, min_bedrooms=2, max_bedrooms=2, ) listings = await listing_repository.get_listings(query_parameters=query_params) assert len(listings) == 1 assert listings[0].number_of_bedrooms == 2 async def test_filter_by_price_range( self, listing_repository: ListingRepository, sample_rent_listings: list[RentListing], ) -> None: """Test filtering by price range.""" await listing_repository.upsert_listings(sample_rent_listings) query_params = QueryParameters( listing_type=ListingType.RENT, min_price=1800, max_price=2500, ) listings = await listing_repository.get_listings(query_parameters=query_params) assert len(listings) == 1 assert listings[0].price == 2000.0 async def test_filter_by_min_sqm( self, listing_repository: ListingRepository, sample_rent_listings: list[RentListing], ) -> None: """Test filtering by minimum square meters.""" await listing_repository.upsert_listings(sample_rent_listings) query_params = QueryParameters( listing_type=ListingType.RENT, min_sqm=60, ) listings = await listing_repository.get_listings(query_parameters=query_params) assert len(listings) == 1 assert listings[0].square_meters == 80.0 async def test_filter_by_furnish_type( self, listing_repository: ListingRepository, sample_rent_listings: list[RentListing], ) -> None: """Test filtering by furnish type.""" await listing_repository.upsert_listings(sample_rent_listings) query_params = QueryParameters( listing_type=ListingType.RENT, furnish_types=[FurnishType.UNFURNISHED], ) listings = await listing_repository.get_listings(query_parameters=query_params) assert len(listings) == 1 assert listings[0].furnish_type == FurnishType.UNFURNISHED async def test_filter_by_last_seen_days( self, listing_repository: ListingRepository, sample_rent_listings: list[RentListing], ) -> None: """Test filtering by last_seen_days.""" # Make one listing old sample_rent_listings[0].last_seen = datetime.now() - timedelta(days=30) await listing_repository.upsert_listings(sample_rent_listings) query_params = QueryParameters( listing_type=ListingType.RENT, last_seen_days=7, ) listings = await listing_repository.get_listings(query_parameters=query_params) # Only 2 should be recent enough assert len(listings) == 2 async def test_combined_filters( self, listing_repository: ListingRepository, sample_rent_listings: list[RentListing], ) -> None: """Test combining multiple filters.""" await listing_repository.upsert_listings(sample_rent_listings) query_params = QueryParameters( listing_type=ListingType.RENT, min_bedrooms=1, max_bedrooms=2, min_price=1000, max_price=2500, furnish_types=[FurnishType.FURNISHED, FurnishType.UNFURNISHED], ) listings = await listing_repository.get_listings(query_parameters=query_params) # Should match listings with 1-2 bedrooms in price range assert len(listings) == 2