File size: 5,410 Bytes
ed832a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b88dc75
12e244e
ed832a7
 
12e244e
 
ed832a7
b88dc75
 
 
ed832a7
 
 
 
 
 
 
 
 
 
 
12e244e
ed832a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b88dc75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ed832a7
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import json
import tempfile
import unittest
from pathlib import Path
from types import SimpleNamespace

import admin_service as admin
import classroom_service as classroom


class AdminServiceTests(unittest.TestCase):
    def setUp(self):
        self.temp_dir = tempfile.TemporaryDirectory()
        self.root = Path(self.temp_dir.name)
        self.data = self.root / "classroom_data"
        self.templates = self.data / "templates"
        self.projects = self.root / "projects"
        self.templates.mkdir(parents=True)
        self.projects.mkdir()
        (self.data / "course.json").write_text(json.dumps({
            "title": "測試課程",
            "weeks": [{
                "id": "week02", "week": 2, "title": "舊標題",
                "project": "舊專題", "output": "舊產出", "template": False,
            }],
        }, ensure_ascii=False), encoding="utf-8")
        (self.data / "classes.json").write_text(json.dumps([{"code": "L6A", "name": "測試班", "students": []}], ensure_ascii=False), encoding="utf-8")
        self.old = (classroom.DATA, classroom.TEMPLATES, classroom.CHECKPOINTS, classroom.VERSIONS, classroom.PASSWORD, classroom.RUNTIME, classroom.DB, admin.ROOT, admin.PROJECTS, admin.commit_changes)
        classroom.DATA = self.data
        classroom.TEMPLATES = self.templates
        classroom.CHECKPOINTS = self.data / "checkpoints"
        classroom.VERSIONS = self.data / "versions"
        classroom.PASSWORD = "teacher-test"
        classroom.RUNTIME = self.root / "runtime"
        classroom.DB = classroom.RUNTIME / "classroom.sqlite3"
        classroom.init_db()
        admin.ROOT = self.root
        admin.PROJECTS = self.projects
        self.commits = []

        def fake_commit(additions, deletions, message):
            self.commits.append((additions, deletions, message))
            return SimpleNamespace(commit_url="https://example.test/commit")

        admin.commit_changes = fake_commit

    def tearDown(self):
        classroom.DATA, classroom.TEMPLATES, classroom.CHECKPOINTS, classroom.VERSIONS, classroom.PASSWORD, classroom.RUNTIME, classroom.DB, admin.ROOT, admin.PROJECTS, admin.commit_changes = self.old
        self.temp_dir.cleanup()

    def test_teacher_updates_week_and_template_files(self):
        request = admin.WeekSave(
            password="teacher-test", week_id="week02", title="新標題",
            project="新專題", output="新產出",
            files={"main.py": 'print("ok")\n', "data/case.json": "{}\n"},
        )
        result = admin.save_week(request)
        course = json.loads((self.data / "course.json").read_text(encoding="utf-8"))
        self.assertTrue(result["ok"])
        self.assertEqual(course["weeks"][0]["title"], "新標題")
        self.assertTrue(course["weeks"][0]["template"])
        self.assertEqual((self.templates / "week02" / "main.py").read_text(), 'print("ok")\n')
        self.assertEqual(len(self.commits), 1)

    def test_teacher_creates_renames_and_deletes_demo_project(self):
        created = admin.save_demo(admin.DemoSave(
            password="teacher-test", class_name="進階班", student_name="Alex",
            project_name="互動故事", files={"main.py": 'print("start")\n'},
        ))
        original = admin.ProjectRef(**created["project"])
        project_root = self.projects / "進階班" / "Alex" / "互動故事"
        (project_root / "picture.png").write_bytes(b"png")
        renamed = admin.save_demo(admin.DemoSave(
            password="teacher-test", original=original, class_name="進階班",
            student_name="Alex", project_name="互動故事完整版",
            files={"main.py": 'print("done")\n'},
        ))
        renamed_root = self.projects / "進階班" / "Alex" / "互動故事完整版"
        self.assertFalse(project_root.exists())
        self.assertEqual((renamed_root / "main.py").read_text(), 'print("done")\n')
        self.assertEqual((renamed_root / "picture.png").read_bytes(), b"png")
        admin.delete_demo(admin.DemoRequest(
            password="teacher-test", project=admin.ProjectRef(**renamed["project"])
        ))
        self.assertFalse(renamed_root.exists())
        self.assertEqual(len(self.commits), 3)

    def test_teacher_backs_up_and_manages_submitted_content(self):
        state = classroom.empty("L6A", "alex", "Alex", "week02")
        state["project_name"] = "謎案"
        state["files"] = {"main.py": 'print("saved")\n'}
        state["final_files"] = dict(state["files"])
        state["submitted_at"] = 123456789
        classroom.save(state)

        result = admin.backup_submissions(admin.ClassroomBackupRequest(password="teacher-test", class_code="L6A", week_id="week02"))
        saved = self.data / "submissions" / "L6A" / "alex" / "week02.json"
        self.assertEqual(result["count"], 1)
        self.assertTrue(saved.is_file())
        detail = admin.admin_submission(admin.ClassroomSubmissionRequest(password="teacher-test", class_code="L6A", student_id="alex", week_id="week02"))
        self.assertIn("saved", detail["submission"]["files"]["main.py"])

        admin.delete_submission(admin.ClassroomSubmissionRequest(password="teacher-test", class_code="L6A", student_id="alex", week_id="week02"))
        self.assertFalse(saved.exists())
        self.assertEqual(classroom.submission_catalog(), [])


if __name__ == "__main__":
    unittest.main()