"""Unit tests for Justice Laws XML parsing (canlex/ingest.py).
Offline: builds a tiny Justice Laws-shaped XML document and parses it, so no
network or real corpus is touched. Focuses on the per-section in-force date and
repeal-status metadata.
"""
import tempfile
import unittest
from pathlib import Path
from canlex import ingest
_XML = b"""
Humanitarian and compassionate considerationsThe Minister may grant relief.[Repealed, 2018, c. 27, s. 174]Live section with a repealed subsectionIntro.Still in force.[Repealed, 2020, c. 1]- 1991, c. 43, s. 10A transitional related provision.- 2026, c. 8, s. 3Coercive controlSection 264 is amended by adding a coercive control offence."""
def _path():
with tempfile.NamedTemporaryFile(suffix=".xml", delete=False) as f:
f.write(_XML)
return Path(f.name)
def _parse():
# I-2.5 is a real SOURCES code; parse_legislation only reads its short/
# name/web_base for citation building. Keyed by section, so the NIF chunk
# (section="") is excluded here; NotInForceTests reads it by id.
return {c["section"]: c for c in ingest.parse_legislation(_path(), "I-2.5")
if c["section"]}
class InForceTests(unittest.TestCase):
def test_every_section_carries_its_in_force_date(self):
by_sec = _parse()
self.assertEqual(by_sec["25"]["in_force"], "2015-01-01")
self.assertEqual(by_sec["40"]["in_force"], "2001-06-28")
class AmendmentStubTests(unittest.TestCase):
def test_matches_bare_amendment_markers(self):
for s in ["30 [Amendment]", "162 [Amendments]", "5 [Related provision]",
"5.1 [Related provisions]"]:
self.assertTrue(ingest._AMENDMENT_STUB.match(s), s)
def test_does_not_match_real_or_repealed_content(self):
for s in ["13 [Repealed, 2018, c. 27, s. 174]",
"34 The Minister may [Amendment] later amend...",
"40 Inadmissibility on security grounds"]:
self.assertIsNone(ingest._AMENDMENT_STUB.match(s), s)
class NotInForceTests(unittest.TestCase):
def test_nif_schedule_entry_ingested_as_pending_law(self):
chunks = ingest.parse_legislation(_path(), "I-2.5")
nif = [c for c in chunks if c["id"].startswith("I-2.5-nif-")]
self.assertEqual(len(nif), 1)
c = nif[0]
self.assertEqual(c["status"], "not-in-force")
self.assertEqual(c["section"], "") # never satisfies a lookup
self.assertIn("2026, c. 8, s. 3", c["history"])
self.assertIn("coercive control", c["text"].lower())
self.assertIn("not in force", c["citation"].lower())
def test_related_provisions_schedule_is_not_ingested(self):
chunks = ingest.parse_legislation(_path(), "I-2.5")
self.assertFalse(any("transitional related provision" in c["text"].lower()
for c in chunks))
class RepealStatusTests(unittest.TestCase):
def test_wholly_repealed_section_is_flagged(self):
self.assertEqual(_parse()["13"]["status"], "repealed")
def test_live_section_with_a_repealed_subsection_is_not_flagged(self):
# The sits inside a Subsection, not the section's own Text,
# so the section itself is still in force.
self.assertEqual(_parse()["40"]["status"], "in force")
def test_ordinary_section_is_in_force(self):
self.assertEqual(_parse()["25"]["status"], "in force")
if __name__ == "__main__":
unittest.main()