require "./spec_helper" describe JosieHealth::Utils::Dosage do describe ".parse" do it "parses dosage with unit (100mg)" do result = JosieHealth::Utils::Dosage.parse("100mg") result.should_not be_nil result.not_nil![:amount].should eq("100") result.not_nil![:unit].should eq("mg") end it "parses decimal dosage (0.5ml)" do result = JosieHealth::Utils::Dosage.parse("0.5ml") result.should_not be_nil result.not_nil![:amount].should eq("0.5") result.not_nil![:unit].should eq("ml") end it "parses leading decimal (.38ml)" do result = JosieHealth::Utils::Dosage.parse(".38ml") result.should_not be_nil result.not_nil![:amount].should eq(".38") result.not_nil![:unit].should eq("ml") end it "parses dosage without unit (100)" do result = JosieHealth::Utils::Dosage.parse("100") result.should_not be_nil result.not_nil![:amount].should eq("100") result.not_nil![:unit].should eq("") end it "parses microgram units (50ug)" do result = JosieHealth::Utils::Dosage.parse("50ug") result.should_not be_nil result.not_nil![:amount].should eq("50") result.not_nil![:unit].should eq("ug") end it "returns nil for invalid format" do JosieHealth::Utils::Dosage.parse("abc").should be_nil end it "returns nil for empty string" do JosieHealth::Utils::Dosage.parse("").should be_nil end end describe ".parse_math" do it "parses division (47.5mg/2)" do result = JosieHealth::Utils::Dosage.parse_math("47.5mg/2") result.should_not be_nil result.not_nil![:amount].should eq("23.75") result.not_nil![:unit].should eq("mg") end it "parses division with trailing unit (100/2mg)" do result = JosieHealth::Utils::Dosage.parse_math("100/2mg") result.should_not be_nil result.not_nil![:amount].should eq("50") result.not_nil![:unit].should eq("mg") end it "parses multiplication (50mg*0.5)" do result = JosieHealth::Utils::Dosage.parse_math("50mg*0.5") result.should_not be_nil result.not_nil![:amount].should eq("25") result.not_nil![:unit].should eq("mg") end it "handles division resulting in integer" do result = JosieHealth::Utils::Dosage.parse_math("100mg/2") result.should_not be_nil result.not_nil![:amount].should eq("50") end it "handles division resulting in decimal" do result = JosieHealth::Utils::Dosage.parse_math("100mg/3") result.should_not be_nil result.not_nil![:amount].should eq("33.33") end it "handles division by zero gracefully" do result = JosieHealth::Utils::Dosage.parse_math("100mg/0") result.should_not be_nil result.not_nil![:amount].should eq("100") end it "returns nil for non-math expression" do JosieHealth::Utils::Dosage.parse_math("100mg").should be_nil end end describe ".parse_any" do it "parses math expression first" do result = JosieHealth::Utils::Dosage.parse_any("100mg/2") result.should_not be_nil result.not_nil![:amount].should eq("50") end it "falls back to simple parse" do result = JosieHealth::Utils::Dosage.parse_any("100mg") result.should_not be_nil result.not_nil![:amount].should eq("100") result.not_nil![:unit].should eq("mg") end it "returns nil for invalid input" do JosieHealth::Utils::Dosage.parse_any("invalid").should be_nil end end describe ".extract_from_text" do it "extracts simple dosage (50mg caffeine)" do result = JosieHealth::Utils::Dosage.extract_from_text("50mg caffeine") result.should_not be_nil result.not_nil![:dosage].should eq("50") result.not_nil![:unit].should eq("mg") result.not_nil![:substance].should eq("caffeine") end it "extracts with verb (took 2g kratom oral)" do result = JosieHealth::Utils::Dosage.extract_from_text("took 2g kratom oral") result.should_not be_nil result.not_nil![:dosage].should eq("2") result.not_nil![:unit].should eq("g") result.not_nil![:substance].should eq("kratom") result.not_nil![:route].should eq("oral") end it "extracts decimal dosage (0.5ml dxm)" do result = JosieHealth::Utils::Dosage.extract_from_text("0.5ml dxm") result.should_not be_nil result.not_nil![:dosage].should eq("0.5") result.not_nil![:unit].should eq("ml") result.not_nil![:substance].should eq("dxm") end it "extracts without unit (100 caffeine)" do result = JosieHealth::Utils::Dosage.extract_from_text("100 caffeine") result.should_not be_nil result.not_nil![:dosage].should eq("100") result.not_nil![:unit].should eq("mg") result.not_nil![:substance].should eq("caffeine") end it "handles snorted verb" do result = JosieHealth::Utils::Dosage.extract_from_text("snorted 50mg ketamine") result.should_not be_nil result.not_nil![:substance].should eq("ketamine") end it "returns nil for text without dosage" do JosieHealth::Utils::Dosage.extract_from_text("hello world").should be_nil end end describe ".format" do it "formats amount with unit" do JosieHealth::Utils::Dosage.format("100", "mg").should eq("100mg") end it "formats amount without unit" do JosieHealth::Utils::Dosage.format("100", "").should eq("100") end end describe ".looks_like_dosage?" do it "detects standard dosages (100mg)" do JosieHealth::Utils::Dosage.looks_like_dosage?("100mg").should be_true end it "detects decimal dosages (2.5g)" do JosieHealth::Utils::Dosage.looks_like_dosage?("2.5g").should be_true end it "detects ml dosages (0.5ml)" do JosieHealth::Utils::Dosage.looks_like_dosage?("0.5ml").should be_true end it "detects pure numbers (100)" do JosieHealth::Utils::Dosage.looks_like_dosage?("100").should be_true end it "detects math expressions (47.5mg/2)" do JosieHealth::Utils::Dosage.looks_like_dosage?("47.5mg/2").should be_true end it "detects malformed double-dosage (10mg/25mg)" do JosieHealth::Utils::Dosage.looks_like_dosage?("10mg/25mg").should be_true end it "detects microgram units (50ug)" do JosieHealth::Utils::Dosage.looks_like_dosage?("50ug").should be_true end it "does not detect substance names (caffeine)" do JosieHealth::Utils::Dosage.looks_like_dosage?("caffeine").should be_false end it "does not detect substance with numbers (4-mmc)" do JosieHealth::Utils::Dosage.looks_like_dosage?("4-mmc").should be_false end it "does not detect complex names (alpha-pvp)" do JosieHealth::Utils::Dosage.looks_like_dosage?("alpha-pvp").should be_false end it "handles empty strings" do JosieHealth::Utils::Dosage.looks_like_dosage?("").should be_false end it "handles whitespace" do JosieHealth::Utils::Dosage.looks_like_dosage?(" 100mg ").should be_true end end describe ".looks_like_hhmm_timestamp?" do it "detects 0005 as HHMM timestamp" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("0005").should be_true end it "detects 0010 as HHMM timestamp" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("0010").should be_true end it "detects 0216 as HHMM timestamp" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("0216").should be_true end it "detects 1544 as HHMM timestamp" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("1544").should be_true end it "detects 2359 as HHMM timestamp (max valid time)" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("2359").should be_true end it "detects 0000 as HHMM timestamp (midnight)" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("0000").should be_true end it "does NOT detect HHMM with mg suffix (0005mg is a valid dose)" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("0005mg").should be_false end it "does NOT detect 1200mg (valid dose, not timestamp)" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("1200mg").should be_false end it "does NOT detect 1500mg (valid dose, not timestamp)" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("1500mg").should be_false end it "rejects 2400 as invalid HHMM (hour too high)" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("2400").should be_false end it "rejects 0060 as invalid HHMM (minute too high)" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("0060").should be_false end it "rejects 3-digit numbers (100)" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("100").should be_false end it "rejects 5-digit numbers (10000)" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("10000").should be_false end it "rejects regular dosages (100mg)" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("100mg").should be_false end it "rejects substance names" do JosieHealth::Utils::Dosage.looks_like_hhmm_timestamp?("caffeine").should be_false end end describe ".validate_dose_substance" do it "accepts correct order (dosage, substance)" do result = JosieHealth::Utils::Dosage.validate_dose_substance("100mg", "caffeine") result.should_not be_nil result.not_nil![:dosage].should eq("100mg") result.not_nil![:substance].should eq("caffeine") result.not_nil![:swapped].should be_false end it "corrects swapped arguments (substance, dosage)" do result = JosieHealth::Utils::Dosage.validate_dose_substance("caffeine", "100mg") result.should_not be_nil result.not_nil![:dosage].should eq("100mg") result.not_nil![:substance].should eq("caffeine") result.not_nil![:swapped].should be_true end it "returns nil when both look like dosages" do result = JosieHealth::Utils::Dosage.validate_dose_substance("100mg", "50mg") result.should be_nil end it "returns nil for malformed double-dosage as substance" do result = JosieHealth::Utils::Dosage.validate_dose_substance("100mg", "10mg/25mg") result.should be_nil end it "handles substances with numbers (4-mmc)" do result = JosieHealth::Utils::Dosage.validate_dose_substance("100mg", "4-mmc") result.should_not be_nil result.not_nil![:substance].should eq("4-mmc") result.not_nil![:swapped].should be_false end it "accepts when neither looks like dosage (unusual but valid)" do result = JosieHealth::Utils::Dosage.validate_dose_substance("some", "thing") result.should_not be_nil result.not_nil![:swapped].should be_false end end end