File size: 2,514 Bytes
b233cf7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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"]