File size: 3,905 Bytes
b233cf7
 
2671b56
 
 
 
 
b233cf7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2671b56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
89
90
91
92
93
94
95
96
import pytest
from pino.verifier import FragrancePipelineVerifier
from pathlib import Path
import sys

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from scripts.ingest_fraterworks_free_formulas import extract_pdf_text, parse_formula_text

def test_classic_accord_evaporation():
    # Test formula: 10% Limonene, 20% Linalool, 70% Ethanol base
    formula = [
        {"cas": "5989-27-5", "weight_fraction": 0.10}, # Limonene
        {"cas": "78-70-6", "weight_fraction": 0.20},  # Linalool
        {"cas": "64-17-5", "weight_fraction": 0.70}   # Ethanol
    ]

    verifier = FragrancePipelineVerifier()
    trajectory = verifier.run_sim(formula, duration_seconds=3600)

    assert "trajectory" in trajectory
    assert len(trajectory["trajectory"]) > 0
    # Ensure ethanol depletes significantly faster than linalool
    assert trajectory["depletion_rates"]["64-17-5"] > trajectory["depletion_rates"]["78-70-6"]


def test_out_of_applicability_domain_graceful():
    # Invalid CAS that PubChem and the registry cannot resolve.
    formula = [
        {"cas": "0000-00-0", "weight_fraction": 0.50},
        {"cas": "64-17-5", "weight_fraction": 0.50},
    ]
    verifier = FragrancePipelineVerifier()
    result = verifier.run_sim(formula, duration_seconds=3600)
    assert result["status"] == "rejected"
    assert result["applicability_errors"]


def test_ifra_rejection():
    # Cinnamaldehyde is restricted/prohibited in the embedded IFRA table.
    formula = [
        {"cas": "104-55-2", "weight_fraction": 0.10},
        {"cas": "64-17-5", "weight_fraction": 0.90},
    ]
    verifier = FragrancePipelineVerifier()
    result = verifier.run_sim(formula, duration_seconds=3600)
    assert result["status"] == "rejected"
    assert result["ifra_report"]["passed"] is False


def test_five_component_accord_with_registry():
    # Classic 5-component accord in ethanol base via the registry path.
    formula = [
        {"cas": "64-17-5", "weight_fraction": 0.70},
        {"cas": "5989-27-5", "weight_fraction": 0.10},
        {"cas": "78-70-6", "weight_fraction": 0.08},
        {"cas": "24851-98-7", "weight_fraction": 0.06},  # Hedione via registry
        {"cas": "1222-05-5", "weight_fraction": 0.04},  # Galaxolide
        {"cas": "6790-58-5", "weight_fraction": 0.02},  # Ambroxan
    ]
    verifier = FragrancePipelineVerifier()
    result = verifier.run_sim(formula, duration_seconds=28800, interval_seconds=600)
    assert result["status"] == "passed"
    assert len(result["trajectory"]) == 49
    # Ethanol depletes faster than musks
    assert result["depletion_rates"]["64-17-5"] > result["depletion_rates"]["6790-58-5"]


def test_fraterworks_parser_skips_multipage_title_rows():
    pdf = Path("data/fraterworks_free_pdfs/F_FABULOUS_242463.pdf")
    if not pdf.exists():
        pytest.skip("Fraterworks fixture PDF is not present")

    parsed = parse_formula_text(extract_pdf_text(pdf))

    assert parsed["name"] == "F* Fabulous"
    assert parsed["formula_code"] == "242463"
    assert parsed["declared_profile"] == "a leather fragrance"
    assert parsed["declared_total_parts"] == 1000.0
    assert not any(row["name"] == "F* FABULOUS" for row in parsed["raw_formula"])
    assert max(row["parts"] for row in parsed["raw_formula"]) == 230.0


def test_fraterworks_parser_handles_title_after_total():
    pdf = Path("data/fraterworks_free_pdfs/incense-rori.pdf")
    if not pdf.exists():
        pytest.skip("Fraterworks fixture PDF is not present")

    parsed = parse_formula_text(extract_pdf_text(pdf))

    assert parsed["name"] == "Incense Rori"
    assert parsed["formula_code"] == "989045"
    assert parsed["declared_profile"] == "an oriental woody attar"
    assert parsed["declared_total_parts"] == 1000.0
    assert parsed["raw_formula"][0]["name"] == "Helvetolide®"
    assert not any(row["name"] == "INCENSE RORI" for row in parsed["raw_formula"])