From a5dae11c4c30c9cd0bc73cc542d462760a815808 Mon Sep 17 00:00:00 2001 From: Thomas Jensen Date: Wed, 20 Oct 2021 22:28:34 +0200 Subject: [PATCH] Add the first cmocka-based unit tests --- .github/workflows/boxes.yml | 9 +++-- .gitignore | 1 + .vscode/c_cpp_properties.json | 3 +- .vscode/settings.json | 8 +++- Makefile | 14 ++++++- src/Makefile | 8 ++-- test/testrunner.sh | 6 +-- utest/Makefile | 74 +++++++++++++++++++++++++++++++++++ utest/global_mock.c | 34 ++++++++++++++++ utest/report.sh | 37 ++++++++++++++++++ utest/tools_test.c | 70 +++++++++++++++++++++++++++++++++ 11 files changed, 251 insertions(+), 13 deletions(-) create mode 100644 utest/Makefile create mode 100644 utest/global_mock.c create mode 100755 utest/report.sh create mode 100644 utest/tools_test.c diff --git a/.github/workflows/boxes.yml b/.github/workflows/boxes.yml index b332296..1ac0294 100644 --- a/.github/workflows/boxes.yml +++ b/.github/workflows/boxes.yml @@ -11,16 +11,19 @@ jobs: - name: add-packages run: | sudo apt-get update -y - sudo apt-get install -y git flex bison libunistring-dev libpcre2-dev diffutils vim-common lcov + sudo apt-get install -y git flex bison libunistring-dev libpcre2-dev diffutils vim-common lcov libcmocka-dev - name: make cov run: make cov - - name: make covtest + - name: Run white-box tests + run: make utest + + - name: Run black-box tests run: make covtest - name: Coveralls uses: coverallsapp/github-action@master with: github-token: ${{ secrets.GITHUB_TOKEN }} - path-to-lcov: out/lcov-blackbox.info + path-to-lcov: out/lcov-total.info diff --git a/.gitignore b/.gitignore index 1f3ea5d..b8a1e8f 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ /doc/boxes.1.html /pcre2-*/ /flex_bison_*/ +/cmocka-*/ /out/ *.o *.a diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index de12a45..6ec274e 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -6,7 +6,8 @@ "${workspaceFolder}/src", "${workspaceFolder}/src/misc", "${workspaceFolder}/out", - "${workspaceFolder}/pcre2-10.36/src" + "${workspaceFolder}/pcre2-10.36/src", + "${workspaceFolder}/cmocka-1.1.0/include" ], "defines": [ "_DEBUG", diff --git a/.vscode/settings.json b/.vscode/settings.json index e6509d0..1c214a7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,7 +6,10 @@ "**/_support": true, "**/cmake-build-debug": true, "**/coverage": true, - "**/out": true + "**/out": true, + "**/flex_bison_*": true, + "**/pcre2-*": true, + "**/cmocka-*": true }, "editor.autoClosingBrackets": "never", "editor.dragAndDrop": false, @@ -31,7 +34,8 @@ "**/_site/**", "**/_support/**", "**/flex_bison_*/**", - "**/pcre2-*/**" + "**/pcre2-*/**", + "**/cmocka-*/**" ], "todo-tree.general.statusBar": "total", "todo-tree.general.tags": ["TODO", "FIXME", "CHECK"], diff --git a/Makefile b/Makefile index 2a0e4d9..a627aac 100644 --- a/Makefile +++ b/Makefile @@ -32,9 +32,11 @@ WIN_PCRE2_VERSION = 10.36 WIN_PCRE2_DIR = pcre2-$(WIN_PCRE2_VERSION) WIN_FLEX_BISON_VERSION = 2.5.24 WIN_FLEX_BISON_DIR = flex_bison_$(WIN_FLEX_BISON_VERSION) +WIN_CMOCKA_VERSION = 1.1.0 +WIN_CMOCKA_DIR = cmocka-$(WIN_CMOCKA_VERSION) .PHONY: clean build cov win32 debug win32.debug win32.pcre infomsg replaceinfos test covtest \ - package win32.package package_common + package win32.package package_common utest win32.utest # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -56,9 +58,11 @@ win32.prereq: # download components curl -LO https://ftp.pcre.org/pub/pcre/pcre2-$(WIN_PCRE2_VERSION).tar.gz curl -LO https://downloads.sourceforge.net/project/winflexbison/win_flex_bison-$(WIN_FLEX_BISON_VERSION).zip + curl -LO https://cmocka.org/files/$(WIN_CMOCKA_VERSION:%.0=%)/cmocka-$(WIN_CMOCKA_VERSION)-mingw.zip # unpack components tar xfz $(WIN_PCRE2_DIR).tar.gz unzip win_flex_bison-$(WIN_FLEX_BISON_VERSION).zip -d $(WIN_FLEX_BISON_DIR) + unzip cmocka-$(WIN_CMOCKA_VERSION)-mingw.zip # build the pcre2 dependency (only needed on Windows MinGW) cd $(WIN_PCRE2_DIR) ; \ ./configure --disable-pcre2-8 --disable-pcre2-16 --enable-pcre2-32 --disable-shared \ @@ -67,6 +71,7 @@ win32.prereq: # remove downloaded archives rm pcre2-$(WIN_PCRE2_VERSION).tar.gz rm win_flex_bison-$(WIN_FLEX_BISON_VERSION).zip + rm cmocka-$(WIN_CMOCKA_VERSION)-mingw.zip # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -153,6 +158,13 @@ test: covtest: cd test; ./testrunner.sh --suite --coverage +utest: + $(MAKE) -C utest BOXES_PLATFORM=unix utest + +win32.utest: + cp $(WIN_CMOCKA_DIR)/bin/cmocka.dll $(OUT_DIR)/ + $(MAKE) -C utest BOXES_PLATFORM=win32 C_INCLUDE_PATH=../$(WIN_PCRE2_DIR)/src:../$(WIN_CMOCKA_DIR)/include \ + LDFLAGS="-L../$(WIN_PCRE2_DIR)/.libs -L../$(WIN_CMOCKA_DIR)/lib" utest # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Cleanup diff --git a/src/Makefile b/src/Makefile index 98aee7c..52c853e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -44,7 +44,7 @@ ORIG_FILES = $(ORIG_SRC) $(ORIG_HDR) check_dir: @if [ "$(shell pwd | sed -e 's/^.*\///')" != "out" ] ; then \ echo ERROR: Please call make from the top level directory. ; \ - exit 1 ; \ + exit 1 ; \ fi $(OUT_DIR): @@ -75,15 +75,17 @@ boxes.exe: $(ALL_OBJ) | check_dir flags_unix: $(eval CFLAGS := -I. -I$(SRC_DIR) -Wall -W $(CFLAGS_ADDTL)) - $(eval LDFLAGS := $(LDFLAGS_ADDTL)) + $(eval LDFLAGS := $(LDFLAGS) $(LDFLAGS_ADDTL)) $(eval BOXES_EXECUTABLE_NAME := boxes) $(eval ALL_OBJ := $(GEN_SRC:.c=.o) $(ORIG_NORM:.c=.o)) + echo $(filter-out boxes.o,$(ALL_OBJ)) > $(OUT_DIR)/modules.txt flags_win32: $(eval CFLAGS := -Os -s -m32 -I. -I$(SRC_DIR) -Wall -W $(CFLAGS_ADDTL)) - $(eval LDFLAGS := -s -m32) + $(eval LDFLAGS := $(LDFLAGS) -s -m32) $(eval BOXES_EXECUTABLE_NAME := boxes.exe) $(eval ALL_OBJ := $(GEN_SRC:.c=.o) $(ORIG_NORM:.c=.o) getopt.o) + echo $(filter-out boxes.o,$(ALL_OBJ)) > $(OUT_DIR)/modules.txt flags_: @echo Please call make from the top level directory. diff --git a/test/testrunner.sh b/test/testrunner.sh index c9d8153..aae3a2f 100755 --- a/test/testrunner.sh +++ b/test/testrunner.sh @@ -20,7 +20,7 @@ set -uo pipefail declare -r SRC_DIR=../src declare -r OUT_DIR=../out declare -r BASELINE_FILE=${OUT_DIR}/lcov-baseline.info -declare -r COVERAGE_FILE=${OUT_DIR}/lcov-blackbox.info +declare -r COVERAGE_FILE=${OUT_DIR}/lcov-total.info # Command Line Options declare opt_coverage=false @@ -161,9 +161,9 @@ function consolidate_coverage() function report_coverage() { - local testReportDir=${OUT_DIR}/coverage + local testReportDir=${OUT_DIR}/report mkdir -p ${testReportDir} - genhtml --title "Boxes / Black-box tests" --branch-coverage --legend \ + genhtml --title "Boxes / All Tests" --branch-coverage --legend \ --output-directory ${testReportDir} ${COVERAGE_FILE} echo -e "\nTest coverage report available at ${testReportDir}/index.html" } diff --git a/utest/Makefile b/utest/Makefile new file mode 100644 index 0000000..ee4dc34 --- /dev/null +++ b/utest/Makefile @@ -0,0 +1,74 @@ +# +# boxes - Command line filter to draw/remove ASCII boxes around text +# Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License, version 2, as published +# by the Free Software Foundation. +# +# This program 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 General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +#____________________________________________________________________________ +#============================================================================ + +CC = gcc + +OUT_DIR = ../out +SRC_DIR = ../src +UTEST_DIR = ../utest +VPATH = $(SRC_DIR):$(SRC_DIR)/misc:$(UTEST_DIR) + +UTEST_NORM = global_mock.c tools_test.c + +.PHONY: check_dir flags_unix flags_win32 flags_ utest + +.NOTPARALLEL: + +check_dir: + @if [ "$(shell pwd | sed -e 's/^.*\///')" != "out" ] ; then \ + echo ERROR: Please call make from the top level directory. ; \ + exit 1 ; \ + fi + +$(OUT_DIR): + mkdir $(OUT_DIR) + +flags_unix: + $(eval CFLAGS := -I. -I$(SRC_DIR) -O -Wall -W $(CFLAGS_ADDTL)) + $(eval LDFLAGS := $(LDFLAGS) --coverage $(LDFLAGS_ADDTL)) + $(eval UTEST_EXECUTABLE_NAME := unittest) + $(eval UTEST_OBJ := $(UTEST_NORM:.c=.o)) + +flags_win32: + $(eval CFLAGS := -Os -s -m32 -I. -I$(SRC_DIR) -Wall -W $(CFLAGS_ADDTL)) + $(eval LDFLAGS := $(LDFLAGS) --coverage -s -m32 $(LDFLAGS_ADDTL)) + $(eval UTEST_EXECUTABLE_NAME := unittest.exe) + $(eval UTEST_OBJ := $(UTEST_NORM:.c=.o)) + +flags_: + @echo Please call make from the top level directory. + exit 1 + +utest: flags_$(BOXES_PLATFORM) | $(OUT_DIR) + $(MAKE) -C $(OUT_DIR) -f $(UTEST_DIR)/Makefile BOXES_PLATFORM=$(BOXES_PLATFORM) UTEST_OBJ="$(UTEST_OBJ)" \ + CFLAGS_ADDTL="$(CFLAGS_ADDTL)" flags_$(BOXES_PLATFORM) $(UTEST_EXECUTABLE_NAME) + rm -f $(OUT_DIR)/*.gcda + cd $(OUT_DIR) ; ./$(UTEST_EXECUTABLE_NAME) + @OUT_DIR=$(OUT_DIR) SRC_DIR=$(SRC_DIR) ./report.sh + +unittest: $(UTEST_OBJ) | check_dir + $(CC) $(LDFLAGS) $^ $(shell cat modules.txt) -o $@ -lunistring -lpcre2-32 -lcmocka + +unittest.exe: $(UTEST_OBJ) | check_dir + $(CC) $(LDFLAGS) $^ $(shell cat modules.txt) -o $@ \ + -lkernel32 -l:libunistring.a -l:libpcre2-32.a -l:libiconv.a -l:libcmocka.dll.a + + +global_mock.o: global_mock.c boxes.h +tools_test.o: tools_test.c tools.h diff --git a/utest/global_mock.c b/utest/global_mock.c new file mode 100644 index 0000000..6ae3375 --- /dev/null +++ b/utest/global_mock.c @@ -0,0 +1,34 @@ +/* + * boxes - Command line filter to draw/remove ASCII boxes around text + * Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2, as published + * by the Free Software Foundation. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + */ + +/* + * Mocks of boxes' global variables. + */ + +#include "boxes.h" + + +design_t *designs = NULL; + +int num_designs = 0; + +opt_t opt; + +input_t input; diff --git a/utest/report.sh b/utest/report.sh new file mode 100755 index 0000000..ca648a0 --- /dev/null +++ b/utest/report.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# +# boxes - Command line filter to draw/remove ASCII boxes around text +# Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors +# +# This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public +# License, version 2, as published by the Free Software Foundation. +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# You should have received a copy of the GNU General Public License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# _____________________________________________________________________________________________________________________ +# +# Calculate and report the unit test coverage. Invoked by Makefile. +# _____________________________________________________________________________________________________________________ + + +# Expects environment variables OUT_DIR and SRC_DIR. +declare -r tcBaseName=unittest +declare -r testResultsDir=${OUT_DIR}/test-results/${tcBaseName} +declare -r testReportDir=${OUT_DIR}/report-utest + +if test -n "$(find ${OUT_DIR} -maxdepth 1 -name '*.gcda' -print -quit)" \ + && test -n "$(find ${OUT_DIR} -maxdepth 1 -name '*.gcno' -print -quit)" \ + && test -n "$(lcov --version)" +then + mkdir -p ${testResultsDir} + mkdir -p ${testReportDir} + cp ${OUT_DIR}/*.gc* ${testResultsDir} + lcov --capture --directory ${testResultsDir} --base-directory ${SRC_DIR} --test-name ${tcBaseName} --quiet \ + --exclude '*/lex.yy.c' --exclude '*/parser.c' --rc lcov_branch_coverage=1 \ + --output-file ${testResultsDir}/coverage.info + echo -n "[ Coverage ] " + genhtml --title "Boxes / Unit Tests" --branch-coverage --legend --output-directory ${testReportDir} \ + ${testResultsDir}/coverage.info | grep 'lines...' | grep -oP '\d+\.\d*%' + echo "[ Report ] Unit test coverage report available at ${testReportDir}/index.html" +fi diff --git a/utest/tools_test.c b/utest/tools_test.c new file mode 100644 index 0000000..68c8f15 --- /dev/null +++ b/utest/tools_test.c @@ -0,0 +1,70 @@ +/* + * boxes - Command line filter to draw/remove ASCII boxes around text + * Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2, as published + * by the Free Software Foundation. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + */ + +/* + * Unit tests of the 'tools' module + */ + +#include +#include +#include +#include +#include "tools.h" + + +static void test_strisyes_true() +{ + assert_int_equal(1, strisyes("On")); + assert_int_equal(1, strisyes("on")); + assert_int_equal(1, strisyes("yes")); + assert_int_equal(1, strisyes("YEs")); + assert_int_equal(1, strisyes("true")); + assert_int_equal(1, strisyes("True")); + assert_int_equal(1, strisyes("1")); + assert_int_equal(1, strisyes("t")); + assert_int_equal(1, strisyes("T")); +} + + +static void test_strisyes_false() +{ + assert_int_equal(0, strisyes(NULL)); + assert_int_equal(0, strisyes("")); + assert_int_equal(0, strisyes(" ")); + assert_int_equal(0, strisyes("off")); + assert_int_equal(0, strisyes("false")); + assert_int_equal(0, strisyes("no")); + assert_int_equal(0, strisyes("0")); + assert_int_equal(0, strisyes("f")); + assert_int_equal(0, strisyes("F")); + assert_int_equal(0, strisyes("tru")); + assert_int_equal(0, strisyes("yes sir")); + assert_int_equal(0, strisyes("100")); +} + + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_strisyes_true), + cmocka_unit_test(test_strisyes_false)}; + + return cmocka_run_group_tests(tests, NULL, NULL); +}