Files
WiseGrade/backend/tests/test_foundation.py
T

62 lines
3.0 KiB
Python

from pathlib import Path
import pytest
from sqlalchemy import select
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_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"] == "机器人系统"