require "spec" require "../src/josie-health-lut" describe JosieHealth::LUT::Fuzzy do describe ".damerau_distance" do it "returns 0 for identical strings" do JosieHealth::LUT::Fuzzy.damerau_distance("ketamine", "ketamine").should eq(0) end it "handles substitution" do JosieHealth::LUT::Fuzzy.damerau_distance("ketamine", "ketamina").should eq(1) end it "handles deletion" do JosieHealth::LUT::Fuzzy.damerau_distance("ketamine", "ketamin").should eq(1) end it "handles insertion" do JosieHealth::LUT::Fuzzy.damerau_distance("ketamin", "ketamine").should eq(1) end it "handles transposition" do JosieHealth::LUT::Fuzzy.damerau_distance("ketamien", "ketamine").should eq(1) end it "handles multiple edits" do JosieHealth::LUT::Fuzzy.damerau_distance("clonazpam", "clonazepam").should eq(1) end it "returns correct distance for completely different strings" do JosieHealth::LUT::Fuzzy.damerau_distance("abc", "xyz").should eq(3) end it "handles empty strings" do JosieHealth::LUT::Fuzzy.damerau_distance("", "abc").should eq(3) JosieHealth::LUT::Fuzzy.damerau_distance("abc", "").should eq(3) JosieHealth::LUT::Fuzzy.damerau_distance("", "").should eq(0) end end describe ".max_distance" do it "returns 0 for very short strings" do JosieHealth::LUT::Fuzzy.max_distance(1).should eq(0) JosieHealth::LUT::Fuzzy.max_distance(2).should eq(0) end it "returns 1 for short strings" do JosieHealth::LUT::Fuzzy.max_distance(3).should eq(1) JosieHealth::LUT::Fuzzy.max_distance(5).should eq(1) end it "returns 2 for medium strings" do JosieHealth::LUT::Fuzzy.max_distance(6).should eq(2) JosieHealth::LUT::Fuzzy.max_distance(8).should eq(2) end it "returns 3 for long strings" do JosieHealth::LUT::Fuzzy.max_distance(9).should eq(3) JosieHealth::LUT::Fuzzy.max_distance(15).should eq(3) end end describe ".auto_correct?" do it "never auto-corrects short strings" do JosieHealth::LUT::Fuzzy.auto_correct?(2, 1).should be_false end it "auto-corrects distance 1 for 3-5 char strings" do JosieHealth::LUT::Fuzzy.auto_correct?(4, 1).should be_true end it "auto-corrects distance 1 for 6-8 char strings" do JosieHealth::LUT::Fuzzy.auto_correct?(7, 1).should be_true end it "does not auto-correct distance 2 for 6-8 char strings" do JosieHealth::LUT::Fuzzy.auto_correct?(7, 2).should be_false end it "auto-corrects distance 2 for 9+ char strings" do JosieHealth::LUT::Fuzzy.auto_correct?(10, 2).should be_true end it "does not auto-correct distance 3 for 9+ char strings" do JosieHealth::LUT::Fuzzy.auto_correct?(10, 3).should be_false end end end describe JosieHealth::LUT::DrugLUT do describe ".fuzzy_normalize" do it "returns exact match with distance 0" do result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("ketamine") result.should_not be_nil result = result.not_nil! result.canonical.should eq("ketamine") result.distance.should eq(0) result.auto_correct.should be_true end it "finds ketamine from typo 'ketanine'" do result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("ketanine") result.should_not be_nil result = result.not_nil! result.canonical.should eq("ketamine") result.distance.should eq(1) result.auto_correct.should be_true end it "finds ibuprofen from 'ibuprofn'" do result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("ibuprofn") result.should_not be_nil result = result.not_nil! result.canonical.should eq("ibuprofen") result.auto_correct.should be_true end it "finds amphetamine from 'amphetamin'" do result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("amphetamin") result.should_not be_nil result = result.not_nil! result.canonical.should eq("amphetamine") result.distance.should eq(1) result.auto_correct.should be_true end it "finds clonazepam from 'clonazpam' (already an alias)" do result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("clonazpam") result.should_not be_nil result = result.not_nil! result.canonical.should eq("clonazepam") result.distance.should eq(0) # it's a known alias end it "rejects strings <= 2 chars" do JosieHealth::LUT::DrugLUT.fuzzy_normalize("k").should be_nil JosieHealth::LUT::DrugLUT.fuzzy_normalize("lsd").should_not be_nil # 3 chars exact match is ok end it "rejects completely unknown substances" do JosieHealth::LUT::DrugLUT.fuzzy_normalize("zzzzzzzzz").should be_nil end it "does not cross-match lsd and lsa" do result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("lsd") result.should_not be_nil result.not_nil!.canonical.should eq("lsd") result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("lsa") result.should_not be_nil result.not_nil!.canonical.should eq("lsa") end it "does not cross-match mda and mdma at distance 1" do result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("mda") result.should_not be_nil result.not_nil!.canonical.should eq("mda") end it "does not fuzzy-match 3-cmc to 3-mmc (distance 1 but different substances)" do # "3cmc" is an exact alias for 3-cmc, and "3mmc" is an exact alias for 3-mmc result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("3cmc") result.should_not be_nil result.not_nil!.canonical.should eq("3-cmc") result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("3mmc") result.should_not be_nil result.not_nil!.canonical.should eq("3-mmc") end it "handles case-insensitive input" do result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("KETAMINE") result.should_not be_nil result.not_nil!.canonical.should eq("ketamine") end it "finds pregabalin from 'pregabaln'" do result = JosieHealth::LUT::DrugLUT.fuzzy_normalize("pregabaln") result.should_not be_nil result = result.not_nil! result.canonical.should eq("pregabalin") result.auto_correct.should be_true end end end describe JosieHealth::LUT::RouteLUT do describe ".fuzzy_normalize" do it "returns exact match with distance 0" do result = JosieHealth::LUT::RouteLUT.fuzzy_normalize("oral") result.should_not be_nil result = result.not_nil! result.canonical.should eq("oral") result.distance.should eq(0) end it "finds insufflated from 'insuflated' (now an alias)" do result = JosieHealth::LUT::RouteLUT.fuzzy_normalize("insuflated") result.should_not be_nil result.not_nil!.canonical.should eq("insufflated") result.not_nil!.distance.should eq(0) # it's a known alias now end it "finds smoked from 'smoled' (now an alias)" do result = JosieHealth::LUT::RouteLUT.fuzzy_normalize("smoled") result.should_not be_nil result.not_nil!.canonical.should eq("smoked") result.not_nil!.distance.should eq(0) end it "finds sublingual from 'subligual' (now an alias)" do result = JosieHealth::LUT::RouteLUT.fuzzy_normalize("subligual") result.should_not be_nil result.not_nil!.canonical.should eq("sublingual") result.not_nil!.distance.should eq(0) end it "finds oral from 'orla' (now an alias)" do result = JosieHealth::LUT::RouteLUT.fuzzy_normalize("orla") result.should_not be_nil result.not_nil!.canonical.should eq("oral") result.not_nil!.distance.should eq(0) end it "finds vaped from 'vapd' (now an alias)" do result = JosieHealth::LUT::RouteLUT.fuzzy_normalize("vapd") result.should_not be_nil result.not_nil!.canonical.should eq("vaped") result.not_nil!.distance.should eq(0) end it "finds subcutaneous from 'subcutanous' via fuzzy" do result = JosieHealth::LUT::RouteLUT.fuzzy_normalize("subcutanous") result.should_not be_nil result.not_nil!.canonical.should eq("subcutaneous") end it "rejects strings <= 2 chars" do JosieHealth::LUT::RouteLUT.fuzzy_normalize("iv").should be_nil JosieHealth::LUT::RouteLUT.fuzzy_normalize("im").should be_nil end it "rejects unknown routes" do JosieHealth::LUT::RouteLUT.fuzzy_normalize("zzzzz").should be_nil end end end describe JosieHealth::LUT do describe ".fuzzy_normalize_substance" do it "delegates to DrugLUT.fuzzy_normalize" do result = JosieHealth::LUT.fuzzy_normalize_substance("ketamine") result.should_not be_nil result.not_nil!.canonical.should eq("ketamine") end end describe ".fuzzy_normalize_route" do it "delegates to RouteLUT.fuzzy_normalize" do result = JosieHealth::LUT.fuzzy_normalize_route("oral") result.should_not be_nil result.not_nil!.canonical.should eq("oral") end end end