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