Files
WiseGrade/backend/tests/test_foundation.py
T

68 lines
3.3 KiB
Python

from pathlib import Path
import pytest
from sqlalchemy import select, text
from wisegrade.models import CourseObjective, CourseVersion, GraduationIndicator, RubricCriterion, RubricScoreLevel, RubricVersion, TopicDirection
from wisegrade.rules import RubricData, totals
from wisegrade.storage import classify, extract_identity, parse_student_folder, secure_path, sha256
def test_postgresql_migrations_and_vector_extension(db):
assert db.bind.dialect.name == "postgresql"
assert db.scalar(text("SELECT version_num FROM alembic_version")) == "0006"
assert db.scalar(text("SELECT extname FROM pg_extension WHERE extname = 'vector'")) == "vector"
def test_seeded_course_and_weights(db):
version = db.scalar(select(CourseVersion))
rubric = db.scalar(select(RubricVersion))
assert version.published and rubric.published
assert {item["code"] for item in version.indicators} == {"2.3", "2.4", "4.1", "4.2", "4.3", "4.4", "11.1", "11.2"}
assert len(RubricData(criteria=rubric.criteria, weights=rubric.weights).criteria) == 22
assert rubric.weights == {"stage1": .1, "stage2": .1, "stage3": .1, "final": .7}
assert len(db.scalars(select(CourseObjective)).all()) == 4
assert len(db.scalars(select(GraduationIndicator)).all()) == 8
assert len(db.scalars(select(TopicDirection)).all()) == 3
assert len(db.scalars(select(RubricCriterion)).all()) == 22
assert len(db.scalars(select(RubricScoreLevel)).all()) == 66
def test_score_totals_preserve_missing(db):
rubric = db.scalar(select(RubricVersion))
scores = {item["criterion_id"]: item["max_score"] for item in rubric.criteria}
assert totals(scores, rubric.criteria, rubric.weights)["overall"] == 100
scores.pop("stage2.hardware")
result = totals(scores, rubric.criteria, rubric.weights)
assert result["stage2"] is None and result["overall"] is None
def test_invalid_rubric_weights(db):
rubric = db.scalar(select(RubricVersion))
with pytest.raises(ValueError):
RubricData(criteria=rubric.criteria, weights={"stage1": .2, "stage2": .1, "stage3": .1, "final": .7})
def test_path_security_and_hash(environment):
root = environment / "inbox"
target = root / "student" / "report.pdf"
target.parent.mkdir()
target.write_bytes(b"unchanged")
assert secure_path("student/report.pdf", root=root) == target
assert sha256(target) == "aaa8d3c8d74ad3e8f6b1772aa9c7e0eaa528cb42fc93599ce2f125b00d4c424c"
for bad in ("../outside", "/etc/passwd", "student/../../outside", "student\\report.pdf"):
with pytest.raises(ValueError):
secure_path(bad, root=root)
(root / "link").symlink_to(environment)
with pytest.raises(ValueError):
secure_path("link/test.db", root=root, must_exist=False)
def test_student_folder_and_file_recognition():
assert parse_student_folder("1023009006_李傲琦_基于ROS2系统的自瞄移动机器人")["topic"].startswith("基于ROS2")
assert parse_student_folder("bad_name")["status"] == "needs_confirmation"
assert classify(Path("汇报PPT.pdf")) == ("presentation", "needs_confirmation")
assert classify(Path("阶段报告2.docx")) == ("stage2", "recognized")
assert classify(Path("legacy.doc")) == ("unknown", "unsupported")
assert extract_identity("学号:1023009006\n姓名:李傲琦\n题目:机器人系统")["topic"] == "机器人系统"