diff --git a/src/regulex.c b/src/regulex.c index 66855e1..34947f8 100644 --- a/src/regulex.c +++ b/src/regulex.c @@ -55,7 +55,7 @@ pcre2_code *compile_pattern(char *pattern) if (re == NULL) { PCRE2_UCHAR buffer[256]; pcre2_get_error_message(errornumber, buffer, sizeof(buffer)); - fprintf(stderr, "Regular expression pattern \"%s\" failed to compile at offset %d: %s\n", + fprintf(stderr, "Regular expression pattern \"%s\" failed to compile at position %d: %s\n", pattern, (int) erroroffset, u32_strconv_to_output(buffer)); } return re; diff --git a/utest/Makefile b/utest/Makefile index ee4dc34..53ee963 100644 --- a/utest/Makefile +++ b/utest/Makefile @@ -24,7 +24,8 @@ SRC_DIR = ../src UTEST_DIR = ../utest VPATH = $(SRC_DIR):$(SRC_DIR)/misc:$(UTEST_DIR) -UTEST_NORM = global_mock.c tools_test.c +UTEST_NORM = global_mock.c tools_test.c regulex_test.o main.o +MOCKS = fprintf .PHONY: check_dir flags_unix flags_win32 flags_ utest @@ -41,13 +42,13 @@ $(OUT_DIR): flags_unix: $(eval CFLAGS := -I. -I$(SRC_DIR) -O -Wall -W $(CFLAGS_ADDTL)) - $(eval LDFLAGS := $(LDFLAGS) --coverage $(LDFLAGS_ADDTL)) + $(eval LDFLAGS := $(LDFLAGS) $(foreach MOCK,$(MOCKS),-Wl,--wrap=$(MOCK)) --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 LDFLAGS := $(LDFLAGS) $(foreach MOCK,$(MOCKS),-Wl,--wrap=$(MOCK)) --coverage -s -m32 $(LDFLAGS_ADDTL)) $(eval UTEST_EXECUTABLE_NAME := unittest.exe) $(eval UTEST_OBJ := $(UTEST_NORM:.c=.o)) @@ -70,5 +71,7 @@ unittest.exe: $(UTEST_OBJ) | check_dir -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 +global_mock.o: global_mock.c global_mock.h boxes.h unicode.h config.h | check_dir +tools_test.o: tools_test.c tools_test.h tools.h config.h | check_dir +regulex_test.o: regulex_test.c regulex_test.h global_mock.h regulex.h config.h | check_dir +main.o: main.c global_mock.h tools_test.h regulex_test.h config.h | check_dir diff --git a/utest/global_mock.c b/utest/global_mock.c index 6ae3375..55624ce 100644 --- a/utest/global_mock.c +++ b/utest/global_mock.c @@ -22,8 +22,15 @@ * Mocks of boxes' global variables. */ +#include "config.h" +#include +#include +#include +#include +#include #include "boxes.h" - +#include "unicode.h" +#include "tools.h" design_t *designs = NULL; @@ -32,3 +39,73 @@ int num_designs = 0; opt_t opt; input_t input; + +char **collect_out = NULL; +int collect_out_size = 0; + +char **collect_err = NULL; +int collect_err_size = 0; + + +void collect_reset() +{ + for (int i = 0; i < collect_out_size; i++) { + BFREE(collect_out[i]); + } + BFREE(collect_out); + + for (int i = 0; i < collect_err_size; i++) { + BFREE(collect_err[i]); + } + BFREE(collect_err); + + collect_out_size = 0; + collect_err_size = 0; +} + + +/** + * Mock of the `fprintf()` function which records its output instead of printing it. Assumes that no output string will + * be longer than 512 characters. + * @param __stream `stdout` or `stderr` + * @param __format the format string, followed by the arguments + */ +void __wrap_fprintf(FILE *__stream, const char *__format, ...) +{ + char **collect = __stream == stdout ? collect_out : collect_err; + int collect_size = __stream == stdout ? collect_out_size : collect_err_size; + collect = (char **) realloc(collect, ++collect_size * sizeof(char *)); + + char *s = (char *) malloc(512); + va_list va; + va_start(va, __format); + vsprintf(s, __format, va); + va_end(va); + collect[collect_size - 1] = s; + + if (__stream == stdout) { + collect_out = collect; + collect_out_size = collect_size; + } + else { + collect_err = collect; + collect_err_size = collect_size; + } +} + + +void setup_mocks() +{ + setlocale(LC_ALL, ""); + encoding = check_encoding("UTF-8", locale_charset()); + collect_reset(); +} + + +void teardown() +{ + collect_reset(); +} + + +/*EOF*/ /* vim: set cindent sw=4: */ diff --git a/utest/global_mock.h b/utest/global_mock.h new file mode 100644 index 0000000..1cb304b --- /dev/null +++ b/utest/global_mock.h @@ -0,0 +1,44 @@ +/* + * 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. + * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + */ + +/* + * Test fixtures and mocks of global shared state. + */ + +#ifndef GLOBAL_MOCK_H +#define GLOBAL_MOCK_H + + +extern char **collect_out; +extern int collect_out_size; + +extern char **collect_err; +extern int collect_err_size; + +void collect_reset(); + + +void setup_mocks(); +void teardown(); + + +#endif + +/*EOF*/ /* vim: set cindent sw=4: */ diff --git a/utest/main.c b/utest/main.c new file mode 100644 index 0000000..575befa --- /dev/null +++ b/utest/main.c @@ -0,0 +1,61 @@ +/* + * 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. + * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + */ + +/* + * Main module for running the unit tests. + */ + +#include "config.h" +#include +#include +#include +#include + +#include "global_mock.h" +#include "tools_test.h" +#include "regulex_test.h" + + +int main(void) +{ + setup_mocks(); + + const struct CMUnitTest tools_tests[] = { + cmocka_unit_test(test_strisyes_true), + cmocka_unit_test(test_strisyes_false), + cmocka_unit_test(test_strisno_true), + cmocka_unit_test(test_strisno_false) + }; + + const struct CMUnitTest regulex_tests[] = { + cmocka_unit_test(test_compile_pattern_error), + cmocka_unit_test(test_compile_pattern_empty) + }; + + int num_failed = 0; + num_failed += cmocka_run_group_tests(tools_tests, NULL, NULL); + num_failed += cmocka_run_group_tests(regulex_tests, NULL, NULL); + + teardown(); + return num_failed; +} + + +/*EOF*/ /* vim: set cindent sw=4: */ diff --git a/utest/regulex_test.c b/utest/regulex_test.c new file mode 100644 index 0000000..b676b6e --- /dev/null +++ b/utest/regulex_test.c @@ -0,0 +1,60 @@ +/* + * 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 'regulex' module + */ + +#include "config.h" +#include +#include +#include +#include +#include "global_mock.h" +#include "regulex.h" + + +void test_compile_pattern_empty(void **state) +{ + (void) state; /* unused */ + + assert_null(compile_pattern(NULL)); + assert_non_null(compile_pattern("")); +} + + +void test_compile_pattern_error(void **state) +{ + (void) state; /* unused */ + + assert_null(compile_pattern("incomplete[x")); + assert_int_equal(1, collect_err_size); + assert_string_equal("Regular expression pattern \"incomplete[x\" failed to compile at position 12: " + "missing terminating ] for character class\n", collect_err[0]); + + collect_reset(); + assert_null(compile_pattern("incomplete\\")); + assert_int_equal(1, collect_err_size); + assert_string_equal("Regular expression pattern \"incomplete\\\" failed to compile at position 11: " + "\\ at end of pattern\n", collect_err[0]); +} + + +/*EOF*/ /* vim: set cindent sw=4: */ diff --git a/utest/regulex_test.h b/utest/regulex_test.h new file mode 100644 index 0000000..cd6fc88 --- /dev/null +++ b/utest/regulex_test.h @@ -0,0 +1,36 @@ +/* + * 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 'regulex' module + */ + +#ifndef REGULEX_TEST_H +#define REGULEX_TEST_H + + +void test_compile_pattern_empty(void **state); +void test_compile_pattern_error(void **state); + + +#endif + + +/*EOF*/ /* vim: set cindent sw=4: */ diff --git a/utest/tools_test.c b/utest/tools_test.c index 98bf533..cfe71c9 100644 --- a/utest/tools_test.c +++ b/utest/tools_test.c @@ -22,15 +22,19 @@ * Unit tests of the 'tools' module */ +#include "config.h" #include #include #include #include #include "tools.h" +#include "tools_test.h" -static void test_strisyes_true() +void test_strisyes_true(void **state) { + (void) state; /* unused */ + assert_int_equal(1, strisyes("On")); assert_int_equal(1, strisyes("on")); assert_int_equal(1, strisyes("yes")); @@ -43,8 +47,10 @@ static void test_strisyes_true() } -static void test_strisyes_false() +void test_strisyes_false(void **state) { + (void) state; /* unused */ + assert_int_equal(0, strisyes(NULL)); assert_int_equal(0, strisyes("")); assert_int_equal(0, strisyes(" ")); @@ -60,8 +66,10 @@ static void test_strisyes_false() } -static void test_strisno_true() +void test_strisno_true(void **state) { + (void) state; /* unused */ + assert_int_equal(1, strisno("off")); assert_int_equal(1, strisno("Off")); assert_int_equal(1, strisno("no")); @@ -74,8 +82,10 @@ static void test_strisno_true() } -static void test_strisno_false() +void test_strisno_false(void **state) { + (void) state; /* unused */ + assert_int_equal(0, strisno(NULL)); assert_int_equal(0, strisno("")); assert_int_equal(0, strisno(" ")); @@ -91,14 +101,4 @@ static void test_strisno_false() } -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_strisyes_true), - cmocka_unit_test(test_strisyes_false), - cmocka_unit_test(test_strisno_true), - cmocka_unit_test(test_strisno_false) - }; - - return cmocka_run_group_tests(tests, NULL, NULL); -} +/*EOF*/ /* vim: set cindent sw=4: */ diff --git a/utest/tools_test.h b/utest/tools_test.h new file mode 100644 index 0000000..26e4058 --- /dev/null +++ b/utest/tools_test.h @@ -0,0 +1,38 @@ +/* + * 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 + */ + +#ifndef TOOLS_TEST_H +#define TOOLS_TEST_H + + +void test_strisyes_true(void **state); +void test_strisyes_false(void **state); + +void test_strisno_true(void **state); +void test_strisno_false(void **state); + + +#endif + +/*EOF*/ /* vim: set cindent sw=4: */