Spaces:
Configuration error
Configuration error
Download tests/test_app.py from ZainabEman/OCR-Based-Spare-Part-Localization: direct link, hf CLI and curl.
- Browser
- Download file 5.77 kB
-
https://huggingface.co/spaces/ZainabEman/OCR-Based-Spare-Part-Localization/resolve/main/tests/test_app.py
- Command line
-
hf download hf://spaces/ZainabEman/OCR-Based-Spare-Part-Localization/tests/test_app.py
-
curl -L -o test_app.py https://huggingface.co/spaces/ZainabEman/OCR-Based-Spare-Part-Localization/resolve/main/tests/test_app.py
5.77 kB
| """End-to-end checks of the Streamlit app, run headlessly via AppTest. | |
| These drive the real `app.py` script: type into the box, submit, inspect what | |
| was rendered. They are deliberately few -- enough to prove the search path, | |
| the multi-occurrence path and the error paths work. | |
| """ | |
| import pytest | |
| from spareparts import config | |
| pytest.importorskip("streamlit") | |
| from streamlit.testing.v1 import AppTest # noqa: E402 | |
| pytestmark = pytest.mark.skipif( | |
| not config.DB_PATH.exists(), reason="run `python -m spareparts.build_index` first" | |
| ) | |
| APP = str(config.PROJECT_ROOT / "app.py") | |
| def _search(term: str, timeout: int = 60) -> AppTest: | |
| app = AppTest.from_file(APP, default_timeout=timeout).run() | |
| app.text_input[0].set_value(term) | |
| app.button[0].click().run() | |
| return app | |
| def _text(app: AppTest) -> str: | |
| parts = [el.value for el in app.markdown] + [el.value for el in app.caption] | |
| parts += [el.value for el in app.subheader] + [el.value for el in app.warning] | |
| parts += [el.value for el in app.error] + [el.value for el in app.info] | |
| return "\n".join(str(p) for p in parts) | |
| def test_app_starts_without_a_search(): | |
| app = AppTest.from_file(APP, default_timeout=60).run() | |
| assert not app.exception | |
| assert app.title[0].value == "Machine Part Finder" | |
| assert app.text_input[0].label == "Part number" | |
| def test_valid_part_shows_metadata_and_an_image(): | |
| app = _search("30642") | |
| assert not app.exception | |
| body = _text(app) | |
| assert "30642" in body | |
| assert "worm,cpl." in body # canonical English name | |
| assert "Motor-drive" in body # catalogue section title | |
| assert "Located" in body # localization method, stated plainly | |
| # PDF page and section number are shown as distinct facts. | |
| metrics = {m.label: m.value for m in app.metric} | |
| assert metrics["PDF page"] == "34" | |
| assert metrics["Catalogue section"] == "07" | |
| assert len(app.image) == 1, "the annotated diagram should be displayed" | |
| def test_unknown_part_is_reported_not_crashed(): | |
| app = _search("99999") | |
| assert not app.exception | |
| assert app.error, "an unknown part must produce an error message" | |
| assert "not found in the catalogue" in app.error[0].value | |
| assert not app.image | |
| def test_empty_and_non_numeric_input_is_handled(term): | |
| app = _search(term) | |
| assert not app.exception | |
| assert not app.image | |
| if term.strip(): | |
| assert app.warning or app.error | |
| def test_messy_input_is_normalized_then_found(): | |
| app = _search(" part no. 30642 ") | |
| assert not app.exception | |
| assert not app.error | |
| assert "worm,cpl." in _text(app) | |
| def test_multiple_occurrences_offer_a_selector(): | |
| app = _search("73290") # drawn on ten catalogue pages | |
| assert not app.exception | |
| assert app.radio, "a part on several pages must offer a choice" | |
| options = app.radio[0].options | |
| assert len(options) > 1 | |
| assert all(o.startswith("Occurrence ") for o in options) | |
| assert "PDF page" in options[0] | |
| # One page is shown at a time, and it is one the user chose. | |
| assert len(app.image) == 1 | |
| def test_selecting_another_occurrence_switches_page(): | |
| app = _search("73290") | |
| first = {m.label: m.value for m in app.metric}["PDF page"] | |
| app.radio[0].set_value(app.radio[0].options[2]).run() | |
| assert not app.exception | |
| second = {m.label: m.value for m in app.metric}["PDF page"] | |
| assert first != second | |
| def test_low_confidence_result_is_shown_as_approximate(): | |
| """A conservative fallback must be visible as such, not dressed up.""" | |
| from spareparts import index_db | |
| conn = index_db.connect() | |
| try: | |
| row = conn.execute( | |
| "SELECT l.part_no FROM labels l JOIN components c ON c.label_id = l.id" | |
| " WHERE c.method = 'capped' AND l.part_no IN" | |
| " (SELECT part_no FROM labels GROUP BY part_no HAVING COUNT(*) = 1)" | |
| " LIMIT 1" | |
| ).fetchone() | |
| finally: | |
| conn.close() | |
| app = _search(row[0]) | |
| assert not app.exception | |
| body = _text(app) | |
| assert "Approximate" in body | |
| assert "Confidence" in body | |
| def test_listed_but_not_drawn_part_shows_the_page_and_says_so(): | |
| app = _search("70248") # listed on page 39, not drawn there | |
| assert not app.exception | |
| assert not app.error | |
| assert app.warning, "the user must be told why there is no highlight" | |
| assert "no callout" in app.warning[0].value | |
| assert len(app.image) == 1, "the page itself should still be shown" | |
| def test_no_ocr_engine_is_loaded_during_a_search(): | |
| """Definition of done: searching must not run OCR or localization. | |
| Checked in a subprocess so that nothing another test imported can mask it. | |
| """ | |
| import subprocess | |
| import sys | |
| import textwrap | |
| script = textwrap.dedent( | |
| """ | |
| import sys | |
| from streamlit.testing.v1 import AppTest | |
| app = AppTest.from_file(sys.argv[1], default_timeout=60).run() | |
| app.text_input[0].set_value("30642") | |
| app.button[0].click().run() | |
| assert not app.exception, app.exception | |
| banned = [m for m in sys.modules | |
| if "rapidocr" in m or m.startswith("spareparts.ocr") | |
| or m.startswith("spareparts.localizer")] | |
| print("LOADED:" + ",".join(sorted(banned))) | |
| """ | |
| ) | |
| result = subprocess.run( | |
| [sys.executable, "-c", script, APP], | |
| capture_output=True, text=True, cwd=str(config.PROJECT_ROOT), timeout=300, | |
| ) | |
| assert result.returncode == 0, result.stderr[-2000:] | |
| line = next(l for l in result.stdout.splitlines() if l.startswith("LOADED:")) | |
| assert line == "LOADED:", f"search pulled in offline-only modules: {line}" | |