File size: 3,022 Bytes
1e17a3c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Tests build SCORM zips in-memory and validate them."""
from __future__ import annotations

import io
import zipfile
from pathlib import Path

from scorm_qa.checks import validate_package
from scorm_qa.manifest import parse_manifest


def _write_zip(path: Path, files: dict[str, str]) -> None:
    with zipfile.ZipFile(path, "w") as zf:
        for name, contents in files.items():
            zf.writestr(name, contents)


GOOD_MANIFEST = """<?xml version="1.0"?>
<manifest identifier="MANIFEST-1" version="1.0">
  <metadata>
    <schemaversion>1.2</schemaversion>
  </metadata>
  <organizations default="ORG-1">
    <organization identifier="ORG-1">
      <title>Course</title>
      <item identifier="ITEM-1" identifierref="RES-1"><title>Lesson</title></item>
    </organization>
  </organizations>
  <resources>
    <resource identifier="RES-1" type="webcontent" scormtype="sco" href="lesson.html">
      <file href="lesson.html"/>
    </resource>
  </resources>
</manifest>
"""


def test_good_package_passes(tmp_path):
    pkg = tmp_path / "good.zip"
    _write_zip(pkg, {
        "imsmanifest.xml": GOOD_MANIFEST,
        "lesson.html": "<html>Hi</html>",
    })
    defects, manifest = validate_package(str(pkg))
    assert defects == []
    assert manifest is not None
    assert manifest.schemaversion == "1.2"


def test_missing_manifest_is_critical(tmp_path):
    pkg = tmp_path / "no_manifest.zip"
    _write_zip(pkg, {"lesson.html": "<html/>"})
    defects, manifest = validate_package(str(pkg))
    assert manifest is None
    assert any(d["severity"] == "CRITICAL" and "imsmanifest" in d["message"] for d in defects)


def test_malformed_xml_is_critical(tmp_path):
    pkg = tmp_path / "bad_xml.zip"
    _write_zip(pkg, {"imsmanifest.xml": "<manifest><unclosed>"})
    defects, manifest = validate_package(str(pkg))
    assert manifest is None
    assert any(d["severity"] == "CRITICAL" and "malformed" in d["message"].lower() for d in defects)


def test_unsupported_schema_version(tmp_path):
    bad = GOOD_MANIFEST.replace("<schemaversion>1.2</schemaversion>",
                                "<schemaversion>9.9</schemaversion>")
    pkg = tmp_path / "badver.zip"
    _write_zip(pkg, {"imsmanifest.xml": bad, "lesson.html": "<html/>"})
    defects, _ = validate_package(str(pkg))
    assert any("9.9" in d["message"] for d in defects)


def test_missing_referenced_file(tmp_path):
    pkg = tmp_path / "missing_file.zip"
    _write_zip(pkg, {"imsmanifest.xml": GOOD_MANIFEST})  # lesson.html absent
    defects, _ = validate_package(str(pkg))
    assert any("lesson.html" in d["location"] and d["severity"] == "HIGH" for d in defects)


def test_dangling_file_flagged_low(tmp_path):
    pkg = tmp_path / "dangling.zip"
    _write_zip(pkg, {
        "imsmanifest.xml": GOOD_MANIFEST,
        "lesson.html": "<html/>",
        "extras/notes.txt": "junk",
    })
    defects, _ = validate_package(str(pkg))
    assert any("extras/notes.txt" in d["location"] and d["severity"] == "LOW" for d in defects)