aboutsummaryrefslogtreecommitdiffstats
path: root/test_llamachat.py
diff options
context:
space:
mode:
Diffstat (limited to 'test_llamachat.py')
-rwxr-xr-xtest_llamachat.py51
1 files changed, 51 insertions, 0 deletions
diff --git a/test_llamachat.py b/test_llamachat.py
index 0986631..f23a576 100755
--- a/test_llamachat.py
+++ b/test_llamachat.py
@@ -217,6 +217,21 @@ def test_sse_parsing():
)
assert opening is None
assert opening != backend.DONE
+
+ # A delta carrying both fields is thinking, not reply. Classifying it as
+ # content splices the tail of the reasoning onto the front of the reply.
+ both = backend._parse_sse_line(
+ 'data: {"choices":[{"delta":'
+ '{"reasoning_content":"still thinking","content":""}}]}'
+ )
+ assert both == ("reasoning", "still thinking"), both
+
+ # An empty reasoning delta renders nothing and must not fall through to
+ # the content branch.
+ empty = backend._parse_sse_line(
+ 'data: {"choices":[{"delta":{"reasoning_content":""}}]}'
+ )
+ assert empty is None, empty
print("ok sse parsing")
@@ -365,6 +380,41 @@ def test_markdown_rendering():
print("ok markdown rendering")
+def test_unbalanced_backticks():
+ """An odd backtick cannot reflow the rest of a reply as code."""
+ import os
+
+ os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
+ from PySide6.QtWidgets import QApplication
+
+ from llamachat.ui import _close_fences, _markdown_to_fragment
+
+ app = QApplication.instance() or QApplication([])
+ assert app is not None
+
+ # An unclosed fence gets one, so the tail is not swallowed.
+ assert _close_fences("a\n```py\nx=1").endswith("\n```")
+ # A closed fence is left exactly as it was.
+ balanced = "a\n```py\nx=1\n```\ntail"
+ assert _close_fences(balanced) == balanced
+ # A longer opener needs a closer at least as long.
+ assert _close_fences("````\nx").endswith("\n````")
+ # Tildes are fences too.
+ assert _close_fences("~~~\nx").endswith("\n~~~")
+ # A lone inline tick is dropped rather than opening a run.
+ assert "`" not in _close_fences("use ` here")
+ # Balanced inline ticks survive untouched.
+ assert _close_fences("a `b` c") == "a `b` c"
+
+ # The real failure: reasoning text full of ticks must not become one
+ # block that eats the prose after it.
+ leaked = "` (wait)\nthen `find / -perm -4000` and more prose here"
+ rendered = _markdown_to_fragment(leaked)
+ assert "more prose here" in rendered
+ assert "<pre" not in rendered, rendered
+ print("ok unbalanced backticks")
+
+
def test_system_qt_theme_guard():
"""The plugin path is only borrowed when the Qt versions agree."""
import os
@@ -864,6 +914,7 @@ if __name__ == "__main__":
test_session_prompt_storage()
test_prompt_column_migration()
test_markdown_rendering()
+ test_unbalanced_backticks()
test_sidebar_toggle()
test_shortcuts()
test_system_qt_theme_guard()