aboutsummaryrefslogtreecommitdiff
path: root/app/tests
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-28 04:45:29 -0400
committerhistoria <historiavg@proton.me>2026-08-28 04:45:29 -0400
commit5ed31309b6d0db94ccd566914653d367f4577c64 (patch)
treeb909445125629181eb8aa38e4805f672bdaf9c20 /app/tests
parent0dda9a5921eafd03853d233e077138ff72d64e4d (diff)
downloadtts-audiobook-generator-5ed31309b6d0db94ccd566914653d367f4577c64.tar.gz
fix: japanese characters not truncated correctly in tui terminal output
Diffstat (limited to 'app/tests')
-rw-r--r--app/tests/test_runview.py11
-rw-r--r--app/tests/test_taskview.py19
-rw-r--r--app/tests/test_tui.py25
3 files changed, 55 insertions, 0 deletions
diff --git a/app/tests/test_runview.py b/app/tests/test_runview.py
index 8feeee1..3f77ed0 100644
--- a/app/tests/test_runview.py
+++ b/app/tests/test_runview.py
@@ -62,10 +62,21 @@ class FormatTests(_FakeTui, unittest.TestCase):
self.assertEqual(runview._fit("hello", 3), "he~")
self.assertEqual(runview._fit("hi", 10), "hi")
+ def test_fit_truncates_wide_characters_by_display_columns(self):
+ # Japanese characters fill two terminal cells each, so fitting
+ # by character count would let lines overflow their pane.
+ self.assertEqual(runview._fit("你好", 4), "你好")
+ self.assertEqual(runview._fit("你好你好", 5), "你好~")
+ self.assertEqual(runview._fit("こんにちは", 3), "こ~")
+
def test_wrap_wraps_on_word_boundaries(self):
self.assertEqual(runview._wrap("aaaa bbbb cccc dddd", 12),
["aaaa bbbb", "cccc dddd"])
+ def test_wrap_counts_wide_characters_as_two_columns(self):
+ self.assertEqual(runview._wrap("日本語 テスト", 10),
+ ["日本語", "テスト"])
+
class StateTransitionTests(_FakeTui, unittest.TestCase):
def test_boot_flow_starting_to_ready(self):
diff --git a/app/tests/test_taskview.py b/app/tests/test_taskview.py
index 1db708d..78cc2f1 100644
--- a/app/tests/test_taskview.py
+++ b/app/tests/test_taskview.py
@@ -725,6 +725,25 @@ class LanesViewTests(_FakeTui, unittest.TestCase):
pane_w = (screen.width - 3) // 2
self.assertLessEqual(x + len(label) - 1, 1 + pane_w - 2)
+ def test_split_render_truncates_wide_log_lines_to_their_pane(self):
+ # Regression: Japanese characters fill two terminal cells each,
+ # so fitting by character count let transcription results spill
+ # out of the right pane onto the left one.
+ view, screen = self.make_view(self._two_lanes(), width=80)
+ view._ingest_lane_line(view._lanes[1],
+ "[OK] 一号: " + "語" * 40)
+ view.render()
+ found = [(x, t) for _, x, t, _ in screen.strings
+ if t.startswith("[OK] ")]
+ self.assertEqual(len(found), 1)
+ x, line = found[0]
+ self.assertTrue(line.endswith("~"))
+ pane_w = (screen.width - 3) // 2
+ px, pw = 1 + pane_w + 1, (screen.width - 3) - pane_w
+ self.assertGreaterEqual(x, px + 1)
+ self.assertLessEqual(x + taskview.tui._disp_width(line) - 1,
+ px + pw - 2)
+
class SilenceCueTests(_FakeTui, unittest.TestCase):
"""The "(no output 6m)" cue for a running step that stopped emitting."""
diff --git a/app/tests/test_tui.py b/app/tests/test_tui.py
index 6fc3fd5..4c8b431 100644
--- a/app/tests/test_tui.py
+++ b/app/tests/test_tui.py
@@ -1501,6 +1501,31 @@ class TextViewerTests(TuiTestCase):
self.assertTrue(drawn[0].endswith("~"))
+class FitTests(TuiTestCase):
+ """Column-aware fitting: East Asian Wide characters occupy 2 cells."""
+
+ def test_disp_width_counts_wide_characters_twice(self):
+ self.assertEqual(tui._disp_width(""), 0)
+ self.assertEqual(tui._disp_width("hello"), 5)
+ self.assertEqual(tui._disp_width("一号"), 4)
+ self.assertEqual(tui._disp_width("mix語end"), 8)
+
+ def test_fit_truncates_by_display_columns(self):
+ self.assertEqual(tui._fit("hello", 3), "he~")
+ self.assertEqual(tui._fit("hi", 10), "hi")
+ # Exact fit keeps the wide pair; one column more would overflow.
+ self.assertEqual(tui._fit("你好", 4), "你好")
+ self.assertEqual(tui._fit("你好你好", 5), "你好~")
+ self.assertEqual(tui._fit("こんにちは", 3), "こ~")
+
+ def test_wrap_segments_counts_wide_characters_twice(self):
+ # "語 語 語" is 8 cells, so at width 5 only two words fit per
+ # line even though 5 characters would fit by count.
+ lines = tui._wrap_segments([("語 語 語", None)], 5)
+ self.assertEqual(["".join(t for t, _ in line) for line in lines],
+ ["語 語", "語"])
+
+
class WizardTests(unittest.TestCase):
"""The tui.Wizard screen-stack driver: Esc steps back one screen."""