Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import sys | |
| import unittest | |
| from pathlib import Path | |
| from unittest.mock import patch | |
| from typer.testing import CliRunner | |
| SRC = Path(__file__).resolve().parents[1] / "src" | |
| if str(SRC) not in sys.path: | |
| sys.path.insert(0, str(SRC)) | |
| from legawa.cli import app | |
| from legawa.config import LLMConfig, Settings | |
| class FakeLLM: | |
| def __init__(self, response: str): | |
| self.response = response | |
| self.calls: list[tuple[list[dict], dict]] = [] | |
| def chat(self, messages, **kwargs): | |
| self.calls.append((messages, kwargs)) | |
| return self.response | |
| class FakePool: | |
| def __init__(self, settings: Settings): | |
| self.settings = settings | |
| self.big = FakeLLM("OK") | |
| self.small = FakeLLM("OK") | |
| class FakePasalClient: | |
| def __init__(self, settings: Settings): | |
| self.settings = settings | |
| self.closed = False | |
| self.calls: list[dict] = [] | |
| def close(self): | |
| self.closed = True | |
| def __enter__(self): | |
| return self | |
| def __exit__(self, *_): | |
| self.close() | |
| def search(self, q=None, limit=1, **kwargs): | |
| if q is None: | |
| q = kwargs.get("q") | |
| self.calls.append({"q": q, "limit": limit, **kwargs}) | |
| if q in {"UU 31/1999", "UU 20/2001", "Perpres 16/2018", "Perpres 12/2021"}: | |
| kind_map = { | |
| "UU 31/1999": ("uu", "1999", "31", "Undang-Undang Nomor 31 Tahun 1999"), | |
| "UU 20/2001": ("uu", "2001", "20", "Undang-Undang Nomor 20 Tahun 2001"), | |
| "Perpres 16/2018": ("perpres", "2018", "16", "Peraturan Presiden Nomor 16 Tahun 2018"), | |
| "Perpres 12/2021": ("perpres", "2021", "12", "Peraturan Presiden Nomor 12 Tahun 2021"), | |
| } | |
| kind, year, number, title = kind_map[q] | |
| return { | |
| "results": [ | |
| { | |
| "title": title, | |
| "frbr_uri": f"akn/id/act/{kind}/{year}/{number}", | |
| "status": "berlaku", | |
| } | |
| ] | |
| } | |
| return {"results": [{"title": "UU test", "frbr_uri": "akn/id/act/uu/2003/13", "status": "berlaku"}]} | |
| class FakeCachingPasalClient: | |
| def __init__(self, raw): | |
| self.raw = raw | |
| self.closed = False | |
| def stats(self): | |
| return {"entries": 2, "bytes": 128, "session_hits": 1, "session_misses": 0} | |
| def purge_expired(self): | |
| return 3 | |
| def close(self): | |
| self.closed = True | |
| def make_settings() -> Settings: | |
| cfg = LLMConfig(base_url="http://example.invalid", api_key="x", model="qwen3", temperature=0.3, max_tokens=4096) | |
| return Settings( | |
| pasal_token="token", | |
| pasal_base_url="http://pasal.invalid", | |
| big=cfg, | |
| small=cfg, | |
| run_date="2026-04-30", | |
| corpus_watermark="2026-04-30", | |
| strict_citations=True, | |
| ) | |
| class CliSmokeTests(unittest.TestCase): | |
| def setUp(self) -> None: | |
| self.runner = CliRunner() | |
| self.settings = make_settings() | |
| def test_health_smoke(self) -> None: | |
| with ( | |
| patch("legawa.cli.load_settings", return_value=self.settings), | |
| patch("legawa.cli.LLMPool", return_value=FakePool(self.settings)), | |
| patch("legawa.cli.PasalClient", side_effect=lambda settings: FakePasalClient(settings)), | |
| ): | |
| result = self.runner.invoke(app, ["health"]) | |
| self.assertEqual(result.exit_code, 0, result.output) | |
| self.assertIn("OK big", result.output) | |
| self.assertIn("OK small", result.output) | |
| self.assertIn("OK pasal.id", result.output) | |
| def test_cache_commands_smoke(self) -> None: | |
| with ( | |
| patch("legawa.cli.load_settings", return_value=self.settings), | |
| patch("legawa.cli.LLMPool", return_value=FakePool(self.settings)), | |
| patch("legawa.cli.PasalClient", side_effect=lambda settings: FakePasalClient(settings)), | |
| patch("legawa.cli.CachingPasalClient", side_effect=lambda raw: FakeCachingPasalClient(raw)), | |
| ): | |
| stats = self.runner.invoke(app, ["cache", "stats"]) | |
| purge = self.runner.invoke(app, ["cache", "purge"]) | |
| self.assertEqual(stats.exit_code, 0, stats.output) | |
| self.assertIn("'entries': 2", stats.output) | |
| self.assertEqual(purge.exit_code, 0, purge.output) | |
| self.assertIn("purged 3 expired entries", purge.output) | |
| def test_draft_cli_it_audit_perspective(self) -> None: | |
| source = (Path(__file__).resolve().parents[1] / "tests" / "fixtures" / "ibam-it-audit-perspective.txt").read_text( | |
| encoding="utf-8" | |
| ) | |
| fake_pool = FakePool(self.settings) | |
| fake_pool.big.response = ( | |
| "# Memo Teknis\n" | |
| "Kami menilai serial number, audit trail, CDM license history, firmware, dan MDM policy.\n" | |
| "Rujukan: UU 31/1999, UU 20/2001, Perpres 16/2018." | |
| ) | |
| fake_pasal = FakePasalClient(self.settings) | |
| def bootstrap(): | |
| return fake_pool, fake_pasal | |
| with patch("legawa.cli._bootstrap", side_effect=bootstrap): | |
| result = self.runner.invoke( | |
| app, | |
| [ | |
| "draft", | |
| "memo_kebijakan", | |
| "audit teknis dan tata kelola perangkat digital pada Kasus Ibam", | |
| "--instruksi", | |
| source, | |
| "--no-research", | |
| ], | |
| ) | |
| self.assertEqual(result.exit_code, 0, result.output) | |
| self.assertIn("Memo Teknis", result.output) | |
| self.assertIn("UU 31/1999", result.output) | |
| self.assertNotIn("Perguruan Tinggi", result.output) | |
| system_prompt = fake_pool.big.calls[0][0][0]["content"] | |
| self.assertIn("forensik digital", system_prompt) | |
| self.assertIn("Tanggal penyusunan: 2026-04-30", system_prompt) | |
| if __name__ == "__main__": | |
| unittest.main() | |