CanLex / tests /test_decisive_card.py
Beemer0's picture Beemer's picture
claude opus 5 (1m context)
Beemer's picture
claude fable 5
Super-squash branch 'main' using huggingface_hub
ed26ce9
Raw History Blame Contribute Delete
33.9 kB
"""The pure chain, the decisive facts, the confidence block, the result card
and completion IF SERVED AS IMPOSED (roadmap T4.1, T4.2, T4.7, T4.5; track A
step A14, 2026-09-15).
The chain is a refactor with no verdict change of its own (proved against
the tree before the step: every screening case and a 60-record set gave the
same CANLEX_RESULT fields and the same memo text once the new blocks are
removed -- scratchpad a14_diff.py). These tests hold what the step adds:
- the decisive facts list only facts whose values change the branch, the
allegation paragraph or the rehabilitation status, and fold into ASSUMED;
- every screening tool's CANLEX_RESULT carries 'confidence';
- detail 'card' gives about ten lines and the same result line;
- the IF SERVED EXACTLY AS IMPOSED footing never gives a status, and a fine
blocks it; its Guide 5312 rules are verbatim in the corpus;
- conviction_date bounds the Tran maximum;
- all of it runs on the APPROVED curated JSON (a composed release).
Offline over the real curated files and a stub index."""
import datetime as dt
import json
import subprocess
import unittest
from pathlib import Path
from unittest import mock
ROOT = Path(__file__).resolve().parent.parent
PROCESSED = ROOT / "data" / "processed"
T = "2026-09-15"
def result_of(out):
lines = [l for l in out.splitlines() if l.startswith("CANLEX_RESULT: ")]
return json.loads(lines[-1][len("CANLEX_RESULT: "):])
def _chunks(name):
path = PROCESSED / name
if not path.exists():
return None
data = json.loads(path.read_text(encoding="utf-8"))
return data["chunks"] if isinstance(data, dict) else data
class _Base(unittest.TestCase):
@classmethod
def setUpClass(cls):
from canlex import server
cls.s = server
cls._saved = server._INDEX
server._INDEX = object.__new__(type("Stub", (), {"semantic": False}))
@classmethod
def tearDownClass(cls):
cls.s._INDEX = cls._saved
def record(self, **kw):
kw.setdefault("today", T)
return self.s.canlex_screen_record(**kw)
def history(self, entries, **kw):
kw.setdefault("today", T)
return self.s.canlex_screen_history(json.dumps(entries), **kw)
@staticmethod
def decisive(r):
return {d["fact"]: d for d in r["decisive_missing"]}
class ChainTests(_Base):
def test_the_chain_without_text_gives_the_tools_answer(self):
"""render=False (the decisive re-runs) and the memo agree."""
from canlex.screening import parse_date
cases = [dict(offense="DUI", disposition="convicted", state="TX",
offence_date="2015-01-01", sentence_completed="2016-01-01"),
dict(offense="theft", disposition="convicted", state="TX",
offence_date="2018-01-01", sentence_completed="2018-06-01"),
dict(offense="DUI", disposition="convicted", state="TX",
sentence_completed="2019-06-01"),
dict(offense="assault", disposition="withheld adjudication", state="FL",
offence_date="2016-01-01"),
dict(offense="attempted burglary", disposition="convicted", state="CA",
offence_date="2005-01-01", sentence_completed="2007-01-01")]
for c in cases:
r = result_of(self.record(**c))
j = self.s._jurisdiction(c.get("state"), None)
ch = self.s._chain_entry(c["offense"], c["disposition"], j,
parse_date(c.get("offence_date")),
parse_date(c.get("sentence_completed")),
"foreign-national", dt.date.fromisoformat(T))
eq = ch["eq"] or {}
self.assertEqual((eq.get("pairing"), eq.get("branch"), eq.get("max_years")),
(r["pairing"], r["branch"], r["max_years"]), c)
self.assertEqual((ch["rehab"] or {}).get("status"), r.get("rehab_status"), c)
def test_allegation_paragraphs_are_the_ones_drafted(self):
p = {"canadian_offence": "X"}
for branch in ("serious-criminality", "criminality", "criminality-two-plus-only"):
for conv, unknown in ((True, False), (False, False), (False, True)):
for count in ("one", "two-plus-summary-only"):
lines = " ".join(self.s._allegation_lines({"branch": branch}, p, conv,
unknown, count))
paras = [x for x, _ in self.s._allegation_paras(branch, conv, unknown, count)]
for para in paras:
self.assertIn(f"IRPA paragraph {para} ", lines, (branch, conv, count))
self.assertEqual(lines.count("Draft allegation paragraph"), len(paras),
(branch, conv, unknown, count))
class DecisiveFactsTests(_Base):
def test_a_straddled_maximum_lists_the_offence_date(self):
r = result_of(self.record(offense="DUI", disposition="convicted", state="TX",
sentence_completed="2019-06-01"))
d = self.decisive(r)["offence_date"]
self.assertEqual(sorted(v["branch"] for v in d["values"]),
["criminality", "serious-criminality"])
self.assertEqual({tuple(v["paragraphs"]) for v in d["values"]},
{("36(2)(b)",), ("36(1)(b)",)})
def test_a_tie_lists_its_deciding_fact(self):
r = result_of(self.record(offense="theft", disposition="convicted", state="TX",
offence_date="2018-01-01", sentence_completed="2018-06-01"))
d = self.decisive(r)["value_over_5000"]
self.assertEqual(sorted(v["branch"] for v in d["values"]),
["criminality", "serious-criminality"])
# the value given: the tie is settled, the fact is not asked again
r2 = result_of(self.record(offense="theft", disposition="convicted", state="TX",
offence_date="2018-01-01", sentence_completed="2018-06-01",
value_over_5000=False))
self.assertNotIn("value_over_5000", self.decisive(r2))
def test_status_other_record_and_relief_fold_into_assumed(self):
out = self.record(offense="DUI", disposition="convicted", state="TX",
offence_date="2015-01-01", sentence_completed="2016-01-01")
r = result_of(out)
dec = self.decisive(r)
self.assertEqual({v["value"]: v["branch"] for v in dec["status"]["values"]},
{"foreign-national": "criminality",
"permanent-resident": "not-inadmissible-pr"})
self.assertEqual(dec["status"]["assumed"], "status-foreign-national")
self.assertEqual({v["value"]: v["rehab_status"] for v in dec["other_record"]["values"]},
{False: ["deemed-rehabilitated"], True: ["apply-conditional"]})
self.assertIn("relief", dec)
# the block sits at the top, and the ASSUMED lines it replaces say so
top = out.split("## Step 1")[0]
self.assertIn(self.s.DECISIVE_HEAD, top)
self.assertLess(top.index(self.s.DECISIVE_HEAD), top.index("ASSUMED (not given"))
for code in ("status-foreign-national", "clean-record", "no-foreign-relief"):
self.assertIn(self.s._ASSUMED_TEXT[code] + self.s.DECISIVE_SUFFIX, top)
# 'assumed' is unchanged: the decisive facts are added, nothing removed
self.assertEqual(r["assumed"], ["status-foreign-national", "application-unknown",
"adult-at-offence", "no-foreign-relief",
"clean-record"])
def test_a_fact_given_is_not_re_run(self):
r = result_of(self.record(offense="DUI", disposition="convicted", state="TX",
offence_date="2015-01-01", sentence_completed="2016-01-01",
status="permanent-resident", other_record=True))
self.assertNotIn("status", r["decisive_checked"])
self.assertNotIn("other_record", r["decisive_checked"])
def test_the_age_is_re_run_and_never_decisive_for_a_foreign_record(self):
r = result_of(self.record(offense="DUI", disposition="convicted", state="TX",
offence_date="2015-01-01", sentence_completed="2016-01-01"))
self.assertIn("age", r["decisive_checked"])
self.assertNotIn("age", self.decisive(r))
def test_no_decisive_fact_is_said(self):
out = self.record(offense="trespass", disposition="convicted", state="TX",
offence_date="2018-01-01", sentence_completed="2018-02-01",
status="foreign-national", other_record=True,
date_of_birth="1980-01-01")
r = result_of(out)
if not r["decisive_missing"]:
self.assertIn("THE ANSWER CHANGES WITH THESE FACTS: none found", out)
def test_only_changing_facts_are_kept(self):
for kw in (dict(offense="DUI", disposition="convicted", state="TX",
sentence_completed="2019-06-01"),
dict(offense="assault", disposition="convicted", state="NY",
offence_date="2016-01-01", sentence_completed="2017-01-01")):
r = result_of(self.record(**kw))
for d in r["decisive_missing"]:
answers = {(v["branch"], tuple(v["paragraphs"]), tuple(v["rehab_status"]))
for v in d["values"]}
self.assertGreater(len(answers), 1, d)
def test_a_statute_codes_specification_is_re_run_with_its_answer(self):
"""The step memo keys a match on the record context too: the former
UCMJ Art. 90's limbs are read from the specification answer, so a
match made without it must never be reused for a reading that has it
(found by the before/after diff, 2026-09-15). The Art. 90 element
split is held for review (85802df): skipped where it is absent, as a
composed release on the approved baseline is."""
alias = ((self.s._load_equivalency() or {}).get("aliases") or {}).get("article 90") or {}
if not any(isinstance(r, dict) and r.get("elements")
for r in [alias] + list(alias.get("dated") or [])):
self.skipTest("held content absent: the UCMJ Art. 90 element split")
out = self.record(offense="Article 90", disposition="court-martial conviction",
offence_date="2016-01-01", sentence_completed="2017-01-01")
r = result_of(out)
self.assertEqual({e["answer"]: e["pairing"] for e in r["element_readings"]},
{"assault": "assault-simple", "disobedience": "military-offences"})
dec = self.decisive(r)["ucmj-specification"]
self.assertEqual({v["value"]: v["branch"] for v in dec["values"]},
{"ucmj-specification: assault": "tie",
"ucmj-specification: disobedience": "none"})
def test_a_canadian_record_re_runs_status(self):
r = result_of(self.record(offense="impaired driving", disposition="convicted",
country="Canada", offence_date="2019-06-01",
sentence_completed="2020-01-01", canada_sentence="fine"))
self.assertIn("status", r["decisive_checked"])
self.assertIn("confidence", r)
def test_history_lists_an_entrys_offence_date_and_the_status(self):
r = result_of(self.history([
dict(offense="DUI", disposition="convicted", state="TX",
sentence_completed="2019-06-01"),
dict(offense="theft", disposition="convicted", state="TX",
offence_date="2015-01-01", sentence_completed="2015-06-01",
value_over_5000=False)]))
dec = self.decisive(r)
self.assertIn("#1 offence_date", dec)
self.assertEqual({v["count"] for v in dec["#1 offence_date"]["values"]},
{"multiple"})
self.assertIn("#1 relief", r["decisive_checked"])
self.assertIn("status", r["decisive_checked"])
for d in r["decisive_missing"]:
self.assertGreater(len({json.dumps([v["entries"], v["count"], v["rehab_status"]])
for v in d["values"]}), 1, d)
class ConfidenceTests(_Base):
KEYS = {"step1", "step2", "step3"}
def test_every_screening_tool_carries_it(self):
outs = {
"canlex_us_disposition": self.s.canlex_us_disposition(disposition="deferred adjudication",
state="TX"),
"canlex_us_equivalency": self.s.canlex_us_equivalency(offense="DUI",
offence_date="2015-01-01"),
"canlex_rehabilitation": self.s.canlex_rehabilitation(
basis="foreign-conviction", max_penalty_lt_10=True, count="one",
clean_record=True, sentence_completed="2016-01-01", today=T),
"canlex_screen_record": self.record(offense="DUI", disposition="convicted",
state="TX", offence_date="2015-01-01",
sentence_completed="2016-01-01"),
"canlex_screen_history": self.history([dict(offense="DUI", disposition="convicted",
state="TX", offence_date="2015-01-01",
sentence_completed="2016-01-01")]),
"canlex_transborder": self.s.canlex_transborder(act="Criminal Code", section="95",
offence="loaded handgun"),
}
for tool, out in outs.items():
r = result_of(out)
self.assertEqual(r["tool"], tool)
self.assertEqual(set(r["confidence"]), self.KEYS, tool)
def test_the_values(self):
c = result_of(self.record(offense="DUI", disposition="convicted", state="TX",
offence_date="2015-01-01",
sentence_completed="2016-01-01"))["confidence"]
self.assertEqual(c["step1"][0]["entry"], "conviction")
self.assertIn(c["step1"][0]["entry_status"],
("settled", "judicially-considered", "guidance-only", "no-authority"))
s2 = c["step2"][0]
self.assertEqual((s2["pairing"], s2["maximum_source"]), ("dui", "history"))
self.assertRegex(s2["authorities_in_corpus"] or "0/0", r"^\d+/\d+$")
self.assertEqual(c["step3"], {"limbs_tested": False, "limbs_unknown": None})
c2 = result_of(self.record(offense="DUI", disposition="convicted", state="TX",
offence_date="2020-06-01",
sentence_completed="2021-06-01"))["confidence"]
self.assertEqual(c2["step2"][0]["maximum_source"], "current")
tie = result_of(self.record(offense="theft", disposition="convicted", state="TX",
offence_date="2018-01-01"))["confidence"]
self.assertEqual(sorted(x["pairing"] for x in tie["step2"]), ["theft-over", "theft-under"])
h = result_of(self.history([dict(offense="DUI", disposition="convicted", state="TX",
offence_date="2015-01-01",
sentence_completed="2016-01-01")]))["confidence"]
self.assertEqual(h["step1"][0]["n"], 1)
self.assertTrue(h["step3"]["limbs_tested"])
self.assertIsInstance(h["step3"]["limbs_unknown"], int)
def test_a_verified_state_row_says_so(self):
from canlex.screening import step1_confidence
self.assertTrue(step1_confidence({"id": "x"}, {"verified": "2026-09-01"})["row_verified"])
self.assertFalse(step1_confidence({"id": "x"}, {"unverifiable": "why"})["row_verified"])
self.assertIsNone(step1_confidence({"id": "x"}, None)["row_verified"])
class CardTests(_Base):
def body(self, out):
return [l for l in out.splitlines() if not l.startswith("CANLEX_RESULT: ")]
def test_the_card_is_short_and_carries_the_same_result(self):
kw = dict(offense="DUI", disposition="convicted", state="TX",
offence_date="2015-01-01", sentence_completed="2016-01-01")
card = self.record(detail="card", **kw)
full = self.record(**kw)
body = self.body(card)
self.assertLessEqual(len(body), 13)
for head in ("# Result card", "Result:", "Step 1:", "Dates:", "Action:"):
self.assertTrue(any(l.startswith(head) for l in body), head)
self.assertEqual(body[-1], self.s.CARD_FULL)
rc, rf = result_of(card), result_of(full)
self.assertEqual(rc.pop("detail"), "card")
self.assertEqual(rc, rf)
self.assertNotIn("detail", rf)
def test_not_settled_names_the_deciding_fact(self):
card = self.record(detail="card", offense="theft", disposition="convicted", state="TX",
offence_date="2018-01-01", sentence_completed="2018-06-01")
result = next(l for l in self.body(card) if l.startswith("Result:"))
self.assertIn("NOT SETTLED", result)
self.assertIn("CAD 5,000", result)
self.assertIn(self.s.CARD_NOT_SETTLED_ACTION, card)
def test_an_open_result_says_the_assumed_facts_were_not_compared_per_reading(self):
"""Wave-4 verifier (2026-09-15): on a tie or an open limb the status and
relief re-runs compare the whole answer, not each reading -- the memo,
the card and CANLEX_RESULT say so rather than implying they cannot
matter."""
kw = dict(offense="assault causing bodily injury", disposition="convicted",
state="TX", offence_date="2016-01-01", sentence_completed="2016-06-01")
full, card = self.record(**kw), self.record(detail="card", **kw)
r = result_of(full)
self.assertEqual(r["branch"], "tie")
self.assertIn("status", r["decisive_whole_answer_only"])
self.assertIn("relief", r["decisive_whole_answer_only"])
self.assertIn("NOTE -- NOT SETTLED at step 2: the re-runs of status", full)
self.assertIn("compared on the whole answer only, not reading by reading", card)
settled = result_of(self.record(offense="robbery", disposition="convicted", state="IL",
offence_date="2001-01-01",
sentence_completed="2004-01-01"))
self.assertNotIn("decisive_whole_answer_only", settled)
def test_the_actions(self):
fn = self.record(detail="card", offense="DUI", disposition="convicted", state="TX",
offence_date="2020-06-01", sentence_completed="2021-06-01",
status="foreign-national")
self.assertIn("s. 44(1) report on IRPA s. 36(1)(b)", fn)
self.assertIn("IRPR s. 42(1)", fn)
# wave-4 verifier: s. 42(1) 'shall allow' (subject to s. 42(2)); s. 44(2)
# 'may refer' -- the card neither softens the one nor hardens the other
self.assertIn("the officer 'shall allow' it -- mandatory unless s. 42(2) applies", fn)
pr = self.record(detail="card", offense="robbery", disposition="convicted", state="IL",
offence_date="2001-01-01", sentence_completed="2004-01-01",
status="permanent-resident")
self.assertIn("the Minister may refer it to the Immigration Division (IRPA s. 44(2))",
pr)
self.assertNotIn("is referred to the Immigration Division", pr)
none = self.record(detail="card", offense="trespass", disposition="convicted",
state="TX", offence_date="2018-01-01",
sentence_completed="2018-02-01")
self.assertIn(self.s.CARD_NO_GROUND_ACTION, none)
deemed = self.record(detail="card", offense="DUI", disposition="convicted", state="TX",
offence_date="2015-01-01", sentence_completed="2016-01-01")
self.assertIn(self.s.CARD_DEEMED_ACTION, deemed)
def test_history_card(self):
ents = [dict(offense="DUI", disposition="convicted", state="TX",
offence_date="2016-03-01", sentence_completed="2017-03-01"),
dict(offense="disorderly conduct", disposition="pled guilty", state="TX",
offence_date="2019-05-05", sentence_completed="2019-06-01")]
card = self.history(ents, detail="card")
body = self.body(card)
self.assertLessEqual(len(body), 12)
self.assertTrue(body[0].startswith("# Result card -- a record of 2 entries"))
self.assertTrue(any(l.startswith("Entries: #1") for l in body))
rc, rf = result_of(card), result_of(self.history(ents))
rc.pop("detail")
self.assertEqual(rc, rf)
def test_a_bad_detail_is_refused(self):
self.assertTrue(self.record(offense="DUI", disposition="convicted",
detail="short").startswith("Error: detail"))
class SentenceTests(unittest.TestCase):
def test_the_common_forms(self):
from canlex.screening import parse_sentence
got = {t: [(p["kind"], p["n"], p["unit"], p["suspended"])
for p in parse_sentence(t)["parts"]]
for t in ("3 YRS PROB", "30 DAYS JAIL SUSP", "$500 FINE", "12 MOS DL SUSP")}
self.assertEqual(got, {"3 YRS PROB": [("probation", 3.0, "years", False)],
"30 DAYS JAIL SUSP": [("imprisonment", 30.0, "days", True)],
"$500 FINE": [("fine", None, None, False)],
"12 MOS DL SUSP": [("driving", 12.0, "months", False)]})
self.assertEqual(parse_sentence("$500 FINE")["parts"][0]["amount"], 500.0)
self.assertEqual(parse_sentence("40 HRS COMMUNITY SERVICE")["unread"],
["40 HRS COMMUNITY SERVICE"])
def test_a_thousands_comma_in_a_fine_is_one_part(self):
"""The code audit of 2026-09-21 (HELD): '$1,000 fine' split at the comma into
a $1 fine and an unread '500 fine'. Before/after on '2 yrs prob, $1,500 fine':
blocked ('cannot read: 500 fine') -> blocked (the fine rule, amount $1,500).
The readings the audit proposed for '6 mos jail, 3 mos susp', '1 yr 6 mos
jail' and '5 years tdcj' are NOT added here: each is a new reading of a
record's words for the maintainer to approve one by one, so they stay
unread (pinned as such)."""
from canlex.screening import parse_sentence, projected_completion
p = parse_sentence("$1,000 fine")
self.assertEqual(([x["kind"] for x in p["parts"]], p["parts"][0]["amount"], p["unread"]),
(["fine"], 1000.0, []))
p = parse_sentence("2 yrs prob, $1,500 fine")
self.assertEqual([(x["kind"], x["amount"]) for x in p["parts"]],
[("probation", None), ("fine", 1500.0)])
self.assertEqual(p["unread"], [])
self.assertEqual(parse_sentence("$1,000,000 fine")["parts"][0]["amount"], 1000000.0)
# a comma with no space still splits ('2 yrs prob,180 days jail' is two parts)
self.assertEqual([x["kind"] for x in parse_sentence("2 yrs prob,180 days jail")["parts"]],
["probation", "imprisonment"])
blocked = projected_completion("2 yrs prob, $1,500 fine", dt.date(2020, 1, 1))["blocked"]
self.assertIn("$1,500 fine", blocked)
self.assertIn("Guide 5312", blocked)
self.assertNotIn("cannot read", blocked)
# the optional readings stay unread for now
for s, unread in (("6 mos jail, 3 mos susp", ["3 mos susp"]),
("1 yr 6 mos jail", ["1 yr 6 mos jail"]),
("5 years tdcj", ["5 years tdcj"])):
self.assertEqual(parse_sentence(s)["unread"], unread, s)
def test_the_projection(self):
from canlex.screening import projected_completion
d = dt.date(2019, 3, 1)
p = projected_completion("3 YRS PROB, 30 DAYS JAIL SUSP", d)
self.assertEqual((p["date"], p["rule"], p["blocked"]), (dt.date(2022, 3, 1), "probation", None))
self.assertEqual(projected_completion("30 DAYS JAIL SUSP", d)["date"], d)
self.assertEqual(projected_completion("180 DAYS JAIL, 170 SUSP", d)["date"],
dt.date(2019, 3, 11))
self.assertEqual(projected_completion("3 MONTHS JAIL", dt.date(2002, 12, 13))["date"],
dt.date(2003, 3, 13)) # Guide 5312 example 1
dl = projected_completion("3 MOS JAIL; 12 MOS DL SUSP", d)
self.assertEqual((dl["date"], dl["if_administrative"]),
(dt.date(2020, 3, 1), dt.date(2019, 6, 1)))
self.assertIn("fine", projected_completion("2 years probation, $500 fine", d)["blocked"])
self.assertIn("cannot read", projected_completion("40 HRS COMMUNITY SERVICE", d)["blocked"])
def test_months_end_on_the_last_day(self):
from canlex.screening import add_months
self.assertEqual(add_months(dt.date(2019, 1, 31), 1), dt.date(2019, 2, 28))
self.assertEqual(add_months(dt.date(2019, 11, 30), 3), dt.date(2020, 2, 29))
def test_guide_5312_rules_are_verbatim(self):
from canlex.screening import GUIDE_5312_CHUNK, GUIDE_5312_COURT, GUIDE_5312_RULES
chunks = _chunks("policy.json")
if chunks is None:
self.skipTest("corpus not ingested")
text = next(c["text"] for c in chunks if c["id"] == GUIDE_5312_CHUNK)
for rule in list(GUIDE_5312_RULES.values()) + [GUIDE_5312_COURT]:
self.assertIn(rule, text)
def test_the_statute_phrases_the_card_and_questions_rely_on(self):
irpr, irpa = _chunks("SOR-2002-227.json"), _chunks("I-2.5.json")
if irpr is None or irpa is None:
self.skipTest("corpus not ingested")
s42 = next(c["text"] for c in irpr if c["id"] == "SOR-2002-227-s42")
self.assertIn("shall allow the foreign national to withdraw their application and "
"leave Canada", s42)
self.assertIn("If a report is being prepared or has been prepared under subsection "
"44(1) of the Act", s42)
s44 = next(c["text"] for c in irpa if c["id"] == "I-2.5-s44")
self.assertIn("the Minister may refer the report to the Immigration Division", s44)
irpa_text = "\n".join(c["text"] for c in irpa)
self.assertIn("A foreign national is inadmissible on grounds of criminality for",
irpa_text)
class ProjectionMemoTests(_Base):
KW = dict(offense="DUI", disposition="convicted", state="TX", offence_date="2019-06-01")
def test_no_verdict_on_the_footing(self):
out = self.record(sentence_imposed="3 YRS PROB, 30 DAYS JAIL SUSP",
sentence_date="2020-01-10", **self.KW)
r = result_of(out)
self.assertEqual(r["completion_basis"], "if-served-as-imposed")
self.assertIsNone(r.get("rehab_status"))
p = r["if_served_as_imposed"]
self.assertEqual((p["completion"], p["earliest_apply"], p["source"]),
("2023-01-10", "2028-01-10", "policy-imm-5312-12"))
from canlex.screening import IF_SERVED_LABEL
self.assertIn(IF_SERVED_LABEL, out)
self.assertIn("No verdict is given on this footing", out)
def test_a_fine_blocks_it(self):
r = result_of(self.record(sentence_imposed="2 years probation, $500 fine",
sentence_date="2020-01-10", **self.KW))
self.assertEqual(r["completion_basis"], "not-projected")
self.assertIn("fine", r["if_served_as_imposed"]["blocked"])
def test_a_given_completion_wins(self):
r = result_of(self.record(sentence_imposed="3 YRS PROB", sentence_date="2020-01-10",
sentence_completed="2023-01-10", **self.KW))
self.assertEqual(r["completion_basis"], "sentence_completed")
self.assertNotIn("if_served_as_imposed", r)
def test_the_margin(self):
r = result_of(self.record(sentence_imposed="2 YRS PROB", sentence_date="2019-12-01",
offense="DUI", disposition="convicted", state="TX",
offence_date="2019-06-01"))
# completion 2021-12-01; application from 2026-12-01, within 12 months of 2026-09-15
self.assertTrue(r["if_served_as_imposed"]["margin"])
class ConvictionDateTests(_Base):
def test_it_bounds_the_tran_maximum(self):
base = dict(offense="DUI", disposition="convicted", state="TX",
sentence_completed="2019-06-01")
self.assertEqual(result_of(self.record(**base))["branch"], "tran-open")
out = self.record(conviction_date="2018-06-01", **base)
r = result_of(out)
self.assertEqual((r["branch"], r["max_years"], r["assessed_basis"]),
("criminality", 5, "inferred-from-conviction"))
self.assertIn("inferred from the conviction date", out)
# a conviction after the amendment settles nothing
self.assertEqual(result_of(self.record(conviction_date="2019-01-10", **base))["branch"],
"tran-open")
def test_out_of_order_dates_are_said(self):
out = self.record(offense="DUI", disposition="convicted", state="TX",
offence_date="2018-01-01", conviction_date="2017-06-01",
sentence_date="2017-01-01")
self.assertIn("WARNING: the conviction date 2017-06-01 precedes the offence date", out)
self.assertIn("WARNING: the sentence date 2017-01-01 precedes", out)
def test_history_reads_it_too(self):
out = self.history([dict(offense="DUI", disposition="convicted", state="TX",
sentence_completed="2019-06-01",
conviction_date="2018-06-01")])
self.assertIn("maximum inferred from the conviction date (2018-06-01)", out)
def _git_json(commit, path):
try:
out = subprocess.run(["git", "-C", str(ROOT), "show", f"{commit}:{path}"],
capture_output=True, timeout=60)
except (OSError, subprocess.SubprocessError):
return None
return json.loads(out.stdout.decode("utf-8")) if out.returncode == 0 else None
class ApprovedBaselineTests(_Base):
"""main's code on the approved curated JSON (what a composed release
ships): every new block runs, and says nothing it cannot."""
@classmethod
def setUpClass(cls):
super().setUpClass()
try:
state = json.loads((ROOT / "data" / "curated" / "review_state.json")
.read_text(encoding="utf-8"))
commit = state["approved"]["commit"]
except (OSError, ValueError, KeyError):
raise unittest.SkipTest("no review state")
cls.eq = _git_json(commit, "data/curated/us_equivalency.json")
cls.disp = _git_json(commit, "data/curated/us_dispositions.json")
if cls.eq is None or cls.disp is None:
raise unittest.SkipTest("approved baseline not readable with git here")
@classmethod
def tearDownClass(cls):
cls.s._load_equivalency() # the working tree's alias table again
super().tearDownClass()
def test_the_new_blocks_run_on_the_approved_data(self):
from canlex.screening import load_aliases
def eq():
load_aliases(self.eq.get("aliases"))
return self.eq
with mock.patch.object(self.s, "_load_equivalency", eq), \
mock.patch.object(self.s, "_load_dispositions", lambda: self.disp):
for detail in ("full", "card"):
for kw in (dict(offense="DUI", disposition="convicted", state="TX",
sentence_completed="2019-06-01", conviction_date="2018-06-01"),
dict(offense="theft", disposition="convicted", state="TX",
offence_date="2018-01-01", sentence_imposed="3 YRS PROB",
sentence_date="2018-03-01"),
dict(offense="assault", disposition="deferred adjudication",
state="TX", offence_date="2014-01-01"),
dict(offense="Article 90", disposition="court-martial conviction"),
dict(offense="impaired driving", disposition="convicted",
country="Canada", offence_date="2019-06-01")):
r = result_of(self.record(detail=detail, **kw))
self.assertIn("confidence", r, kw)
self.assertIn("decisive_missing", r, kw)
r = result_of(self.history([dict(offense="DUI", disposition="convicted",
state="TX", sentence_completed="2019-06-01"),
dict(offense="theft", disposition="convicted",
state="TX", offence_date="2016-01-01",
sentence_completed="2016-02-01")],
detail=detail))
self.assertIn("confidence", r)
if __name__ == "__main__":
unittest.main()