""" Unit tests for database operations. """ import pytest import tempfile import os from datetime import datetime, timedelta import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from src.database import Database @pytest.fixture def db(): """Create a temporary database for testing""" with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as f: db_path = f.name database = Database(db_path) yield database # Cleanup os.unlink(db_path) class TestProductOperations: """Tests for product CRUD operations""" def test_create_product(self, db): """Test creating a new product""" product_id = db.get_or_create_product( url="https://example.com/product/123", name="Test Pokemon Card", site="pokemoncenter", product_id="123", price="$19.99", in_stock=True ) assert product_id is not None assert product_id > 0 def test_get_product_by_url(self, db): """Test retrieving product by URL""" url = "https://example.com/product/456" db.get_or_create_product( url=url, name="Pikachu ETB", site="target", in_stock=True ) product = db.get_product_by_url(url) assert product is not None assert product['name'] == "Pikachu ETB" assert product['site'] == "target" def test_update_product_price(self, db): """Test updating product price""" product_id = db.get_or_create_product( url="https://example.com/product/789", name="Booster Box", site="bestbuy", price="$99.99", in_stock=True ) # Update price db.update_product_price(product_id, "$89.99") product = db.get_product(product_id) assert product['current_price'] == "$89.99" # Check price history was recorded history = db.get_price_history(product_id, days=1) assert len(history) >= 1 def test_update_product_stock(self, db): """Test updating product stock status""" product_id = db.get_or_create_product( url="https://example.com/product/stock-test", name="Limited Edition", site="pokemoncenter", in_stock=True ) # Mark out of stock db.update_product_stock(product_id, False) product = db.get_product(product_id) assert product['in_stock'] == 0 # SQLite stores as 0/1 def test_category_detection(self, db): """Test automatic category detection from product name""" test_cases = [ ("Pokemon Scarlet Elite Trainer Box", "ETB"), ("Charizard Booster Bundle", "Booster Bundle"), ("Display Booster Box 36 Packs", "Booster Box"), ("Sleeved Booster Pack", "Booster Pack"), ("Premium Collection Box", "Collection Box"), ("Pokemon Trading Card Tin", "Tin"), ("Card Binder Album", "Accessories"), ("Random Pokemon Item", "Other"), ] for name, expected_category in test_cases: product_id = db.get_or_create_product( url=f"https://example.com/{name.replace(' ', '-')}", name=name, site="test", in_stock=True ) product = db.get_product(product_id) assert product['category'] == expected_category, f"Failed for: {name}" class TestStockEvents: """Tests for stock event tracking""" def test_record_stock_event(self, db): """Test recording stock events""" product_id = db.get_or_create_product( url="https://example.com/event-test", name="Event Test Product", site="test", in_stock=True ) db.record_stock_event(product_id, "new_drop") db.record_stock_event(product_id, "out_of_stock") db.record_stock_event(product_id, "restock") events = db.get_recent_events(limit=10) # Should have 3 events product_events = [e for e in events if e['product_id'] == product_id] assert len(product_events) == 3 def test_events_today_count(self, db): """Test counting events from today""" product_id = db.get_or_create_product( url="https://example.com/today-test", name="Today Test", site="test", in_stock=True ) db.record_stock_event(product_id, "new_drop") db.record_stock_event(product_id, "restock") new_drops = db.get_events_today("new_drop") restocks = db.get_events_today("restock") assert new_drops >= 1 assert restocks >= 1 def test_selling_rate_calculation(self, db): """Test that selling rate can be calculated from events""" product_id = db.get_or_create_product( url="https://example.com/sellrate-test", name="Fast Seller", site="pokemoncenter", in_stock=True ) # Simulate: drop -> sold out db.record_stock_event(product_id, "new_drop") db.record_stock_event(product_id, "out_of_stock") # Get stock duration stats stats = db.get_stock_duration_stats() # Should return at least an empty list (stats depend on timing) assert isinstance(stats, list) class TestPriceHistory: """Tests for price history tracking""" def test_record_price_change(self, db): """Test that price changes are recorded""" product_id = db.get_or_create_product( url="https://example.com/price-test", name="Price Test", site="test", price="$49.99", in_stock=True ) # Record initial price db.record_price(product_id, "$49.99") # Change price db.record_price(product_id, "$39.99") history = db.get_price_history(product_id, days=1) # Should have at least 2 price points assert len(history) >= 1 def test_duplicate_price_not_recorded(self, db): """Test that same price is not recorded multiple times""" product_id = db.get_or_create_product( url="https://example.com/dup-price-test", name="Dup Price Test", site="test", in_stock=True ) # Record same price multiple times db.record_price(product_id, "$29.99") db.record_price(product_id, "$29.99") db.record_price(product_id, "$29.99") history = db.get_price_history(product_id, days=1) # Should only have 1 entry assert len(history) == 1 class TestDashboardStats: """Tests for dashboard statistics""" def test_get_dashboard_stats(self, db): """Test getting dashboard stats summary""" # Add some test data for i in range(5): product_id = db.get_or_create_product( url=f"https://example.com/stats-{i}", name=f"Stats Product {i}", site="pokemoncenter", in_stock=(i % 2 == 0) ) db.record_stock_event(product_id, "new_drop") stats = db.get_dashboard_stats() assert 'total_products' in stats assert 'in_stock_count' in stats assert 'new_drops_today' in stats assert stats['total_products'] >= 5 def test_get_site_stats(self, db): """Test per-site statistics""" sites = ['target', 'bestbuy', 'pokemoncenter'] for site in sites: db.get_or_create_product( url=f"https://{site}.com/test", name=f"{site} Product", site=site, in_stock=True ) stats = db.get_site_stats() assert len(stats) == 3 site_names = [s['site'] for s in stats] assert 'target' in site_names assert 'bestbuy' in site_names class TestFavorites: """Tests for favorites functionality""" def test_add_favorite(self, db): """Test adding a favorite""" fav_id = db.add_favorite( fav_type="product", value="https://example.com/fav-product", display_name="My Favorite Card", priority="high" ) assert fav_id is not None favorite = db.get_favorite(fav_id) assert favorite['display_name'] == "My Favorite Card" def test_check_is_favorite(self, db): """Test checking if product is favorited""" url = "https://example.com/check-fav" # Not a favorite yet result = db.check_is_favorite(url=url) assert result is None # Add as favorite db.add_favorite(fav_type="product", value=url) # Now should be found result = db.check_is_favorite(url=url) assert result is not None if __name__ == "__main__": pytest.main([__file__, "-v"])