From 9c846ee493862ef11b46942a6e5af3c1ed8468d1 Mon Sep 17 00:00:00 2001 From: Chris Mumford Date: Fri, 27 Aug 2021 06:49:31 -0700 Subject: [PATCH] test convert Makefile to CMake (#2495) * Convert tests/Makefile to a cmake project file. This change switches the building of LVGL tests to use cmake which is more portable than make. Additionally, whenever cmake can be used, instead of the Python script (`main.py`), the former is preferred. The interface to `main.py` is unchanged, and tests are built and executated the same as before. This closes https://github.com/lvgl/lvgl/issues/2474. * Installing `gcovr` in GitHub workflow. * Documented steps to install libpng-dev. * Added missing stdout flush when running tests. * Grammar tweak in README. Co-authored-by: Gabor Kiss-Vamosi --- .github/workflows/ccpp.yml | 2 +- .gitignore | 3 + CMakeLists.txt | 5 +- tests/.gitignore | 1 - tests/CMakeLists.txt | 294 +++++++++++++++++++++++++++++++++++++ tests/Makefile | 56 ------- tests/README.md | 11 +- tests/build.py | 105 ------------- tests/defines.py | 231 ----------------------------- tests/main.py | 207 ++++++++++++++++++++------ tests/src/lv_test_main.c | 17 --- tests/test.py | 22 --- 12 files changed, 474 insertions(+), 480 deletions(-) create mode 100644 tests/CMakeLists.txt delete mode 100644 tests/Makefile delete mode 100755 tests/build.py delete mode 100644 tests/defines.py delete mode 100644 tests/src/lv_test_main.c delete mode 100644 tests/test.py diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 8f6bab37e..f7d83abd3 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v2 - uses: ammaraskar/gcc-problem-matcher@master - name: Run tests - run: sudo apt-get install libpng-dev ruby-full; cd tests; python ./main.py report + run: sudo apt-get install libpng-dev ruby-full gcovr; cd tests; python ./main.py report - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 if: github.event_name == 'push' diff --git a/.gitignore b/.gitignore index 06df6e1a6..6a8878be6 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ out_html __pycache__ /emscripten_builder test_screenshot_error.h +build/ +tests/build_*/ +tests/report/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d2f3cdf4..cdc1e40f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,7 +68,10 @@ endif() # CONFIG_LVGL else() -file(GLOB_RECURSE SOURCES src/*.c) +file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c) add_library(lvgl STATIC ${SOURCES}) +file(GLOB_RECURSE EXAMPLE_SOURCES ${CMAKE_CURRENT_LIST_DIR}/examples/*.c) +add_library(lvgl_examples STATIC ${EXAMPLE_SOURCES}) + endif() diff --git a/tests/.gitignore b/tests/.gitignore index 1fce10c0e..d484e9e15 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,3 +1,2 @@ *.out *_Runner.c -/report \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 000000000..92efe0c77 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,294 @@ +if(ESP_PLATFORM) + +################################### +# Tests do not build for ESP-IDF. # +################################### + +else() + +cmake_minimum_required(VERSION 3.13) +project(lvgl_tests LANGUAGES C) + +set(LVGL_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +set(LVGL_TEST_OPTIONS_MINIMAL_MONOCHROME + -DLV_COLOR_DEPTH=1 + -DLV_MEM_SIZE=65535 + -DLV_DPI_DEF=40 + -DLV_DRAW_COMPLEX=0 + -DLV_USE_METER=0 + -DLV_USE_LOG=1 + -DLV_USE_ASSERT_NULL=0 + -DLV_USE_ASSERT_MALLOC=0 + -DLV_USE_ASSERT_MEM_INTEGRITY=0 + -DLV_USE_ASSERT_OBJ=0 + -DLV_USE_ASSERT_STYLE=0 + -DLV_USE_USER_DATA=0 + -DLV_FONT_UNSCII_8=1 + -DLV_USE_BIDI=0 + -DLV_USE_ARABIC_PERSIAN_CHARS=0 + -DLV_BUILD_EXAMPLES=1 + -DLV_FONT_DEFAULT=&lv_font_montserrat_14 +) + +set(LVGL_TEST_OPTIONS_NORMAL_8BIT + -DLV_COLOR_DEPTH=8 + -DLV_MEM_SIZE=65535 + -DLV_DPI_DEF=40 + -DLV_DRAW_COMPLEX=1 + -DLV_USE_LOG=1 + -DLV_USE_ASSERT_NULL=0 + -DLV_USE_ASSERT_MALLOC=0 + -DLV_USE_ASSERT_MEM_INTEGRITY=0 + -DLV_USE_ASSERT_OBJ=0 + -DLV_USE_ASSERT_STYLE=0 + -DLV_USE_USER_DATA=0 + -DLV_FONT_UNSCII_8=1 + -DLV_USE_FONT_SUBPX=1 + -DLV_USE_BIDI=0 + -DLV_USE_ARABIC_PERSIAN_CHARS=0 + -DLV_BUILD_EXAMPLES=1 + -DLV_FONT_DEFAULT=&lv_font_montserrat_14 +) + +set(LVGL_TEST_OPTIONS_16BIT + -DLV_COLOR_DEPTH=16 + -DLV_COLOR_16_SWAP=0 + -DLV_MEM_SIZE=65536 + -DLV_DPI_DEF=40 + -DLV_DRAW_COMPLEX=1 + -DLV_USE_LOG=1 + -DLV_USE_ASSERT_NULL=0 + -DLV_USE_ASSERT_MALLOC=0 + -DLV_USE_ASSERT_MEM_INTEGRITY=0 + -DLV_USE_ASSERT_OBJ=0 + -DLV_USE_ASSERT_STYLE=0 + -DLV_USE_USER_DATA=0 + -DLV_FONT_UNSCII_8=1 + -DLV_USE_FONT_SUBPX=1 + -DLV_USE_BIDI=0 + -DLV_USE_ARABIC_PERSIAN_CHARS=0 + -DLV_BUILD_EXAMPLES=1 + -DLV_FONT_DEFAULT=&lv_font_montserrat_14 +) + +set(LVGL_TEST_OPTIONS_16BIT_SWAP + -DLV_COLOR_DEPTH=16 + -DLV_COLOR_16_SWAP=1 + -DLV_MEM_SIZE=65536 + -DLV_DPI_DEF=40 + -DLV_DRAW_COMPLEX=1 + -DLV_USE_LOG=1 + -DLV_USE_ASSERT_NULL=0 + -DLV_USE_ASSERT_MALLOC=0 + -DLV_USE_ASSERT_MEM_INTEGRITY=0 + -DLV_USE_ASSERT_OBJ=0 + -DLV_USE_ASSERT_STYLE=0 + -DLV_USE_USER_DATA=0 + -DLV_FONT_UNSCII_8=1 + -DLV_USE_FONT_SUBPX=1 + -DLV_USE_BIDI=0 + -DLV_USE_ARABIC_PERSIAN_CHARS=0 + -DLV_BUILD_EXAMPLES=1 + -DLV_FONT_DEFAULT=&lv_font_montserrat_14 +) + +set(LVGL_TEST_OPTIONS_FULL_32BIT + -DLV_COLOR_DEPTH=32 + -DLV_MEM_SIZE=8388608 + -DLV_DPI_DEF=160 + -DLV_DRAW_COMPLEX=1 + -DLV_SHADOW_CACHE_SIZE=1 + -DLV_IMG_CACHE_DEF_SIZE=32 + -DLV_USE_LOG=1 + -DLV_USE_LOG_LEVEL=LV_LOG_LEVEL_TRACE + -DLV_LOG_PRINTF=1 + -DLV_USE_FONT_SUBPX=1 + -DLV_FONT_SUBPX_BGR=1 + -DLV_USE_PERF_MONITOR=1 + -DLV_USE_ASSERT_NULL=1 + -DLV_USE_ASSERT_MALLOC=1 + -DLV_USE_ASSERT_MEM_INTEGRITY=1 + -DLV_USE_ASSERT_OBJ=1 + -DLV_USE_ASSERT_STYLE=1 + -DLV_USE_USER_DATA=1 + -DLV_USE_LARGE_COORD=1 + -DLV_FONT_MONTSERRAT_8=1 + -DLV_FONT_MONTSERRAT_10=1 + -DLV_FONT_MONTSERRAT_12=1 + -DLV_FONT_MONTSERRAT_14=1 + -DLV_FONT_MONTSERRAT_16=1 + -DLV_FONT_MONTSERRAT_18=1 + -DLV_FONT_MONTSERRAT_20=1 + -DLV_FONT_MONTSERRAT_22=1 + -DLV_FONT_MONTSERRAT_24=1 + -DLV_FONT_MONTSERRAT_26=1 + -DLV_FONT_MONTSERRAT_28=1 + -DLV_FONT_MONTSERRAT_30=1 + -DLV_FONT_MONTSERRAT_32=1 + -DLV_FONT_MONTSERRAT_34=1 + -DLV_FONT_MONTSERRAT_36=1 + -DLV_FONT_MONTSERRAT_38=1 + -DLV_FONT_MONTSERRAT_40=1 + -DLV_FONT_MONTSERRAT_42=1 + -DLV_FONT_MONTSERRAT_44=1 + -DLV_FONT_MONTSERRAT_46=1 + -DLV_FONT_MONTSERRAT_48=1 + -DLV_FONT_MONTSERRAT_12_SUBPX=1 + -DLV_FONT_MONTSERRAT_28_COMPRESSED=1 + -DLV_FONT_DEJAVU_16_PERSIAN_HEBREW=1 + -DLV_FONT_SIMSUN_16_CJK=1 + -DLV_FONT_UNSCII_8=1 + -DLV_FONT_UNSCII_16=1 + -DLV_FONT_FMT_TXT_LARGE=1 + -DLV_USE_FONT_COMPRESSED=1 + -DLV_USE_BIDI=1 + -DLV_USE_ARABIC_PERSIAN_CHARS=1 + -DLV_USE_PERF_MONITOR=1 + -DLV_USE_MEM_MONITOR=1 + -DLV_LABEL_TEXT_SELECTION=1 + -DLV_BUILD_EXAMPLES=1 + -DLV_FONT_DEFAULT=&lv_font_montserrat_24 + ) + + set(LVGL_TEST_OPTIONS_TEST + --coverage + -DLV_COLOR_DEPTH=32 + -DLV_MEM_SIZE=2097152 + -DLV_SHADOW_CACHE_SIZE=10240 + -DLV_IMG_CACHE_DEF_SIZE=32 + -DLV_USE_LOG=1 + -DLV_LOG_PRINTF=1 + -DLV_USE_FONT_SUBPX=1 + -DLV_FONT_SUBPX_BGR=1 + -DLV_USE_ASSERT_NULL=0 + -DLV_USE_ASSERT_MALLOC=0 + -DLV_USE_ASSERT_MEM_INTEGRITY=0 + -DLV_USE_ASSERT_OBJ=0 + -DLV_USE_ASSERT_STYLE=0 + -DLV_USE_USER_DATA=1 + -DLV_USE_LARGE_COORD=1 + -DLV_FONT_MONTSERRAT_14=1 + -DLV_FONT_MONTSERRAT_16=1 + -DLV_FONT_MONTSERRAT_18=1 + -DLV_FONT_MONTSERRAT_24=1 + -DLV_FONT_MONTSERRAT_48=1 + -DLV_FONT_MONTSERRAT_12_SUBPX=1 + -DLV_FONT_MONTSERRAT_28_COMPRESSED=1 + -DLV_FONT_DEJAVU_16_PERSIAN_HEBREW=1 + -DLV_FONT_SIMSUN_16_CJK=1 + -DLV_FONT_UNSCII_8=1 + -DLV_FONT_UNSCII_16=1 + -DLV_FONT_FMT_TXT_LARGE=1 + -DLV_USE_FONT_COMPRESSED=1 + -DLV_USE_BIDI=1 + -DLV_USE_ARABIC_PERSIAN_CHARS=1 + -DLV_LABEL_TEXT_SELECTION=1 + -DLV_BUILD_EXAMPLES=1 + -DLV_FONT_DEFAULT=&lv_font_montserrat_14 +) + +if (OPTIONS_MINIMAL_MONOCHROME) + set (TEST_OPTIONS ${LVGL_TEST_OPTIONS_MINIMAL_MONOCHROME}) +elseif (OPTIONS_NORMAL_8BIT) + set (TEST_OPTIONS ${LVGL_TEST_OPTIONS_NORMAL_8BIT}) +elseif (OPTIONS_16BIT) + set (TEST_OPTIONS ${LVGL_TEST_OPTIONS_16BIT}) +elseif (OPTIONS_16BIT_SWAP) + set (TEST_OPTIONS ${LVGL_TEST_OPTIONS_16BIT_SWAP}) +elseif (OPTIONS_FULL_32BIT) + set (TEST_OPTIONS ${LVGL_TEST_OPTIONS_FULL_32BIT}) +elseif (OPTIONS_TEST) + set (TEST_OPTIONS ${LVGL_TEST_OPTIONS_TEST}) + set (TEST_LIBS --coverage) +else() + message(FATAL_ERROR "Must provide an options value.") +endif() + +# Options lvgl and all test files are compiled with. +set(COMPILE_OPTIONS + -DLV_CONF_PATH=${LVGL_TEST_DIR}/src/lv_test_conf.h + -DLV_BUILD_TEST + -pedantic-errors + -Wall + -Wclobbered + -Wdeprecated + -Wdouble-promotion + -Wempty-body + -Werror + -Wextra + -Wformat-security + -Wmaybe-uninitialized + -Wmissing-prototypes + -Wpointer-arith + -Wmultichar + -Wno-discarded-qualifiers + -Wpedantic + -Wreturn-type + -Wshadow + -Wshift-negative-value + -Wsizeof-pointer-memaccess + -Wstack-usage=2048 + -Wtype-limits + -Wundef + -Wuninitialized + -Wunreachable-code + ${TEST_OPTIONS} +) + +get_filename_component(LVGL_DIR ${LVGL_TEST_DIR} DIRECTORY) + +# Include lvgl project file. +include(${LVGL_DIR}/CMakeLists.txt) +target_compile_options(lvgl PUBLIC ${COMPILE_OPTIONS}) +target_compile_options(lvgl_examples PUBLIC ${COMPILE_OPTIONS}) + + +set(TEST_INCLUDE_DIRS + $ + $ + $ +) + +add_library(test_common + STATIC + src/lv_test_indev.c + src/lv_test_init.c + src/test_fonts/font_1.c + src/test_fonts/font_2.c + src/test_fonts/font_3.c + unity/unity_support.c + unity/unity.c +) +target_include_directories(test_common PUBLIC ${TEST_INCLUDE_DIRS}) +target_compile_options(test_common PUBLIC ${COMPILE_OPTIONS}) + +# Some examples `#include "lvgl/lvgl.h"` - which is a path which is not +# in this source repository. If this repo is in a directory names 'lvgl' +# then we can add our parent directory to the include path. +# TODO: This is not good practice and should be fixed. +get_filename_component(LVGL_PARENT_DIR ${LVGL_DIR} DIRECTORY) +target_include_directories(lvgl_examples PUBLIC $) + +# Generate one test executable for each source file pair. +# The sources in src/test_runners is auto-generated, the +# sources in src/test_cases is the actual test case. +file( GLOB TEST_CASE_FILES src/test_cases/*.c ) +foreach( test_case_fname ${TEST_CASE_FILES} ) + # If test file is foo/bar/baz.c then test_name is "baz". + get_filename_component(test_name ${test_case_fname} NAME_WLE) + if (${test_name} STREQUAL "_test_template") + continue() + endif() + # Create path to auto-generated source file. + set(test_runner_fname src/test_runners/${test_name}_Runner.c) + add_executable( ${test_name} + ${test_case_fname} + ${test_runner_fname} + ) + target_link_libraries(${test_name} test_common lvgl_examples lvgl png ${TEST_LIBS}) + target_include_directories(${test_name} PUBLIC ${TEST_INCLUDE_DIRS}) + target_compile_options(${test_name} PUBLIC ${COMPILE_OPTIONS}) +endforeach( test_case_fname ${TEST_CASE_FILES} ) + +endif() diff --git a/tests/Makefile b/tests/Makefile deleted file mode 100644 index 1ecc96aa5..000000000 --- a/tests/Makefile +++ /dev/null @@ -1,56 +0,0 @@ -# -# Makefile -# -CC ?= gcc -LVGL_DIR ?= ${shell pwd}/../.. -LVGL_DIR_NAME ?= lvgl - -WARNINGS = -Werror -Wall -Wextra \ - -Wshadow -Wundef -Wmaybe-uninitialized -Wmissing-prototypes -Wpointer-arith -Wuninitialized \ - -Wunreachable-code -Wreturn-type -Wmultichar -Wformat-security -Wdouble-promotion -Wclobbered -Wdeprecated \ - -Wempty-body -Wshift-negative-value -Wstack-usage=2048 \ - -Wtype-limits -Wsizeof-pointer-memaccess -Wmissing-prototypes -Wno-discarded-qualifiers - -WARNINGS += -Wpedantic -pedantic-errors - -#-Wno-unused-value -Wno-unused-parameter -OPTIMIZATION ?= -g0 - -CFLAGS ?= -I$(LVGL_DIR)/ --coverage -Isrc -Iunity $(DEFINES) $(WARNINGS) $(OPTIMIZATION) -I$(LVGL_DIR) -I. - -LDFLAGS ?= -lpng --coverage -BIN ?= test - -include ../lvgl.mk - -CSRCS += ${TEST_SRC} -CSRCS += src/lv_test_init.c -CSRCS += src/lv_test_indev.c -CSRCS := $(CSRCS) $(EXTRA_CSRCS) - -OBJEXT ?= .o - -AOBJS = $(ASRCS:.S=$(OBJEXT)) -COBJS = $(CSRCS:.c=$(OBJEXT)) - -MAINOBJ = $(MAINSRC:.c=$(OBJEXT)) - -SRCS = $(ASRCS) $(CSRCS) $(MAINSRC) -OBJS = $(AOBJS) $(COBJS) - -## MAINOBJ -> OBJFILES - -all: default - -%.o: %.c - @$(CC) $(CFLAGS) -c -o $@ $< -# @echo "CC $<" - -default: $(AOBJS) $(COBJS) $(MAINOBJ) - $(CC) -o $(BIN) $(MAINOBJ) $(AOBJS) $(COBJS) $(LDFLAGS) - -clean: - find ../ -type f -name '*.o' -exec rm -f {} + - find ../ -type f -name '*.gcda' -exec rm -f {} + - find ../ -type f -name '*.gcno' -exec rm -f {} + - rm -f $(BIN) diff --git a/tests/README.md b/tests/README.md index 56c9223b9..8481a3522 100644 --- a/tests/README.md +++ b/tests/README.md @@ -5,9 +5,11 @@ The tests in the folder can be run locally and automatically by GitHub CI. ## Running locally ### Requirements (Linux) -1. Be sure GCC and Python3 is installed. -2. Install [gcovr](https://gcovr.com/en/stable/index.html) with `pip install gcovr` -3. Install Ruby with `sudo apt-get install ruby-full` +1. Be sure GCC and Python3 are installed. +2. Install [cmake](https://cmake.org/) with `sudo apt install cmake`. +3. Install [gcovr](https://gcovr.com/en/stable/index.html) with `sudo apt install gcovr` +4. Install Ruby with `sudo apt install ruby-full` +5. Install libpng development package with `sudo apt install libpng-dev` ### Run test 1. Enter `lvgl/tests/` @@ -18,11 +20,10 @@ The tests in the folder can be run locally and automatically by GitHub CI. For example: - `./main.py` Run all the test as they run in the CI. -- `./main.py report test noclean` Run only the test, should be sued when writing tests. +- `./main.py report test noclean` Run only the test, should be used when writing tests. ## Running automatically -TODO GitHub's CI automatically runs these tests on pushes and pull requests to `master` and `releasev8.*` branches. diff --git a/tests/build.py b/tests/build.py deleted file mode 100755 index 9275c0016..000000000 --- a/tests/build.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python3 - -import os -import re -import subprocess - -test_dir = os.path.dirname(os.path.realpath(__file__)) -lvgl_dir = os.path.abspath(os.path.join(test_dir, os.pardir)) -lvgl_dir_name = 'lvgl' # LVGL subdirectory (base name) in lvgl_dir. -lvgl_parent_dir = os.path.abspath(os.path.join(lvgl_dir, os.pardir)) - -lv_conf_path = os.path.join(lvgl_dir, 'tests/src/lv_test_conf.h') -base_defines = ['-DLV_CONF_PATH="%s"' % lv_conf_path, '-DLV_BUILD_TEST'] - -def maybe_quote(obj): - if type(obj) == str: - return '"%s"' % obj - return obj - - -def zip_defines(defines): - return ['-D%s=%s' % (key, maybe_quote(defines[key])) for key in defines] - - -def build(defines): - global base_defines - optimization = ['-O3', '-g0'] - d_all = base_defines + zip_defines(defines) - - cmd_env = os.environ.copy() - cmd_env['BIN'] = 'test.bin' - cmd_env['MAINSRC'] = 'src/lv_test_main.c' - cmd_env['LVGL_DIR'] = lvgl_parent_dir - cmd_env['LVGL_DIR_NAME'] = lvgl_dir_name - cmd_env['DEFINES'] = ' '.join(d_all) - cmd_env['OPTIMIZATION'] = ' '.join(optimization) - - print("") - print("Build") - print("-----------------------", flush=True) - # -s makes it silence - subprocess.check_call(['make', '-s', '--jobs=%d' % os.cpu_count()], env=cmd_env) - - print("") - print("Run") - print("-----------------------", flush=True) - subprocess.check_call("./test.bin") - - -def build_test(defines, test_name): - global base_defines - optimization = ['-g0'] - - print("") - print("") - print("~~~~~~~~~~~~~~~~~~~~~~~~") - print(re.search("/[a-z_]*$", test_name).group(0)[1:]) - print("~~~~~~~~~~~~~~~~~~~~~~~~", flush=True) - - d_all = base_defines + zip_defines(defines) - - test_file_name = test_name + ".c" - test_file_runner_name = test_name + "_Runner.c" - test_file_runner_name = test_file_runner_name.replace( - "/test_cases/", "/test_runners/") - cmd_env = os.environ.copy() - cmd_env['BIN'] = 'test.bin' - cmd_env['MAINSRC'] = test_file_name - cmd_env['TEST_SRC'] = test_file_runner_name - cmd_env['LVGL_DIR'] = lvgl_parent_dir - cmd_env['LVGL_DIR_NAME'] = lvgl_dir_name - cmd_env['DEFINES'] = ' '.join(d_all) - cmd_env['OPTIMIZATION'] = ' '.join(optimization) - extra_csrcs = [ - 'unity/unity.c', 'unity/unity_support.c', - 'src/test_fonts/font_1.c', 'src/test_fonts/font_2.c', - 'src/test_fonts/font_3.c' - ] - cmd_env['EXTRA_CSRCS'] = ' '.join(extra_csrcs) - - print("") - print("Build") - print("-----------------------", flush=True) - # -s makes it silence - subprocess.check_call(['make', '-s', '--jobs=%d' % os.cpu_count()], env=cmd_env) - - print("") - print("Run") - print("-----------------------") - subprocess.check_call('./test.bin') - - -def clean(): - print("") - print("Clean") - print("-----------------------", flush=True) - - cmd_env = os.environ.copy() - cmd_env['LVGL_DIR'] = lvgl_parent_dir - cmd_env['LVGL_DIR_NAME'] = lvgl_dir_name - subprocess.check_call(['make', 'clean'], env=cmd_env) - try: - os.remove('test.bin') - except FileNotFoundError: - pass diff --git a/tests/defines.py b/tests/defines.py deleted file mode 100644 index a34a0a741..000000000 --- a/tests/defines.py +++ /dev/null @@ -1,231 +0,0 @@ - -minimal_monochrome = { - "LV_COLOR_DEPTH":1, - "LV_MEM_SIZE":64 * 1024, - - "LV_DPI_DEF":40, - "LV_DRAW_COMPLEX":0, - "LV_USE_METER":0, - - "LV_USE_LOG":1, - - "LV_USE_ASSERT_NULL":0, - "LV_USE_ASSERT_MALLOC":0, - "LV_USE_ASSERT_MEM_INTEGRITY":0, - "LV_USE_ASSERT_OBJ":0, - "LV_USE_ASSERT_STYLE":0, - - "LV_USE_USER_DATA": 0, - - "LV_FONT_UNSCII_8":1, - - "LV_USE_BIDI": 0, - "LV_USE_ARABIC_PERSIAN_CHARS":0, - - "LV_BUILD_EXAMPLES":1, - - "LV_FONT_DEFAULT":"&lv_font_montserrat_14", - -} - -normal_8bit = { - "LV_COLOR_DEPTH":8, - - "LV_MEM_SIZE":64 * 1024, - - "LV_DPI_DEF":40, - "LV_DRAW_COMPLEX":1, - - "LV_USE_LOG":1, - - "LV_USE_ASSERT_NULL":0, - "LV_USE_ASSERT_MALLOC":0, - "LV_USE_ASSERT_MEM_INTEGRITY":0, - "LV_USE_ASSERT_OBJ":0, - "LV_USE_ASSERT_STYLE":0, - - "LV_USE_USER_DATA": 0, - - "LV_FONT_UNSCII_8":1, - - "LV_USE_FONT_SUBPX": 1, - "LV_USE_BIDI": 0, - "LV_USE_ARABIC_PERSIAN_CHARS":0, - - "LV_BUILD_EXAMPLES":1, - - "LV_FONT_DEFAULT":"&lv_font_montserrat_14", -} - - -minimal_16bit = { - "LV_COLOR_DEPTH":16, - "LV_MEM_CUSTOM":1, - - "LV_DPI_DEF":40, - "LV_DRAW_COMPLEX":0, - "LV_USE_METER":0, - - "LV_USE_LOG":1, - - "LV_USE_ASSERT_NULL":0, - "LV_USE_ASSERT_MALLOC":0, - "LV_USE_ASSERT_MEM_INTEGRITY":0, - "LV_USE_ASSERT_OBJ":0, - "LV_USE_ASSERT_STYLE":0, - - "LV_USE_USER_DATA": 0, - - "LV_FONT_UNSCII_8":1, - - "LV_USE_BIDI": 0, - "LV_USE_ARABIC_PERSIAN_CHARS":0, - - "LV_BUILD_EXAMPLES":1, - - "LV_FONT_DEFAULT":"&lv_font_montserrat_14", - -} - -normal_16bit_swap = { - "LV_COLOR_DEPTH":16, - "LV_COLOR_16_SWAP":1, - - "LV_MEM_SIZE":64 * 1024, - - "LV_DPI_DEF":40, - "LV_DRAW_COMPLEX":1, - - "LV_USE_LOG":1, - - "LV_USE_ASSERT_NULL":0, - "LV_USE_ASSERT_MALLOC":0, - "LV_USE_ASSERT_MEM_INTEGRITY":0, - "LV_USE_ASSERT_OBJ":0, - "LV_USE_ASSERT_STYLE":0, - - "LV_USE_USER_DATA": 0, - - "LV_FONT_UNSCII_8":1, - - "LV_USE_FONT_SUBPX": 1, - "LV_USE_BIDI": 0, - "LV_USE_ARABIC_PERSIAN_CHARS":0, - - "LV_BUILD_EXAMPLES":1, - - "LV_FONT_DEFAULT":"&lv_font_montserrat_14", -} - -full_32bit = { - "LV_COLOR_DEPTH":32, - "LV_MEM_SIZE":8 * 1024 * 1024, - - "LV_DPI_DEF":160, - "LV_DRAW_COMPLEX":1, - "LV_SHADOW_CACHE_SIZE":1, - "LV_IMG_CACHE_DEF_SIZE":32, - - "LV_USE_LOG":1, - "LV_USE_LOG_LEVEL":"LV_LOG_LEVEL_TRACE", - "LV_LOG_PRINTF":1, - "LV_USE_FONT_SUBPX": 1, - "LV_FONT_SUBPX_BGR":1, - "LV_USE_PERF_MONITOR":1, - - "LV_USE_ASSERT_NULL":1, - "LV_USE_ASSERT_MALLOC":1, - "LV_USE_ASSERT_MEM_INTEGRITY":1, - "LV_USE_ASSERT_OBJ":1, - "LV_USE_ASSERT_STYLE":1, - - "LV_USE_USER_DATA": 1, - - "LV_USE_LARGE_COORD": 1, - - "LV_FONT_MONTSERRAT_8":1, - "LV_FONT_MONTSERRAT_10":1, - "LV_FONT_MONTSERRAT_12":1, - "LV_FONT_MONTSERRAT_14":1, - "LV_FONT_MONTSERRAT_16":1, - "LV_FONT_MONTSERRAT_18":1, - "LV_FONT_MONTSERRAT_20":1, - "LV_FONT_MONTSERRAT_22":1, - "LV_FONT_MONTSERRAT_24":1, - "LV_FONT_MONTSERRAT_26":1, - "LV_FONT_MONTSERRAT_28":1, - "LV_FONT_MONTSERRAT_30":1, - "LV_FONT_MONTSERRAT_32":1, - "LV_FONT_MONTSERRAT_34":1, - "LV_FONT_MONTSERRAT_36":1, - "LV_FONT_MONTSERRAT_38":1, - "LV_FONT_MONTSERRAT_40":1, - "LV_FONT_MONTSERRAT_42":1, - "LV_FONT_MONTSERRAT_44":1, - "LV_FONT_MONTSERRAT_46":1, - "LV_FONT_MONTSERRAT_48":1, - "LV_FONT_MONTSERRAT_12_SUBPX":1, - "LV_FONT_MONTSERRAT_28_COMPRESSED":1, - "LV_FONT_DEJAVU_16_PERSIAN_HEBREW":1, - "LV_FONT_SIMSUN_16_CJK":1, - "LV_FONT_UNSCII_8":1, - "LV_FONT_UNSCII_16":1, - "LV_FONT_FMT_TXT_LARGE":1, - "LV_USE_FONT_COMPRESSED":1, - - "LV_USE_BIDI": 1, - "LV_USE_ARABIC_PERSIAN_CHARS":1, - "LV_USE_PERF_MONITOR":1, - "LV_USE_MEM_MONITOR":1, - - "LV_LABEL_TEXT_SELECTION":1, - - "LV_BUILD_EXAMPLES":1, - - "LV_FONT_DEFAULT":"&lv_font_montserrat_24", -} - -test = { - "LV_COLOR_DEPTH":32, - "LV_MEM_SIZE":2 * 1024 * 1024, - - "LV_SHADOW_CACHE_SIZE":10*1024, - "LV_IMG_CACHE_DEF_SIZE":32, - - "LV_USE_LOG":1, - "LV_LOG_PRINTF":1, - "LV_USE_FONT_SUBPX": 1, - "LV_FONT_SUBPX_BGR":1, - - "LV_USE_ASSERT_NULL":0, - "LV_USE_ASSERT_MALLOC":0, - "LV_USE_ASSERT_MEM_INTEGRITY":0, - "LV_USE_ASSERT_OBJ":0, - "LV_USE_ASSERT_STYLE":0, - - "LV_USE_USER_DATA": 1, - "LV_USE_LARGE_COORD": 1, - - "LV_FONT_MONTSERRAT_14":1, - "LV_FONT_MONTSERRAT_16":1, - "LV_FONT_MONTSERRAT_18":1, - "LV_FONT_MONTSERRAT_24":1, - "LV_FONT_MONTSERRAT_48":1, - "LV_FONT_MONTSERRAT_12_SUBPX":1, - "LV_FONT_MONTSERRAT_28_COMPRESSED":1, - "LV_FONT_DEJAVU_16_PERSIAN_HEBREW":1, - "LV_FONT_SIMSUN_16_CJK":1, - "LV_FONT_UNSCII_8":1, - "LV_FONT_UNSCII_16":1, - "LV_FONT_FMT_TXT_LARGE":1, - "LV_USE_FONT_COMPRESSED":1, - - "LV_USE_BIDI": 1, - "LV_USE_ARABIC_PERSIAN_CHARS":1, - - "LV_LABEL_TEXT_SELECTION":1, - - "LV_BUILD_EXAMPLES":1, - - "LV_FONT_DEFAULT":"&lv_font_montserrat_14", -} diff --git a/tests/main.py b/tests/main.py index 79898c81a..48346c0d4 100755 --- a/tests/main.py +++ b/tests/main.py @@ -1,55 +1,180 @@ #!/usr/bin/env python3 -import defines -import build +import glob import shutil -import test +import subprocess import sys import os +lvgl_test_dir = os.path.dirname(os.path.realpath(__file__)) +num_test_case_failures = 0 -def build_conf(title, defs): - print("") - print("") - print("============================================") - print(title) - print("============================================") - print("", flush=True) +# Key values must match variable names in CMakeLists.txt. +options = { + 'OPTIONS_MINIMAL_MONOCHROME': 'Minimal config monochrome', + 'OPTIONS_NORMAL_8BIT': 'Normal config, 8 bit color depth', + 'OPTIONS_16BIT': 'Minimal config, 16 bit color depth', + 'OPTIONS_16BIT_SWAP': 'Normal config, 16 bit color depth swapped', + 'OPTIONS_FULL_32BIT': 'Full config, 32 bit color depth', + 'OPTIONS_TEST': 'Test config, 32 bit color depth', +} - build.clean() - build.build(defs) +# Most test configurations only build - this is the one that also +# executes. +run_tests_option_name = 'OPTIONS_TEST' -test_only = "test" in sys.argv -test_report = "report" in sys.argv -test_noclean = "noclean" in sys.argv - -if not test_only: - build_conf("Minimal config monochrome", defines.minimal_monochrome) - build_conf("Normal config, 8 bit color depth", defines.normal_8bit) - build_conf("Minimal config, 16 bit color depth", defines.minimal_16bit) - build_conf("Normal config, 16 bit color depth swapped", - defines.normal_16bit_swap) - build_conf("Full config, 32 bit color depth", defines.full_32bit) - - -files = test.prepare() -if test_noclean == False: - build.clean() - -for f in files: - name = f[:-2] # test_foo.c -> test_foo - build.build_test(defines.test, name) - -if test_report: - print("") - print("Generating report") - print("-----------------------", flush=True) +def delete_dir_ignore_missing(dir_path): + '''Recursively delete a directory and ignore if missing.''' try: - shutil.rmtree('report') + shutil.rmtree(dir_path) except FileNotFoundError: pass + + +def generate_test_runners(): + '''Generate the test runner source code. + + Returns a list of test names.''' + global lvgl_test_dir + os.chdir(lvgl_test_dir) + delete_dir_ignore_missing('src/test_runners') + os.mkdir('src/test_runners') + + # TODO: Intermediate files should be in the build folders, not alongside + # the other repo source. + test_names = [] + for f in glob.glob("./src/test_cases/test_*.c"): + test_names.append(os.path.splitext(os.path.basename(f))[0]) + r = f[:-2] + "_Runner.c" + r = r.replace("/test_cases/", "/test_runners/") + subprocess.check_call(['ruby', 'unity/generate_test_runner.rb', + f, r, 'config.yml']) + return test_names + + +def options_abbrev(options_name): + '''Return an abbreviated version of the option name.''' + prefix = 'OPTIONS_' + assert options_name.startswith(prefix) + return options_name[len(prefix):].lower() + + +def get_build_dir(options_name): + '''Given the build options name, return the build directory name. + + Does not return the full path to the directory - just the base name.''' + return 'build_%s' % options_abbrev(options_name) + + +def delete_build_dir(options_name): + '''Recursively delete the build directory for the given options name.''' + global lvgl_test_dir + build_dir = os.path.join(lvgl_test_dir, get_build_dir(options_name)) + delete_dir_ignore_missing(build_dir) + + +def build_tests(options_name, build_type): + '''Build all tests for the specified options name.''' + global options, lvgl_test_dir, test_noclean + + print() + print() + label = 'Building: %s: %s' % (options_abbrev( + options_name), options[options_name]) + print('=' * len(label)) + print(label) + print('=' * len(label)) + print(flush=True) + + if not test_noclean: + delete_build_dir(options_name) + + os.chdir(lvgl_test_dir) + build_dir = get_build_dir(options_name) + created_build_dir = False + if not os.path.isdir(build_dir): + os.mkdir(build_dir) + created_build_dir = True + os.chdir(build_dir) + if created_build_dir: + subprocess.check_call(['cmake', '-DCMAKE_BUILD_TYPE=%s' % build_type, + '-D%s=1' % options_name, '..']) + subprocess.check_call(['cmake', '--build', os.path.join(lvgl_test_dir, build_dir), + '--parallel', str(os.cpu_count())]) + + +def run_tests(options_name, test_names): + '''Run the tests for the given options name.''' + global num_test_case_failures + relative_bd = get_build_dir(options_name) + abs_bd = os.path.join(lvgl_test_dir, relative_bd) + for test_name in test_names: + + print() + print() + label = 'Running: %s' % os.path.join( + options_abbrev(options_name), test_name) + print('=' * len(label)) + print(label) + print('=' * len(label), flush=True) + + try: + os.chdir(lvgl_test_dir) + subprocess.check_call([os.path.join(abs_bd, test_name)]) + except subprocess.CalledProcessError as e: + num_test_case_failures += 1 + + +def generate_code_coverage_report(): + '''Produce code coverage test reports for the test execution.''' + global lvgl_test_dir + + print() + print() + label = 'Generating code coverage reports' + print('=' * len(label)) + print(label) + print('=' * len(label)) + print(flush=True) + + os.chdir(lvgl_test_dir) + delete_dir_ignore_missing('report') os.mkdir('report') - os.system("gcovr -r ../ --html-details -o report/index.html --exclude-directories '\.\./examples' --exclude-directories 'src/.*' --exclude-directories 'unity' --exclude 'lv_test_.*\.c'") - os.system("gcovr -r ../ -x report/coverage.xml --exclude-directories '\.\./examples' --exclude-directories 'src/.*' --exclude-directories 'unity' --exclude 'lv_test_.*\.c'") - print("Done: See report/index.html", flush=True) + root_dir = os.pardir + html_report_file = 'report/index.html' + cmd = ['gcovr', '--root', root_dir, '--html-details', '--output', + html_report_file, '--xml', 'report/coverage.xml', + '-j', str(os.cpu_count()), '--print-summary', + '--html-title', 'LVGL Test Coverage'] + for d in ('.*\\bexamples/.*', '\\bsrc/test_.*', '\\bsrc/lv_test.*', '\\bunity\\b'): + cmd.extend(['--exclude', d]) + + subprocess.check_call(cmd) + print("Done: See %s" % html_report_file, flush=True) + + +run_test_only = "test" in sys.argv +generate_gcov_report = "report" in sys.argv +test_noclean = "noclean" in sys.argv + +test_names = generate_test_runners() + +for options_name in options.keys(): + is_test = options_name == run_tests_option_name + build_type = 'Release' if is_test else 'Debug' + if is_test or not run_test_only: + build_tests(options_name, build_type) + if options_name == run_tests_option_name: + run_tests(options_name, test_names) + +if generate_gcov_report: + generate_code_coverage_report() + +print() +if num_test_case_failures: + print('There were %d test case failures.' % + num_test_case_failures, file=sys.stderr) +else: + print('All test cases passed.') +sys.exit(num_test_case_failures) diff --git a/tests/src/lv_test_main.c b/tests/src/lv_test_main.c deleted file mode 100644 index 52f467601..000000000 --- a/tests/src/lv_test_main.c +++ /dev/null @@ -1,17 +0,0 @@ -#if LV_BUILD_TEST && !defined(LV_BUILD_TEST_NO_MAIN) -#include "../lvgl.h" -#include -#include - -#include -#include "lv_test_init.h" - -int main(void) -{ - lv_test_init(); - - printf("Exit with success!\n"); - return 0; -} - -#endif diff --git a/tests/test.py b/tests/test.py deleted file mode 100644 index 52ca66674..000000000 --- a/tests/test.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import glob - -def prepare(): - os.system("rm src/*.o") - os.system("rm -rdf src/test_runners") - os.system("mkdir src/test_runners") - files = glob.glob("./src/test_cases/test_*.c") - - for index, item in enumerate(files): - if item == "./src/test_cases/test_config.c": - files.pop(index) - break - - files.insert(0, "./src/test_cases/test_config.c") - - for f in files: - r = f[:-2] + "_Runner.c" - r = r.replace("/test_cases/", "/test_runners/") - cmd = "ruby unity/generate_test_runner.rb " + f + " " + r + " config.yml" - os.system(cmd) - return files