"""Tests for app.utils.units.""" from decimal import Decimal import pytest from app.utils.units import UnitConverter, convert_qty, normalize_unit class TestNormalizeUnit: def test_synonyms(self): assert normalize_unit("pounds") == "lb" assert normalize_unit("OUNCE") == "oz" assert normalize_unit("Cups") == "cup" assert normalize_unit("TBS") == "tbsp" assert normalize_unit("each") == "ea" assert normalize_unit("doz") == "dozen" def test_already_canonical(self): assert normalize_unit("lb") == "lb" assert normalize_unit("cup") == "cup" assert normalize_unit("ea") == "ea" def test_unknown_passthrough(self): assert normalize_unit("bunch") == "bunch" assert normalize_unit("can") == "can" def test_none(self): assert normalize_unit(None) == "unknown" assert normalize_unit("") == "unknown" class TestWithinFamilyConversion: def test_weight_lb_to_oz(self): assert convert_qty(2.0, "lb", "oz") == Decimal("32") def test_weight_oz_to_lb(self): result = convert_qty(16.0, "oz", "lb") assert result == Decimal("1.0000") def test_volume_cup_to_tbsp(self): result = convert_qty(1.0, "cup", "tbsp") assert result == Decimal("16") def test_volume_tbsp_to_tsp(self): result = convert_qty(1.0, "tbsp", "tsp") assert result == Decimal("3") def test_count_dozen_to_ea(self): result = convert_qty(1.0, "dozen", "ea") assert result == Decimal("12") def test_same_unit(self): assert convert_qty(5.0, "lb", "lb") == Decimal("5") class TestDensityConversion: def test_olive_oil_tbsp_to_cup(self): # 1 cup = 16 tbsp result = convert_qty( 1.0, "cup", "tbsp", ingredient_name_lower="olive oil" ) assert result == Decimal("16") def test_rice_cup_to_lb(self): # 1 cup rice = 185 g; 1 lb = 453.592 g → 1 cup = 185/453.592 ≈ 0.4079 lb result = convert_qty( 1.0, "cup", "lb", ingredient_name_lower="rice, long-grain white" ) assert result == Decimal("0.4079") def test_butter_tbsp_to_cup(self): result = convert_qty( 1.0, "cup", "tbsp", ingredient_name_lower="butter, unsalted" ) assert result == Decimal("16") def test_seed_size_ea_to_lb(self): # 1 avocado ≈ 170 g = 0.3748 lb result = convert_qty( 1.0, "ea", "lb", ingredient_name_lower="avocado" ) assert result == Decimal("0.3748") def test_unknown_density_falls_back(self): # No density for "dragon fruit" → fallback to dimensionless qty result = convert_qty(2.0, "cup", "lb", ingredient_name_lower="dragon fruit") assert result == Decimal("2") class TestFallback: def test_incommensurable_units_without_name(self): result = convert_qty(2.0, "cup", "lb") assert result == Decimal("2") def test_incommensurable_units_with_unmapped_name(self): result = convert_qty(2.0, "cup", "lb", ingredient_name_lower="xyz") assert result == Decimal("2") def test_missing_from_unit(self): result = convert_qty(2.0, None, "lb") assert result == Decimal("2") def test_missing_to_unit(self): result = convert_qty(2.0, "lb", None) assert result == Decimal("2")