""" Tests for the kushya generator API. These tests use mocked external callers; no real API requests are made. """ import sys from pathlib import Path from unittest.mock import patch # Add parent inference/ dir sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "inference")) # Add the shorashim repo's korban_processor src to sys.path sys.path.insert( 0, str(Path(__file__).resolve().parent.parent.parent / "korban_processor" / "src"), ) from kushya_api import KushyaResult, generate_kushya, _extract_refs # noqa: E402 # ============================================================ # Backend selection # ============================================================ def test_fallback_returns_no_kushya_with_explanation(): """The fallback path honestly reports no challenge — never invents one.""" result = generate_kushya("Some interpretation.", backend="fallback") assert isinstance(result, KushyaResult) assert result.kushya is None assert result.backend == "fallback" assert "does not invent" in (result.notes or "") def test_fine_tuned_without_endpoint_falls_back_in_auto(): """auto mode skips fine_tuned when no endpoint is configured, then skips external when not available, ending in fallback.""" # We expect the Korban Processor's external model call to either succeed # (if API key is present) or fail (if not) — either way, the result has # a clear backend. Mock to ensure deterministic behavior. from korban_processor.external_offering import consult_external_model # noqa: F401 with patch("kushya_api.consult_external_model") as mock_consult: mock_consult.side_effect = RuntimeError("simulated API failure") result = generate_kushya("Some interpretation.", backend="auto") assert result.kushya is None assert result.backend in ("fallback", "external") def test_fine_tuned_explicit_without_endpoint_raises(): """When backend='fine_tuned' is forced but no endpoint is configured, we raise rather than silently falling through.""" import pytest with pytest.raises(ValueError, match="fine_tuned_endpoint"): generate_kushya("Some interpretation.", backend="fine_tuned") # ============================================================ # External backend — mocked, exercises the full eish-zarah path # ============================================================ def test_external_backend_returns_kushya_via_korban_processor(): """When external consultation succeeds, the result is recorded with 'external' backend and a notes field that emphasizes it is testimony, not ruling.""" from kushya_api import _try_external fake_consultation = type("FakeConsultation", (), {})() fake_consultation.raw_response = type( "FakeResponse", (), {"content": "raw response with a question?"} )() fake_consultation.processed = type( "FakeProcessed", (), {"vital_content": "What about Shemot 35:3 — does the prohibition extend to passive heating?"}, )() with patch("kushya_api.consult_external_model", return_value=fake_consultation): result = _try_external("Cooking on Shabbat is forbidden.", allow_fallback=True) assert result.kushya assert result.backend == "external" assert "testimony" in (result.notes or "").lower() assert "Shemot 35:3" in result.torah_refs def test_external_backend_handles_empty_vital_content(): """If zerikah extracts nothing vital from external response, we record None — we do not pretend an empty kushya is real.""" from kushya_api import _try_external fake_consultation = type("FakeConsultation", (), {})() fake_consultation.raw_response = type("FakeResp", (), {"content": "Great question!"})() fake_consultation.processed = type("FakeProc", (), {"vital_content": ""})() with patch("kushya_api.consult_external_model", return_value=fake_consultation): result = _try_external("Some interp.", allow_fallback=True) assert result.kushya is None assert result.backend == "external" assert "no vital content" in (result.notes or "").lower() # ============================================================ # Reference extraction # ============================================================ def test_extract_refs_finds_torah_citations(): text = "What about Shemot 35:3 and also Vayikra 18:5?" refs = _extract_refs(text) assert "Shemot 35:3" in refs assert "Vayikra 18:5" in refs def test_extract_refs_handles_verse_ranges(): text = "Devarim 21:1-9 and Bereishit 1:1" refs = _extract_refs(text) assert any("Devarim 21:1" in r for r in refs) assert "Bereishit 1:1" in refs def test_extract_refs_returns_empty_for_no_citations(): assert _extract_refs("This text has no Torah references.") == []