feat(review): #90 wood primary category + derived thickness band
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user