1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 09:58:01 +00:00
putty-source/test/test_terminal.c

509 lines
18 KiB
C
Raw Normal View History

#include "putty.h"
#include "terminal.h"
void modalfatalbox(const char *p, ...)
{
va_list ap;
fprintf(stderr, "FATAL ERROR: ");
va_start(ap, p);
vfprintf(stderr, p, ap);
va_end(ap);
fputc('\n', stderr);
exit(1);
}
const char *const appname = "test_lineedit";
char *platform_default_s(const char *name)
{ return NULL; }
bool platform_default_b(const char *name, bool def)
{ return def; }
int platform_default_i(const char *name, int def)
{ return def; }
FontSpec *platform_default_fontspec(const char *name)
{ return fontspec_new_default(); }
Filename *platform_default_filename(const char *name)
{ return filename_from_str(""); }
const struct BackendVtable *const backends[] = { NULL };
typedef struct Mock {
Terminal *term;
Conf *conf;
struct unicode_data ucsdata[1];
strbuf *context;
bool any_test_failed;
TermWin tw;
} Mock;
static bool mock_setup_draw_ctx(TermWin *win) { return false; }
static void mock_draw_text(TermWin *win, int x, int y, wchar_t *text, int len,
unsigned long attrs, int lattrs, truecolour tc) {}
static void mock_draw_cursor(TermWin *win, int x, int y, wchar_t *text,
int len, unsigned long attrs, int lattrs,
truecolour tc) {}
static void mock_set_raw_mouse_mode(TermWin *win, bool enable) {}
static void mock_set_raw_mouse_mode_pointer(TermWin *win, bool enable) {}
static void mock_palette_set(TermWin *win, unsigned start, unsigned ncolours,
const rgb *colours) {}
static void mock_palette_get_overrides(TermWin *tw, Terminal *term) {}
static const TermWinVtable mock_termwin_vt = {
.setup_draw_ctx = mock_setup_draw_ctx,
.draw_text = mock_draw_text,
.draw_cursor = mock_draw_cursor,
.set_raw_mouse_mode = mock_set_raw_mouse_mode,
.set_raw_mouse_mode_pointer = mock_set_raw_mouse_mode_pointer,
.palette_set = mock_palette_set,
.palette_get_overrides = mock_palette_get_overrides,
};
static Mock *mock_new(void)
{
Mock *mk = snew(Mock);
memset(mk, 0, sizeof(*mk));
mk->conf = conf_new();
do_defaults(NULL, mk->conf);
init_ucs_generic(mk->conf, mk->ucsdata);
mk->ucsdata->line_codepage = CP_ISO8859_1;
mk->context = strbuf_new();
mk->tw.vt = &mock_termwin_vt;
return mk;
}
static void mock_free(Mock *mk)
{
strbuf_free(mk->context);
conf_free(mk->conf);
term_free(mk->term);
sfree(mk);
}
static void reset(Mock *mk)
{
term_pwron(mk->term, true);
term_size(mk->term, 24, 80, 0);
term_set_trust_status(mk->term, false);
strbuf_clear(mk->context);
}
#if 0
static void test_context(Mock *mk, const char *fmt, ...)
{
strbuf_clear(mk->context);
va_list ap;
va_start(ap, fmt);
put_fmtv(mk->context, fmt, ap);
va_end(ap);
}
#endif
static void report_fail(Mock *mk, const char *file, int line,
const char *fmt, ...)
{
printf("%s:%d", file, line);
if (mk->context->len)
printf(" (%s)", mk->context->s);
printf(": ");
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
mk->any_test_failed = true;
}
static inline void check_iequal(Mock *mk, const char *file, int line,
long long lhs, long long rhs)
{
if (lhs != rhs)
report_fail(mk, file, line, "%lld != %lld / %#llx != %#llx",
lhs, rhs, lhs, rhs);
}
#define IEQUAL(lhs, rhs) check_iequal(mk, __FILE__, __LINE__, lhs, rhs)
static inline void term_datapl(Terminal *term, ptrlen pl)
{
term_data(term, pl.ptr, pl.len);
}
static struct termchar get_termchar(Terminal *term, int x, int y)
{
termline *tl = term_get_line(term, y);
termchar tc;
if (0 <= x && x < tl->cols)
tc = tl->chars[x];
else
tc = term->erase_char;
term_release_line(tl);
return tc;
}
static unsigned short get_lineattr(Terminal *term, int y)
{
termline *tl = term_get_line(term, y);
unsigned short lattr = tl->lattr;
term_release_line(tl);
return lattr;
}
static void test_hello_world(Mock *mk)
{
/* A trivial test just to kick off this test framework */
mk->ucsdata->line_codepage = CP_ISO8859_1;
reset(mk);
term_datapl(mk->term, PTRLEN_LITERAL("hello, world"));
IEQUAL(mk->term->curs.x, 12);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(get_termchar(mk->term, 0, 0).chr, CSET_ASCII | 'h');
IEQUAL(get_termchar(mk->term, 1, 0).chr, CSET_ASCII | 'e');
IEQUAL(get_termchar(mk->term, 2, 0).chr, CSET_ASCII | 'l');
IEQUAL(get_termchar(mk->term, 3, 0).chr, CSET_ASCII | 'l');
IEQUAL(get_termchar(mk->term, 4, 0).chr, CSET_ASCII | 'o');
IEQUAL(get_termchar(mk->term, 5, 0).chr, CSET_ASCII | ',');
IEQUAL(get_termchar(mk->term, 6, 0).chr, CSET_ASCII | ' ');
IEQUAL(get_termchar(mk->term, 7, 0).chr, CSET_ASCII | 'w');
IEQUAL(get_termchar(mk->term, 8, 0).chr, CSET_ASCII | 'o');
IEQUAL(get_termchar(mk->term, 9, 0).chr, CSET_ASCII | 'r');
IEQUAL(get_termchar(mk->term, 10, 0).chr, CSET_ASCII | 'l');
IEQUAL(get_termchar(mk->term, 11, 0).chr, CSET_ASCII | 'd');
}
static void test_wrap(Mock *mk)
{
/* Test behaviour when printing characters wrap to the next line */
mk->ucsdata->line_codepage = CP_UTF8;
/* Print 'abc' without enough space for the c, in wrapping mode */
reset(mk);
mk->term->curs.x = 78;
mk->term->curs.y = 0;
mk->term->wrap = true;
/* The 'a' prints without anything unusual happening */
term_datapl(mk->term, PTRLEN_LITERAL("a"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
/* The 'b' prints, leaving the cursor where it is with wrapnext set */
term_datapl(mk->term, PTRLEN_LITERAL("b"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_lineattr(mk->term, 0), 0);
IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'b');
/* And now the 'c' causes a deferred wrap and goes to the next line */
term_datapl(mk->term, PTRLEN_LITERAL("c"));
IEQUAL(mk->term->curs.x, 1);
IEQUAL(mk->term->curs.y, 1);
IEQUAL(mk->term->wrapnext, 0);
IEQUAL(get_lineattr(mk->term, 0), LATTR_WRAPPED);
IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'b');
IEQUAL(get_termchar(mk->term, 0, 1).chr, CSET_ASCII | 'c');
/* If we backspace once, the cursor moves back on to the c */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 0);
IEQUAL(mk->term->curs.y, 1);
IEQUAL(mk->term->wrapnext, 0);
/* Now backspace again, and the cursor returns to the b */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
/* Now try it with a double-width character in place of ab */
mk->term->curs.x = 78;
mk->term->curs.y = 0;
mk->term->wrap = true;
/* The DW character goes directly to the wrapnext state */
term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_termchar(mk->term, 78, 0).chr, 0xAC00);
IEQUAL(get_termchar(mk->term, 79, 0).chr, UCSWIDE);
/* And the 'c' causes a deferred wrap as before */
term_datapl(mk->term, PTRLEN_LITERAL("c"));
IEQUAL(mk->term->curs.x, 1);
IEQUAL(mk->term->curs.y, 1);
IEQUAL(mk->term->wrapnext, 0);
IEQUAL(get_lineattr(mk->term, 0), LATTR_WRAPPED);
IEQUAL(get_termchar(mk->term, 78, 0).chr, 0xAC00);
IEQUAL(get_termchar(mk->term, 79, 0).chr, UCSWIDE);
IEQUAL(get_termchar(mk->term, 0, 1).chr, CSET_ASCII | 'c');
/* If we backspace once, the cursor moves back on to the c */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 0);
IEQUAL(mk->term->curs.y, 1);
IEQUAL(mk->term->wrapnext, 0);
/* Now backspace again, and the cursor goes to the RHS of the DW char */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
/* Now put the DW character in place of bc */
reset(mk);
mk->term->curs.x = 78;
mk->term->curs.y = 0;
mk->term->wrap = true;
/* The 'a' prints as before */
term_datapl(mk->term, PTRLEN_LITERAL("a"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
/* The DW character wraps, setting LATTR_WRAPPED2 */
term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
IEQUAL(mk->term->curs.x, 2);
IEQUAL(mk->term->curs.y, 1);
IEQUAL(mk->term->wrapnext, 0);
IEQUAL(get_lineattr(mk->term, 0), LATTR_WRAPPED | LATTR_WRAPPED2);
IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | ' ');
IEQUAL(get_termchar(mk->term, 0, 1).chr, 0xAC00);
IEQUAL(get_termchar(mk->term, 1, 1).chr, UCSWIDE);
/* If we backspace once, cursor moves to the RHS of the DW char */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 1);
IEQUAL(mk->term->curs.y, 1);
IEQUAL(mk->term->wrapnext, 0);
/* Backspace again, and cursor moves from RHS to LHS of that char */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 0);
IEQUAL(mk->term->curs.y, 1);
IEQUAL(mk->term->wrapnext, 0);
Make backspace take account of LATTR_WRAPPED2. Suppose an application tries to print a double-width character starting in the rightmost column of the screen, so that we apply our emergency fix of wrapping to the next line immediately and printing the character in the first two columns. Suppose they then backspace twice, taking the cursor to the RHS and then the LHS of that character. What should happen if they backspace a third time? Our previous behaviour was to completely ignore the unusual situation, and do the same thing we'd do in any other backspace from column 0: anti-wrap the cursor to the last column of the previous line, leaving it in the empty character cell that was skipped when the DW char couldn't be printed in it. But I think this isn't the best response, because it breaks the invariant that printing N columns' worth of graphic characters and then backspacing N times should leave the cursor on the first of those characters. If I print "a가" (for example) and then backspace three times, I want the cursor on the a, _even_ if weird line wrapping behaviour happened somewhere in that sequence. (Rationale: this helps naïve terminal applications which don't even know what the terminal width is, and aren't tracking their absolute x position. In particular, the simplistic line-based input systems that appear in OS kernels and our own lineedit.c will want to emit a fixed number of backspace-space-backspace sequences to delete characters previously entered on to the line by the user. They still need to check the wcwidth of the characters they're emitting, so that they can BSB twice for a DW character or 0 times for a combining one, but it would be *hugely* more awkward for them to ask the terminal where the cursor is so that they can take account of difficult line wraps!) We already have the ability to _recognise_ this situation: on a line that was wrapped in this unusual way, we set the LATTR_WRAPPED2 line attribute flag, to prevent the empty rightmost column from injecting an unwanted space into copy-pastes from the terminal. Now we also use the same flag to cause the backspace control character to do something interesting. This was the fix that inspired me to start writing test_terminal, because I knew it was touching a delicate area. However, in the course of writing this fix and its tests, I encountered two (!) further bugs, which I'll fix in followup commits!
2023-03-05 09:31:06 +00:00
/* Now backspace again, and the cursor skips the empty column so
* that it can return to the previous logical character, to wit, the a */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
Make backspace take account of LATTR_WRAPPED2. Suppose an application tries to print a double-width character starting in the rightmost column of the screen, so that we apply our emergency fix of wrapping to the next line immediately and printing the character in the first two columns. Suppose they then backspace twice, taking the cursor to the RHS and then the LHS of that character. What should happen if they backspace a third time? Our previous behaviour was to completely ignore the unusual situation, and do the same thing we'd do in any other backspace from column 0: anti-wrap the cursor to the last column of the previous line, leaving it in the empty character cell that was skipped when the DW char couldn't be printed in it. But I think this isn't the best response, because it breaks the invariant that printing N columns' worth of graphic characters and then backspacing N times should leave the cursor on the first of those characters. If I print "a가" (for example) and then backspace three times, I want the cursor on the a, _even_ if weird line wrapping behaviour happened somewhere in that sequence. (Rationale: this helps naïve terminal applications which don't even know what the terminal width is, and aren't tracking their absolute x position. In particular, the simplistic line-based input systems that appear in OS kernels and our own lineedit.c will want to emit a fixed number of backspace-space-backspace sequences to delete characters previously entered on to the line by the user. They still need to check the wcwidth of the characters they're emitting, so that they can BSB twice for a DW character or 0 times for a combining one, but it would be *hugely* more awkward for them to ask the terminal where the cursor is so that they can take account of difficult line wraps!) We already have the ability to _recognise_ this situation: on a line that was wrapped in this unusual way, we set the LATTR_WRAPPED2 line attribute flag, to prevent the empty rightmost column from injecting an unwanted space into copy-pastes from the terminal. Now we also use the same flag to cause the backspace control character to do something interesting. This was the fix that inspired me to start writing test_terminal, because I knew it was touching a delicate area. However, in the course of writing this fix and its tests, I encountered two (!) further bugs, which I'll fix in followup commits!
2023-03-05 09:31:06 +00:00
IEQUAL(mk->term->curs.x, 78);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
/* Print 'ab' up to the rightmost column, and then backspace */
reset(mk);
mk->term->curs.x = 78;
mk->term->curs.y = 0;
mk->term->wrap = true;
/* As before, the 'ab' put us in the rightmost column with wrapnext set */
term_datapl(mk->term, PTRLEN_LITERAL("ab"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_lineattr(mk->term, 0), 0);
IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'b');
/* Backspacing just clears the wrapnext flag, so we're logically
* back on the b again */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
/* For completeness, the easy case: just print 'a' then backspace */
reset(mk);
mk->term->curs.x = 78;
mk->term->curs.y = 0;
mk->term->wrap = true;
/* 'a' printed in column n-1 takes us to column n */
term_datapl(mk->term, PTRLEN_LITERAL("a"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
IEQUAL(get_lineattr(mk->term, 0), 0);
IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
/* Backspacing moves us back a space on to the a */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 78);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
/*
* Now test the special cases that arise when the terminal is only
* one column wide!
*/
reset(mk);
term_size(mk->term, 24, 1, 0);
mk->term->curs.x = 0;
mk->term->curs.y = 0;
mk->term->wrap = true;
/* Printing a single-width character takes us into wrapnext immediately */
term_datapl(mk->term, PTRLEN_LITERAL("a"));
IEQUAL(mk->term->curs.x, 0);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_lineattr(mk->term, 0), 0);
IEQUAL(get_termchar(mk->term, 0, 0).chr, CSET_ASCII | 'a');
/* Printing a second one wraps, and takes us _back_ to wrapnext */
term_datapl(mk->term, PTRLEN_LITERAL("b"));
IEQUAL(mk->term->curs.x, 0);
IEQUAL(mk->term->curs.y, 1);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_lineattr(mk->term, 0), LATTR_WRAPPED);
IEQUAL(get_termchar(mk->term, 0, 0).chr, CSET_ASCII | 'a');
IEQUAL(get_termchar(mk->term, 0, 1).chr, CSET_ASCII | 'b');
/* Backspacing once clears the wrapnext flag, putting us on the b */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 0);
IEQUAL(mk->term->curs.y, 1);
IEQUAL(mk->term->wrapnext, 0);
/* Backspacing again returns to the previous line, putting us on the a */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 0);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
/* And now try with a double-width character */
reset(mk);
term_size(mk->term, 24, 1, 0);
mk->term->curs.x = 0;
mk->term->curs.y = 0;
mk->term->wrap = true;
/* DW character won't fit at all, so it transforms into U+FFFD
* REPLACEMENT CHARACTER and then behaves like a SW char */
term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
IEQUAL(mk->term->curs.x, 0);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_lineattr(mk->term, 0), 0);
IEQUAL(get_termchar(mk->term, 0, 0).chr, 0xFFFD);
}
static void test_nonwrap(Mock *mk)
{
/* Test behaviour when printing characters hit end of line without wrap */
mk->ucsdata->line_codepage = CP_UTF8;
/* Print 'abc' without enough space for the c */
reset(mk);
mk->term->curs.x = 78;
mk->term->curs.y = 0;
mk->term->wrap = false;
/* The 'a' prints without anything unusual happening */
term_datapl(mk->term, PTRLEN_LITERAL("a"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
/* The 'b' prints, leaving the cursor where it is with wrapnext set */
term_datapl(mk->term, PTRLEN_LITERAL("b"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_lineattr(mk->term, 0), 0);
IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'b');
/* The 'c' overwrites the b, leaving wrapnext still set */
term_datapl(mk->term, PTRLEN_LITERAL("c"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_lineattr(mk->term, 0), 0);
IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'c');
/* So backspacing clears wrapnext, leaving us on the c */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
/* And backspacing again returns the cursor to the a */
term_datapl(mk->term, PTRLEN_LITERAL("\b"));
IEQUAL(mk->term->curs.x, 78);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
/* Now try it with a double-width character in place of ab */
mk->term->curs.x = 78;
mk->term->curs.y = 0;
mk->term->wrap = false;
/* The DW character goes directly to the wrapnext state */
term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_termchar(mk->term, 78, 0).chr, 0xAC00);
IEQUAL(get_termchar(mk->term, 79, 0).chr, UCSWIDE);
/* The 'c' must overprint the RHS of the DW char, clearing the LHS */
term_datapl(mk->term, PTRLEN_LITERAL("c"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_lineattr(mk->term, 0), 0);
IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | ' ');
IEQUAL(get_termchar(mk->term, 79, 0).chr, CSET_ASCII | 'c');
/* Now put the DW char in place of the bc */
reset(mk);
mk->term->curs.x = 78;
mk->term->curs.y = 0;
mk->term->wrap = false;
/* The 'a' prints as before */
term_datapl(mk->term, PTRLEN_LITERAL("a"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 0);
IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
/* The DW char won't fit, so turns into U+FFFD REPLACEMENT CHARACTER */
term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_lineattr(mk->term, 0), 0);
IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | 'a');
IEQUAL(get_termchar(mk->term, 79, 0).chr, 0xFFFD);
/* Just for completeness, try both of those together */
reset(mk);
mk->term->curs.x = 78;
mk->term->curs.y = 0;
mk->term->wrap = false;
/* First DW character goes directly to the wrapnext state */
term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_termchar(mk->term, 78, 0).chr, 0xAC00);
IEQUAL(get_termchar(mk->term, 79, 0).chr, UCSWIDE);
/* Second DW char becomes U+FFFD, overwriting RHS of the first one */
term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x81"));
IEQUAL(mk->term->curs.x, 79);
IEQUAL(mk->term->curs.y, 0);
IEQUAL(mk->term->wrapnext, 1);
IEQUAL(get_lineattr(mk->term, 0), 0);
IEQUAL(get_termchar(mk->term, 78, 0).chr, CSET_ASCII | ' ');
IEQUAL(get_termchar(mk->term, 79, 0).chr, 0xFFFD);
}
int main(void)
{
Mock *mk = mock_new();
mk->term = term_init(mk->conf, mk->ucsdata, &mk->tw);
test_hello_world(mk);
test_wrap(mk);
test_nonwrap(mk);
bool failed = mk->any_test_failed;
mock_free(mk);
if (failed) {
printf("Test suite FAILED!\n");
return 1;
} else {
printf("Test suite passed\n");
return 0;
}
}