test-term-page.c revision 84da4a3022bc599b26d9601cf1b7bf51d1d9f915
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
/*
* This tests internals of terminal page, line, cell and char handling. It
* relies on some implementation details, so it might need to be updated if
* those internals are changed. They should be fairly obvious, though.
*/
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "macro.h"
#include "term-internal.h"
#include "util.h"
do { \
if (_unlikely_(!(expr))) \
} while (false) \
/*
* Character Tests
*
* These tests rely on some implementation details of term_char_t, including
* the way we pack characters and the internal layout of "term_char_t". These
* tests have to be updated once we change the implementation.
*/
0x1) \
)
static void test_term_char_misc(void) {
term_char_t c, t;
/* test TERM_CHAR_NULL handling */
c = TERM_CHAR_NULL; /* c is NULL */
/* test single char handling */
assert_se(!term_char_same(c, t));
assert_se(!term_char_equal(c, t));
assert_se(!term_char_is_null(t));
/* test basic combined char handling */
t = term_char_dup_append(t, '~');
assert_se(!term_char_same(c, t));
assert_se(!term_char_is_null(t));
c = term_char_dup_append(c, 'A');
c = term_char_dup_append(c, '~');
assert_se(term_char_same(c, t));
assert_se(term_char_equal(c, t));
/* test more than 2 comb-chars so the chars are allocated */
assert_se(!term_char_same(c, t));
assert_se(term_char_equal(c, t));
/* test dup_append() on allocated chars */
term_char_free(t);
assert_se(!term_char_same(c, t));
assert_se(!term_char_equal(c, t));
assert_se(!term_char_same(c, t));
assert_se(term_char_equal(c, t));
term_char_free(t);
term_char_free(c);
}
static void test_term_char_packing(void) {
{ -1 },
{ 0, -1 },
{ 'A', '~', -1 },
{ 'A', '~', 0, -1 },
{ 'A', '~', 'a', -1 },
};
term_char_t res[] = {
PACK1(0),
};
unsigned int i, j;
/*
* This creates term_char_t objects based on the data in @seqs and
* compares the result to @res. Only basic packed types are tested, no
* allocations are done.
*/
for (i = 0; i < ELEMENTSOF(seqs); ++i) {
for (j = 0; j < ELEMENTSOF(seqs[i]); ++j) {
break;
c = term_char_merge(c, next);
}
c = term_char_free(c);
}
}
static void test_term_char_allocating(void) {
{ 0, -1 },
{ 'A', '~', -1 },
{ 'A', '~', 0, -1 },
{ 'A', '~', 'a', -1 },
{ 'A', '~', 'a', 'b', 'c', 'd', -1 },
{ 'A', '~', 'a', 'b', 'c', 'd', 0, '^', -1 },
/* exceeding implementation-defined soft-limit of 64 */
{ 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', -1 },
};
term_char_t res[] = {
PACK1(0),
TERM_CHAR_NULL, /* allocated */
TERM_CHAR_NULL, /* allocated */
TERM_CHAR_NULL, /* allocated */
};
{ 0, -1 },
{ 'A', '~', -1 },
{ 'A', '~', 0, -1 },
{ 'A', '~', 'a', -1 },
{ 'A', '~', 'a', 'b', 'c', 'd', -1 },
{ 'A', '~', 'a', 'b', 'c', 'd', 0, '^', -1 },
{ 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', -1 },
};
size_t n;
unsigned int i, j;
const uint32_t *t;
/*
* This builds term_char_t objects based on the data in @seqs. It
* compares the result to @res for packed chars, otherwise it requires
* them to be allocated.
* After that, we resolve the UCS-4 string and compare it to the
* expected strings in @str.
*/
for (i = 0; i < ELEMENTSOF(seqs); ++i) {
for (j = 0; j < ELEMENTSOF(seqs[i]); ++j) {
break;
c = term_char_merge(c, next);
}
/* we use TERM_CHAR_NULL as marker for allocated chars here */
if (term_char_is_null(res[i]))
else
t = term_char_resolve(c, &n, NULL);
for (j = 0; j < ELEMENTSOF(str[i]); ++j) {
break;
}
assert_se(n == j);
}
}
/*
* Line Tests
*
* The following tests work on term_line objects and verify their behavior when
* we modify them. To verify and set line layouts, we have two simple helpers
* to avoid harcoding the cell-verification all the time:
* line_set(): Set a line to a given layout
* line_assert(): Verify that a line has a given layout
*
* These functions take the line-layout encoded as a string and verify it
* against, or set it on, a term_line object. The format used to describe a
* line looks like this:
* example: "| | A | | | | | | 10 *AB* |"
*
* The string describes the contents of all cells of a line, separated by
* pipe-symbols ('|'). Whitespace are ignored, the leading pipe-symbol is
* optional.
* The description of each cell can contain an arbitrary amount of characters
* in the range 'A'-'Z', 'a'-'z'. All those are combined and used as term_char_t
* on this cell. Any numbers in the description are combined and are used as
* cell-age.
* The occurance of a '*'-symbol marks the cell as bold, '/' marks it as italic.
* You can use those characters multiple times, but only the first one has an
* effect.
* For further symbols, see parse_attr().
*
* Therefore, the following descriptions are equivalent:
* 1) "| | /A* | | | | | | 10 *AB* |"
* 2) "| | /A** | | | | | | 10 *AB* |"
* 3) "| | A* // | | | | | | 10 *AB* |"
* 4) "| | A* // | | | | | | 1 *AB* 0 |"
* 5) "| | A* // | | | | | | A1B0* |"
*
* but simply appends all found chars. Don't make use of that feature! It's
* just a stupid parser to simplify these tests. Make them readable!
*/
switch (c) {
case ' ':
/* ignore */
break;
case '0' ... '9':
/* increase age */
break;
case 'A' ... 'Z':
case 'a' ... 'z':
/* add to character */
break;
case '*':
break;
case '/':
break;
default:
assert_se(0);
break;
}
}
static void cell_assert(MY_ASSERT_ARGS, term_cell *c, term_char_t ch, const term_attr *attr, term_age_t age) {
}
#define CELL_ASSERT(_cell, _ch, _attr, _age) cell_assert(MY_ASSERT_VALS, (_cell), (_ch), (_attr), (_age))
unsigned int cell_i;
char c;
/* skip leading whitespace */
while (*str == ' ')
++str;
/* skip leading '|' */
if (*str == '|')
++str;
cell_i = 0;
while ((c = *str++)) {
switch (c) {
case '|':
/* end of cell-description; compare it */
ch,
&attr,
age);
++cell_i;
age = TERM_AGE_NULL;
break;
default:
break;
}
}
}
char c;
while ((c = *str++))
}
term_line_set_width(l, width);
}
static void test_term_line_misc(void) {
term_line *l;
assert_se(term_line_new(&l) >= 0);
assert_se(!term_line_free(l));
assert_se(term_line_new(&l) >= 0);
assert_se(!term_line_free(l));
}
static void test_term_line_ops(void) {
term_line *l;
term_attr attr_regular = { };
assert_se(term_line_new(&l) >= 0);
LINE_ASSERT(l, "| | | | | | | | |", 0);
LINE_ASSERT(l, "| | | | | | | | |", 0);
assert_se(!term_line_free(l));
}
return 0;
}