Spaces:
Running
Running
| import sys | |
| import os | |
| from datetime import date | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from logic import ( | |
| safe_parse, | |
| build_schedule, | |
| check_refill, | |
| make_medication, | |
| build_daily_agenda, | |
| format_time_12h, | |
| ) | |
| def test_safe_parse_plain_json(): | |
| raw = '{"drug_name": "Metformin", "dose": "500 mg", "frequency_text": "twice daily", "quantity": 60, "refill_or_expiry_date": "2026-07-01"}' | |
| data = safe_parse(raw) | |
| assert data["drug_name"] == "Metformin" | |
| assert data["quantity"] == 60.0 | |
| def test_safe_parse_with_code_fence_and_prose(): | |
| raw = "Here is the result:\n```json\n{\"drug_name\": \"Lisinopril\", \"quantity\": \"30 tablets\", \"frequency_text\": \"once daily\", \"dose\": null, \"refill_or_expiry_date\": null}\n```\nDone." | |
| data = safe_parse(raw) | |
| assert data["drug_name"] == "Lisinopril" | |
| assert data["quantity"] == 30.0 | |
| def test_safe_parse_empty_strings_become_none(): | |
| raw = '{"drug_name": "X", "dose": "", "frequency_text": "daily", "quantity": null, "refill_or_expiry_date": "unknown"}' | |
| data = safe_parse(raw) | |
| assert data["dose"] is None | |
| assert data["refill_or_expiry_date"] is None | |
| def test_safe_parse_garbage_returns_none(): | |
| assert safe_parse("the model said nothing useful") is None | |
| assert safe_parse("") is None | |
| def test_schedule_twice_daily(): | |
| times, doses = build_schedule({"frequency_text": "take 1 tablet twice daily"}) | |
| assert doses == 2.0 | |
| assert times == ["08:00", "20:00"] | |
| def test_schedule_once_daily(): | |
| times, doses = build_schedule({"frequency_text": "take 1 tablet once daily"}) | |
| assert doses == 1.0 | |
| assert times == ["08:00"] | |
| def test_schedule_three_times(): | |
| times, doses = build_schedule({"frequency_text": "3 times a day"}) | |
| assert doses == 3.0 | |
| assert len(times) == 3 | |
| def test_schedule_every_n_hours(): | |
| times, doses = build_schedule({"frequency_text": "take 1 capsule every 8 hours"}) | |
| assert doses == 3.0 | |
| assert times[0] == "08:00" | |
| def test_schedule_bedtime(): | |
| times, doses = build_schedule({"frequency_text": "take 1 tablet at bedtime"}) | |
| assert doses == 1.0 | |
| assert times == ["21:00"] | |
| def test_schedule_as_needed_has_no_fixed_times(): | |
| times, doses = build_schedule({"frequency_text": "take as needed for pain"}) | |
| assert times == [] | |
| assert doses is None | |
| def test_schedule_unparseable_returns_empty(): | |
| times, doses = build_schedule({"frequency_text": "follow doctor's special plan"}) | |
| assert times == [] | |
| assert doses is None | |
| def test_refill_warns_when_low(): | |
| today = date(2026, 6, 5) | |
| run_out, warning = check_refill({"quantity": 10}, doses_per_day=2.0, today=today) | |
| assert run_out == "2026-06-10" | |
| assert warning is not None and "Refill soon" in warning | |
| def test_refill_no_warning_when_plenty(): | |
| today = date(2026, 6, 5) | |
| run_out, warning = check_refill({"quantity": 60}, doses_per_day=1.0, today=today) | |
| assert run_out == "2026-08-04" | |
| assert warning is None | |
| def test_refill_out_now(): | |
| today = date(2026, 6, 5) | |
| run_out, warning = check_refill({"quantity": 0}, doses_per_day=2.0, today=today) | |
| assert "Out of medication" in warning | |
| def test_refill_label_date_passed(): | |
| today = date(2026, 6, 5) | |
| _, warning = check_refill( | |
| {"quantity": None, "refill_or_expiry_date": "2026-06-01"}, | |
| doses_per_day=None, | |
| today=today, | |
| ) | |
| assert warning is not None and "passed" in warning | |
| def test_format_time_12h(): | |
| assert format_time_12h("08:00") == "8:00 AM" | |
| assert format_time_12h("20:00") == "8:00 PM" | |
| assert format_time_12h("00:30") == "12:30 AM" | |
| assert format_time_12h("12:00") == "12:00 PM" | |
| assert format_time_12h("bad") == "bad" | |
| def test_build_daily_agenda_groups_and_sorts(): | |
| m1 = make_medication(safe_parse('{"drug_name":"A","dose":"10 mg","frequency_text":"twice daily","quantity":30,"refill_or_expiry_date":null}')) | |
| m2 = make_medication(safe_parse('{"drug_name":"B","dose":"5 mg","frequency_text":"once daily","quantity":30,"refill_or_expiry_date":null}')) | |
| m3 = make_medication(safe_parse('{"drug_name":"C","dose":null,"frequency_text":"as needed for pain","quantity":20,"refill_or_expiry_date":null}')) | |
| timed, as_needed = build_daily_agenda([m1, m2, m3]) | |
| times = [t for t, _ in timed] | |
| assert times == sorted(times) | |
| eight = dict(timed)["08:00"] | |
| assert "A (10 mg)" in eight and "B (5 mg)" in eight | |
| assert dict(timed)["20:00"] == ["A (10 mg)"] | |
| assert len(as_needed) == 1 and "C" in as_needed[0] and "as needed" in as_needed[0] | |
| def test_build_daily_agenda_empty(): | |
| timed, as_needed = build_daily_agenda([]) | |
| assert timed == [] and as_needed == [] | |
| def test_make_medication_full(): | |
| data = safe_parse( | |
| '{"drug_name": "Amoxicillin", "dose": "500 mg", "frequency_text": "every 8 hours", "quantity": 21, "refill_or_expiry_date": null}' | |
| ) | |
| med = make_medication(data, today=date(2026, 6, 5)) | |
| assert med.drug_name == "Amoxicillin" | |
| assert med.doses_per_day == 3.0 | |
| assert med.run_out_date == "2026-06-12" | |
| assert med.refill_warning is not None | |