Files
Autoparts-DB/console/tests/test_db.py
consultoria-as 3b884e24d3 feat(console): add database abstraction layer with tests
Implement console/db.py with Database class providing all data access
methods for the console application, plus 36 passing tests in
console/tests/test_db.py covering vehicle navigation, parts catalog,
search, VIN cache, stats, manufacturers, and admin CRUD operations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:34:22 +00:00

274 lines
8.0 KiB
Python

"""
Tests for the Database abstraction layer.
All tests run against the real SQLite database at vehicle_database/vehicle_database.db.
"""
import pytest
from console.db import Database
@pytest.fixture(scope="module")
def db():
"""Provide a shared Database instance for all tests in this module."""
return Database()
# =========================================================================
# Vehicle navigation
# =========================================================================
class TestGetBrands:
def test_returns_nonempty_list(self, db):
brands = db.get_brands()
assert isinstance(brands, list)
assert len(brands) > 0
def test_each_brand_has_name_key(self, db):
brands = db.get_brands()
for b in brands:
assert "name" in b
def test_each_brand_has_id_and_country(self, db):
brands = db.get_brands()
for b in brands:
assert "id" in b
assert "country" in b
class TestGetModels:
def test_no_filter_returns_nonempty(self, db):
models = db.get_models()
assert isinstance(models, list)
assert len(models) > 0
def test_filter_by_uppercase_brand(self, db):
models = db.get_models(brand="TOYOTA")
assert isinstance(models, list)
assert len(models) > 0
def test_filter_by_lowercase_brand(self, db):
"""Brand filtering must be case-insensitive."""
models = db.get_models(brand="toyota")
assert isinstance(models, list)
assert len(models) > 0
def test_each_model_has_id_and_name(self, db):
models = db.get_models()
for m in models[:5]:
assert "id" in m
assert "name" in m
class TestGetYears:
def test_returns_list(self, db):
years = db.get_years()
assert isinstance(years, list)
assert len(years) > 0
def test_filter_by_brand(self, db):
years = db.get_years(brand="TOYOTA")
assert isinstance(years, list)
assert len(years) > 0
def test_each_year_has_id_and_year(self, db):
years = db.get_years()
for y in years[:5]:
assert "id" in y
assert "year" in y
class TestGetEngines:
def test_returns_list(self, db):
engines = db.get_engines()
assert isinstance(engines, list)
assert len(engines) > 0
def test_filter_by_brand(self, db):
engines = db.get_engines(brand="TOYOTA")
assert isinstance(engines, list)
assert len(engines) > 0
class TestGetModelYearEngine:
def test_returns_list(self, db):
result = db.get_model_year_engine(
brand="TOYOTA", model="Corolla", year=2020, engine_id=None
)
assert isinstance(result, list)
# =========================================================================
# Parts catalog
# =========================================================================
class TestGetCategories:
def test_returns_exactly_12(self, db):
categories = db.get_categories()
assert isinstance(categories, list)
assert len(categories) == 12
def test_each_has_expected_keys(self, db):
categories = db.get_categories()
for c in categories:
assert "id" in c
assert "name" in c
class TestGetGroups:
def test_returns_nonempty_for_known_category(self, db):
groups = db.get_groups(category_id=2)
assert isinstance(groups, list)
assert len(groups) > 0
def test_each_group_has_name(self, db):
groups = db.get_groups(category_id=2)
for g in groups:
assert "name" in g
class TestGetParts:
def test_returns_list(self, db):
parts = db.get_parts()
assert isinstance(parts, list)
assert len(parts) > 0
def test_pagination(self, db):
page1 = db.get_parts(page=1, per_page=5)
page2 = db.get_parts(page=2, per_page=5)
assert len(page1) <= 5
assert len(page2) <= 5
# Pages should contain different items (if enough data)
if page1 and page2:
ids1 = {p["id"] for p in page1}
ids2 = {p["id"] for p in page2}
assert ids1.isdisjoint(ids2)
class TestGetPart:
def test_returns_dict_with_oem_part_number(self, db):
part = db.get_part(1)
assert isinstance(part, dict)
assert "oem_part_number" in part
def test_includes_group_and_category_info(self, db):
part = db.get_part(1)
assert "group_name" in part
assert "category_name" in part
def test_nonexistent_returns_none(self, db):
part = db.get_part(999999)
assert part is None
class TestGetAlternatives:
def test_returns_list(self, db):
alts = db.get_alternatives(1)
assert isinstance(alts, list)
class TestGetCrossReferences:
def test_returns_list(self, db):
refs = db.get_cross_references(1)
assert isinstance(refs, list)
class TestGetVehiclesForPart:
def test_returns_list(self, db):
vehicles = db.get_vehicles_for_part(1)
assert isinstance(vehicles, list)
assert len(vehicles) > 0
# =========================================================================
# Search
# =========================================================================
class TestSearchParts:
def test_returns_results_for_brake(self, db):
results = db.search_parts("brake")
assert isinstance(results, list)
assert len(results) > 0
def test_each_result_has_expected_keys(self, db):
results = db.search_parts("brake")
for r in results[:3]:
assert "id" in r
assert "name" in r
assert "oem_part_number" in r
class TestSearchPartNumber:
def test_returns_results_for_04465(self, db):
results = db.search_part_number("04465")
assert isinstance(results, list)
assert len(results) > 0
def test_each_result_has_match_type(self, db):
results = db.search_part_number("04465")
for r in results:
assert "match_type" in r
# =========================================================================
# VIN cache
# =========================================================================
class TestVinCache:
def test_get_nonexistent_vin_returns_none(self, db):
result = db.get_vin_cache("00000000000000000")
assert result is None
# =========================================================================
# Stats
# =========================================================================
class TestGetStats:
def test_returns_dict_with_required_keys(self, db):
stats = db.get_stats()
assert isinstance(stats, dict)
assert "brands" in stats
assert "models" in stats
assert "parts" in stats
def test_counts_are_positive(self, db):
stats = db.get_stats()
assert stats["brands"] > 0
assert stats["models"] > 0
assert stats["parts"] > 0
def test_includes_top_brands(self, db):
stats = db.get_stats()
assert "top_brands" in stats
assert isinstance(stats["top_brands"], list)
# =========================================================================
# Manufacturers
# =========================================================================
class TestGetManufacturers:
def test_returns_nonempty_list(self, db):
manufacturers = db.get_manufacturers()
assert isinstance(manufacturers, list)
assert len(manufacturers) > 0
def test_each_has_name(self, db):
manufacturers = db.get_manufacturers()
for m in manufacturers:
assert "name" in m
assert "id" in m
# =========================================================================
# Admin CRUD — smoke tests
# =========================================================================
class TestCrossrefsPaginated:
def test_returns_list(self, db):
refs = db.get_crossrefs_paginated(page=1, per_page=5)
assert isinstance(refs, list)
assert len(refs) <= 5