"""Explicit batch membership regressions, isolated from real grading and credentials.""" import pytest from fastapi import HTTPException from pydantic import ValidationError from sqlalchemy import create_engine from sqlalchemy.orm import Session from wisegrade import api, services from wisegrade.db import Base from wisegrade.models import CourseVersion, Project, ScoringBatch, Student from wisegrade.seed import seed_initial @pytest.fixture def batch_db(environment): engine = create_engine("sqlite://") Base.metadata.create_all(engine) with Session(engine, expire_on_commit=False) as db: seed_initial(db) students = [Student(student_no=f"900000000{i}", name=f"测试{i}") for i in (1, 2, 3)] db.add_all(students) db.flush() other = CourseVersion(course_id=1, version=2, title="另一课程版本", published=True, objectives=[], indicators=[], directions=[], prompts={}, templates=[]) db.add(other) db.flush() db.add_all([Project(student_id=students[0].id, course_version_id=1, topic="项目甲", source_dir="a"), Project(student_id=students[1].id, course_version_id=1, topic="项目乙", source_dir="b"), Project(student_id=students[2].id, course_version_id=other.id, topic="其他版本", source_dir="c")]) db.commit() yield db engine.dispose() def test_select_one_project_and_preserve_batch_membership(batch_db): data = api.BatchInput(course_version_id=1, rubric_version_id=1, project_ids=[2]) created = api.create_batch(data, batch_db) batch = batch_db.get(ScoringBatch, created["id"]) assert batch.project_ids == [2] # Importing another project later cannot change this batch's selected membership. batch_db.add(Project(student_id=1, course_version_id=1, topic="后来导入", source_dir="later")) batch_db.commit() assert api.batch_progress(batch.id, batch_db)["project_ids"] == [2] def test_omitted_selection_preserves_existing_all_projects_api(batch_db): created = api.create_batch(api.BatchInput(course_version_id=1, rubric_version_id=1), batch_db) assert batch_db.get(ScoringBatch, created["id"]).project_ids == [1, 2] @pytest.mark.parametrize("ids", [[999], [3], [2, 2]]) def test_reject_unknown_cross_version_and_duplicate_project_ids(batch_db, ids): with pytest.raises(HTTPException) as exc: api.create_batch(api.BatchInput(course_version_id=1, rubric_version_id=1, project_ids=ids), batch_db) assert exc.value.status_code == 400 assert batch_db.query(ScoringBatch).count() == 0 def test_empty_explicit_selection_cannot_silently_grade_everyone(): with pytest.raises(ValidationError): api.BatchInput(course_version_id=1, rubric_version_id=1, project_ids=[]) def test_batch_list_uses_saved_human_readable_version_metadata(batch_db): created = api.create_batch(api.BatchInput(course_version_id=1, rubric_version_id=1, project_ids=[1]), batch_db) batch = batch_db.get(ScoringBatch, created["id"]) batch.course_snapshot = {**batch.course_snapshot, "version": 7, "title": "创建时课程"} batch.rubric_snapshot = {**batch.rubric_snapshot, "version": 9} batch_db.commit() listed = api.list_batches(batch_db)[0] assert listed["course_version"] == 7 and listed["course_title"] == "创建时课程" assert listed["rubric_version"] == 9 and listed["criterion_count"] == 22