164 lines
5.7 KiB
Python
164 lines
5.7 KiB
Python
# tests/conftest.py
|
||
import os
|
||
import pytest
|
||
|
||
# ----------------------------------------------------------------------
|
||
# Import the concrete classes from your backend package.
|
||
# Adjust the import path if your package layout differs.
|
||
# ----------------------------------------------------------------------
|
||
from backend.db import DatabaseConnection
|
||
from backend.repositories import (
|
||
MemberRepository,
|
||
ClassificationRepository,
|
||
ServiceTypeRepository,
|
||
ServiceAvailabilityRepository,
|
||
)
|
||
|
||
|
||
# ----------------------------------------------------------------------
|
||
# Path to the full schema (DDL) that creates every table, including
|
||
# ServiceAvailability.
|
||
# ----------------------------------------------------------------------
|
||
@pytest.fixture(scope="session")
|
||
def schema_path() -> str:
|
||
"""Absolute path to the SQL file that creates the test schema."""
|
||
return os.path.abspath(
|
||
os.path.join(os.path.dirname(__file__), "..", "schema.sql")
|
||
)
|
||
|
||
|
||
# ----------------------------------------------------------------------
|
||
# Fresh in‑memory SQLite DB with the full schema applied.
|
||
# ----------------------------------------------------------------------
|
||
@pytest.fixture
|
||
def db_connection(schema_path: str) -> DatabaseConnection:
|
||
conn = DatabaseConnection(":memory:")
|
||
|
||
# Load the DDL.
|
||
with open(schema_path, "r", encoding="utf-8") as f:
|
||
ddl = f.read()
|
||
conn._conn.executescript(ddl) # apply the whole schema
|
||
conn._conn.commit()
|
||
|
||
yield conn
|
||
conn.close()
|
||
|
||
|
||
# ----------------------------------------------------------------------
|
||
# Seed lookup tables that have foreign‑key relationships.
|
||
# ----------------------------------------------------------------------
|
||
@pytest.fixture
|
||
def seed_lookup_tables(db_connection: DatabaseConnection):
|
||
"""
|
||
Insert rows into lookup tables that other tables reference.
|
||
Currently we need:
|
||
• Classifications – for Member tests
|
||
• ServiceTypes – for ServiceTypeRepository tests
|
||
• ServiceAvailability – for the repo we are testing now
|
||
"""
|
||
# ---- Classifications -------------------------------------------------
|
||
classifications = [
|
||
("Soprano",), # ClassificationId = 1
|
||
("Alto / Mezzo",), # ClassificationId = 2
|
||
("Tenor",), # ClassificationId = 3
|
||
("Baritone",), # ClassificationId = 4
|
||
]
|
||
for name in classifications:
|
||
db_connection.execute(
|
||
"INSERT INTO Classifications (ClassificationName) VALUES (?)",
|
||
name,
|
||
)
|
||
|
||
# ---- ServiceTypes ----------------------------------------------------
|
||
# These are the three time‑slot examples you asked for.
|
||
service_types = [("9AM",), ("11AM",), ("6PM",)]
|
||
for name in service_types:
|
||
db_connection.execute(
|
||
"INSERT INTO ServiceTypes (TypeName) VALUES (?)",
|
||
name,
|
||
)
|
||
|
||
# ---- ServiceAvailability ---------------------------------------------
|
||
# We need a couple of members first, otherwise the FK constraints will
|
||
# reject the inserts. We'll create two dummy members (Alice = 1,
|
||
# Bob = 2) and then map them to the three slots.
|
||
#
|
||
# NOTE: In a real test suite you would probably use the MemberRepository
|
||
# to create these rows, but inserting directly keeps the fixture fast and
|
||
# independent of the Member repo implementation.
|
||
dummy_members = [
|
||
("Alice", "Smith", "alice@example.com", None, None, 1, None, 1),
|
||
("Bob", "Jones", "bob@example.com", None, None, 2, None, 1),
|
||
]
|
||
for (
|
||
fn, ln, email, phone, notes,
|
||
classification_id, is_active, member_id_placeholder,
|
||
) in dummy_members:
|
||
# The MemberId column is AUTOINCREMENT, so we omit it.
|
||
db_connection.execute(
|
||
"""
|
||
INSERT INTO Members
|
||
(FirstName, LastName, Email, PhoneNumber, Notes,
|
||
ClassificationId, IsActive)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||
""",
|
||
(fn, ln, email, phone, notes, classification_id, is_active),
|
||
)
|
||
|
||
# At this point SQLite has assigned MemberIds 1 and 2.
|
||
# Map them to the three service‑type slots:
|
||
# Alice → 9AM (id = 1) and 6PM (id = 3)
|
||
# Bob → 11AM (id = 2) and 6PM (id = 3)
|
||
availability = [
|
||
(1, 1), # Alice – 9AM
|
||
(1, 3), # Alice – 6PM
|
||
(2, 2), # Bob – 11AM
|
||
(2, 3), # Bob – 6PM
|
||
]
|
||
for member_id, service_type_id in availability:
|
||
db_connection.execute(
|
||
"""
|
||
INSERT INTO ServiceAvailability (MemberId, ServiceTypeId)
|
||
VALUES (?, ?)
|
||
""",
|
||
(member_id, service_type_id),
|
||
)
|
||
|
||
# Commit everything so downstream fixtures see the data.
|
||
db_connection._conn.commit()
|
||
|
||
|
||
# ----------------------------------------------------------------------
|
||
# Repository factories – each receives the same fresh DB that already has
|
||
# the lookup data seeded.
|
||
# ----------------------------------------------------------------------
|
||
@pytest.fixture
|
||
def member_repo(
|
||
db_connection: DatabaseConnection,
|
||
seed_lookup_tables,
|
||
) -> MemberRepository:
|
||
return MemberRepository(db_connection)
|
||
|
||
|
||
@pytest.fixture
|
||
def classification_repo(
|
||
db_connection: DatabaseConnection,
|
||
seed_lookup_tables,
|
||
) -> ClassificationRepository:
|
||
return ClassificationRepository(db_connection)
|
||
|
||
|
||
@pytest.fixture
|
||
def service_type_repo(
|
||
db_connection: DatabaseConnection,
|
||
seed_lookup_tables,
|
||
) -> ServiceTypeRepository:
|
||
return ServiceTypeRepository(db_connection)
|
||
|
||
|
||
@pytest.fixture
|
||
def service_availability_repo(
|
||
db_connection: DatabaseConnection,
|
||
seed_lookup_tables,
|
||
) -> ServiceAvailabilityRepository:
|
||
return ServiceAvailabilityRepository(db_connection) |