test_terminal.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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. const struct BackendVtable *const backends[] = { NULL };
  25. typedef struct Mock {
  26. Terminal *term;
  27. Conf *conf;
  28. struct unicode_data ucsdata[1];
  29. strbuf *context;
  30. bool any_test_failed;
  31. TermWin tw;
  32. } Mock;
  33. static bool mock_setup_draw_ctx(TermWin *win) { return false; }
  34. static void mock_draw_text(TermWin *win, int x, int y, wchar_t *text, int len,
  35. unsigned long attrs, int lattrs, truecolour tc) {}
  36. static void mock_draw_cursor(TermWin *win, int x, int y, wchar_t *text,
  37. int len, unsigned long attrs, int lattrs,
  38. truecolour tc) {}
  39. static void mock_set_raw_mouse_mode(TermWin *win, bool enable) {}
  40. static void mock_set_raw_mouse_mode_pointer(TermWin *win, bool enable) {}
  41. static void mock_palette_set(TermWin *win, unsigned start, unsigned ncolours,
  42. const rgb *colours) {}
  43. static void mock_palette_get_overrides(TermWin *tw, Terminal *term) {}
  44. static const TermWinVtable mock_termwin_vt = {
  45. .setup_draw_ctx = mock_setup_draw_ctx,
  46. .draw_text = mock_draw_text,
  47. .draw_cursor = mock_draw_cursor,
  48. .set_raw_mouse_mode = mock_set_raw_mouse_mode,
  49. .set_raw_mouse_mode_pointer = mock_set_raw_mouse_mode_pointer,
  50. .palette_set = mock_palette_set,
  51. .palette_get_overrides = mock_palette_get_overrides,
  52. };
  53. static Mock *mock_new(void)
  54. {
  55. Mock *mk = snew(Mock);
  56. memset(mk, 0, sizeof(*mk));
  57. mk->conf = conf_new();
  58. do_defaults(NULL, mk->conf);
  59. init_ucs_generic(mk->conf, mk->ucsdata);
  60. mk->ucsdata->line_codepage = CP_ISO8859_1;
  61. mk->context = strbuf_new();
  62. mk->tw.vt = &mock_termwin_vt;
  63. return mk;
  64. }
  65. static void mock_free(Mock *mk)
  66. {
  67. strbuf_free(mk->context);
  68. conf_free(mk->conf);
  69. term_free(mk->term);
  70. sfree(mk);
  71. }
  72. static void reset(Mock *mk)
  73. {
  74. term_pwron(mk->term, true);
  75. term_size(mk->term, 24, 80, 0);
  76. term_set_trust_status(mk->term, false);
  77. strbuf_clear(mk->context);
  78. }
  79. #if 0
  80. static void test_context(Mock *mk, const char *fmt, ...)
  81. {
  82. strbuf_clear(mk->context);
  83. va_list ap;
  84. va_start(ap, fmt);
  85. put_fmtv(mk->context, fmt, ap);
  86. va_end(ap);
  87. }
  88. #endif
  89. static void report_fail(Mock *mk, const char *file, int line,
  90. const char *fmt, ...)
  91. {
  92. printf("%s:%d", file, line);
  93. if (mk->context->len)
  94. printf(" (%s)", mk->context->s);
  95. printf(": ");
  96. va_list ap;
  97. va_start(ap, fmt);
  98. vprintf(fmt, ap);
  99. va_end(ap);
  100. printf("\n");
  101. mk->any_test_failed = true;
  102. }
  103. static inline void check_iequal(Mock *mk, const char *file, int line,
  104. long long lhs, long long rhs)
  105. {
  106. if (lhs != rhs)
  107. report_fail(mk, file, line, "%lld != %lld / %#llx != %#llx",
  108. lhs, rhs, lhs, rhs);
  109. }
  110. #define IEQUAL(lhs, rhs) check_iequal(mk, __FILE__, __LINE__, lhs, rhs)
  111. static inline void term_datapl(Terminal *term, ptrlen pl)
  112. {
  113. term_data(term, pl.ptr, pl.len);
  114. }
  115. static struct termchar get_termchar(Terminal *term, int x, int y)
  116. {
  117. termline *tl = term_get_line(term, y);
  118. termchar tc;
  119. if (0 <= x && x < tl->cols)
  120. tc = tl->chars[x];
  121. else
  122. tc = term->erase_char;
  123. term_release_line(tl);
  124. return tc;
  125. }
  126. static unsigned short get_lineattr(Terminal *term, int y)
  127. {
  128. termline *tl = term_get_line(term, y);
  129. unsigned short lattr = tl->lattr;
  130. term_release_line(tl);
  131. return lattr;
  132. }
  133. static void test_hello_world(Mock *mk)
  134. {
  135. /* A trivial test just to kick off this test framework */
  136. mk->ucsdata->line_codepage = CP_ISO8859_1;
  137. reset(mk);
  138. term_datapl(mk->term, PTRLEN_LITERAL("hello, world"));
  139. IEQUAL(mk->term->curs.x, 12);
  140. IEQUAL(mk->term->curs.y, 0);
  141. IEQUAL(get_termchar(mk->term, 0, 0).chr, CSET_ASCII | 'h');
  142. IEQUAL(get_termchar(mk->term, 1, 0).chr, CSET_ASCII | 'e');
  143. IEQUAL(get_termchar(mk->term, 2, 0).chr, CSET_ASCII | 'l');
  144. IEQUAL(get_termchar(mk->term, 3, 0).chr, CSET_ASCII | 'l');
  145. IEQUAL(get_termchar(mk->term, 4, 0).chr, CSET_ASCII | 'o');
  146. IEQUAL(get_termchar(mk->term, 5, 0).chr, CSET_ASCII | ',');
  147. IEQUAL(get_termchar(mk->term, 6, 0).chr, CSET_ASCII | ' ');
  148. IEQUAL(get_termchar(mk->term, 7, 0).chr, CSET_ASCII | 'w');
  149. IEQUAL(get_termchar(mk->term, 8, 0).chr, CSET_ASCII | 'o');
  150. IEQUAL(get_termchar(mk->term, 9, 0).chr, CSET_ASCII | 'r');
  151. IEQUAL(get_termchar(mk->term, 10, 0).chr, CSET_ASCII | 'l');
  152. IEQUAL(get_termchar(mk->term, 11, 0).chr, CSET_ASCII | 'd');
  153. }
  154. static void test_wrap(Mock *mk)
  155. {
  156. /* Test behaviour when printing characters wrap to the next line */
  157. mk->ucsdata->line_codepage = CP_UTF8;
  158. /* Print 'abc' without enough space for the c, in wrapping mode */
  159. reset(mk);
  160. mk->term->curs.x = 78;
  161. mk->term->curs.y = 0;
  162. mk->term->wrap = true;
  163. /* The 'a' prints without anything unusual happening */
  164. term_datapl(mk->term, PTRLEN_LITERAL("a"));
  165. IEQUAL(mk->term->curs.x, 79);
  166. IEQUAL(mk->term->curs.y, 0);
  167. IEQUAL(mk->term->wrapnext, 0);
  168. IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
  169. /* The 'b' prints, leaving the cursor where it is with wrapnext set */
  170. term_datapl(mk->term, PTRLEN_LITERAL("b"));
  171. IEQUAL(mk->term->curs.x, 79);
  172. IEQUAL(mk->term->curs.y, 0);
  173. IEQUAL(mk->term->wrapnext, 1);
  174. IEQUAL(get_lineattr(mk->term, 0), 0);
  175. IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'b');
  176. /* And now the 'c' causes a deferred wrap and goes to the next line */
  177. term_datapl(mk->term, PTRLEN_LITERAL("c"));
  178. IEQUAL(mk->term->curs.x, 1);
  179. IEQUAL(mk->term->curs.y, 1);
  180. IEQUAL(mk->term->wrapnext, 0);
  181. IEQUAL(get_lineattr(mk->term, 0), LATTR_WRAPPED);
  182. IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'b');
  183. IEQUAL(get_termchar(mk->term, 0, 1).chr, CSET_ASCII | 'c');
  184. /* If we backspace once, the cursor moves back on to the c */
  185. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  186. IEQUAL(mk->term->curs.x, 0);
  187. IEQUAL(mk->term->curs.y, 1);
  188. IEQUAL(mk->term->wrapnext, 0);
  189. /* Now backspace again, and the cursor returns to the b */
  190. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  191. IEQUAL(mk->term->curs.x, 79);
  192. IEQUAL(mk->term->curs.y, 0);
  193. IEQUAL(mk->term->wrapnext, 0);
  194. /* Now try it with a double-width character in place of ab */
  195. mk->term->curs.x = 78;
  196. mk->term->curs.y = 0;
  197. mk->term->wrap = true;
  198. /* The DW character goes directly to the wrapnext state */
  199. term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
  200. IEQUAL(mk->term->curs.x, 79);
  201. IEQUAL(mk->term->curs.y, 0);
  202. IEQUAL(mk->term->wrapnext, 1);
  203. IEQUAL(get_termchar(mk->term, 78, 0).chr, 0xAC00);
  204. IEQUAL(get_termchar(mk->term, 79, 0).chr, UCSWIDE);
  205. /* And the 'c' causes a deferred wrap as before */
  206. term_datapl(mk->term, PTRLEN_LITERAL("c"));
  207. IEQUAL(mk->term->curs.x, 1);
  208. IEQUAL(mk->term->curs.y, 1);
  209. IEQUAL(mk->term->wrapnext, 0);
  210. IEQUAL(get_lineattr(mk->term, 0), LATTR_WRAPPED);
  211. IEQUAL(get_termchar(mk->term, 78, 0).chr, 0xAC00);
  212. IEQUAL(get_termchar(mk->term, 79, 0).chr, UCSWIDE);
  213. IEQUAL(get_termchar(mk->term, 0, 1).chr, CSET_ASCII | 'c');
  214. /* If we backspace once, the cursor moves back on to the c */
  215. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  216. IEQUAL(mk->term->curs.x, 0);
  217. IEQUAL(mk->term->curs.y, 1);
  218. IEQUAL(mk->term->wrapnext, 0);
  219. /* Now backspace again, and the cursor goes to the RHS of the DW char */
  220. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  221. IEQUAL(mk->term->curs.x, 79);
  222. IEQUAL(mk->term->curs.y, 0);
  223. IEQUAL(mk->term->wrapnext, 0);
  224. /* Now put the DW character in place of bc */
  225. reset(mk);
  226. mk->term->curs.x = 78;
  227. mk->term->curs.y = 0;
  228. mk->term->wrap = true;
  229. /* The 'a' prints as before */
  230. term_datapl(mk->term, PTRLEN_LITERAL("a"));
  231. IEQUAL(mk->term->curs.x, 79);
  232. IEQUAL(mk->term->curs.y, 0);
  233. IEQUAL(mk->term->wrapnext, 0);
  234. IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
  235. /* The DW character wraps, setting LATTR_WRAPPED2 */
  236. term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
  237. IEQUAL(mk->term->curs.x, 2);
  238. IEQUAL(mk->term->curs.y, 1);
  239. IEQUAL(mk->term->wrapnext, 0);
  240. IEQUAL(get_lineattr(mk->term, 0), LATTR_WRAPPED | LATTR_WRAPPED2);
  241. IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
  242. IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | ' ');
  243. IEQUAL(get_termchar(mk->term, 0, 1).chr, 0xAC00);
  244. IEQUAL(get_termchar(mk->term, 1, 1).chr, UCSWIDE);
  245. /* If we backspace once, cursor moves to the RHS of the DW char */
  246. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  247. IEQUAL(mk->term->curs.x, 1);
  248. IEQUAL(mk->term->curs.y, 1);
  249. IEQUAL(mk->term->wrapnext, 0);
  250. /* Backspace again, and cursor moves from RHS to LHS of that char */
  251. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  252. IEQUAL(mk->term->curs.x, 0);
  253. IEQUAL(mk->term->curs.y, 1);
  254. IEQUAL(mk->term->wrapnext, 0);
  255. /* Now backspace again, and the cursor skips the empty column so
  256. * that it can return to the previous logical character, to wit, the a */
  257. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  258. IEQUAL(mk->term->curs.x, 78);
  259. IEQUAL(mk->term->curs.y, 0);
  260. IEQUAL(mk->term->wrapnext, 0);
  261. /* Print 'ab' up to the rightmost column, and then backspace */
  262. reset(mk);
  263. mk->term->curs.x = 78;
  264. mk->term->curs.y = 0;
  265. mk->term->wrap = true;
  266. /* As before, the 'ab' put us in the rightmost column with wrapnext set */
  267. term_datapl(mk->term, PTRLEN_LITERAL("ab"));
  268. IEQUAL(mk->term->curs.x, 79);
  269. IEQUAL(mk->term->curs.y, 0);
  270. IEQUAL(mk->term->wrapnext, 1);
  271. IEQUAL(get_lineattr(mk->term, 0), 0);
  272. IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
  273. IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'b');
  274. /* Backspacing just clears the wrapnext flag, so we're logically
  275. * back on the b again */
  276. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  277. IEQUAL(mk->term->curs.x, 79);
  278. IEQUAL(mk->term->curs.y, 0);
  279. IEQUAL(mk->term->wrapnext, 0);
  280. /* For completeness, the easy case: just print 'a' then backspace */
  281. reset(mk);
  282. mk->term->curs.x = 78;
  283. mk->term->curs.y = 0;
  284. mk->term->wrap = true;
  285. /* 'a' printed in column n-1 takes us to column n */
  286. term_datapl(mk->term, PTRLEN_LITERAL("a"));
  287. IEQUAL(mk->term->curs.x, 79);
  288. IEQUAL(mk->term->curs.y, 0);
  289. IEQUAL(mk->term->wrapnext, 0);
  290. IEQUAL(get_lineattr(mk->term, 0), 0);
  291. IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
  292. /* Backspacing moves us back a space on to the a */
  293. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  294. IEQUAL(mk->term->curs.x, 78);
  295. IEQUAL(mk->term->curs.y, 0);
  296. IEQUAL(mk->term->wrapnext, 0);
  297. /*
  298. * Now test the special cases that arise when the terminal is only
  299. * one column wide!
  300. */
  301. reset(mk);
  302. term_size(mk->term, 24, 1, 0);
  303. mk->term->curs.x = 0;
  304. mk->term->curs.y = 0;
  305. mk->term->wrap = true;
  306. /* Printing a single-width character takes us into wrapnext immediately */
  307. term_datapl(mk->term, PTRLEN_LITERAL("a"));
  308. IEQUAL(mk->term->curs.x, 0);
  309. IEQUAL(mk->term->curs.y, 0);
  310. IEQUAL(mk->term->wrapnext, 1);
  311. IEQUAL(get_lineattr(mk->term, 0), 0);
  312. IEQUAL(get_termchar(mk->term, 0, 0).chr, CSET_ASCII | 'a');
  313. /* Printing a second one wraps, and takes us _back_ to wrapnext */
  314. term_datapl(mk->term, PTRLEN_LITERAL("b"));
  315. IEQUAL(mk->term->curs.x, 0);
  316. IEQUAL(mk->term->curs.y, 1);
  317. IEQUAL(mk->term->wrapnext, 1);
  318. IEQUAL(get_lineattr(mk->term, 0), LATTR_WRAPPED);
  319. IEQUAL(get_termchar(mk->term, 0, 0).chr, CSET_ASCII | 'a');
  320. IEQUAL(get_termchar(mk->term, 0, 1).chr, CSET_ASCII | 'b');
  321. /* Backspacing once clears the wrapnext flag, putting us on the b */
  322. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  323. IEQUAL(mk->term->curs.x, 0);
  324. IEQUAL(mk->term->curs.y, 1);
  325. IEQUAL(mk->term->wrapnext, 0);
  326. /* Backspacing again returns to the previous line, putting us on the a */
  327. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  328. IEQUAL(mk->term->curs.x, 0);
  329. IEQUAL(mk->term->curs.y, 0);
  330. IEQUAL(mk->term->wrapnext, 0);
  331. /* And now try with a double-width character */
  332. reset(mk);
  333. term_size(mk->term, 24, 1, 0);
  334. mk->term->curs.x = 0;
  335. mk->term->curs.y = 0;
  336. mk->term->wrap = true;
  337. /* DW character won't fit at all, so it transforms into U+FFFD
  338. * REPLACEMENT CHARACTER and then behaves like a SW char */
  339. term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
  340. IEQUAL(mk->term->curs.x, 0);
  341. IEQUAL(mk->term->curs.y, 0);
  342. IEQUAL(mk->term->wrapnext, 1);
  343. IEQUAL(get_lineattr(mk->term, 0), 0);
  344. IEQUAL(get_termchar(mk->term, 0, 0).chr, 0xFFFD);
  345. }
  346. static void test_nonwrap(Mock *mk)
  347. {
  348. /* Test behaviour when printing characters hit end of line without wrap.
  349. * The wrapnext flag is never set in this mode. */
  350. mk->ucsdata->line_codepage = CP_UTF8;
  351. /* Print 'abc' without enough space for the c */
  352. reset(mk);
  353. mk->term->curs.x = 78;
  354. mk->term->curs.y = 0;
  355. mk->term->wrap = false;
  356. /* The 'a' prints without anything unusual happening */
  357. term_datapl(mk->term, PTRLEN_LITERAL("a"));
  358. IEQUAL(mk->term->curs.x, 79);
  359. IEQUAL(mk->term->curs.y, 0);
  360. IEQUAL(mk->term->wrapnext, 0);
  361. IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
  362. /* The 'b' prints, leaving the cursor where it is */
  363. term_datapl(mk->term, PTRLEN_LITERAL("b"));
  364. IEQUAL(mk->term->curs.x, 79);
  365. IEQUAL(mk->term->curs.y, 0);
  366. IEQUAL(mk->term->wrapnext, 0);
  367. IEQUAL(get_lineattr(mk->term, 0), 0);
  368. IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'b');
  369. /* The 'c' overwrites the b */
  370. term_datapl(mk->term, PTRLEN_LITERAL("c"));
  371. IEQUAL(mk->term->curs.x, 79);
  372. IEQUAL(mk->term->curs.y, 0);
  373. IEQUAL(mk->term->wrapnext, 0);
  374. IEQUAL(get_lineattr(mk->term, 0), 0);
  375. IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
  376. IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'c');
  377. /* Since wrapnext was never set, backspacing returns us to the a */
  378. term_datapl(mk->term, PTRLEN_LITERAL("\b"));
  379. IEQUAL(mk->term->curs.x, 78);
  380. IEQUAL(mk->term->curs.y, 0);
  381. IEQUAL(mk->term->wrapnext, 0);
  382. /* Now try it with a double-width character in place of ab */
  383. mk->term->curs.x = 78;
  384. mk->term->curs.y = 0;
  385. mk->term->wrap = false;
  386. /* The DW character occupies the rightmost two columns */
  387. term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
  388. IEQUAL(mk->term->curs.x, 79);
  389. IEQUAL(mk->term->curs.y, 0);
  390. IEQUAL(mk->term->wrapnext, 0);
  391. IEQUAL(get_termchar(mk->term, 78, 0).chr, 0xAC00);
  392. IEQUAL(get_termchar(mk->term, 79, 0).chr, UCSWIDE);
  393. /* The 'c' must overprint the RHS of the DW char, clearing the LHS */
  394. term_datapl(mk->term, PTRLEN_LITERAL("c"));
  395. IEQUAL(mk->term->curs.x, 79);
  396. IEQUAL(mk->term->curs.y, 0);
  397. IEQUAL(mk->term->wrapnext, 0);
  398. IEQUAL(get_lineattr(mk->term, 0), 0);
  399. IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | ' ');
  400. IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'c');
  401. /* Now put the DW char in place of the bc */
  402. reset(mk);
  403. mk->term->curs.x = 78;
  404. mk->term->curs.y = 0;
  405. mk->term->wrap = false;
  406. /* The 'a' prints as before */
  407. term_datapl(mk->term, PTRLEN_LITERAL("a"));
  408. IEQUAL(mk->term->curs.x, 79);
  409. IEQUAL(mk->term->curs.y, 0);
  410. IEQUAL(mk->term->wrapnext, 0);
  411. IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
  412. /* The DW char won't fit, so turns into U+FFFD REPLACEMENT CHARACTER */
  413. term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
  414. IEQUAL(mk->term->curs.x, 79);
  415. IEQUAL(mk->term->curs.y, 0);
  416. IEQUAL(mk->term->wrapnext, 0);
  417. IEQUAL(get_lineattr(mk->term, 0), 0);
  418. IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
  419. IEQUAL(get_termchar(mk->term, 79, 0).chr, 0xFFFD);
  420. /* Just for completeness, try both of those together */
  421. reset(mk);
  422. mk->term->curs.x = 78;
  423. mk->term->curs.y = 0;
  424. mk->term->wrap = false;
  425. /* First DW character occupies the rightmost columns */
  426. term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
  427. IEQUAL(mk->term->curs.x, 79);
  428. IEQUAL(mk->term->curs.y, 0);
  429. IEQUAL(mk->term->wrapnext, 0);
  430. IEQUAL(get_termchar(mk->term, 78, 0).chr, 0xAC00);
  431. IEQUAL(get_termchar(mk->term, 79, 0).chr, UCSWIDE);
  432. /* Second DW char becomes U+FFFD, overwriting RHS of the first one */
  433. term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x81"));
  434. IEQUAL(mk->term->curs.x, 79);
  435. IEQUAL(mk->term->curs.y, 0);
  436. IEQUAL(mk->term->wrapnext, 0);
  437. IEQUAL(get_lineattr(mk->term, 0), 0);
  438. IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | ' ');
  439. IEQUAL(get_termchar(mk->term, 79, 0).chr, 0xFFFD);
  440. }
  441. int main(void)
  442. {
  443. Mock *mk = mock_new();
  444. mk->term = term_init(mk->conf, mk->ucsdata, &mk->tw);
  445. test_hello_world(mk);
  446. test_wrap(mk);
  447. test_nonwrap(mk);
  448. bool failed = mk->any_test_failed;
  449. mock_free(mk);
  450. if (failed) {
  451. printf("Test suite FAILED!\n");
  452. return 1;
  453. } else {
  454. printf("Test suite passed\n");
  455. return 0;
  456. }
  457. }