test_lineedit.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. #include "putty.h"
  2. #include "terminal.h"
  3. void modalfatalbox(const char *p, ...)
  4. {
  5. va_list ap;
  6. fprintf(stderr, "FATAL ERROR: ");
  7. va_start(ap, p);
  8. vfprintf(stderr, p, ap);
  9. va_end(ap);
  10. fputc('\n', stderr);
  11. exit(1);
  12. }
  13. const char *const appname = "test_lineedit";
  14. char *platform_default_s(const char *name)
  15. { return NULL; }
  16. bool platform_default_b(const char *name, bool def)
  17. { return def; }
  18. int platform_default_i(const char *name, int def)
  19. { return def; }
  20. FontSpec *platform_default_fontspec(const char *name)
  21. { return fontspec_new_default(); }
  22. Filename *platform_default_filename(const char *name)
  23. { return filename_from_str(""); }
  24. struct SpecialRecord {
  25. SessionSpecialCode code;
  26. int arg;
  27. };
  28. typedef struct Mock {
  29. Terminal *term;
  30. Ldisc *ldisc;
  31. Conf *conf;
  32. struct unicode_data ucsdata[1];
  33. bool echo, edit;
  34. strbuf *to_terminal, *to_backend;
  35. struct SpecialRecord *specials;
  36. size_t nspecials, specialsize;
  37. strbuf *context; /* for printing in failed tests */
  38. bool any_test_failed;
  39. TermWin tw;
  40. Seat seat;
  41. Backend backend;
  42. } Mock;
  43. static size_t mock_output(Seat *seat, SeatOutputType type,
  44. const void *data, size_t len)
  45. {
  46. Mock *mk = container_of(seat, Mock, seat);
  47. put_data(mk->to_terminal, data, len);
  48. return 0;
  49. }
  50. static void mock_send(Backend *be, const char *buf, size_t len)
  51. {
  52. Mock *mk = container_of(be, Mock, backend);
  53. put_data(mk->to_backend, buf, len);
  54. }
  55. static void mock_special(Backend *be, SessionSpecialCode code, int arg)
  56. {
  57. Mock *mk = container_of(be, Mock, backend);
  58. sgrowarray(mk->specials, mk->specialsize, mk->nspecials);
  59. mk->specials[mk->nspecials].code = code;
  60. mk->specials[mk->nspecials].arg = arg;
  61. mk->nspecials++;
  62. }
  63. static bool mock_ldisc_option_state(Backend *be, int option)
  64. {
  65. Mock *mk = container_of(be, Mock, backend);
  66. switch (option) {
  67. case LD_ECHO:
  68. return mk->echo;
  69. case LD_EDIT:
  70. return mk->edit;
  71. default:
  72. unreachable("bad ldisc option");
  73. }
  74. }
  75. static void mock_provide_ldisc(Backend *be, Ldisc *ldisc)
  76. {
  77. Mock *mk = container_of(be, Mock, backend);
  78. mk->ldisc = ldisc;
  79. }
  80. static bool mock_sendok(Backend *be)
  81. {
  82. Mock *mk = container_of(be, Mock, backend);
  83. (void)mk;
  84. /* FIXME: perhaps make this settable, to test the input_queue system? */
  85. return true;
  86. }
  87. static void mock_set_raw_mouse_mode(TermWin *win, bool enable) {}
  88. static void mock_palette_get_overrides(TermWin *tw, Terminal *term) {}
  89. static const TermWinVtable mock_termwin_vt = {
  90. .set_raw_mouse_mode = mock_set_raw_mouse_mode,
  91. .palette_get_overrides = mock_palette_get_overrides,
  92. };
  93. static const SeatVtable mock_seat_vt = {
  94. .output = mock_output,
  95. .echoedit_update = nullseat_echoedit_update,
  96. };
  97. static const BackendVtable mock_backend_vt = {
  98. .sendok = mock_sendok,
  99. .send = mock_send,
  100. .special = mock_special,
  101. .ldisc_option_state = mock_ldisc_option_state,
  102. .provide_ldisc = mock_provide_ldisc,
  103. .id = "mock",
  104. };
  105. static Mock *mock_new(void)
  106. {
  107. Mock *mk = snew(Mock);
  108. memset(mk, 0, sizeof(*mk));
  109. mk->conf = conf_new();
  110. do_defaults(NULL, mk->conf);
  111. init_ucs_generic(mk->conf, mk->ucsdata);
  112. mk->ucsdata->line_codepage = CP_437;
  113. mk->context = strbuf_new();
  114. mk->to_terminal = strbuf_new();
  115. mk->to_backend = strbuf_new();
  116. mk->tw.vt = &mock_termwin_vt;
  117. mk->seat.vt = &mock_seat_vt;
  118. mk->backend.vt = &mock_backend_vt;
  119. return mk;
  120. }
  121. static void mock_free(Mock *mk)
  122. {
  123. strbuf_free(mk->context);
  124. strbuf_free(mk->to_terminal);
  125. strbuf_free(mk->to_backend);
  126. conf_free(mk->conf);
  127. term_free(mk->term);
  128. sfree(mk->specials);
  129. sfree(mk);
  130. }
  131. static void reset(Mock *mk)
  132. {
  133. strbuf_clear(mk->context);
  134. strbuf_clear(mk->to_terminal);
  135. strbuf_clear(mk->to_backend);
  136. mk->nspecials = 0;
  137. }
  138. static void test_context(Mock *mk, const char *fmt, ...)
  139. {
  140. strbuf_clear(mk->context);
  141. va_list ap;
  142. va_start(ap, fmt);
  143. put_fmtv(mk->context, fmt, ap);
  144. va_end(ap);
  145. }
  146. static void print_context(Mock *mk, const char *file, int line)
  147. {
  148. printf("%s:%d", file, line);
  149. if (mk->context->len)
  150. printf(" (%s)", mk->context->s);
  151. printf(": ");
  152. }
  153. #define EXPECT(mk, what, ...) \
  154. expect_ ## what(mk, __FILE__, __LINE__, __VA_ARGS__)
  155. static void expect_backend(Mock *mk, const char *file, int line,
  156. ptrlen expected)
  157. {
  158. ptrlen actual = ptrlen_from_strbuf(mk->to_backend);
  159. if (!ptrlen_eq_ptrlen(expected, actual)) {
  160. print_context(mk, file, line);
  161. printf("expected backend output \"");
  162. write_c_string_literal(stdout, expected);
  163. printf("\", got \"");
  164. write_c_string_literal(stdout, actual);
  165. printf("\"\n");
  166. mk->any_test_failed = true;
  167. }
  168. }
  169. static void expect_terminal(Mock *mk, const char *file, int line,
  170. ptrlen expected)
  171. {
  172. ptrlen actual = ptrlen_from_strbuf(mk->to_terminal);
  173. if (!ptrlen_eq_ptrlen(expected, actual)) {
  174. print_context(mk, file, line);
  175. printf("expected terminal output \"");
  176. write_c_string_literal(stdout, expected);
  177. printf("\", got \"");
  178. write_c_string_literal(stdout, actual);
  179. printf("\"\n");
  180. mk->any_test_failed = true;
  181. }
  182. }
  183. static void expect_specials(Mock *mk, const char *file, int line,
  184. size_t nspecials, ...)
  185. {
  186. va_list ap;
  187. static const char *const special_names[] = {
  188. #define SPECIAL(x) #x,
  189. #include "specials.h"
  190. #undef SPECIAL
  191. };
  192. bool match;
  193. if (nspecials != mk->nspecials) {
  194. match = false;
  195. } else {
  196. match = true;
  197. va_start(ap, nspecials);
  198. for (size_t i = 0; i < nspecials; i++) {
  199. SessionSpecialCode code = va_arg(ap, SessionSpecialCode);
  200. int arg = va_arg(ap, int);
  201. if (code != mk->specials[i].code || arg != mk->specials[i].arg)
  202. match = false;
  203. }
  204. va_end(ap);
  205. }
  206. if (!match) {
  207. print_context(mk, file, line);
  208. printf("expected specials [");
  209. va_start(ap, nspecials);
  210. for (size_t i = 0; i < nspecials; i++) {
  211. SessionSpecialCode code = va_arg(ap, SessionSpecialCode);
  212. int arg = va_arg(ap, int);
  213. printf(" %s.%d", special_names[code], arg);
  214. }
  215. va_end(ap);
  216. printf(" ], got [");
  217. for (size_t i = 0; i < mk->nspecials; i++) {
  218. printf(" %s.%d", special_names[mk->specials[i].code],
  219. mk->specials[i].arg);
  220. }
  221. printf(" ]\n");
  222. mk->any_test_failed = true;
  223. }
  224. }
  225. static void test_noedit(Mock *mk)
  226. {
  227. mk->edit = false;
  228. mk->echo = false;
  229. /*
  230. * In non-echo and non-edit mode, the channel is 8-bit clean
  231. */
  232. for (unsigned c = 0; c < 256; c++) {
  233. char buf[1];
  234. test_context(mk, "c=%02x", c);
  235. buf[0] = c;
  236. ldisc_send(mk->ldisc, buf, 1, false);
  237. EXPECT(mk, backend, make_ptrlen(buf, 1));
  238. reset(mk);
  239. }
  240. /* ... regardless of the 'interactive' flag */
  241. for (unsigned c = 0; c < 256; c++) {
  242. char buf[1];
  243. test_context(mk, "c=%02x", c);
  244. buf[0] = c;
  245. ldisc_send(mk->ldisc, buf, 1, true);
  246. EXPECT(mk, backend, make_ptrlen(buf, 1));
  247. reset(mk);
  248. }
  249. /* ... and any nonzero character does the same thing even if sent
  250. * with the magic -1 length flag */
  251. for (unsigned c = 1; c < 256; c++) {
  252. char buf[2];
  253. test_context(mk, "c=%02x", c);
  254. buf[0] = c;
  255. buf[1] = '\0';
  256. ldisc_send(mk->ldisc, buf, -1, true);
  257. EXPECT(mk, backend, make_ptrlen(buf, 1));
  258. reset(mk);
  259. }
  260. /*
  261. * Test the special-character cases for Telnet.
  262. */
  263. conf_set_int(mk->conf, CONF_protocol, PROT_TELNET);
  264. conf_set_bool(mk->conf, CONF_telnet_newline, false);
  265. conf_set_bool(mk->conf, CONF_telnet_keyboard, false);
  266. ldisc_configure(mk->ldisc, mk->conf);
  267. /* Without telnet_newline or telnet_keyboard, these all do the
  268. * normal thing */
  269. ldisc_send(mk->ldisc, "\x0D", -1, true);
  270. EXPECT(mk, backend, PTRLEN_LITERAL("\x0D"));
  271. reset(mk);
  272. ldisc_send(mk->ldisc, "\x08", -1, true);
  273. EXPECT(mk, backend, PTRLEN_LITERAL("\x08"));
  274. reset(mk);
  275. ldisc_send(mk->ldisc, "\x7F", -1, true);
  276. EXPECT(mk, backend, PTRLEN_LITERAL("\x7F"));
  277. reset(mk);
  278. ldisc_send(mk->ldisc, "\x03", -1, true);
  279. EXPECT(mk, backend, PTRLEN_LITERAL("\x03"));
  280. reset(mk);
  281. ldisc_send(mk->ldisc, "\x1A", -1, true);
  282. EXPECT(mk, backend, PTRLEN_LITERAL("\x1A"));
  283. reset(mk);
  284. /* telnet_newline controls translation of CR into SS_EOL */
  285. conf_set_bool(mk->conf, CONF_telnet_newline, true);
  286. ldisc_configure(mk->ldisc, mk->conf);
  287. ldisc_send(mk->ldisc, "\x0D", -1, true);
  288. EXPECT(mk, specials, 1, SS_EOL, 0);
  289. reset(mk);
  290. /* And telnet_keyboard controls the others */
  291. conf_set_bool(mk->conf, CONF_telnet_newline, false);
  292. conf_set_bool(mk->conf, CONF_telnet_keyboard, true);
  293. ldisc_configure(mk->ldisc, mk->conf);
  294. ldisc_send(mk->ldisc, "\x08", -1, true);
  295. EXPECT(mk, specials, 1, SS_EC, 0);
  296. reset(mk);
  297. ldisc_send(mk->ldisc, "\x7F", -1, true);
  298. EXPECT(mk, specials, 1, SS_EC, 0);
  299. reset(mk);
  300. ldisc_send(mk->ldisc, "\x03", -1, true);
  301. EXPECT(mk, specials, 1, SS_IP, 0);
  302. reset(mk);
  303. ldisc_send(mk->ldisc, "\x1A", -1, true);
  304. EXPECT(mk, specials, 1, SS_SUSP, 0);
  305. reset(mk);
  306. /*
  307. * In echo-but-no-edit mode, we also expect that every character
  308. * is echoed back to the display as a side effect, including when
  309. * it's sent as a special -1 keystroke.
  310. *
  311. * This state only comes up in Telnet, because that has protocol
  312. * options to independently configure echo and edit. Telnet is
  313. * also the most complicated of the protocols because of the above
  314. * special cases, so we stay in Telnet mode for this test.
  315. */
  316. mk->echo = true;
  317. for (unsigned c = 0; c < 256; c++) {
  318. char buf[1];
  319. test_context(mk, "c=%02x", c);
  320. buf[0] = c;
  321. ldisc_send(mk->ldisc, buf, 1, false);
  322. EXPECT(mk, terminal, make_ptrlen(buf, 1));
  323. reset(mk);
  324. }
  325. for (unsigned c = 1; c < 256; c++) {
  326. char buf[2];
  327. test_context(mk, "c=%02x", c);
  328. buf[0] = c;
  329. buf[1] = '\0';
  330. ldisc_send(mk->ldisc, buf, -1, true);
  331. EXPECT(mk, terminal, make_ptrlen(buf, 1));
  332. reset(mk);
  333. }
  334. do_defaults(NULL, mk->conf);
  335. ldisc_configure(mk->ldisc, mk->conf);
  336. }
  337. static void test_edit(Mock *mk, bool echo)
  338. {
  339. static const char *const ctls = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
  340. mk->edit = true;
  341. mk->echo = echo;
  342. #define EXPECT_TERMINAL(mk, val) do { \
  343. if (!echo) EXPECT(mk, terminal, PTRLEN_LITERAL("")); \
  344. else EXPECT(mk, terminal, val); \
  345. } while (0)
  346. /* ASCII printing characters all print when entered, but don't go
  347. * to the terminal until Return is pressed */
  348. for (unsigned c = 0x20; c < 0x7F; c++) {
  349. char buf[3];
  350. test_context(mk, "c=%02x", c);
  351. buf[0] = c;
  352. ldisc_send(mk->ldisc, buf, 1, false);
  353. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  354. EXPECT_TERMINAL(mk, make_ptrlen(buf, 1));
  355. ldisc_send(mk->ldisc, "\015", 1, false);
  356. buf[1] = '\015';
  357. buf[2] = '\012';
  358. EXPECT(mk, backend, make_ptrlen(buf, 3));
  359. EXPECT_TERMINAL(mk, make_ptrlen(buf, 3));
  360. reset(mk);
  361. }
  362. /* C0 control characters mostly show up as ^X or similar */
  363. for (unsigned c = 0; c < 0x1F; c++) {
  364. char backbuf[3];
  365. char termbuf[4];
  366. switch (ctls[c]) {
  367. case 'D': continue; /* ^D sends EOF */
  368. case 'M': continue; /* ^M is Return */
  369. case 'R': continue; /* ^R redisplays line */
  370. case 'U': continue; /* ^U deletes the line */
  371. case 'V': continue; /* ^V makes the next char literal */
  372. case 'W': continue; /* ^W deletes a word */
  373. /*
  374. * ^H / ^? are not included here. Those are treated
  375. * literally if sent as plain input bytes. Only sending
  376. * them as special via length==-1 causes them to act as
  377. * backspace, which I think was simply because there _is_
  378. * a dedicated key that can do that function, so there's
  379. * no need to also eat the Ctrl+thing combo.
  380. */
  381. /*
  382. * Also, ^C, ^Z and ^\ self-insert (when not in Telnet
  383. * mode) but have the side effect of erasing the line
  384. * buffer so far. In this loop, that doesn't show up,
  385. * because the line buffer is empty already. However, I
  386. * don't test that, because it's silly, and probably
  387. * doesn't want to keep happening!
  388. */
  389. }
  390. test_context(mk, "c=%02x", c);
  391. backbuf[0] = c;
  392. ldisc_send(mk->ldisc, backbuf, 1, false);
  393. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  394. termbuf[0] = '^';
  395. termbuf[1] = ctls[c];
  396. EXPECT_TERMINAL(mk, make_ptrlen(termbuf, 2));
  397. ldisc_send(mk->ldisc, "\015", 1, false);
  398. backbuf[1] = '\015';
  399. backbuf[2] = '\012';
  400. EXPECT(mk, backend, make_ptrlen(backbuf, 3));
  401. termbuf[2] = '\015';
  402. termbuf[3] = '\012';
  403. EXPECT_TERMINAL(mk, make_ptrlen(termbuf, 4));
  404. reset(mk);
  405. }
  406. /* Prefixed with ^V, the same is true of _all_ C0 controls */
  407. for (unsigned c = 0; c < 0x1F; c++) {
  408. char backbuf[3];
  409. char termbuf[4];
  410. test_context(mk, "c=%02x", c);
  411. backbuf[0] = 'V' & 0x1F;
  412. ldisc_send(mk->ldisc, backbuf, 1, false);
  413. backbuf[0] = c;
  414. ldisc_send(mk->ldisc, backbuf, 1, false);
  415. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  416. termbuf[0] = '^';
  417. termbuf[1] = ctls[c];
  418. EXPECT_TERMINAL(mk, make_ptrlen(termbuf, 2));
  419. ldisc_send(mk->ldisc, "\015", 1, false);
  420. backbuf[1] = '\015';
  421. backbuf[2] = '\012';
  422. EXPECT(mk, backend, make_ptrlen(backbuf, 3));
  423. termbuf[2] = '\015';
  424. termbuf[3] = '\012';
  425. EXPECT_TERMINAL(mk, make_ptrlen(termbuf, 4));
  426. reset(mk);
  427. }
  428. /* Deleting an ASCII character sends a single BSB and deletes just
  429. * that byte from the buffer */
  430. ldisc_send(mk->ldisc, "ab", 2, false);
  431. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  432. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("ab"));
  433. ldisc_send(mk->ldisc, "\x08", -1, false);
  434. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  435. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("ab\x08 \x08"));
  436. ldisc_send(mk->ldisc, "\x0D", -1, false);
  437. EXPECT(mk, backend, PTRLEN_LITERAL("a\x0D\x0A"));
  438. reset(mk);
  439. /* Deleting a character written as a ^X code sends two BSBs to
  440. * wipe out the two-character display sequence */
  441. ldisc_send(mk->ldisc, "a\x02", 2, false);
  442. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  443. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("a^B"));
  444. ldisc_send(mk->ldisc, "\x7F", -1, false);
  445. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  446. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("a^B\x08 \x08\x08 \x08"));
  447. ldisc_send(mk->ldisc, "\x0D", -1, false);
  448. EXPECT(mk, backend, PTRLEN_LITERAL("a\x0D\x0A"));
  449. reset(mk);
  450. /* ^D sends the line editing buffer without a trailing Return, if
  451. * it's non-empty */
  452. ldisc_send(mk->ldisc, "abc\x04", 4, false);
  453. EXPECT(mk, backend, PTRLEN_LITERAL("abc"));
  454. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc"));
  455. ldisc_send(mk->ldisc, "\x0D", -1, false);
  456. EXPECT(mk, backend, PTRLEN_LITERAL("abc\x0D\x0A"));
  457. reset(mk);
  458. /* But if the buffer is empty, ^D sends SS_EOF */
  459. ldisc_send(mk->ldisc, "\x04", 1, false);
  460. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  461. EXPECT_TERMINAL(mk, PTRLEN_LITERAL(""));
  462. EXPECT(mk, specials, 1, SS_EOF, 0);
  463. reset(mk);
  464. /* ^M with the special flag is the Return key, and sends the line */
  465. ldisc_send(mk->ldisc, "abc", 3, false);
  466. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  467. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc"));
  468. ldisc_send(mk->ldisc, "\x0D", -1, true);
  469. EXPECT(mk, backend, PTRLEN_LITERAL("abc\x0D\x0A"));
  470. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x0D\x0A"));
  471. reset(mk);
  472. /* In non-LE_CRLF_NEWLINE mode, either of ^M or ^J without the
  473. * special flag also sends the line */
  474. conf_set_int(mk->conf, CONF_protocol, PROT_SSH);
  475. ldisc_configure(mk->ldisc, mk->conf);
  476. ldisc_send(mk->ldisc, "abc", 3, false);
  477. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  478. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc"));
  479. ldisc_send(mk->ldisc, "\x0D", 1, true);
  480. EXPECT(mk, backend, PTRLEN_LITERAL("abc\x0D"));
  481. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x0D\x0A"));
  482. reset(mk);
  483. ldisc_send(mk->ldisc, "abc", 3, false);
  484. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  485. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc"));
  486. ldisc_send(mk->ldisc, "\x0A", 1, true);
  487. EXPECT(mk, backend, PTRLEN_LITERAL("abc\x0D"));
  488. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x0D\x0A"));
  489. reset(mk);
  490. /* In LE_CRLF_NEWLINE mode, non-special ^J is just literal */
  491. conf_set_int(mk->conf, CONF_protocol, PROT_RAW);
  492. ldisc_configure(mk->ldisc, mk->conf);
  493. ldisc_send(mk->ldisc, "abc", 3, false);
  494. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  495. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc"));
  496. ldisc_send(mk->ldisc, "\x0A", 1, true);
  497. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  498. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc^J"));
  499. /* So when we press Return it's sent */
  500. ldisc_send(mk->ldisc, "\x0D", -1, true);
  501. EXPECT(mk, backend, PTRLEN_LITERAL("abc\x0A\x0D\x0A"));
  502. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc^J\x0D\x0A"));
  503. reset(mk);
  504. /* In LE_CRLF_NEWLINE mode, non-special ^M is literal, but if
  505. * followed with ^J, they combine into a Return */
  506. conf_set_int(mk->conf, CONF_protocol, PROT_RAW);
  507. ldisc_configure(mk->ldisc, mk->conf);
  508. ldisc_send(mk->ldisc, "abc", 3, false);
  509. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  510. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc"));
  511. ldisc_send(mk->ldisc, "\x0D", 1, true);
  512. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  513. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc^M"));
  514. /* So when we press Return it's sent */
  515. ldisc_send(mk->ldisc, "\x0A", 1, true);
  516. EXPECT(mk, backend, PTRLEN_LITERAL("abc\x0D\x0A"));
  517. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc^M\x08 \x08\x08 \x08\x0D\x0A"));
  518. reset(mk);
  519. /* ^R redraws the current line, after printing "^R" at the end of
  520. * the previous attempt to make it clear that that's what
  521. * happened */
  522. ldisc_send(mk->ldisc, "a\x01", 2, false);
  523. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  524. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("a^A"));
  525. ldisc_send(mk->ldisc, "\x12", 1, false);
  526. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  527. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("a^A^R\x0D\x0A" "a^A"));
  528. ldisc_send(mk->ldisc, "\x0D", -1, false);
  529. reset(mk);
  530. /* ^U deletes the whole line */
  531. ldisc_send(mk->ldisc, "a b c", 5, false);
  532. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  533. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("a b c"));
  534. ldisc_send(mk->ldisc, "\x15", 1, false);
  535. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  536. EXPECT_TERMINAL(
  537. mk, PTRLEN_LITERAL(
  538. "a b c\x08 \x08\x08 \x08\x08 \x08\x08 \x08\x08 \x08"));
  539. ldisc_send(mk->ldisc, "\x0D", -1, false);
  540. EXPECT(mk, backend, PTRLEN_LITERAL("\x0D\x0A"));
  541. EXPECT_TERMINAL(
  542. mk, PTRLEN_LITERAL(
  543. "a b c\x08 \x08\x08 \x08\x08 \x08\x08 \x08\x08 \x08\x0D\x0A"));
  544. reset(mk);
  545. /* And it still knows that a control character written as ^X takes
  546. * two BSBs to delete */
  547. ldisc_send(mk->ldisc, "a\x02" "c", 3, false);
  548. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  549. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("a^Bc"));
  550. ldisc_send(mk->ldisc, "\x15", 1, false);
  551. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  552. EXPECT_TERMINAL(
  553. mk, PTRLEN_LITERAL("a^Bc\x08 \x08\x08 \x08\x08 \x08\x08 \x08"));
  554. ldisc_send(mk->ldisc, "\x0D", -1, false);
  555. reset(mk);
  556. /* ^W deletes a word, which means that it deletes to the most
  557. * recent boundary with a space on the left and a nonspace on the
  558. * right. (Or the beginning of the string, whichever comes first.) */
  559. ldisc_send(mk->ldisc, "hello, world\x17", 13, false);
  560. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  561. EXPECT_TERMINAL(
  562. mk, PTRLEN_LITERAL(
  563. "hello, world\x08 \x08\x08 \x08\x08 \x08\x08 \x08\x08 \x08"));
  564. ldisc_send(mk->ldisc, "\x0D", 1, false);
  565. EXPECT(mk, backend, PTRLEN_LITERAL("hello, \x0D\x0A"));
  566. reset(mk);
  567. ldisc_send(mk->ldisc, "hello, world \x17", 14, false);
  568. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  569. EXPECT_TERMINAL(
  570. mk, PTRLEN_LITERAL(
  571. "hello, world "
  572. "\x08 \x08\x08 \x08\x08 \x08\x08 \x08\x08 \x08\x08 \x08"));
  573. ldisc_send(mk->ldisc, "\x0D", 1, false);
  574. EXPECT(mk, backend, PTRLEN_LITERAL("hello, \x0D\x0A"));
  575. reset(mk);
  576. ldisc_send(mk->ldisc, " hello \x17", 8, false);
  577. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  578. EXPECT_TERMINAL(
  579. mk, PTRLEN_LITERAL(
  580. " hello \x08 \x08\x08 \x08\x08 \x08\x08 \x08\x08 \x08\x08 \x08"));
  581. ldisc_send(mk->ldisc, "\x0D", 1, false);
  582. EXPECT(mk, backend, PTRLEN_LITERAL(" \x0D\x0A"));
  583. reset(mk);
  584. ldisc_send(mk->ldisc, "hello \x17", 7, false);
  585. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  586. EXPECT_TERMINAL(
  587. mk, PTRLEN_LITERAL(
  588. "hello \x08 \x08\x08 \x08\x08 \x08\x08 \x08\x08 \x08\x08 \x08"));
  589. ldisc_send(mk->ldisc, "\x0D", 1, false);
  590. EXPECT(mk, backend, PTRLEN_LITERAL("\x0D\x0A"));
  591. reset(mk);
  592. /* And this too knows that a control character written as ^X takes
  593. * two BSBs to delete */
  594. ldisc_send(mk->ldisc, "a\x02" "c", 3, false);
  595. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  596. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("a^Bc"));
  597. ldisc_send(mk->ldisc, "\x17", 1, false);
  598. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  599. EXPECT_TERMINAL(
  600. mk, PTRLEN_LITERAL("a^Bc\x08 \x08\x08 \x08\x08 \x08\x08 \x08"));
  601. ldisc_send(mk->ldisc, "\x0D", -1, false);
  602. reset(mk);
  603. /* Test handling of ^C and friends in non-telnet_keyboard mode */
  604. ldisc_send(mk->ldisc, "abc\x03", 4, false);
  605. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  606. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x08 \x08\x08 \x08\x08 \x08^C"));
  607. EXPECT(mk, specials, 1, SS_EL, 0);
  608. ldisc_send(mk->ldisc, "\x0D", -1, false);
  609. reset(mk);
  610. ldisc_send(mk->ldisc, "abc\x1a", 4, false);
  611. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  612. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x08 \x08\x08 \x08\x08 \x08^Z"));
  613. EXPECT(mk, specials, 1, SS_EL, 0);
  614. ldisc_send(mk->ldisc, "\x0D", -1, false);
  615. reset(mk);
  616. ldisc_send(mk->ldisc, "abc\x1c", 4, false);
  617. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  618. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x08 \x08\x08 \x08\x08 \x08^\\"));
  619. EXPECT(mk, specials, 1, SS_EL, 0);
  620. ldisc_send(mk->ldisc, "\x0D", -1, false);
  621. reset(mk);
  622. /* And in telnet_keyboard mode */
  623. conf_set_bool(mk->conf, CONF_telnet_keyboard, true);
  624. ldisc_configure(mk->ldisc, mk->conf);
  625. /* FIXME: should we _really_ be sending EL before each of these? */
  626. ldisc_send(mk->ldisc, "abc\x03", 4, false);
  627. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  628. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x08 \x08\x08 \x08\x08 \x08"));
  629. EXPECT(mk, specials, 2, SS_EL, 0, SS_IP, 0);
  630. ldisc_send(mk->ldisc, "\x0D", -1, false);
  631. reset(mk);
  632. ldisc_send(mk->ldisc, "abc\x1a", 4, false);
  633. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  634. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x08 \x08\x08 \x08\x08 \x08"));
  635. EXPECT(mk, specials, 2, SS_EL, 0, SS_SUSP, 0);
  636. ldisc_send(mk->ldisc, "\x0D", -1, false);
  637. reset(mk);
  638. ldisc_send(mk->ldisc, "abc\x1c", 4, false);
  639. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  640. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("abc\x08 \x08\x08 \x08\x08 \x08"));
  641. EXPECT(mk, specials, 2, SS_EL, 0, SS_ABORT, 0);
  642. ldisc_send(mk->ldisc, "\x0D", -1, false);
  643. reset(mk);
  644. conf_set_bool(mk->conf, CONF_telnet_keyboard, false);
  645. ldisc_configure(mk->ldisc, mk->conf);
  646. /* Test UTF-8 characters of various lengths and ensure deleting
  647. * one deletes the whole character from the buffer (by pressing
  648. * Return and seeing what gets sent) but sends a number of BSBs
  649. * corresponding to the character's terminal width */
  650. mk->term->utf = true;
  651. ldisc_send(mk->ldisc, "\xC2\xA0\xC2\xA1", 4, false);
  652. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  653. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xC2\xA0\xC2\xA1"));
  654. ldisc_send(mk->ldisc, "\x08", -1, false);
  655. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  656. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xC2\xA0\xC2\xA1\x08 \x08"));
  657. ldisc_send(mk->ldisc, "\x0D", -1, false);
  658. EXPECT(mk, backend, PTRLEN_LITERAL("\xC2\xA0\x0D\x0A"));
  659. reset(mk);
  660. ldisc_send(mk->ldisc, "\xE2\xA0\x80\xE2\xA0\x81", 6, false);
  661. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  662. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xE2\xA0\x80\xE2\xA0\x81"));
  663. ldisc_send(mk->ldisc, "\x08", -1, false);
  664. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  665. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xE2\xA0\x80\xE2\xA0\x81\x08 \x08"));
  666. ldisc_send(mk->ldisc, "\x0D", -1, false);
  667. EXPECT(mk, backend, PTRLEN_LITERAL("\xE2\xA0\x80\x0D\x0A"));
  668. reset(mk);
  669. ldisc_send(mk->ldisc, "\xF0\x90\x80\x80\xF0\x90\x80\x81", 8, false);
  670. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  671. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xF0\x90\x80\x80\xF0\x90\x80\x81"));
  672. ldisc_send(mk->ldisc, "\x08", -1, false);
  673. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  674. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xF0\x90\x80\x80\xF0\x90\x80\x81"
  675. "\x08 \x08"));
  676. ldisc_send(mk->ldisc, "\x0D", -1, false);
  677. EXPECT(mk, backend, PTRLEN_LITERAL("\xF0\x90\x80\x80\x0D\x0A"));
  678. reset(mk);
  679. /* Double-width characters (Hangul, as it happens) */
  680. ldisc_send(mk->ldisc, "\xEA\xB0\x80\xEA\xB0\x81", 6, false);
  681. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  682. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xEA\xB0\x80\xEA\xB0\x81"));
  683. ldisc_send(mk->ldisc, "\x08", -1, false);
  684. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  685. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xEA\xB0\x80\xEA\xB0\x81"
  686. "\x08 \x08\x08 \x08"));
  687. ldisc_send(mk->ldisc, "\x0D", -1, false);
  688. EXPECT(mk, backend, PTRLEN_LITERAL("\xEA\xB0\x80\x0D\x0A"));
  689. reset(mk);
  690. /* Zero-width characters */
  691. ldisc_send(mk->ldisc, "\xE2\x80\x8B\xE2\x80\x8B", 6, false);
  692. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  693. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xE2\x80\x8B\xE2\x80\x8B"));
  694. ldisc_send(mk->ldisc, "\x08", -1, false);
  695. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  696. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xE2\x80\x8B\xE2\x80\x8B"));
  697. ldisc_send(mk->ldisc, "\x0D", -1, false);
  698. EXPECT(mk, backend, PTRLEN_LITERAL("\xE2\x80\x8B\x0D\x0A"));
  699. reset(mk);
  700. /* And reset back to non-UTF-8 mode and expect high-bit-set bytes
  701. * to be treated individually, as characters in a single-byte
  702. * charset. (In our case, given the test config, that will be
  703. * CP437, but it makes no difference to the editing behaviour.) */
  704. mk->term->utf = false;
  705. ldisc_send(mk->ldisc, "\xC2\xA0\xC2\xA1", 4, false);
  706. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  707. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xC2\xA0\xC2\xA1"));
  708. ldisc_send(mk->ldisc, "\x08", -1, false);
  709. EXPECT(mk, backend, PTRLEN_LITERAL(""));
  710. EXPECT_TERMINAL(mk, PTRLEN_LITERAL("\xC2\xA0\xC2\xA1\x08 \x08"));
  711. ldisc_send(mk->ldisc, "\x0D", -1, false);
  712. EXPECT(mk, backend, PTRLEN_LITERAL("\xC2\xA0\xC2\x0D\x0A"));
  713. reset(mk);
  714. /* Make sure we flush all the terminal contents at the end of this
  715. * function */
  716. ldisc_send(mk->ldisc, "\x0D", 1, false);
  717. reset(mk);
  718. #undef EXPECT_TERMINAL
  719. }
  720. const struct BackendVtable *const backends[] = { &mock_backend_vt, NULL };
  721. int main(void)
  722. {
  723. Mock *mk = mock_new();
  724. mk->term = term_init(mk->conf, mk->ucsdata, &mk->tw);
  725. Ldisc *ldisc = ldisc_create(mk->conf, mk->term, &mk->backend, &mk->seat);
  726. term_size(mk->term, 80, 24, 0);
  727. test_noedit(mk);
  728. test_edit(mk, true);
  729. test_edit(mk, false);
  730. ldisc_free(ldisc);
  731. bool failed = mk->any_test_failed;
  732. mock_free(mk);
  733. if (failed) {
  734. printf("Test suite FAILED!\n");
  735. return 1;
  736. } else {
  737. printf("Test suite passed\n");
  738. return 0;
  739. }
  740. }