"""Thickness band resolution (METADATA-15 / QUALITY-95). The owner never picks the Woo thickness band in the UI — the server derives it from the measured thickness_in against the live synced bands. These tests pin the derivation on the real live band names (from the UAT taxonomy) and on the quarter-inch slug fallback. """ import pytest from backend.thickness_band import ( parse_inch_token, resolve_thickness_band_id, term_bounds, ) # The live UAT Thickness attribute (pa_thk) as synced: name, slug. LIVE_TERMS = [ {"id": 347, "name": "Under 1/2\"", "slug": "xthin"}, {"id": 348, "name": "1/2\" - 3/4\"", "slug": "2-3qtr"}, {"id": 349, "name": "3/4\" - 1\"", "slug": "3-4qtr"}, {"id": 350, "name": "1\"- 1 1/2\"", "slug": "4-6qtr"}, {"id": 351, "name": "1 1/2\" - 2\"", "slug": "6-8qtr"}, {"id": 352, "name": "2\" - 3\"", "slug": "8-12qtr"}, {"id": 353, "name": "Over 3\"", "slug": "12qtr"}, ] @pytest.mark.parametrize( "text,expected", [ ("1 1/2", 1.5), ("3/4", 0.75), ("2", 2.0), ("1.75", 1.75), ("2\"", 2.0), ("1 1/2\"", 1.5), ], ) def test_parse_inch_token(text, expected): assert parse_inch_token(text) == pytest.approx(expected) def test_parse_inch_token_rejects_junk(): assert parse_inch_token("") is None assert parse_inch_token(" ") is None def test_term_bounds_from_live_names(): assert term_bounds(LIVE_TERMS[0]) == (0.0, 0.5) assert term_bounds(LIVE_TERMS[1]) == (0.5, 0.75) assert term_bounds(LIVE_TERMS[3]) == (1.0, 1.5) assert term_bounds(LIVE_TERMS[6]) == (3.0, float("inf")) def test_term_bounds_falls_back_to_qtr_slug(): assert term_bounds({"id": 9, "name": "weird", "slug": "4-6qtr"}) == (1.0, 1.5) assert term_bounds({"id": 9, "name": "weird", "slug": "12qtr"}) == (3.0, float("inf")) assert term_bounds({"id": 9, "name": "weird", "slug": "xthin"}) == (0.0, 0.5) @pytest.mark.parametrize( "thickness,expected_id", [ (0.25, 347), # Under 1/2" (0.5, 348), # boundary rounds UP into 1/2"-3/4", not down (0.625, 348), (0.75, 349), # boundary rounds UP (0.875, 349), (1.0, 350), # QUALITY-95: 1 inch rounds up into 1"-1 1/2", not a hardcoded band (1.25, 350), (1.5, 351), (1.75, 351), # the UAT sample thickness (2.0, 352), (2.75, 352), (3.0, 353), (4.0, 353), ], ) def test_resolve_rounds_up_on_boundary(thickness, expected_id): assert resolve_thickness_band_id(thickness, LIVE_TERMS) == expected_id def test_resolve_handles_missing_inputs(): assert resolve_thickness_band_id(None, LIVE_TERMS) is None assert resolve_thickness_band_id(-1, LIVE_TERMS) is None assert resolve_thickness_band_id(1.0, []) is None # A term with no parseable name/slug is skipped, never guessed at. assert resolve_thickness_band_id(1.0, [{"id": 1, "name": "mystery", "slug": "mystery"}]) is None def test_resolve_is_id_order_independent(): """The result must not depend on the sync order of the terms.""" assert resolve_thickness_band_id(1.75, list(reversed(LIVE_TERMS))) == 351