import json from pathlib import Path import pytest from pino.draft_engine import FormulaGenerator RULES_PATH = Path(__file__).parent.parent / "data" / "genre_rules.json" REGISTRY_PATH = Path(__file__).parent.parent / "src" / "pino" / "registry.db" def test_formula_generator_sum_to_one() -> None: gen = FormulaGenerator( genre="citrus_cologne", rules_path=RULES_PATH, registry_path=REGISTRY_PATH, seed=42, min_k=5, max_k=10, ) formula, formula_id = gen.generate(idx=0) total = sum(f["weight_fraction"] for f in formula) assert pytest.approx(total, 1e-6) == 1.0 assert formula_id.startswith("gen_") def test_formula_generator_ethanol_present() -> None: gen = FormulaGenerator( genre="citrus_cologne", rules_path=RULES_PATH, registry_path=REGISTRY_PATH, seed=42, min_k=5, max_k=10, ) formula, _ = gen.generate(idx=0) cas_list = [f["cas"] for f in formula] assert "64-17-5" in cas_list def test_formula_generator_genre_bounds_respected() -> None: """Citrus cologne must contain at least one top-note compound.""" gen = FormulaGenerator( genre="citrus_cologne", rules_path=RULES_PATH, registry_path=REGISTRY_PATH, seed=42, ) top_cas = set(gen.tiers["top"]) for _ in range(20): formula, _ = gen.generate() cas_list = {f["cas"] for f in formula} assert cas_list & top_cas, "citrus_cologne formula missing top notes" def test_formula_generator_bounds_respected() -> None: gen = FormulaGenerator( genre="wildcard", rules_path=RULES_PATH, registry_path=REGISTRY_PATH, seed=42, min_k=5, max_k=10, ) for _ in range(20): formula, _ = gen.generate() for f in formula: meta = gen.compounds.get(f["cas"]) if meta is None: continue # solvent or unknown max_w = meta["max_weight_fraction"] assert f["weight_fraction"] <= max_w + 1e-9 def test_ifra_light_check_blocks_prohibited() -> None: gen = FormulaGenerator( genre="wildcard", rules_path=RULES_PATH, registry_path=REGISTRY_PATH, seed=42, ) # Musk xylene is prohibited (limit 0.0) formula = [ {"cas": "81-15-2", "weight_fraction": 0.01}, {"cas": "64-17-5", "weight_fraction": 0.99}, ] assert not gen.light_ifra_check(formula)["passed"]