"""Pretty-print + ensure_ascii=False on `aborist query` output. The CLI default emits a human-readable render of the query result; ``--json`` switches to the raw record. Both paths must: - render unicode literals (no \\uXXXX escape sequences) - present the answer prominently; metadata is supporting info """ from __future__ import annotations import json import pytest from aborist.cli import _render_query_human # --------------------------------------------------------------------------- # _render_query_human — direct unit tests # --------------------------------------------------------------------------- def _result(**overrides) -> dict: base = { "status": "cache_miss_then_written", "audit_mode": "HYBRID", "cache_key": "35ab7d3355c723b759145d6d446cb1d9010abe0dce9992ca0e8b87837b596610", "context_root": "ab" * 32, "answer_text": "Pikachu is a species of Pokémon creatures.", "sources": [ { "document_root": "cd" * 32, "document_uri": "https://en.wikipedia.org/wiki/Pikachu", "title": "Pikachu", "score": 36.6, "chunk_idx": 6, "shard": "002.db", } ], "n_quotes": 2, "n_verified": 1, "verifier_method": "quote", "unverified_quotes": ["something the model said but didn't ground"], "timings": {"total_ms": 9234.1}, } base.update(overrides) return base def test_render_includes_question_at_top(): out = _render_query_human(_result(), "who is pikachu?") assert out.splitlines()[0] == "who is pikachu?" def test_render_summary_line_has_audit_n_verified_method_elapsed(): out = _render_query_human(_result(), "q") second = out.splitlines()[1] assert "HYBRID" in second assert "1/2 verified" in second assert "via quote" in second assert "9.2s" in second def test_render_marks_cache_hit_distinctly(): out_hit = _render_query_human(_result(status="cache_hit"), "q") out_fresh = _render_query_human(_result(status="cache_miss_then_written"), "q") assert "(cached)" in out_hit assert "(fresh)" in out_fresh def test_render_emits_unicode_literals_not_escapes(): """Pokémon, not Pok\\u00e9mon — the user's terminal should see real é.""" out = _render_query_human(_result(), "who is pikachu?") assert "Pokémon" in out assert "\\u00e9" not in out def test_render_lists_sources_with_clean_host_path(): out = _render_query_human(_result(), "q") # "[1] Pikachu — en.wikipedia.org/wiki/Pikachu (002.db)" assert "[1] Pikachu" in out assert "en.wikipedia.org/wiki/Pikachu" in out # scheme stripped assert "https://" not in out.split("sources (")[1] if "sources (" in out else True assert "(002.db)" in out def test_render_truncates_long_unverified_quotes(): long = "x" * 200 out = _render_query_human(_result(unverified_quotes=[long]), "q") # Truncated form ends in ellipsis assert "..." in out # Original doesn't fully appear assert long not in out def test_render_omits_unverified_section_when_empty(): out = _render_query_human(_result(unverified_quotes=[]), "q") assert "unverified" not in out.lower() def test_render_omits_sources_section_when_empty(): out = _render_query_human(_result(sources=[]), "q") assert "sources (" not in out def test_render_falls_back_for_error_status(): """no_sources / unknown_document / etc. produce a one-line status.""" out = _render_query_human( {"status": "no_sources", "msg": "FTS5 returned no hits"}, "q", ) assert "no_sources" in out assert "FTS5" in out def test_render_includes_short_cache_key_with_pointer_to_json(): out = _render_query_human(_result(), "q") # Short prefix only — full key requires --json assert "cache_key: 35ab7d33" in out assert "--json" in out # --------------------------------------------------------------------------- # json.dumps everywhere uses ensure_ascii=False (regression on the global pass) # --------------------------------------------------------------------------- def test_unicode_round_trips_through_print_path(capsys): """Pin: a result with a Pokémon-style answer prints é, not \\u00e9. Uses argparse via build_parser to exercise the real CLI dispatch.""" from aborist.cli import build_parser parser = build_parser() # Build a fake result and call _cmd_query's render path indirectly. out = _render_query_human(_result(), "who is pikachu?") print(out) captured = capsys.readouterr().out assert "Pokémon" in captured assert "\\u00e9" not in captured def test_json_mode_also_uses_unicode(): """The --json path should also emit unicode literals, not escapes.""" payload = {"answer": "Pokémon"} s = json.dumps(payload, ensure_ascii=False) assert "Pokémon" in s assert "\\u00e9" not in s