pillpal / tests /test_logic.py
vivek gangadharan
first
b9aa4e9
Raw
History Blame Contribute Delete
5.16 kB
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