Added a new `.coveragerc` file configuring coverage thresholds and exclusions. Included `pytest.ini` to enable coverage reporting for multiple backend modules (`main`, `llm`, `prompt`, `geoip`, `tts_asr`) with a 90 % fail‑under requirement and detailed HTML output. Implemented a suite of unit tests: * `test_geoip.py` – validates geo‑location lookup logic. * `test_llm_extended.py` – tests LLm response extraction and Ollama interactions. * `test_main_endpoints.py` – covers API endpoints for completions, OCR, and TTS. * `test_prompt_extended.py` – verifies language sanitization, timestamp generation, and prompt building. * `test_tts_asr_coverage.py` – checks device detection, cache clearing, and model loading under various environment configurations. * `test_tts_asr_extended.py` – further tests TTS/ASR device selection and time‑outs. Updated `backend/requirements.txt` to use newer, compatible packages, removed obsolete testing dependencies, and added `qwen-tts`. Modified `backend/tts_asr.py` to work with the new `Qwen3TTSModel`, simplified imports, and adjusted device mapping logic. Additionally, frontend changes added a new `TreeNodeItem` component, updated Markdown rendering, added TTS instruction fields, and reworked context menu handling. No breaking changes were introduced.
145 lines
5.2 KiB
Python
145 lines
5.2 KiB
Python
import sys
|
|
import os
|
|
import re
|
|
from pathlib import Path
|
|
|
|
# Ensure the project root is in sys.path so imports like `from backend import prompt` work
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from backend import prompt # type: ignore
|
|
|
|
|
|
def test_get_current_datetime_auto_format():
|
|
s = prompt._get_current_datetime("auto")
|
|
assert isinstance(s, str)
|
|
# Expect a date-like prefix: YYYY-MM-DD
|
|
assert re.match(r"^\d{4}-\d{2}-\d{2}", s)
|
|
# Expect a 3-letter weekday somewhere
|
|
assert re.search(r"\b[A-Za-z]{3}\b", s)
|
|
# Accept either an explicit UTC offset or a UTC label
|
|
assert re.search(r"UTC|[+-]\d{2}:?\d{2}", s)
|
|
|
|
|
|
def test_get_current_datetime_utc_plus5():
|
|
s = prompt._get_current_datetime("UTC+5")
|
|
assert isinstance(s, str)
|
|
assert "UTC+5" in s
|
|
|
|
|
|
def test_get_current_datetime_gmt_minus3():
|
|
s = prompt._get_current_datetime("GMT-3")
|
|
assert isinstance(s, str)
|
|
assert "GMT-3" in s
|
|
|
|
|
|
def test_get_current_datetime_new_york_fallback():
|
|
s = prompt._get_current_datetime("America/New_York")
|
|
assert isinstance(s, str)
|
|
# Fallback behavior: allow either an explicit offset or a simple date prefix
|
|
ok = bool(re.search(r"[+-]\d{2}:?\d{2}", s)) or bool(re.match(r"^\d{4}-\d{2}-\d{2}", s))
|
|
assert ok
|
|
|
|
|
|
def test_sanitize_language_id_empty_none_and_chars():
|
|
# Empty / None should map to markdown by design
|
|
assert prompt._sanitize_language_id("") == "markdown"
|
|
assert prompt._sanitize_language_id(None) == "markdown"
|
|
# Dangerous chars should be stripped
|
|
sanitized = prompt._sanitize_language_id("<script>alert(1)</script>")
|
|
assert "<" not in sanitized and ">" not in sanitized
|
|
# Valid input preserved
|
|
assert prompt._sanitize_language_id("python") == "python"
|
|
# Truncation at 32 chars
|
|
long_input = "a" * 50
|
|
trimmed = prompt._sanitize_language_id(long_input)
|
|
assert len(trimmed) <= 32
|
|
assert trimmed == "a" * min(32, len(long_input))
|
|
|
|
|
|
def test_normalize_newlines():
|
|
mixed = "line1\r\nline2\rline3\n"
|
|
norm = prompt._normalize_newlines(mixed)
|
|
assert norm == "line1\nline2\nline3\n"
|
|
|
|
|
|
def test_canonical_language_id_synonyms_and_unknown():
|
|
assert prompt._canonical_language_id("md") == "markdown"
|
|
assert prompt._canonical_language_id("py") == "python"
|
|
assert prompt._canonical_language_id("js") == "javascript"
|
|
assert prompt._canonical_language_id("ts") == "typescript"
|
|
assert prompt._canonical_language_id("yml") == "yaml"
|
|
assert prompt._canonical_language_id("Rust") == "rust"
|
|
|
|
|
|
def test_language_guidance_behaviors():
|
|
# markdown yields empty guidance
|
|
assert prompt._language_guidance("markdown") == ""
|
|
# mermaid guidance should mention mermaid
|
|
g_mermaid = prompt._language_guidance("mermaid")
|
|
assert isinstance(g_mermaid, str)
|
|
assert "mermaid" in g_mermaid.lower()
|
|
# python / javascript should reference the language
|
|
g_py = prompt._language_guidance("python")
|
|
assert isinstance(g_py, str) and "python" in g_py.lower()
|
|
g_js = prompt._language_guidance("javascript")
|
|
assert isinstance(g_js, str) and "javascript" in g_js.lower()
|
|
# unknown language should return a string as fallback
|
|
g_unknown = prompt._language_guidance("unknownlang")
|
|
assert isinstance(g_unknown, str)
|
|
|
|
|
|
def test_build_inline_system_prompt_templates():
|
|
s_md = prompt.build_inline_system_prompt("markdown")
|
|
assert isinstance(s_md, str) and "markdown" in s_md.lower()
|
|
s_mermaid = prompt.build_inline_system_prompt("mermaid")
|
|
assert isinstance(s_mermaid, str) and "mermaid" in s_mermaid.lower()
|
|
|
|
|
|
def test_prepare_context_strips_br_tags():
|
|
prefix, suffix = prompt._prepare_context("<br>hello<br/>", "world<br />")
|
|
assert "<br" not in prefix
|
|
assert "<br" not in suffix
|
|
|
|
|
|
def test_cursor_and_fence_helpers_basic():
|
|
sample = "```python\nprint('hi')\n"
|
|
assert prompt._cursor_in_fenced_code_block(sample) is True
|
|
assert prompt._cursor_in_fenced_code_block("plain text") is False
|
|
assert prompt._active_fence_language(sample) == "python"
|
|
assert prompt._active_fence_language("plain text") == "none"
|
|
|
|
|
|
def test_is_mermaid_context_detection():
|
|
assert prompt._is_mermaid_context("flowchart TD", "", "none") is True
|
|
assert prompt._is_mermaid_context("```mermaid\n", "\n```", "mermaid") is True
|
|
assert prompt._is_mermaid_context("plain text", "", "none") is False
|
|
|
|
|
|
def test_build_completion_prompts_with_userprefs():
|
|
class UserPrefs:
|
|
language = "python"
|
|
currency = "USD"
|
|
timezone = "UTC+0"
|
|
system, user = prompt.build_completion_prompts(
|
|
prefix="hello", suffix="world", language_id="markdown",
|
|
preferences=UserPrefs(),
|
|
)
|
|
assert isinstance(system, str)
|
|
assert isinstance(user, str)
|
|
assert "python" in user.lower() or "USD" in user
|
|
|
|
|
|
def test_build_completion_prompts_privacy_mode_location_empty():
|
|
system, user = prompt.build_completion_prompts(
|
|
prefix="hello", suffix="world", language_id="markdown",
|
|
location="",
|
|
)
|
|
assert isinstance(system, str)
|
|
assert isinstance(user, str)
|
|
|
|
|
|
def test_build_prompt_backward_compatibility():
|
|
res = prompt.build_prompt(prefix="hello", suffix="world", language_id="markdown")
|
|
assert isinstance(res, str)
|