"""Run: python3 -m unittest test_opt_counter.py (from this folder) Expected values are the brief's T1-T11, checked against a reference implementation.""" import unittest from datetime import date as D from opt_counter import count_unemployment, stem_pending_window, to_ranges def job(start, end=None, qualifying=True): return {"start": start, "end": end, "qualifying": qualifying} EAD, END = D(2026, 6, 1), D(2027, 5, 31) STEM_EAD, STEM_END, STEM_START = D(2025, 7, 1), D(2028, 6, 30), D(2026, 7, 1) STEM_JOB = job(D(2025, 9, 19), D(2026, 6, 30)) PAST_JOB = job(D(2025, 6, 1), D(2026, 4, 30)) CASES = [ # id, (ead_start, auth_end, as_of, jobs, stem_start), (used, limit, remaining, first_over) ("T1 Priya", (EAD, END, D(2026, 9, 30), [job(D(2026, 7, 1), D(2026, 8, 14)), job(D(2026, 9, 1))], None), (47, 90, 43, None)), ("T2 no job", (EAD, END, D(2026, 6, 30), [], None), (30, 90, 60, None)), ("T3 weekend gap", (EAD, END, D(2026, 7, 31), [job(D(2026, 6, 1), D(2026, 7, 10)), job(D(2026, 7, 13))], None), (2, 90, 88, None)), ("T4 non-qualifying", (EAD, END, D(2026, 6, 30), [job(D(2026, 6, 1), qualifying=False)], None), (30, 90, 60, None)), ("T5 overlap", (EAD, END, D(2026, 6, 30), [job(D(2026, 6, 5), D(2026, 6, 20)), job(D(2026, 6, 10), D(2026, 6, 25))], None), (9, 90, 81, None)), ("T6 job before EAD", (EAD, END, D(2026, 6, 30), [job(D(2026, 5, 1), D(2026, 6, 10))], None), (20, 90, 70, None)), ("T7a STEM before start", (STEM_EAD, STEM_END, D(2026, 6, 30), [STEM_JOB], STEM_START), (80, 90, 10, None)), ("T7b STEM after start", (STEM_EAD, STEM_END, D(2026, 7, 31), [STEM_JOB], STEM_START), (111, 150, 39, None)), ("T8 over limit", (EAD, END, D(2026, 8, 31), [], None), (92, 90, -2, D(2026, 8, 30))), ("T9 as_of after auth end", (D(2025, 6, 1), D(2026, 5, 31), D(2026, 9, 30), [PAST_JOB], None), (31, 90, 59, None)), ("T10 cap-gap", (D(2025, 6, 1), D(2026, 9, 30), D(2026, 7, 15), [PAST_JOB], None), (76, 90, 14, None)), ("T11 leap day", (D(2028, 2, 1), D(2029, 1, 31), D(2028, 2, 29), [], None), (29, 90, 61, None)), ] class TestCountUnemployment(unittest.TestCase): def test_stem_pending(self): jobs = [job(D(2026, 7, 1), D(2027, 5, 11))] cases = [ # as_of, (used, limit) (D(2027, 5, 31), (50, 90)), # before the OPT end date (D(2027, 6, 10), (60, 150)), # pending: OPT days carry into the 150 (D(2027, 11, 27), (230, 150)), # day 180 (D(2027, 11, 28), (50, 90)), # day 181: back to the OPT end date, as in EADly ] for as_of, expected in cases: with self.subTest(as_of): auth_end, stem_start = stem_pending_window(END, as_of) r = count_unemployment(EAD, auth_end, as_of, jobs, stem_start) self.assertEqual((r["days_used"], r["limit"]), expected) def test_cases(self): for name, args, expected in CASES: with self.subTest(name): r = count_unemployment(*args) got = (r["days_used"], r["limit"], r["days_remaining"], r["first_day_over_limit"]) self.assertEqual(got, expected) self.assertEqual(len(r["unemployed_dates"]), r["days_used"]) def test_weekend_gap_dates(self): r = count_unemployment(*CASES[2][1]) self.assertEqual(r["unemployed_dates"], [D(2026, 7, 11), D(2026, 7, 12)]) def test_ranges(self): r = count_unemployment(*CASES[0][1]) self.assertEqual(to_ranges(r["unemployed_dates"]), [[D(2026, 6, 1), D(2026, 6, 30)], [D(2026, 8, 15), D(2026, 8, 31)]]) if __name__ == "__main__": unittest.main()