| import pytest |
| from backend.app.engine.query_parser import QueryParser, ParsedQuery |
|
|
|
|
| @pytest.fixture |
| def parser(): |
| return QueryParser() |
|
|
|
|
| class TestCategoryParsing: |
| def test_dress(self, parser): |
| result = parser.parse("black midi dress") |
| assert result.category_filter == "Dresses" |
|
|
| def test_jacket(self, parser): |
| result = parser.parse("leather jacket") |
| assert result.category_filter == "Coats & Jackets" |
|
|
| def test_jeans(self, parser): |
| result = parser.parse("blue jeans") |
| assert result.category_filter == "Jeans" |
|
|
| def test_hoodie(self, parser): |
| result = parser.parse("oversized hoodie") |
| assert result.category_filter == "Hoodies & Sweatshirts" |
|
|
| def test_trainers(self, parser): |
| result = parser.parse("white trainers") |
| assert result.category_filter == "Shoes" |
|
|
| def test_bag(self, parser): |
| result = parser.parse("leather bag") |
| assert result.category_filter == "Bags" |
|
|
| def test_no_category(self, parser): |
| result = parser.parse("something nice") |
| assert result.category_filter is None |
|
|
| def test_multi_word_category(self, parser): |
| result = parser.parse("puffer jacket warm") |
| assert result.category_filter == "Coats & Jackets" |
|
|
|
|
| class TestColorParsing: |
| def test_basic_color(self, parser): |
| result = parser.parse("black dress") |
| assert result.color_filter == "black" |
|
|
| def test_synonym_color(self, parser): |
| result = parser.parse("scarlet top") |
| assert result.color_filter == "red" |
|
|
| def test_navy(self, parser): |
| result = parser.parse("navy blazer") |
| assert result.color_filter == "navy" |
|
|
| def test_multi_word_color(self, parser): |
| result = parser.parse("sky blue dress") |
| assert result.color_filter == "blue" |
|
|
| def test_no_color(self, parser): |
| result = parser.parse("casual hoodie") |
| assert result.color_filter is None |
|
|
|
|
| class TestPriceParsing: |
| def test_under(self, parser): |
| result = parser.parse("dress under £40") |
| assert result.price_max == 40.0 |
| assert result.price_min is None |
|
|
| def test_over(self, parser): |
| result = parser.parse("jacket over £100") |
| assert result.price_min == 100.0 |
|
|
| def test_range(self, parser): |
| result = parser.parse("shoes £20-£50") |
| assert result.price_min == 20.0 |
| assert result.price_max == 50.0 |
|
|
| def test_budget(self, parser): |
| result = parser.parse("budget dress") |
| assert result.price_max == 30.0 |
|
|
| def test_luxury(self, parser): |
| result = parser.parse("luxury jacket") |
| assert result.price_min == 100.0 |
|
|
| def test_no_price(self, parser): |
| result = parser.parse("blue dress") |
| assert result.price_min is None |
| assert result.price_max is None |
|
|
|
|
| class TestGenderParsing: |
| def test_mens(self, parser): |
| result = parser.parse("mens hoodie") |
| assert result.gender_filter == "Men" |
|
|
| def test_womens(self, parser): |
| result = parser.parse("for women dress") |
| assert result.gender_filter == "Women" |
|
|
| def test_ladies(self, parser): |
| result = parser.parse("ladies dress elegant") |
| assert result.gender_filter == "Women" |
|
|
| def test_no_gender(self, parser): |
| result = parser.parse("casual hoodie") |
| assert result.gender_filter is None |
|
|
|
|
| class TestMaterialParsing: |
| def test_silk(self, parser): |
| result = parser.parse("silk midi dress") |
| assert result.material_filter == "silk" |
|
|
| def test_leather(self, parser): |
| result = parser.parse("leather jacket") |
| assert result.material_filter == "leather" |
|
|
| def test_denim(self, parser): |
| result = parser.parse("denim jacket") |
| assert result.material_filter == "denim" |
|
|
| def test_no_material(self, parser): |
| result = parser.parse("black dress") |
| assert result.material_filter is None |
|
|
|
|
| class TestSizeParsing: |
| def test_named_size(self, parser): |
| result = parser.parse("size small hoodie") |
| assert result.size_filter == "S" |
|
|
| def test_numeric_size(self, parser): |
| result = parser.parse("size 10 dress") |
| assert result.size_filter == "10" |
|
|
| def test_xl(self, parser): |
| result = parser.parse("XL casual shirt") |
| assert result.size_filter == "XL" |
|
|
| def test_no_size(self, parser): |
| result = parser.parse("black dress") |
| assert result.size_filter is None |
|
|
|
|
| class TestExclusions: |
| def test_not(self, parser): |
| result = parser.parse("black dress not floral") |
| assert "floral" in result.exclusions |
|
|
| def test_without(self, parser): |
| result = parser.parse("jacket without leather") |
| assert "leather" in result.exclusions |
|
|
| def test_no_keyword(self, parser): |
| result = parser.parse("summer top no black") |
| assert "black" in result.exclusions |
|
|
| def test_material_exclusion_conflict(self, parser): |
| result = parser.parse("jacket not cotton") |
| assert result.material_filter is None |
| assert "cotton" in result.exclusions |
|
|
| def test_no_exclusions(self, parser): |
| result = parser.parse("black dress") |
| assert result.exclusions == [] |
|
|
|
|
| class TestStyleTags: |
| def test_single_tag(self, parser): |
| result = parser.parse("casual hoodie") |
| assert "casual" in result.style_tags |
|
|
| def test_multiple_tags(self, parser): |
| result = parser.parse("vintage boho dress") |
| assert "vintage" in result.style_tags |
| assert "boho" in result.style_tags |
|
|
| def test_no_tags(self, parser): |
| result = parser.parse("blue jeans") |
| assert "casual" not in result.style_tags |
|
|
|
|
| class TestVibeText: |
| def test_preserves_raw_query(self, parser): |
| result = parser.parse("black dress under £40") |
| assert result.raw_query == "black dress under £40" |
|
|
| def test_vibe_not_empty(self, parser): |
| result = parser.parse("black dress") |
| assert len(result.vibe_text) > 0 |
|
|