home · contact · privacy
In testing, improve flexibility of screen line check command. master
authorChristian Heller <c.heller@plomlompom.de>
Sat, 18 Oct 2025 18:51:07 +0000 (20:51 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Sat, 18 Oct 2025 18:51:07 +0000 (20:51 +0200)
src/ircplom/testing.py
src/tests/tui_draw.test

index 926c338c98f2f12b965ccee8655368b192e33508..0c1d8ea240c7bda6159b8e38e8c0bfe1e20e5468 100644 (file)
@@ -28,6 +28,8 @@ _MARK_WAIT = 'wait'
 _SEP_0 = ' '
 _SEP_1 = ','
 _SEP_2 = ':'
+_SCREENLINE_IGNORE_CHAR = '§'
+_SCREENLINE_PADDING_SUFFIX = 2 * _SCREENLINE_IGNORE_CHAR
 
 _N_ARGS_FOR_CMD = {
     _MARK_ANCHOR: 1,
@@ -36,7 +38,7 @@ _N_ARGS_FOR_CMD = {
     _MARK_LOGSRVRMSG: 3,
     _MARK_PROMPT: 1,
     _MARK_REPEAT: 3,
-    _MARK_SCREENLINE: 4,
+    _MARK_SCREENLINE: 3,
     _MARK_SERVERMSG: 2,
     _MARK_WAIT: 1
 }
@@ -87,18 +89,21 @@ class TestTerminal(QueueMixin, TerminalInterface):
             yield TuiEvent.affector('handle_keyboard_event'
                                     ).kw(typed_in=to_yield)
 
-    def assert_screen_line(self, y: int, x: int, attrs_str: str, text: str
-                           ) -> None:
-        'Assert test screen at (y,x) shows text, with attrs of attrs_str set.'
-        assert len(text) + x <= self.size.x
+    def assert_screen_line(self, y: int, attrs_str: str, text: str) -> None:
+        'Assert test screen at line y shows text, attrs of attrs_str set.'
         assert 0 <= y < self.size.y
+        if text.endswith(_SCREENLINE_PADDING_SUFFIX):
+            text = text[:-len(_SCREENLINE_PADDING_SUFFIX)]
+            text += ' ' * (self.size.x - len(text))
         for idx, cell_expected in enumerate(
                 (self._attrs_tuple_from_str(attrs_str), c) for c in text):
-            cell_found = self._screen[y][x + idx]
-            info = ('AT_X', x + idx,
+            if _SCREENLINE_IGNORE_CHAR == cell_expected[1]:
+                continue
+            cell_found = self._screen[y][idx]
+            info = ('AT_X', idx,
                     'CHAR EXPECTED', cell_expected, 'FOUND', cell_found,
                     'FULL LINE EXPECTED', text,
-                    'FOUND', ''.join(t[1] for t in self._screen[y][x:]))
+                    'FOUND', ''.join(t[1] for t in self._screen[y]))
             assert cell_expected == cell_found, info
 
 
@@ -341,7 +346,7 @@ class _Playbook:
                 assert self.assert_screen_line is not None
                 assert self.redraw_affected is not None
                 self.redraw_affected()
-                self.assert_screen_line(int(args[0]), int(args[1]), *args[2:])
+                self.assert_screen_line(int(args[0]), *args[1:])
             elif cmd_name == _MARK_WAIT:
                 sleep(int(args[0]))
             self._idx += 1
@@ -388,7 +393,7 @@ class TestingClientTui(ClientTui):
 
     def log(self, msg: str, **kwargs) -> None:
         def test_after(cmd_name: str, args: tuple[str, ...], ret) -> None:
-            assert cmd_name == _MARK_LOG
+            assert cmd_name == _MARK_LOG, f'WANTED {_MARK_LOG}, GOT {cmd_name}'
             win_ids, logged_msg = ret
             fmt, time_str, msg_sans_time = logged_msg.split(' ', maxsplit=2)
             msg_sans_time = fmt + ' ' + msg_sans_time
index 360bcd895f7df42ebacb00b4ded4745b3b0f8f5f..029635b5bc81e2b2e6cb63e09a4ec8954a4f37ae 100644 (file)
@@ -4,34 +4,26 @@
 | lines-empty-4-in
 | lines-empty-2-in
 | lines-empty-1-in
-line 0 0 on_black                                                                                 
+line 0 on_black §§
 | lines-empty-1-out
 repeat lines-empty-1-in lines-empty-1-out 1
 | lines-empty-2-out
-repeat lines-empty-1-in lines-empty-1-out 2
-repeat lines-empty-1-in lines-empty-1-out 3
+repeat lines-empty-1-in lines-empty-1-out +2
+repeat lines-empty-1-in lines-empty-1-out +3
 | lines-empty-4-out
-repeat lines-empty-1-in lines-empty-1-out 4
-repeat lines-empty-1-in lines-empty-1-out 5
-repeat lines-empty-1-in lines-empty-1-out 6
-repeat lines-empty-1-in lines-empty-1-out 7
+repeat lines-empty-2-in lines-empty-2-out +4
+repeat lines-empty-2-in lines-empty-2-out +6
 | lines-empty-8-out
-repeat lines-empty-1-in lines-empty-1-out 8
-repeat lines-empty-1-in lines-empty-1-out 9
-repeat lines-empty-1-in lines-empty-1-out 10
-repeat lines-empty-1-in lines-empty-1-out 11
-repeat lines-empty-1-in lines-empty-1-out 12
-repeat lines-empty-1-in lines-empty-1-out 13
-repeat lines-empty-1-in lines-empty-1-out 14
-repeat lines-empty-1-in lines-empty-1-out 15
+repeat lines-empty-4-in lines-empty-4-out +8
+repeat lines-empty-4-in lines-empty-4-out +12
 | lines-empty-16-out
 repeat lines-empty-4-in lines-empty-4-out +16
 repeat lines-empty-2-in lines-empty-2-out +19
+repeat lines-empty-1-in lines-empty-1-out +21
 | status-prompt-empty-in
-line 22 0  :start)=====================================================================([0]
-line 23 0  > 
-line 23 2 reverse  
-line 23 3                                                                               
+line 22 , :start)=====================================================================([0]§§
+line 23 , > § §§
+line 23 reverse §§ §
 | status-prompt-empty-out
 | empty-init-out
 
@@ -40,210 +32,246 @@ line 23 3
 repeat empty-init-in empty-init-out
 
 # non-empty command input starts log at bottom, with date above it
-| input-foo-in
 > foo
 log 0 .!# invalid prompt command: not prefixed by /
-| input-foo-out
 repeat lines-empty-16-in lines-empty-16-out
 repeat lines-empty-4-in lines-empty-4-out +16
-| date-at-20-plus-topmost-in
-| date-at-20-in
-line 20 0 on_black 20
-line 20 4 on_black -
-line 20 7 on_black -
-line 20 10 on_black                                                                     
-| date-at-20-out
-| foo-unprefixed-line-21-in
-line 21 0 on_black,bold,bright_red,bright_cyan .!# 
-line 21 13 on_black,bold,bright_red,bright_cyan invalid prompt command: not prefixed by /                          
-| foo-unprefixed-line-21-out
-| date-at-20-plus-topmost-out
+| history-lines-0:2-at-20-in
+| history-lines-0:1-at-20-in
+line 20 on_black 20§§-§§-§§ §§
+| history-lines-0:1-at-20-out
+line 21 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: not prefixed by / §§
+| history-lines-0:2-at-20-out
 repeat status-prompt-empty-in status-prompt-empty-out
 
 # further inputs grow log upwards
-| input-cmd-foo-in
 > /foo
 log 0 .!# invalid prompt command: /foo unknown
-| input-cmd-foo-out
-repeat input-cmd-foo-in input-cmd-foo-out
+> /bar
+log 0 .!# invalid prompt command: /bar unknown
+| before-1st-scroll-in
 repeat lines-empty-16-in lines-empty-16-out
 repeat lines-empty-2-in lines-empty-2-out +16
-| date-at-18-plus-3-in
-repeat date-at-20-plus-topmost-in date-at-20-plus-topmost-out -2
-| foo-unknown-line-20-in
-line 20 13 on_black,bold,bright_red,bright_cyan invalid prompt command: /foo unknown       
-| foo-unknown-line-20-out
-repeat foo-unknown-line-20-in foo-unknown-line-20-out 21
-| date-at-18-plus-3-out
+| history-lines-0:4-at-18-in
+repeat history-lines-0:2-at-20-in history-lines-0:2-at-20-out -2
+| history-lines-2:4-at-20-in
+line 20 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /foo unknown §§
+line 21 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /bar unknown §§
+| history-lines-2:4-at-20-out
+| history-lines-0:4-at-18-out
 repeat status-prompt-empty-in status-prompt-empty-out
-
-# check wrapping
-> /foo_0123456789_0123456789_01234567
-log 0 .!# invalid prompt command: /foo_0123456789_0123456789_01234567 unknown
-repeat lines-empty-16-in lines-empty-16-out
-repeat lines-empty-1-in lines-empty-1-out +16
-| date-at-17-plus-4-in
-repeat date-at-18-plus-3-in date-at-18-plus-3-out -1
-| unwrapped-at-21-in
-line 21 13 on_black,bold,bright_red,bright_cyan invalid prompt command: /foo_0123456789_0123456789_01234567 unknown
-| unwrapped-at-21-out
-| date-at-17-plus-4-out
-repeat status-prompt-empty-in status-prompt-empty-out
-| input-wrapped-in
-> /foo_0123456789_0123456789_012345678
-log 0 .!# invalid prompt command: /foo_0123456789_0123456789_012345678 unknown
-| input-wrapped-out
-| scroll-returnable-0-in
-repeat lines-empty-8-in lines-empty-8-out
-repeat lines-empty-4-in lines-empty-4-out +8
-repeat lines-empty-2-in lines-empty-2-out +12
-repeat lines-empty-1-in lines-empty-1-out +14
-| date-at-15-plus-6-in
-repeat date-at-17-plus-4-in date-at-17-plus-4-out -2
-| wrapped-at-20-in
-line 20 13 on_black,bold,bright_red,bright_cyan invalid prompt command: /foo_0123456789_0123456789_012345678       
-line 21 0 on_black,bold,bright_red,bright_cyan     unknown                                                                     
-| wrapped-at-20-out
-| date-at-15-plus-6-out
-repeat status-prompt-empty-in status-prompt-empty-out
-| scroll-returnable-0-out
+| before-1st-scroll-out
 
 # check scrolling up on short history
 > /window.history.scroll up
-| topmost-scroll-in
+| after-1st-scroll-in
 repeat lines-empty-16-in lines-empty-16-out
 repeat lines-empty-4-in lines-empty-4-out +16
-repeat date-at-20-in date-at-20-out
-| topmost-scroll-out
-line 21 0 reverse vvv [6] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+repeat history-lines-0:1-at-20-in history-lines-0:1-at-20-out
+line 21 reverse vvv [4] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv§§
 repeat status-prompt-empty-in status-prompt-empty-out
+| after-1st-scroll-out
 
 # check scrolling down on short history
 > /window.history.scroll down
-repeat scroll-returnable-0-in scroll-returnable-0-out
+repeat before-1st-scroll-in before-1st-scroll-out
 
 # check history growing below up-scroll
 > /window.history.scroll up
-| input-foo-cmd-foo-in
-repeat input-foo-in input-foo-out
-repeat input-cmd-foo-in input-cmd-foo-out
-| input-foo-cmd-foo-out
-repeat input-foo-cmd-foo-in input-foo-cmd-foo-out
-repeat input-foo-in input-foo-out
-repeat topmost-scroll-in topmost-scroll-out
-line 21 0 reverse vvv [11] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+repeat after-1st-scroll-in after-1st-scroll-out
+> /help
+log 0 ..# commands available in this window:
+log 0 ..#   /connect HOST_PORT [NICKNAME_PW] [REALNAME_USERNAME]
+log 0 ..#   /help
+log 0 ..#   /list
+log 0 ..#   /prompt_enter
+log 0 ..#   /quit
+log 0 ..#   /window TOWARDS
+log 0 ..#   /window.history.scroll DIRECTION
+log 0 ..#   /window.paste
+log 0 ..#   /window.prompt.backspace
+log 0 ..#   /window.prompt.move_cursor DIRECTION
+log 0 ..#   /window.prompt.scroll DIRECTION
+| before-scrolldown-not-to-bottom-in
+repeat lines-empty-16-in lines-empty-16-out
+repeat lines-empty-4-in lines-empty-4-out +16
+repeat history-lines-0:1-at-20-in history-lines-0:1-at-20-out
+line 21 reverse vvv [16] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv§§
 repeat status-prompt-empty-in status-prompt-empty-out
+| before-scrolldown-not-to-bottom-out
 
-# check scroll-down on longer history
+# check scroll-down on newer history longer than half a screen width does not fully land at bottom
 > /window.history.scroll down
+| after-scrolldown-not-to-bottom-in
 repeat lines-empty-8-in lines-empty-8-out
-repeat lines-empty-2-in lines-empty-2-out +8
-repeat date-at-15-plus-6-in date-at-15-plus-6-out -5
-| foo-only-fails-lines-2-at-17-in
-repeat foo-unprefixed-line-21-in foo-unprefixed-line-21-out 17
-repeat foo-unknown-line-20-in foo-unknown-line-20-out 18
-| foo-only-fails-lines-2-at-17-out
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out +2
-repeat foo-unprefixed-line-21-in foo-unprefixed-line-21-out 21
-repeat status-prompt-empty-in status-prompt-empty-out
-
-# check history growing upwards if scrolled down
-repeat input-foo-cmd-foo-in input-foo-cmd-foo-out
-repeat input-foo-cmd-foo-in input-foo-cmd-foo-out
-repeat input-foo-cmd-foo-in input-foo-cmd-foo-out
-repeat input-foo-cmd-foo-in input-foo-cmd-foo-out
-repeat input-foo-cmd-foo-in input-foo-cmd-foo-out
-repeat input-foo-cmd-foo-in input-foo-cmd-foo-out
-repeat input-foo-cmd-foo-in input-foo-cmd-foo-out
-repeat input-foo-cmd-foo-in input-foo-cmd-foo-out
-repeat input-foo-cmd-foo-in input-foo-cmd-foo-out
-| scroll-returnable-1-in
-repeat foo-unknown-line-20-in foo-unknown-line-20-out 0
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -16
-repeat foo-unprefixed-line-21-in foo-unprefixed-line-21-out 3
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -13
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -11
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -9
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -7
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -5
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -3
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -1
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out +1
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out +3
-repeat status-prompt-empty-in status-prompt-empty-out
-| scroll-returnable-1-out
-
-# check scroll-up on longer history no longer starting at just date, and counting unwrapped below-lines one-to-one
+repeat lines-empty-1-in lines-empty-1-out +8
+| history-lines-0:8-at-9-in
+repeat history-lines-0:4-at-18-in history-lines-0:4-at-18-out -9
+| history-lines-4:8-at-13-in
+| history-lines-4:5-at-13-in
+line 13 on_black,bright_cyan ..# §§:§§:§§ commands available in this window:§§
+| history-lines-4:5-at-13-out
+| history-lines-5:6-at-14-in
+line 14 on_black,bright_cyan ..# §§:§§:§§   /connect HOST_PORT [NICKNAME_PW] [REALNAME_USERNAME]§§
+| history-lines-5:6-at-14-out
+| history-lines-6:8-at-15-in
+line 15 on_black,bright_cyan ..# §§:§§:§§   /help§§
+line 16 on_black,bright_cyan ..# §§:§§:§§   /list§§
+| history-lines-6:8-at-15-out
+| history-lines-4:8-at-13-out
+| history-lines-0:8-at-9-out
+| history-lines-8:12-at-17-in
+line 17 on_black,bright_cyan ..# §§:§§:§§   /prompt_enter§§
+line 18 on_black,bright_cyan ..# §§:§§:§§   /quit§§
+line 19 on_black,bright_cyan ..# §§:§§:§§   /window TOWARDS§§
+line 20 on_black,bright_cyan ..# §§:§§:§§   /window.history.scroll DIRECTION§§
+| history-lines-8:12-at-17-out
+line 21 reverse vvv [5] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv§§
+repeat status-prompt-empty-in status-prompt-empty-out
+| after-scrolldown-not-to-bottom-out
+
+# check previous scroll-down not hitting bottom be fully reversible
+> /window.history.scroll up
+repeat before-scrolldown-not-to-bottom-in before-scrolldown-not-to-bottom-out
+> /window.history.scroll down
+repeat after-scrolldown-not-to-bottom-in after-scrolldown-not-to-bottom-out
+
+# scroll to bottom, check history still growing up even beyond upper fold
+> /window.history.scroll down
+repeat lines-empty-4-in lines-empty-4-out
+repeat lines-empty-1-in lines-empty-1-out +5
+| history-lines-0:16-at-6-in
+repeat history-lines-0:8-at-9-in history-lines-0:8-at-9-out -3
+repeat history-lines-8:12-at-17-in history-lines-8:12-at-17-out -3
+| history-lines-12:16-at-18-in
+| history-lines-12:13-at-18-in
+line 18 on_black,bright_cyan ..# §§:§§:§§   /window.paste§§
+| history-lines-12:13-at-18-out
+line 19 on_black,bright_cyan ..# §§:§§:§§   /window.prompt.backspace§§
+line 20 on_black,bright_cyan ..# §§:§§:§§   /window.prompt.move_cursor DIRECTION§§
+line 21 on_black,bright_cyan ..# §§:§§:§§   /window.prompt.scroll DIRECTION§§
+| history-lines-12:16-at-18-out
+| history-lines-0:16-at-6-out
+repeat status-prompt-empty-in status-prompt-empty-out
+> /0
+log 0 .!# invalid prompt command: /0 unknown
+> /1
+log 0 .!# invalid prompt command: /1 unknown
+> /2
+log 0 .!# invalid prompt command: /2 unknown
+> /3
+log 0 .!# invalid prompt command: /3 unknown
+> /4
+log 0 .!# invalid prompt command: /4 unknown
+> /5
+log 0 .!# invalid prompt command: /5 unknown
+> /6
+log 0 .!# invalid prompt command: /6 unknown
+> /7
+log 0 .!# invalid prompt command: /7 unknown
+| at-bottom-before-wrapped-in
+repeat history-lines-2:4-at-20-in history-lines-2:4-at-20-out -20
+repeat history-lines-4:8-at-13-in history-lines-4:8-at-13-out -11
+repeat history-lines-8:12-at-17-in history-lines-8:12-at-17-out -11
+repeat history-lines-12:16-at-18-in history-lines-12:16-at-18-out -8
+| history-lines-16:24-at-14-in
+line 14 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /0 unknown§§
+line 15 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /1 unknown§§
+line 16 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /2 unknown§§
+line 17 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /3 unknown§§
+line 18 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /4 unknown§§
+line 19 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /5 unknown§§
+line 20 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /6 unknown§§
+line 21 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /7 unknown§§
+| history-lines-16:24-at-14-out
+repeat status-prompt-empty-in status-prompt-empty-out
+| at-bottom-before-wrapped-out
+
+# quick look one scroll up to check single-scroll increase of below-scroll count (when up-scroll not limited, and all lines un-wrapped)
 > /window.history.scroll up
-| scroll-returnable-2-in
-repeat lines-empty-2-in lines-empty-2-out
-repeat date-at-15-plus-6-in date-at-15-plus-6-out -13
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -8
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -6
-repeat foo-unprefixed-line-21-in foo-unprefixed-line-21-out 13
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -3
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -1
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out +1
-repeat foo-unprefixed-line-21-in foo-unprefixed-line-21-out 20
-| scroll-returnable-2-out
-line 21 0 reverse vvv [12] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+repeat lines-empty-8-in lines-empty-8-out
+repeat history-lines-0:8-at-9-in history-lines-0:8-at-9-out -1
+repeat history-lines-8:12-at-17-in history-lines-8:12-at-17-out -1
+repeat history-lines-12:13-at-18-in history-lines-12:13-at-18-out +2
+line 21 reverse vvv [12] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv§§
 repeat status-prompt-empty-in status-prompt-empty-out
 > /window.history.scroll down
-repeat scroll-returnable-1-in scroll-returnable-1-out
+repeat at-bottom-before-wrapped-in at-bottom-before-wrapped-out
+
+# # check wrapping
+> /foo_0123456789_0123456789_01234567
+log 0 .!# invalid prompt command: /foo_0123456789_0123456789_01234567 unknown
+> /foo_0123456789_0123456789_012345678
+log 0 .!# invalid prompt command: /foo_0123456789_0123456789_012345678 unknown
+| at-bottom-after-wrapped-in
+repeat history-lines-5:6-at-14-in history-lines-5:6-at-14-out -14
+repeat history-lines-6:8-at-15-in history-lines-6:8-at-15-out -14
+| history-lines-8:16-at-3-in
+repeat history-lines-8:12-at-17-in history-lines-8:12-at-17-out -14
+repeat history-lines-12:16-at-18-in history-lines-12:16-at-18-out -11
+| history-lines-8:16-at-3-out
+repeat history-lines-16:24-at-14-in history-lines-16:24-at-14-out -3
+| history-lines-24:26-at-19-in
+line 19 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /foo_0123456789_0123456789_01234567 unknown§§
+line 20 on_black,bold,bright_red,bright_cyan .!# §§:§§:§§ invalid prompt command: /foo_0123456789_0123456789_012345678§§ 
+| history-lines-24:26-at-19-out
+| history-lines-26:27-at-21-in
+line 21 on_black,bold,bright_red,bright_cyan     unknown§§
+| history-lines-26:27-at-21-out
+repeat status-prompt-empty-in status-prompt-empty-out
+| at-bottom-after-wrapped-out
 
-# check adding a wrapped line under scroll-up increases visible below-count by one, but scroll down …
+# check scroll-up over wrapped moves up less history lines than screen lines
 > /window.history.scroll up
-repeat input-wrapped-in input-wrapped-out
-repeat scroll-returnable-2-in scroll-returnable-2-out
-line 21 0 reverse vvv [13] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+| scrollup-after-wrapped-in
+repeat lines-empty-4-in lines-empty-4-out
+repeat lines-empty-1-in lines-empty-1-out +4
+repeat history-lines-0:16-at-6-in history-lines-0:16-at-6-out -1
+| scrollup-after-wrapped-out
+line 21 reverse vvv [11] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv§§
+repeat status-prompt-empty-in status-prompt-empty-out
+
+# check scroll-down fully reversible even if over wrapped
 > /window.history.scroll down
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -17
-repeat foo-unprefixed-line-21-in foo-unprefixed-line-21-out 2
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -14
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -12
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -10
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -8
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -6
-repeat foo-unknown-line-20-in foo-unknown-line-20-out 14
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -2
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out +2
-repeat foo-unknown-line-20-in foo-unknown-line-20-out 20
-line 21 0 reverse vvv [2] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-repeat status-prompt-empty-in status-prompt-empty-out
-
-# check scroll-up over wrapped increases visible below-lines count only by fused history lines
+repeat at-bottom-after-wrapped-in at-bottom-after-wrapped-out
+> /window.history.scroll up
+repeat scrollup-after-wrapped-in scrollup-after-wrapped-out
+line 21 reverse vvv [11] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv§§
+repeat status-prompt-empty-in status-prompt-empty-out
+
+# check wrapped input only increases below-scroll count by one 
+> /bar_0123456789_0123456789_012345678
+log 0 .!# invalid prompt command: /bar_0123456789_0123456789_012345678 unknown
+repeat scrollup-after-wrapped-in scrollup-after-wrapped-out
+line 21 reverse vvv [12] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv§§
+repeat status-prompt-empty-in status-prompt-empty-out
+
+# check scroll-down over wrapped will snap down to bottom of wrapped
 > /window.history.scroll down
-repeat foo-unknown-line-20-in foo-unknown-line-20-out 0
-repeat foo-unprefixed-line-21-in foo-unprefixed-line-21-out 1
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -15
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -13
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -11
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -9
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -7
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -5
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -3
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out -1
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out +1
-repeat wrapped-at-20-in wrapped-at-20-out
+repeat history-lines-6:8-at-15-in history-lines-6:8-at-15-out -15
+repeat history-lines-8:16-at-3-in history-lines-8:16-at-3-out -1
+repeat history-lines-16:24-at-14-in history-lines-16:24-at-14-out -4
+repeat history-lines-24:26-at-19-in history-lines-24:26-at-19-out -1
+repeat history-lines-26:27-at-21-in history-lines-26:27-at-21-out -1
+line 21 reverse vvv [2] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv§§
 repeat status-prompt-empty-in status-prompt-empty-out
+
+# # check scrolls-up over longer history until top
 > /window.history.scroll up
-line 21 0 reverse vvv [11] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+repeat scrollup-after-wrapped-in scrollup-after-wrapped-out
+line 21 reverse vvv [12] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv§§
 repeat status-prompt-empty-in status-prompt-empty-out
-
-# check scrolls-up over longer history until top
 > /window.history.scroll up
-repeat lines-empty-8-in lines-empty-8-out
-repeat lines-empty-2-in lines-empty-2-out +8
-repeat lines-empty-1-in lines-empty-1-out +10
-repeat date-at-15-plus-6-in date-at-15-plus-6-out -4
-repeat foo-only-fails-lines-2-at-17-in foo-only-fails-lines-2-at-17-out +1
-repeat foo-unprefixed-line-21-in foo-unprefixed-line-21-out 20
-line 21 0 reverse vvv [22] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+repeat lines-empty-16-in lines-empty-16-out
+repeat history-lines-0:4-at-18-in history-lines-0:4-at-18-out -2
+repeat history-lines-4:5-at-13-in history-lines-4:5-at-13-out +7
+line 21 reverse vvv [23] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv§§
 repeat status-prompt-empty-in status-prompt-empty-out
 > /window.history.scroll up
-repeat topmost-scroll-in topmost-scroll-out
-line 21 0 reverse vvv [30] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+repeat lines-empty-16-in lines-empty-16-out
+repeat lines-empty-4-in lines-empty-4-out +16
+repeat history-lines-0:1-at-20-in history-lines-0:1-at-20-out
+line 21 reverse vvv [27] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv§§
 repeat status-prompt-empty-in status-prompt-empty-out
 
 > /quit