From 8bcc111fdc51be1ccd569a6fc984f9467a6c4146 Mon Sep 17 00:00:00 2001 From: Adam Saponara Date: Sat, 4 Jun 2022 17:27:20 -0400 Subject: [PATCH] Run tests for non-truecolor and non-egc builds. This patch introduces a few new things: * Build artifact termbox.ffi.h for easier FFI header file parsing. As a result, no more `__ffi_strip` bs, but probably more complex overall. The other idea I had would have been uglier. I think the test coverage is worth it. * Functions `tb_has_truecolor` and `tb_has_egc` for determining support for those features at runtime. * Test container uses `debian:11-slim` image instead of `debian:10-slim`. * Test container uses PHP 8 instead of PHP 7. * Test container now accepts `cflags` build argument. * Tests can now be skipped via `$test->skip()`. * Test suite covers 3 different builds: normal, non-truecolor, non-egc. --- .github/workflows/termbox_test.yml | 4 +++- Makefile | 12 +++++++---- termbox.h | 27 +++++++++++++++++++---- tests/Dockerfile | 16 ++++++++------ tests/run.sh | 32 +++++++++++++++++----------- tests/test_color_true/test.php | 5 +++++ tests/test_ffi.php | 24 +++++++++++++++------ tests/test_non_spacing_mark/test.php | 5 +++++ 8 files changed, 90 insertions(+), 35 deletions(-) diff --git a/.github/workflows/termbox_test.yml b/.github/workflows/termbox_test.yml index a92e098..23b6a5c 100644 --- a/.github/workflows/termbox_test.yml +++ b/.github/workflows/termbox_test.yml @@ -5,4 +5,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - run: make test + - run: make clean test + - run: CFLAGS='-UTB_OPT_TRUECOLOR' make clean test # non-truecolor + - run: CFLAGS='-UTB_OPT_EGC' make clean test # non-egc diff --git a/Makefile b/Makefile index 48fbd02..ea056f7 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ termbox_so:=libtermbox.so termbox_a:=libtermbox.a termbox_o:=termbox.o termbox_h:=termbox.h +termbox_ffi_h:=termbox.ffi.h all: $(termbox_demos) @@ -21,14 +22,17 @@ $(termbox_so): $(termbox_o) $(termbox_a): $(termbox_o) $(AR) rcs $@ $(termbox_o) +$(termbox_ffi_h): $(termbox_h) + awk '/__ffi_start/{p=1} p==1 || /__TERMBOX_H/{print}' $^ | $(CC) -DTB_OPT_TRUECOLOR -DTB_OPT_EGC $(termbox_cflags) -P -E - >$@ + terminfo: awk -vg=0 'g==0{print} /BEGIN codegen h/{g=1; system("./codegen.sh h")} /END codegen h/{g=0; print} g==1{next}' termbox.h >termbox.h.tmp && mv -vf termbox.h.tmp termbox.h awk -vg=0 'g==0{print} /BEGIN codegen c/{g=1; system("./codegen.sh c")} /END codegen c/{g=0; print} g==1{next}' termbox.h >termbox.h.tmp && mv -vf termbox.h.tmp termbox.h -test: $(termbox_so) - docker build -f tests/Dockerfile . +test: $(termbox_so) $(termbox_ffi_h) + docker build -f tests/Dockerfile --build-arg=cflags="$(termbox_cflags)" . -test_local: $(termbox_so) +test_local: $(termbox_so) $(termbox_ffi_h) ./tests/run.sh install: @@ -36,6 +40,6 @@ install: install -p -m 644 $(termbox_h) $(DESTDIR)$(prefix)/include/$(termbox_h) clean: - rm -f $(termbox_demos) $(termbox_o) $(termbox_a) $(termbox_so) tests/**/observed.ansi + rm -f $(termbox_demos) $(termbox_o) $(termbox_a) $(termbox_so) $(termbox_ffi_h) tests/**/observed.ansi .PHONY: all terminfo test test_local install clean diff --git a/termbox.h b/termbox.h index 9e79824..518b41e 100644 --- a/termbox.h +++ b/termbox.h @@ -57,7 +57,7 @@ SOFTWARE. #include #ifdef __cplusplus -extern "C" { // __ffi_strip +extern "C" { #endif /* ASCII key constants (tb_event.key) */ @@ -297,10 +297,12 @@ extern "C" { // __ffi_strip #define tb_free free #endif +// __ffi_start + #ifdef TB_OPT_TRUECOLOR typedef uint32_t uintattr_t; #else -typedef uint16_t uintattr_t; // __ffi_strip +typedef uint16_t uintattr_t; #endif /* The terminal screen is represented as 2d array of cells. The structure is @@ -517,11 +519,12 @@ int tb_utf8_char_to_unicode(uint32_t *out, const char *c); int tb_utf8_unicode_to_char(char *out, uint32_t c); int tb_last_errno(); const char *tb_strerror(int err); - struct tb_cell *tb_cell_buffer(); +int tb_has_truecolor(); +int tb_has_egc(); #ifdef __cplusplus -} // __ffi_strip +} #endif #endif /* __TERMBOX_H */ @@ -1826,6 +1829,22 @@ const char *tb_strerror(int err) { } } +int tb_has_truecolor() { +#ifdef TB_OPT_TRUECOLOR + return 1; +#else + return 0; +#endif +} + +int tb_has_egc() { +#ifdef TB_OPT_EGC + return 1; +#else + return 0; +#endif +} + static int tb_reset() { int ttyfd_open = global.ttyfd_open; memset(&global, 0, sizeof(global)); diff --git a/tests/Dockerfile b/tests/Dockerfile index c601476..32b506f 100644 --- a/tests/Dockerfile +++ b/tests/Dockerfile @@ -1,14 +1,16 @@ -FROM debian:10-slim -RUN apt update \ - && apt install -y lsb-release apt-transport-https ca-certificates wget \ - && wget -O /etc/apt/trusted.gpg.d/php.gpg 'https://packages.sury.org/php/apt.gpg' \ +FROM debian:11-slim +ARG cflags="" +RUN export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y update >/dev/null \ + && apt-get -y install lsb-release apt-transport-https ca-certificates wget >/dev/null \ + && wget -qO /etc/apt/trusted.gpg.d/php.gpg 'https://packages.sury.org/php/apt.gpg' \ && echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | \ tee /etc/apt/sources.list.d/php.list \ - && apt update \ - && apt install -y make gcc php7.4 php7.4-mbstring xvfb xterm xvkbd locales locales-all + && apt-get -y update >/dev/null \ + && apt-get -y install make gcc php8.0-cli xvfb xterm xvkbd locales locales-all >/dev/null ENV LC_ALL=en_US.UTF-8 \ LANG=en_US.UTF-8 \ LANGUAGE=en_US.UTF-8 COPY . /termbox WORKDIR /termbox -RUN make clean test_local +RUN CFLAGS="${cflags}" make clean test_local diff --git a/tests/run.sh b/tests/run.sh index aef325d..144c2a7 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -67,14 +67,16 @@ main() { local test_log_cursor=0 local test_log_size=0 local test_end_ts=$(($(date +%s) + $timeout_s)) + local test_skipped=0 while true; do - test_log_size=$(stat --format=%s $test_log_cmd 2>/dev/null) + test_log_size=$(stat -c %s $test_log_cmd 2>/dev/null) [ -z "$test_log_size" ] && break # stat failed or deleted [ "$test_log_size" -lt "$test_log_cursor" ] && break # truncated local test_log_content=$(tail -c "+$test_log_cursor" $test_log_cmd | \ head -c "$((test_log_size-test_log_cursor))") test_log_cursor=$test_log_size echo -n "$test_log_content" + grep -q 'skip' <<<"$test_log_content" && test_skipped=1 && break grep -q 'screencap' <<<"$test_log_content" && break sleep 0.1 if [ "$(date +%s)" -ge "$test_end_ts" ]; then @@ -84,20 +86,24 @@ main() { done echo - # take screencap - # xwd -root -display $x_display -out $test_dir/observed.xwd # graphical - rm -f $test_dir/observed.* - DISPLAY=$x_display xvkbd -window xterm -text '\S\[Home]' &>/dev/null # ansi - local test_log_xterm_count=$(ls -1 ${test_log_xterm}* 2>/dev/null | wc -l) - [ "$test_log_xterm_count" -eq 1 ] && cp ${test_log_xterm}* $test_dir/observed.ansi - - # diff screencap - # convert $test_dir/expected.xwd $test_dir/observed.gif - diff $test_dir/expected.ansi $test_dir/observed.ansi &>/dev/null - diff_ec=$? + if [ "$test_skipped" -ne 1 ]; then + # take screencap + # xwd -root -display $x_display -out $test_dir/observed.xwd # graphical + rm -f $test_dir/observed.* + DISPLAY=$x_display xvkbd -window xterm -text '\S\[Home]' &>/dev/null # ansi + local test_log_xterm_count=$(ls -1 ${test_log_xterm}* 2>/dev/null | wc -l) + [ "$test_log_xterm_count" -eq 1 ] && cp ${test_log_xterm}* $test_dir/observed.ansi + + # diff screencap + # convert $test_dir/expected.xwd $test_dir/observed.gif + diff $test_dir/expected.ansi $test_dir/observed.ansi &>/dev/null + diff_ec=$? + fi # print result - if [ "$diff_ec" -eq 0 ]; then + if [ "$test_skipped" -eq 1 ]; then + echo -e "\x1b[1m$test_name\x1b[0m: \x1b[33mSKIP\x1b[0m" + elif [ "$diff_ec" -eq 0 ]; then echo -e "\x1b[1m$test_name\x1b[0m: \x1b[32mOK\x1b[0m" else echo diff --git a/tests/test_color_true/test.php b/tests/test_color_true/test.php index 32ba877..228b050 100755 --- a/tests/test_color_true/test.php +++ b/tests/test_color_true/test.php @@ -1,6 +1,11 @@ ffi->tb_has_truecolor()) { + // This will only work with truecolor support + $test->skip(); +} + $css_colors = [ 'aliceblue' => 0xf0f8ff, 'antiquewhite' => 0xfaebd7, diff --git a/tests/test_ffi.php b/tests/test_ffi.php index 02d8ce7..636b910 100644 --- a/tests/test_ffi.php +++ b/tests/test_ffi.php @@ -13,22 +13,29 @@ $test = new class() { } private function makeFfi(): object { + // This is a little whacky. `FFI::cdef` isn't smart enough to handle + // preprocessor directives, so we feed it a `gcc -E` version of + // termbox.h (termbox.ffi.h, created by the Makefile). On the other + // hand, it's useful to have `#define` constants for tests, so we parse + // those out from the raw `termbox.h`. $repo_dir = dirname(__DIR__); $termbox_h = "$repo_dir/termbox.h"; + $termbox_ffi_h = "$repo_dir/termbox.ffi.h"; $libtermbox_so = "$repo_dir/libtermbox.so"; - $header_data_and_impl = file_get_contents($termbox_h); + $termbox_h_data = file_get_contents($termbox_h); + // Look at only the content in between `__TERMBOX_H` $matches = []; preg_match( '@#define __TERMBOX_H\n(.*?)#endif /\* __TERMBOX_H \*/@sm', - $header_data_and_impl, + $termbox_h_data, $matches ); - $header_data = $matches[1] ?? ''; + $termbox_h_data = $matches[1] ?? ''; // Extract #define values $matches = []; - preg_match_all('/^#define\s+(TB_\S+)\s+(.+)$/m', $header_data, $matches, PREG_SET_ORDER); + preg_match_all('/^#define\s+(TB_\S+)\s+(.+)$/m', $termbox_h_data, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $define_name = $match[1]; $define_value = $match[2]; @@ -47,8 +54,8 @@ $test = new class() { } // Make FFI - $header_data = preg_replace('/^.*__ffi_strip.*$/m', '', $header_data); - $ffi = FFI::cdef($header_data, $libtermbox_so); + $termbox_ffi_h_data = file_get_contents($termbox_ffi_h); + $ffi = FFI::cdef($termbox_ffi_h_data, $libtermbox_so); // Return wrapper that logs FFI calls return new class($ffi, $this) { @@ -97,4 +104,9 @@ $test = new class() { $this->log('screencap'); sleep(PHP_INT_MAX); } + + public function skip(): void { + $this->log('skip'); + sleep(PHP_INT_MAX); + } }; diff --git a/tests/test_non_spacing_mark/test.php b/tests/test_non_spacing_mark/test.php index 3309a60..4546f5c 100755 --- a/tests/test_non_spacing_mark/test.php +++ b/tests/test_non_spacing_mark/test.php @@ -1,6 +1,11 @@ ffi->tb_has_egc()) { + // This will only work with extended grapheme cluster support + $test->skip(); +} + $test->ffi->tb_init(); $test->ffi->tb_print(0, 0, 0, 0, "STARG\xce\x9b\xcc\x8aTE SG-1"); -- 2.39.5