generated from john/python-template
99 lines
4.0 KiB
Python
99 lines
4.0 KiB
Python
"""Tests for Step 3 library services (revisions, search, export)."""
|
|
|
|
import pytest
|
|
from sqlmodel import select
|
|
|
|
from transcription.models import Document
|
|
from transcription.models import Job
|
|
from transcription.models import JobStatus
|
|
from transcription.models import Transcript
|
|
from transcription.models import TranscriptRevision
|
|
from transcription.services.library import accept_revision
|
|
from transcription.services.library import add_revision
|
|
from transcription.services.library import export_transcripts
|
|
from transcription.services.library import list_revisions
|
|
from transcription.services.library import search_accepted_transcripts
|
|
|
|
|
|
def _create_job(session) -> Job:
|
|
document = Document(filename="letter.jpg", file_path="uploads/letter.jpg")
|
|
session.add(document)
|
|
session.commit()
|
|
session.refresh(document)
|
|
|
|
job = Job(document_id=document.id, status=JobStatus.TRANSCRIBED)
|
|
session.add(job)
|
|
session.commit()
|
|
session.refresh(job)
|
|
return job
|
|
|
|
|
|
@pytest.mark.integration
|
|
class TestRevisionHistoryBehavior:
|
|
"""Verify revision append/accept behavior."""
|
|
|
|
def test_add_revision_appends_incrementing_revision_numbers(self, session):
|
|
"""add_revision creates immutable incrementing revisions per job."""
|
|
job = _create_job(session)
|
|
|
|
r1 = add_revision(job_id=job.id, text="first", session=session)
|
|
r2 = add_revision(job_id=job.id, text="second", session=session)
|
|
|
|
revisions = list_revisions(job_id=job.id, session=session)
|
|
|
|
assert r1.revision_number == 1
|
|
assert r2.revision_number == 2
|
|
assert [revision.revision_number for revision in revisions] == [1, 2]
|
|
|
|
def test_accept_revision_marks_selected_revision_and_sets_job_completed(self, session):
|
|
"""accept_revision marks one revision accepted and transitions job to completed."""
|
|
job = _create_job(session)
|
|
r1 = add_revision(job_id=job.id, text="v1", session=session)
|
|
r2 = add_revision(job_id=job.id, text="v2", session=session)
|
|
|
|
accepted = accept_revision(revision_id=r2.id, session=session)
|
|
session.refresh(job)
|
|
|
|
all_revisions = list(session.exec(select(TranscriptRevision).where(TranscriptRevision.job_id == job.id)).all())
|
|
accepted_flags = {revision.id: revision.accepted for revision in all_revisions}
|
|
transcript = session.exec(select(Transcript).where(Transcript.job_id == job.id)).first()
|
|
|
|
assert accepted.id == r2.id
|
|
assert accepted_flags[r1.id] is False
|
|
assert accepted_flags[r2.id] is True
|
|
assert job.status == JobStatus.COMPLETED
|
|
assert transcript is not None
|
|
assert transcript.text == "v2"
|
|
|
|
|
|
@pytest.mark.integration
|
|
class TestSearchAndExportBehavior:
|
|
"""Verify accepted-only search and export semantics."""
|
|
|
|
def test_search_returns_only_accepted_revisions(self, session):
|
|
"""search_accepted_transcripts filters out non-accepted revisions."""
|
|
job = _create_job(session)
|
|
draft = add_revision(job_id=job.id, text="family archive draft", session=session)
|
|
accepted = add_revision(job_id=job.id, text="family archive final", accepted=True, session=session)
|
|
|
|
results = search_accepted_transcripts(query="archive", session=session)
|
|
|
|
assert results
|
|
result_ids = {result.id for result in results}
|
|
assert accepted.id in result_ids
|
|
assert draft.id not in result_ids
|
|
|
|
def test_export_returns_serializable_records_for_accepted_revisions(self, session):
|
|
"""export_transcripts returns expected fields for accepted-only export."""
|
|
job = _create_job(session)
|
|
accepted = add_revision(job_id=job.id, text="export me", accepted=True, session=session)
|
|
|
|
records = export_transcripts(accepted_only=True, session=session)
|
|
|
|
assert len(records) == 1
|
|
record = records[0]
|
|
assert record["job_id"] == str(job.id)
|
|
assert record["revision_id"] == str(accepted.id)
|
|
assert record["accepted"] is True
|
|
assert record["text"] == "export me"
|