mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-03-18 12:58:39 -05:00

These seem likely to carry on being useful, so let's make sure they pass before allowing any build to complete successfully. I've added code to both test programs to return a sensible exit status indicating pass/fail, and added runs of both to Buildscr.
509 lines
18 KiB
C
509 lines
18 KiB
C
#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);
|
|
/* 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"));
|
|
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;
|
|
}
|
|
}
|