LCOV - code coverage report
Current view: top level - tests/unit - test_input_line.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 99.4 % 167 166
Test Date: 2026-05-07 15:53:07 Functions: 100.0 % 6 6

            Line data    Source code
       1              : #include "test_helpers.h"
       2              : #include "input_line.h"
       3              : #include <string.h>
       4              : #include <stddef.h>
       5              : #include <unistd.h>
       6              : #include <fcntl.h>
       7              : 
       8              : /* ── stdin/stdout redirection helpers ──────────────────────────────────── */
       9              : 
      10              : /**
      11              :  * Redirect STDIN_FILENO from a pipe containing the given bytes.
      12              :  * Saves the old stdin fd into *saved_stdin.
      13              :  * Returns the read-end fd (already dup2'd to STDIN_FILENO; close it after
      14              :  * restoring).
      15              :  */
      16           27 : static int stdin_push(const char *bytes, size_t len, int *saved_stdin) {
      17              :     int pipefd[2];
      18           27 :     if (pipe(pipefd) != 0) return -1;
      19              :     /* Write all bytes then close write-end so read side sees EOF */
      20           27 :     if (write(pipefd[1], bytes, len) != (ssize_t)len) {
      21            0 :         close(pipefd[0]); close(pipefd[1]); return -1;
      22              :     }
      23           27 :     close(pipefd[1]);
      24           27 :     *saved_stdin = dup(STDIN_FILENO);
      25           27 :     dup2(pipefd[0], STDIN_FILENO);
      26           27 :     close(pipefd[0]);
      27           27 :     return 0;
      28              : }
      29              : 
      30              : /** Restore STDIN_FILENO from saved_stdin fd. */
      31           27 : static void stdin_pop(int saved_stdin) {
      32           27 :     dup2(saved_stdin, STDIN_FILENO);
      33           27 :     close(saved_stdin);
      34           27 : }
      35              : 
      36              : /**
      37              :  * Suppress stdout and stderr for the duration of input_line_run
      38              :  * (which emits ANSI escape codes we don't want in test output).
      39              :  * On return, *saved_out and *saved_err hold the real fds.
      40              :  */
      41           27 : static void output_suppress(int *saved_out, int *saved_err) {
      42           27 :     fflush(stdout); fflush(stderr);
      43           27 :     int null_fd = open("/dev/null", O_WRONLY);
      44           27 :     *saved_out = dup(STDOUT_FILENO);
      45           27 :     *saved_err = dup(STDERR_FILENO);
      46           27 :     if (null_fd >= 0) {
      47           27 :         dup2(null_fd, STDOUT_FILENO);
      48           27 :         dup2(null_fd, STDERR_FILENO);
      49           27 :         close(null_fd);
      50              :     }
      51           27 : }
      52              : 
      53           27 : static void output_restore(int saved_out, int saved_err) {
      54           27 :     fflush(stdout); fflush(stderr);
      55           27 :     dup2(saved_out, STDOUT_FILENO);  close(saved_out);
      56           27 :     dup2(saved_err, STDERR_FILENO); close(saved_err);
      57           27 : }
      58              : 
      59              : /**
      60              :  * Run input_line_run with injected keypress bytes.
      61              :  * Suppresses TUI output.  Returns the result of input_line_run.
      62              :  */
      63           27 : static int run_with_keys(InputLine *il, int trow, const char *prompt,
      64              :                          const char *keys, size_t keylen) {
      65              :     int saved_stdin;
      66           27 :     if (stdin_push(keys, keylen, &saved_stdin) != 0) return -99;
      67              : 
      68              :     int saved_out, saved_err;
      69           27 :     output_suppress(&saved_out, &saved_err);
      70              : 
      71           27 :     int result = input_line_run(il, trow, prompt);
      72              : 
      73           27 :     output_restore(saved_out, saved_err);
      74           27 :     stdin_pop(saved_stdin);
      75           27 :     return result;
      76              : }
      77              : 
      78            1 : void test_input_line(void) {
      79              :     char buf[64];
      80              : 
      81              :     /* 1. Init with NULL initial_text → empty buffer, cursor at 0 */
      82              :     InputLine il;
      83            1 :     input_line_init(&il, buf, sizeof(buf), NULL);
      84            1 :     ASSERT(il.buf   == buf,       "buf pointer set");
      85            1 :     ASSERT(il.bufsz == sizeof(buf), "bufsz set");
      86            1 :     ASSERT(il.len   == 0,         "len 0 for NULL initial");
      87            1 :     ASSERT(il.cur   == 0,         "cur 0 for NULL initial");
      88            1 :     ASSERT(buf[0]   == '\0',      "buf NUL-terminated");
      89              : 
      90              :     /* 2. Init with empty string → same as NULL */
      91            1 :     input_line_init(&il, buf, sizeof(buf), "");
      92            1 :     ASSERT(il.len == 0, "len 0 for empty initial");
      93            1 :     ASSERT(il.cur == 0, "cur 0 for empty initial");
      94              : 
      95              :     /* 3. Init with text → len and cur at end */
      96            1 :     input_line_init(&il, buf, sizeof(buf), "hello");
      97            1 :     ASSERT(il.len == 5,           "len 5 for 'hello'");
      98            1 :     ASSERT(il.cur == 5,           "cur at end after init");
      99            1 :     ASSERT(strcmp(buf, "hello") == 0, "buf contains 'hello'");
     100              : 
     101              :     /* 4. Init truncates when text >= bufsz */
     102              :     char small[4];
     103            1 :     input_line_init(&il, small, sizeof(small), "toolong");
     104            1 :     ASSERT(il.len == 3,         "len truncated to bufsz-1");
     105            1 :     ASSERT(small[3] == '\0',    "buf NUL-terminated after truncation");
     106              : 
     107              :     /* 5. All callbacks NULL after init */
     108            1 :     input_line_init(&il, buf, sizeof(buf), "x");
     109            1 :     ASSERT(il.tab_fn       == NULL, "tab_fn NULL after init");
     110            1 :     ASSERT(il.shift_tab_fn == NULL, "shift_tab_fn NULL after init");
     111            1 :     ASSERT(il.render_below == NULL, "render_below NULL after init");
     112              : 
     113              :     /* 6. trow is 0 after init */
     114            1 :     ASSERT(il.trow == 0, "trow 0 after init");
     115              : 
     116              :     /* 7. UTF-8 multi-byte initial text */
     117            1 :     input_line_init(&il, buf, sizeof(buf), "héllo");
     118              :     /* 'é' is 2 bytes (0xC3 0xA9) → len = 6, cur = 6 */
     119            1 :     ASSERT(il.len == 6, "len accounts for UTF-8 bytes");
     120            1 :     ASSERT(il.cur == 6, "cur at byte end for UTF-8 text");
     121            1 :     ASSERT(strcmp(buf, "héllo") == 0, "UTF-8 content preserved");
     122              : 
     123              :     /* ── input_line_run tests ──────────────────────────────────────────── */
     124              : 
     125              :     /* 8. Enter on pre-filled buffer → returns 1, buffer unchanged */
     126              :     {
     127              :         char rbuf[64];
     128              :         InputLine ril;
     129            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "hello");
     130            1 :         int res = run_with_keys(&ril, 5, "> ", "\r", 1);
     131            1 :         ASSERT(res == 1, "input_line_run: Enter returns 1");
     132            1 :         ASSERT(strcmp(rbuf, "hello") == 0, "input_line_run: buffer unchanged after Enter");
     133              :     }
     134              : 
     135              :     /* 9. ESC on pre-filled buffer → returns 0, buffer unchanged */
     136              :     {
     137              :         char rbuf[64];
     138              :         InputLine ril;
     139            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "hello");
     140              :         /* Bare ESC: send ESC then a non-'[' byte so terminal_read_key treats it
     141              :          * as TERM_KEY_ESC (the fallback in the else branch). We use a second \r
     142              :          * which won't be read because input_line_run returns on ESC. */
     143            1 :         int res = run_with_keys(&ril, 5, "> ", "\033x", 2);
     144            1 :         ASSERT(res == 0, "input_line_run: ESC returns 0");
     145            1 :         ASSERT(strcmp(rbuf, "hello") == 0, "input_line_run: buffer unchanged after ESC");
     146              :     }
     147              : 
     148              :     /* 10. Ctrl-C → returns 0 */
     149              :     {
     150              :         char rbuf[64];
     151              :         InputLine ril;
     152            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "test");
     153            1 :         int res = run_with_keys(&ril, 5, "> ", "\x03", 1);
     154            1 :         ASSERT(res == 0, "input_line_run: Ctrl-C returns 0");
     155              :     }
     156              : 
     157              :     /* 11. Enter on empty buffer → returns 1 with empty buffer */
     158              :     {
     159              :         char rbuf[64];
     160              :         InputLine ril;
     161            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), NULL);
     162            1 :         int res = run_with_keys(&ril, 5, "Prompt: ", "\r", 1);
     163            1 :         ASSERT(res == 1, "input_line_run: Enter on empty buffer returns 1");
     164            1 :         ASSERT(rbuf[0] == '\0', "input_line_run: empty buffer stays empty");
     165              :     }
     166              : 
     167              :     /* 12. Type characters then Enter → buffer contains typed text */
     168              :     {
     169              :         char rbuf[64];
     170              :         InputLine ril;
     171            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), NULL);
     172              :         /* inject: 'h','i','\r' */
     173            1 :         int res = run_with_keys(&ril, 5, "> ", "hi\r", 3);
     174            1 :         ASSERT(res == 1, "input_line_run: typing then Enter returns 1");
     175            1 :         ASSERT(strcmp(rbuf, "hi") == 0, "input_line_run: typed chars in buffer");
     176              :     }
     177              : 
     178              :     /* 13. Backspace deletes last character */
     179              :     {
     180              :         char rbuf[64];
     181              :         InputLine ril;
     182            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "ab");
     183              :         /* DEL byte (backspace) then Enter */
     184            1 :         int res = run_with_keys(&ril, 5, "> ", "\x7f\r", 2);
     185            1 :         ASSERT(res == 1, "input_line_run: backspace+Enter returns 1");
     186            1 :         ASSERT(strcmp(rbuf, "a") == 0, "input_line_run: backspace deletes last char");
     187              :     }
     188              : 
     189              :     /* 14. Backspace at start of buffer → no change */
     190              :     {
     191              :         char rbuf[64];
     192              :         InputLine ril;
     193            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), NULL);
     194              :         /* backspace on empty → no-op, then Enter */
     195            1 :         int res = run_with_keys(&ril, 5, "> ", "\x7f\r", 2);
     196            1 :         ASSERT(res == 1, "input_line_run: backspace on empty returns 1");
     197            1 :         ASSERT(rbuf[0] == '\0', "input_line_run: backspace on empty is no-op");
     198              :     }
     199              : 
     200              :     /* 15. Left arrow then Backspace → deletes char before new cursor position */
     201              :     {
     202              :         char rbuf[64];
     203              :         InputLine ril;
     204            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "ab");
     205              :         /* Left arrow: ESC [ D  (3 bytes), then backspace, then Enter */
     206            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[D\x7f\r", 6);
     207            1 :         ASSERT(res == 1, "input_line_run: left+backspace returns 1");
     208            1 :         ASSERT(strcmp(rbuf, "b") == 0, "input_line_run: left+backspace deletes 'a'");
     209              :     }
     210              : 
     211              :     /* 16. Right arrow at end → no change, then Enter */
     212              :     {
     213              :         char rbuf[64];
     214              :         InputLine ril;
     215            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "hi");
     216              :         /* Right arrow at end is a no-op */
     217            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[C\r", 4);
     218            1 :         ASSERT(res == 1, "input_line_run: right at end+Enter returns 1");
     219            1 :         ASSERT(strcmp(rbuf, "hi") == 0, "input_line_run: right at end is no-op");
     220              :     }
     221              : 
     222              :     /* 17. Home key moves cursor to start, then type char prepends it */
     223              :     {
     224              :         char rbuf[64];
     225              :         InputLine ril;
     226            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "bc");
     227              :         /* Home: ESC [ H, then type 'a', then Enter */
     228            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[Ha\r", 5);
     229            1 :         ASSERT(res == 1, "input_line_run: Home+insert+Enter returns 1");
     230            1 :         ASSERT(strcmp(rbuf, "abc") == 0, "input_line_run: Home+insert prepends char");
     231              :     }
     232              : 
     233              :     /* 18. End key moves cursor to end, then type appends */
     234              :     {
     235              :         char rbuf[64];
     236              :         InputLine ril;
     237            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "hi");
     238              :         /* Move to start first, then End, then type '!' */
     239              :         /* Home: ESC[H, End: ESC[F, type '!', Enter */
     240            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[H\033[F!\r", 8);
     241            1 :         ASSERT(res == 1, "input_line_run: Home+End+insert+Enter returns 1");
     242            1 :         ASSERT(strcmp(rbuf, "hi!") == 0, "input_line_run: End+insert appends");
     243              :     }
     244              : 
     245              :     /* 19. Delete key (ESC[3~) removes char at cursor */
     246              :     {
     247              :         char rbuf[64];
     248              :         InputLine ril;
     249            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "abc");
     250              :         /* Home, then Delete: ESC[H ESC[3~, Enter */
     251            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[H\033[3~\r", 8);
     252            1 :         ASSERT(res == 1, "input_line_run: Home+Delete+Enter returns 1");
     253            1 :         ASSERT(strcmp(rbuf, "bc") == 0, "input_line_run: Delete removes char at cursor");
     254              :     }
     255              : 
     256              :     /* 20. Delete at end (no-op) then Enter */
     257              :     {
     258              :         char rbuf[64];
     259              :         InputLine ril;
     260            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "hi");
     261              :         /* Delete at end = no-op */
     262            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[3~\r", 5);
     263            1 :         ASSERT(res == 1, "input_line_run: Delete at end+Enter returns 1");
     264            1 :         ASSERT(strcmp(rbuf, "hi") == 0, "input_line_run: Delete at end is no-op");
     265              :     }
     266              : 
     267              :     /* 21. Buffer full: inserting beyond bufsz is silently ignored */
     268              :     {
     269              :         char rbuf[4]; /* holds 3 chars + NUL */
     270              :         InputLine ril;
     271            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "abc");
     272              :         /* Try to insert 'd' when buffer is full, then Enter */
     273            1 :         int res = run_with_keys(&ril, 5, "> ", "d\r", 2);
     274            1 :         ASSERT(res == 1, "input_line_run: insert into full buffer returns 1");
     275            1 :         ASSERT(strcmp(rbuf, "abc") == 0, "input_line_run: insert into full buffer is no-op");
     276              :     }
     277              : 
     278              :     /* 22. Pre-filled 2-byte UTF-8 'é' in buffer, press Enter
     279              :      *     → il_render calls display_cols on the buffer → exercises 2-byte path
     280              :      *       (input_line.c:38-39) and cp_len 2-byte return (line 16) */
     281              :     {
     282              :         char rbuf[64];
     283              :         InputLine ril;
     284            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "\xC3\xA9");
     285            1 :         int res = run_with_keys(&ril, 5, "> ", "\r", 1);
     286            1 :         ASSERT(res == 1, "input_line_run: UTF-8 2-byte pre-filled + Enter returns 1");
     287            1 :         ASSERT((unsigned char)rbuf[0] == 0xC3,
     288              :                "input_line_run: 2-byte UTF-8 pre-filled preserved");
     289              :     }
     290              : 
     291              :     /* 23. Pre-filled 3-byte UTF-8 '中' in buffer, press Enter
     292              :      *     → exercises display_cols 3-byte path (input_line.c:40-43) */
     293              :     {
     294              :         char rbuf[64];
     295              :         InputLine ril;
     296            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "\xE4\xB8\xAD");
     297            1 :         int res = run_with_keys(&ril, 5, "> ", "\r", 1);
     298            1 :         ASSERT(res == 1, "input_line_run: UTF-8 3-byte pre-filled + Enter returns 1");
     299            1 :         ASSERT((unsigned char)rbuf[0] == 0xE4,
     300              :                "input_line_run: 3-byte UTF-8 pre-filled preserved");
     301              :     }
     302              : 
     303              :     /* 24. Pre-filled 4-byte UTF-8 😀 in buffer, press Enter
     304              :      *     → exercises display_cols 4-byte path (input_line.c:44-48) */
     305              :     {
     306              :         char rbuf[64];
     307              :         InputLine ril;
     308            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "\xF0\x9F\x98\x80");
     309            1 :         int res = run_with_keys(&ril, 5, "> ", "\r", 1);
     310            1 :         ASSERT(res == 1, "input_line_run: UTF-8 4-byte pre-filled + Enter returns 1");
     311            1 :         ASSERT((unsigned char)rbuf[0] == 0xF0,
     312              :                "input_line_run: 4-byte UTF-8 pre-filled preserved");
     313              :     }
     314              : 
     315              :     /* 25. Left over 2-byte UTF-8 → exercises cp_len 2-byte (input_line.c:16)
     316              :      *     and il_backspace over multi-byte sequence */
     317              :     {
     318              :         char rbuf[64];
     319              :         InputLine ril;
     320            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "\xC3\xA9");
     321              :         /* Left arrow moves cursor back over é (2 bytes), then Enter */
     322            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[D\r", 4);
     323            1 :         ASSERT(res == 1, "input_line_run: left over 2-byte returns 1");
     324              :     }
     325              : 
     326              :     /* 26. Delete on 3-byte UTF-8 → exercises il_delete_fwd cp_len 3-byte
     327              :      *     (input_line.c:17,87) */
     328              :     {
     329              :         char rbuf[64];
     330              :         InputLine ril;
     331              :         /* "中x": Home, Delete removes '中' (3 bytes), leaving "x" */
     332            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "\xE4\xB8\xAD" "x");
     333            1 :         int res = run_with_keys(&ril, 5, "> ",
     334              :                                 "\033[H" "\033[3~" "\r", 8);
     335            1 :         ASSERT(res == 1, "input_line_run: delete 3-byte UTF-8 returns 1");
     336            1 :         ASSERT(rbuf[0] == 'x' && rbuf[1] == '\0',
     337              :                "input_line_run: 3-byte UTF-8 deleted");
     338              :     }
     339              : 
     340              :     /* 27. Shift-Tab (ESC[Z) with no shift_tab_fn → no-op, then Enter
     341              :      *     → exercises terminal.c case 'Z' (TERM_KEY_SHIFT_TAB) */
     342              :     {
     343              :         char rbuf[64];
     344              :         InputLine ril;
     345            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "hi");
     346              :         /* ESC [ Z = Shift-Tab, then Enter */
     347            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[Z\r", 4);
     348            1 :         ASSERT(res == 1, "input_line_run: Shift-Tab+Enter returns 1");
     349            1 :         ASSERT(strcmp(rbuf, "hi") == 0, "input_line_run: Shift-Tab is no-op");
     350              :     }
     351              : 
     352              :     /* 28. ESC[1~ → TERM_KEY_HOME (nx == '~') → cursor to start
     353              :      *     → exercises terminal.c case '1' / nx=='~' branch */
     354              :     {
     355              :         char rbuf[64];
     356              :         InputLine ril;
     357            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "bc");
     358              :         /* ESC[1~ moves to start, type 'a', Enter → "abc" */
     359            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[1~a\r", 6);
     360            1 :         ASSERT(res == 1, "input_line_run: ESC[1~+insert+Enter returns 1");
     361            1 :         ASSERT(strcmp(rbuf, "abc") == 0, "input_line_run: ESC[1~ moves to start");
     362              :     }
     363              : 
     364              :     /* 29. ESC[1x → TERM_KEY_IGNORE (nx != '~')
     365              :      *     → exercises terminal.c case '1' / nx!='~' branch */
     366              :     {
     367              :         char rbuf[64];
     368              :         InputLine ril;
     369            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "hi");
     370              :         /* ESC[1x: c3='1', nx='x' → IGNORE, then Enter */
     371            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[1x\r", 5);
     372            1 :         ASSERT(res == 1, "input_line_run: ESC[1x (IGNORE)+Enter returns 1");
     373            1 :         ASSERT(strcmp(rbuf, "hi") == 0, "input_line_run: ESC[1x is no-op");
     374              :     }
     375              : 
     376              :     /* 30. ESC[4~ → TERM_KEY_END → cursor to end
     377              :      *     → exercises terminal.c case '4' */
     378              :     {
     379              :         char rbuf[64];
     380              :         InputLine ril;
     381            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "hi");
     382              :         /* Home, then ESC[4~ (End), type '!', Enter → "hi!" */
     383            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[H\033[4~!\r", 9);
     384            1 :         ASSERT(res == 1, "input_line_run: ESC[4~+insert+Enter returns 1");
     385            1 :         ASSERT(strcmp(rbuf, "hi!") == 0, "input_line_run: ESC[4~ moves to end");
     386              :     }
     387              : 
     388              :     /* 31. ESC[7~ → TERM_KEY_HOME → cursor to start
     389              :      *     → exercises terminal.c case '7' */
     390              :     {
     391              :         char rbuf[64];
     392              :         InputLine ril;
     393            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "bc");
     394              :         /* ESC[7~ moves to start, type 'a', Enter → "abc" */
     395            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[7~a\r", 6);
     396            1 :         ASSERT(res == 1, "input_line_run: ESC[7~+insert+Enter returns 1");
     397            1 :         ASSERT(strcmp(rbuf, "abc") == 0, "input_line_run: ESC[7~ moves to start");
     398              :     }
     399              : 
     400              :     /* 32. ESC[8~ → TERM_KEY_END → cursor to end
     401              :      *     → exercises terminal.c case '8' */
     402              :     {
     403              :         char rbuf[64];
     404              :         InputLine ril;
     405            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "hi");
     406              :         /* Home, then ESC[8~ (End), type '!', Enter → "hi!" */
     407            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[H\033[8~!\r", 9);
     408            1 :         ASSERT(res == 1, "input_line_run: ESC[8~+insert+Enter returns 1");
     409            1 :         ASSERT(strcmp(rbuf, "hi!") == 0, "input_line_run: ESC[8~ moves to end");
     410              :     }
     411              : 
     412              :     /* 33. Unknown ESC sequence → default drain → TERM_KEY_IGNORE → no-op
     413              :      *     → exercises terminal.c default case drain loop */
     414              :     {
     415              :         char rbuf[64];
     416              :         InputLine ril;
     417            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "hi");
     418              :         /* ESC[9x: c3='9' → default, drains until 'x' (letter), then Enter */
     419            1 :         int res = run_with_keys(&ril, 5, "> ", "\033[9x\r", 5);
     420            1 :         ASSERT(res == 1, "input_line_run: unknown ESC seq+Enter returns 1");
     421            1 :         ASSERT(strcmp(rbuf, "hi") == 0, "input_line_run: unknown ESC seq is no-op");
     422              :     }
     423              : 
     424              :     /* 34. TAB key → TERM_KEY_TAB → no-op in input_line
     425              :      *     → exercises terminal.c line 146: result = TERM_KEY_TAB */
     426              :     {
     427              :         char rbuf[64];
     428              :         InputLine ril;
     429            1 :         input_line_init(&ril, rbuf, sizeof(rbuf), "hi");
     430              :         /* TAB then Enter: TAB is TERM_KEY_TAB which input_line ignores */
     431            1 :         int res = run_with_keys(&ril, 5, "> ", "\t\r", 2);
     432            1 :         ASSERT(res == 1, "input_line_run: TAB+Enter returns 1");
     433            1 :         ASSERT(strcmp(rbuf, "hi") == 0, "input_line_run: TAB is no-op");
     434              :     }
     435              : }
        

Generated by: LCOV version 2.0-1