summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2014-05-14 11:50:32 +0200
committerDavid Herrmann <dh.herrmann@gmail.com>2014-05-14 11:50:32 +0200
commitce19ed8ddffd05e0dc846470be7b22b530d5dc6d (patch)
treed7a154356e9b013d8d7352f381f297eb1988cdd3 /test
Initial import
Import new mmap-unifont package, a pre-compiled version of the GNU-Unifont font files: GNU-Unifont is a bitmap Unicode font with almost complete Unicode coverage. It is perfectly suited for low-level system binaries, as fallback font, in emergency situations, and more. mmap-unifont compiles a binary font format based on GNU-Unifont. This compiled file can be memory-mapped by applications to get direct font-access. This extremely simplifies font-usage for system-applications. Advantages over using the original BDF font are: * On-demand glyph loading: The whole font is pre-compiled with fixed offsets. The header includes offsets and limits. Hence, an application can directly access the memory-location of a glyph on-demand. The operating-system can load the required memory-pages on first-access, thus reducing the memory footprint considerably. With BDF fonts, the application has to scan the whole BDF file to find a given glyph. This requires loading 9MB of font-data just to display the U+FFFD glyph. * No need to write a BDF-format parser: While BDF is a quite simple format, it still requires a parser. This is tedious and overkill, if you don't intend to use other fonts than GNU-Unifont. * Stronger guarantees: GNU-Unifont has some very handy features, which cannot be expressed in most font-formats. While it is possible to rely on them using any font-format, you usually violate the rules of the font-format and thus make your application dependent on GNU-Unifont (questioning why you wrote a BDF-parser in the first place). Those features include: * fixed size for all glyphs * fixed underline position and thickness * fixed horizontal/vertical advancement * ... * Additional annotations: Given the very precice use-case of mmap-unifont, we can add additional glyph-annotations that simplify rendering. For instance, combining-characters require you to draw multiple glyphs on top of each other. The mmap-unifont package provides annotations that describe the relative positioning of the glyphs when drawn together. mmap-unifont is strongly targetted at system-applications. It has no external dependencies, is very memory-friendly, but still provides a font with full Unicode-coverage. However, please note that it does not provide any advanced layout-features (like RTL/LTR annotations). To render fully-internationalized text, a layout-engine like HarfBuzz/Pango is required. Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Diffstat (limited to 'test')
-rw-r--r--test/test-common.h75
-rw-r--r--test/test-glyphs.c216
-rw-r--r--test/test-valgrind.c23
3 files changed, 314 insertions, 0 deletions
diff --git a/test/test-common.h b/test/test-common.h
new file mode 100644
index 0000000..a4f0fa2
--- /dev/null
+++ b/test/test-common.h
@@ -0,0 +1,75 @@
+#ifndef TEST_COMMON_H
+#define TEST_COMMON_H
+
+#include <check.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* lower address-space is protected from user-allocation, so this is invalid */
+#define TEST_INVALID_PTR ((void*)0x10)
+
+#define TEST_DEFINE_CASE(_name) \
+ static TCase *test_create_case_##_name(void) \
+ { \
+ TCase *tc; \
+ \
+ tc = tcase_create(#_name); \
+
+#define TEST(_name) tcase_add_test(tc, _name);
+
+#define TEST_END_CASE \
+ return tc; \
+ } \
+
+#define TEST_END NULL
+
+#define TEST_CASE(_name) test_create_case_##_name
+
+static inline Suite *test_create_suite(const char *name, ...)
+{
+ Suite *s;
+ va_list list;
+ TCase *(*fn)(void);
+
+ s = suite_create(name);
+
+ va_start(list, name);
+ while ((fn = va_arg(list, TCase *(*)(void))))
+ suite_add_tcase(s, fn());
+ va_end(list);
+
+ return s;
+}
+
+#define TEST_SUITE(_name, ...) test_create_suite((#_name), ##__VA_ARGS__)
+
+static inline int test_run_suite(Suite *s)
+{
+ int ret;
+ SRunner *sr;
+
+ sr = srunner_create(s);
+ srunner_run_all(sr, CK_NORMAL);
+ ret = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return ret;
+}
+
+#define TEST_DEFINE(_suite) \
+ int main(int argc, char **argv) \
+ { \
+ return test_run_suite(_suite); \
+ }
+
+#endif /* TEST_COMMON_H */
diff --git a/test/test-glyphs.c b/test/test-glyphs.c
new file mode 100644
index 0000000..9c8f621
--- /dev/null
+++ b/test/test-glyphs.c
@@ -0,0 +1,216 @@
+#include "test-common.h"
+
+static int font_open(void)
+{
+ int fd;
+
+ fd = open(PKGDATADIR "/mmap-unifont.bin", O_RDONLY | O_CLOEXEC);
+ ck_assert_int_ge(fd, 0);
+
+ return fd;
+}
+
+static void font_close(int fd)
+{
+ int r;
+
+ r = close(fd);
+ ck_assert_int_ge(r, 0);
+}
+
+static void *font_mmap(int fd, size_t *out_size)
+{
+ struct stat st;
+ void *p;
+ int r;
+
+ r = fstat(fd, &st);
+ ck_assert_int_ge(r, 0);
+
+ p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ ck_assert_ptr_ne(p, MAP_FAILED);
+
+ if (out_size)
+ *out_size = st.st_size;
+
+ return p;
+}
+
+static void font_unmap(void *p, size_t size)
+{
+ int r;
+
+ r = munmap(p, size);
+ ck_assert_int_ge(r, 0);
+}
+
+static int font_fd = -1;
+static void *font_p = NULL;
+static size_t font_size = 0;
+
+static void font_init(void)
+{
+ font_fd = font_open();
+ font_p = font_mmap(font_fd, &font_size);
+}
+
+static void font_destroy(void)
+{
+ if (font_fd < 0)
+ return;
+
+ font_unmap(font_p, font_size);
+ font_close(font_fd);
+ font_fd = -1;
+}
+
+START_TEST(test_misc_setup)
+{
+ int fd;
+ void *p;
+ size_t size;
+
+ fd = font_open();
+ p = font_mmap(fd, &size);
+ font_unmap(p, size);
+ font_close(fd);
+
+ font_init();
+ ck_assert_int_ge(font_fd, 0);
+ font_destroy();
+ ck_assert_int_lt(font_fd, 0);
+ font_destroy();
+ ck_assert_int_lt(font_fd, 0);
+}
+END_TEST
+
+static void font_render(char *w, const uint8_t *glyph, size_t width)
+{
+ unsigned int i, j;
+
+ for (j = 0; j < 16; ++j) {
+ for (i = 0; i < 8 * width; ++i) {
+ if (glyph[i / 8] & (1 << (7 - i % 8)))
+ *w++ = '#';
+ else
+ *w++ = ' ';
+ }
+ *w++ = '\n';
+ glyph += 1 * width;
+ }
+
+ *w++ = 0;
+}
+
+START_TEST(test_misc_draw)
+{
+ char buf[1024];
+ const uint8_t *p, *end, *glyph;
+ size_t size, width;
+ uint32_t header_size, glyph_size;
+
+ font_init();
+
+ p = font_p;
+ size = font_size;
+ end = p + font_size;
+
+ /* parse 4-byte header-size */
+ {
+ ck_assert_int_ge(size, 4);
+ header_size = *(uint32_t*)p;
+ header_size = le32toh(header_size);
+ p += sizeof(uint32_t);
+ }
+
+ /* parse header */
+ {
+ glyph_size = 33;
+
+ switch (header_size) {
+ default:
+ /* fallthrough */
+ case 4:
+ glyph_size = *(uint32_t*)p;
+ glyph_size = le32toh(glyph_size);
+ /* fallthrough */
+ case 0 ... 3:
+ break;
+ }
+
+ ck_assert_int_ge(glyph_size, 33);
+ }
+
+ /* forward @p to end of header */
+ p += header_size;
+
+ /* access glyph 'A' */
+ glyph = p + glyph_size * 'A';
+ ck_assert(end >= glyph + glyph_size);
+ width = *glyph++;
+ ck_assert_int_eq(width, 1);
+
+ /* draw glyph 'A' */
+ font_render(buf, glyph, width);
+ ck_assert(!strcmp(buf,
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " ## \n"
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ " ###### \n"
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ " \n"
+ " \n"
+ ));
+
+ /* access wide glyph 0x4ec0 ('什') */
+ glyph = p + glyph_size * 0x4ec0;
+ ck_assert(end >= glyph + glyph_size);
+ width = *glyph++;
+ ck_assert_int_eq(width, 2);
+
+ /* draw wide glyph */
+ font_render(buf, glyph, width);
+ ck_assert(!strcmp(buf,
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ " ## # \n"
+ " ## ########## \n"
+ " # # # \n"
+ "# # # \n"
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ " # # \n"
+ ));
+
+ /* close font */
+ font_destroy();
+}
+END_TEST
+
+TEST_DEFINE_CASE(misc)
+ TEST(test_misc_setup)
+ TEST(test_misc_draw)
+TEST_END_CASE
+
+TEST_DEFINE(
+ TEST_SUITE(glyphs,
+ TEST_CASE(misc),
+ TEST_END
+ )
+)
diff --git a/test/test-valgrind.c b/test/test-valgrind.c
new file mode 100644
index 0000000..65034c1
--- /dev/null
+++ b/test/test-valgrind.c
@@ -0,0 +1,23 @@
+/* Dummy which just leaks memory. Used to verify valgrind memcheck. */
+
+#include "test-common.h"
+
+START_TEST(test_valgrind)
+{
+ void *p;
+
+ p = malloc(0x100);
+ ck_assert(!!p);
+}
+END_TEST
+
+TEST_DEFINE_CASE(misc)
+ TEST(test_valgrind)
+TEST_END_CASE
+
+TEST_DEFINE(
+ TEST_SUITE(valgrind,
+ TEST_CASE(misc),
+ TEST_END
+ )
+)