dukaan-saathi / tests /test_resolve.py
yobro4619's picture
Deploy: Docker GPU Space (Modal LLM + T4 STT/TTS)
32254a0 verified
Raw
History Blame Contribute Delete
4.38 kB
"""Tests for robust item resolution / dedup (dukaan.resolve + ops.add_inventory).
Covers:
- Exact-name match returns status=="matched" and score==100.0
- Upper-case variant of an existing item restocks (no duplicate row)
- Totally made-up item creates new_item and resolve returns "none"
- candidates_item returns a list; normalize_item_name parses brand/base
"""
from __future__ import annotations
import pytest
from dukaan import db, ops
import dukaan.resolve as resolve
# ------------------------------------------------------------------ helpers
def _an_item() -> dict:
"""Return a real seeded inventory row with a non-trivial name."""
rows = db.qx(
"SELECT * FROM inv.inventory WHERE length(name) > 8 ORDER BY item_id LIMIT 1"
)
assert rows, "seeded DB must have at least one item"
return rows[0]
# ------------------------------------------------------------------ tests
def test_exact_name_matched(seeded_db):
"""An exact seeded name must resolve to 'matched' with score==100.0."""
item = _an_item()
result = resolve.resolve_item(item["name"])
assert result["status"] == "matched", (
f"Expected 'matched' for '{item['name']}', got '{result['status']}'"
)
assert result["score"] == 100.0, (
f"Expected score 100.0, got {result['score']}"
)
def test_case_and_variant_merges(seeded_db):
"""Adding an existing item name uppercased must restock (merge), not create a duplicate row."""
item = _an_item()
original_name = item["name"]
original_qty = int(item["qty"])
# Add 5 units using the uppercased name — should detect as the same item.
result = ops.add_inventory(original_name.upper(), 5)
assert result["ok"] is True, f"add_inventory failed: {result}"
assert result["action"] == "restock", (
f"Expected 'restock' for upper-case variant of '{original_name}', "
f"got action='{result['action']}'"
)
# The qty should have increased by 5.
updated = ops.find_item(original_name)
assert updated is not None, "Item disappeared after restock"
assert updated["qty"] == original_qty + 5, (
f"Expected qty={original_qty + 5}, got {updated['qty']}"
)
# Still only one row with that name (case-insensitive).
count_rows = db.qx(
"SELECT COUNT(*) AS n FROM inv.inventory WHERE lower(name) = lower(?)",
(original_name,),
)
assert count_rows[0]["n"] == 1, (
f"Expected exactly 1 row for '{original_name}', "
f"got {count_rows[0]['n']} (duplicate created!)"
)
def test_new_item_not_matched(seeded_db):
"""A completely invented name must resolve to 'none' against the seeded catalog,
then create a new_item when added via add_inventory."""
weird_name = "Qwzz9 Madeup Brand 500ml 1kg pack"
# FIRST: verify the name has no match in the seeded catalog (spec requirement).
resolve_before = resolve.resolve_item(weird_name)
assert resolve_before["status"] == "none", (
f"Expected 'none' before insertion for '{weird_name}', "
f"got '{resolve_before['status']}'"
)
# THEN: add_inventory should create it as new_item (because resolve returned none).
result = ops.add_inventory(weird_name, 7, mrp=40)
assert result["ok"] is True, f"add_inventory failed: {result}"
assert result["action"] == "new_item", (
f"Expected 'new_item', got '{result['action']}'"
)
def test_candidates_is_list(seeded_db):
"""candidates_item('dal', 5) returns a list; normalize_item_name parses brand/base."""
cands = ops.candidates_item("dal", 5)
assert isinstance(cands, list), (
f"Expected list from candidates_item, got {type(cands)}"
)
# 'dal' should match several seeded dal items (toor dal, moong dal, masoor dal…)
# We just require it returns a list (possibly empty on degenerate seeds).
# Normalise a well-known branded name and check base contains the product keyword.
parsed = resolve.normalize_item_name("TATA SALT 1KG")
assert isinstance(parsed, dict), "normalize_item_name must return a dict"
assert "base" in parsed, "Result must contain 'base' key"
# The base should contain 'salt' (after the brand 'tata' is extracted and size stripped).
assert "salt" in parsed["base"].lower(), (
f"Expected 'salt' in base, got base='{parsed['base']}'"
)