From 6921ec60be059ee64c3dc679795fa7f7bbf7cd8c Mon Sep 17 00:00:00 2001 From: Andreas Gieriet Date: Mon, 10 Feb 2020 00:11:44 +0100 Subject: [PATCH] publish testlib and doxygen shared configuration --- Doxyfile | 319 ++++++++++++++++++++++++++ Makefile | 7 +- testlib/Makefile | 29 +-- testlib/{src => include}/test_utils.h | 66 +++--- testlib/mainpage.dox | 10 + testlib/src/test_utils.c | 182 ++++++++------- testlib/tests/tests.c | 179 ++++++++------- 7 files changed, 568 insertions(+), 224 deletions(-) create mode 100644 Doxyfile mode change 100644 => 100755 testlib/Makefile rename testlib/{src => include}/test_utils.h (64%) create mode 100644 testlib/mainpage.dox diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..221b1c5 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,319 @@ +# Doxyfile 1.8.11 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "PROGC - Labs" +PROJECT_NUMBER = +PROJECT_BRIEF = +PROJECT_LOGO = +OUTPUT_DIRECTORY = +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = YES +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = . +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.h *.c *.dox +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = test*/* +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = NO +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +CLANG_ASSISTED_PARSING = NO +CLANG_OPTIONS = +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = doc +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = NO +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = NO +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_SOURCE_CODE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +MSCGEN_PATH = +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = NO +COLLABORATION_GRAPH = NO +GROUP_GRAPHS = NO +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = NO +DIRECTORY_GRAPH = NO +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = NO +DOT_CLEANUP = NO diff --git a/Makefile b/Makefile index 6c96354..50dbb63 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,11 @@ EMPTY := SPACE := $(EMPTY) $(EMPTY) NL := $(EMPTY)\\n$(EMPTY) -LABS := $(sort $(wildcard lab??-* testlib)) +LABS := $(sort $(wildcard P[0-9][0-9]*)) +EXAMPLE := $(if $(firstword $(LABS)),$(firstword $(LABS)),"Pxx") default: - @echo "**** PROGC Labs ****" + @echo "**** SNP Labs ****" @echo "$(subst $(SPACE),$(NL),$(LABS))" @echo "" @echo "**** Prerequisites ****" @@ -20,7 +21,7 @@ default: @echo "" @echo "**** How to build and run a lab? ****" @echo "1. Change into the respective directory, e.g." - @echo " cd $(firstword $(LABS))" + @echo " cd $(EXAMPLE)" @echo "2. Build the lab, e.g." @echo " make" @echo " The resulting executable is located in the bin folder." diff --git a/testlib/Makefile b/testlib/Makefile old mode 100644 new mode 100755 index 302da60..3e34f63 --- a/testlib/Makefile +++ b/testlib/Makefile @@ -1,8 +1,8 @@ # what to produce -TARGET := bin/libprogctest.a +TARGET := lib/libprogctest.a # public headers -HEADERS := src/test_utils.h +HEADERS := include/test_utils.h # implementation files SOURCES := src/test_utils.c @@ -11,7 +11,7 @@ SOURCES := src/test_utils.c TSTSOURCES := tests/tests.c # directories to create (and remove upon cleanup) -CREATEDIRS := bin doc +CREATEDIRS := lib doc # list of derived file names from the source names OBJECTS := $(SOURCES:%.c=%.o) # list of gcc -c ... produced *.o files @@ -20,22 +20,14 @@ TSTOBJECTS := $(TSTSOURCES:%.c=%.o) # list of gcc -c ... produced *.o files TSTDEPS := $(TSTSOURCES:%.c=%.d) # list of gcc -MD ... produced *.d files TSTTARGET := $(CURDIR)/tests/runtest -# libraries -CUNITINCDIR := $(CURDIR)/../CUnit/include -CUNITLIBDIR := $(CURDIR)/../CUnit/lib - -# where to install the static library and the associated headers -INSTALLLIBDIR := $(CURDIR)/../lib -INSTALLINCDIR := $(CURDIR)/../include - # full path to the target FULLTARGET := $(CURDIR)/$(TARGET) # commands and flags CC = gcc -CFLAGS = -std=c99 -Wall -g -CPPFLAGS = -MD -Isrc -Itests -I$(INSTALLINCDIR) -I$(CUNITINCDIR) -DTARGET=$(FULLTARGET) -LDFLAGS = -static -z muldefs +CFLAGS = -std=c99 -Wall -pedantic -g +CPPFLAGS = -MD -Isrc -Itests -Iinclude -DTARGET=$(FULLTARGET) +LDFLAGS = ARFLAGS = rc # targets which get always visited (without checking any up-to-date state) @@ -54,17 +46,18 @@ clean: @echo "#### $@ done ####" install: $(FULLTARGET) - mkdir -p $(INSTALLLIBDIR) $(INSTALLINCDIR) - cp -f $(FULLTARGET) $(INSTALLLIBDIR)/ - cp -f $(HEADERS) $(INSTALLINCDIR)/ @echo "#### $< installed ####" +doc: + doxygen ../Doxyfile > /dev/null + @echo "#### $@ done ####" + test: $(TSTTARGET) (cd tests; $(TSTTARGET)) @echo "#### $< executed ####" $(TSTTARGET): $(FULLTARGET) $(TSTOBJECTS) - $(LINK.c) -o $(TSTTARGET) $(TSTOBJECTS) $(FULLTARGET) -L$(CUNITLIBDIR) -lcunit + $(LINK.c) -o $(TSTTARGET) $(TSTOBJECTS) $(FULLTARGET) -lcunit @echo "#### $@ built ####" diff --git a/testlib/src/test_utils.h b/testlib/include/test_utils.h similarity index 64% rename from testlib/src/test_utils.h rename to testlib/include/test_utils.h index 87f9b95..99634f7 100644 --- a/testlib/src/test_utils.h +++ b/testlib/include/test_utils.h @@ -16,7 +16,7 @@ #include #include -#include "CUnit/Basic.h" +#include /// Stringize macro (evaluates the passed macro and makes a string out of it). Non-macros are stringized as-is. #define XSTR(x) STR(x) @@ -109,38 +109,38 @@ typedef void (*test_function_t)(void); * } * @endcode */ -#define TestMainBasic(suite, setup, cleanup, ...) \ - do { \ - CU_pSuite pSuite = NULL; \ - \ - /* initialize the CUnit test registry */ \ - if (CUE_SUCCESS != CU_initialize_registry()) \ - return CU_get_error(); \ - \ - /* functions and their names */ \ - test_function_t tests[] = { __VA_ARGS__ }; \ - char all_names[] = #__VA_ARGS__; \ - const size_t n = sizeof(tests)/sizeof(*tests); \ - const char *names[sizeof(tests)/sizeof(*tests)] = { strtok(all_names, ", ") } ; \ - for(size_t i = 1; i < n; i++) { \ - names[i] = strtok(NULL, ", "); \ - } \ - /* init suite and tests */ \ - pSuite = CU_add_suite(suite, setup, cleanup); \ - if (pSuite) { \ - size_t i; \ - for(i = 0; i < n; i++) { \ - if (!CU_add_test(pSuite, names[i], tests[i])) break; \ - } \ - /* Run all tests using the CUnit Basic interface */ \ - if (i == n) { \ - CU_basic_set_mode(CU_BRM_VERBOSE); \ - CU_basic_run_tests(); \ - } \ - } \ - CU_cleanup_registry(); \ - return CU_get_error(); \ - } while(0) \ +#define TestMainBasic(suite, setup, cleanup, ...) \ + do { \ + CU_pSuite pSuite = NULL; \ + \ + /* initialize the CUnit test registry */ \ + if (CUE_SUCCESS != CU_initialize_registry()) \ + return CU_get_error(); \ + \ + /* functions and their names */ \ + test_function_t tests[] = { __VA_ARGS__ }; \ + char all_names[] = #__VA_ARGS__; \ + const size_t n = sizeof(tests)/sizeof(*tests); \ + const char *names[sizeof(tests)/sizeof(*tests)] = { strtok(all_names, ", ") } ; \ + for(size_t i = 1; i < n; i++) { \ + names[i] = strtok(NULL, ", "); \ + } \ + /* init suite and tests */ \ + pSuite = CU_add_suite(suite, setup, cleanup); \ + if (pSuite) { \ + size_t i; \ + for(i = 0; i < n; i++) { \ + if (!CU_add_test(pSuite, names[i], tests[i])) break; \ + } \ + /* Run all tests using the CUnit Basic interface */ \ + if (i == n) { \ + CU_basic_set_mode(CU_BRM_VERBOSE); \ + CU_basic_run_tests(); \ + } \ + } \ + CU_cleanup_registry(); \ + return CU_get_error(); \ + } while(0) \ #endif diff --git a/testlib/mainpage.dox b/testlib/mainpage.dox new file mode 100644 index 0000000..ab128a5 --- /dev/null +++ b/testlib/mainpage.dox @@ -0,0 +1,10 @@ +/** + * @mainpage SNP - Test Utilities + * + * @section Purpose + * + * This is a supporting test library for SNP tests. + * + * This project needs to be built before the labs. + * It provides the needed header files in the include folder and the libraries in the lib folder. + */ diff --git a/testlib/src/test_utils.c b/testlib/src/test_utils.c index ddaa7b3..8d5c954 100644 --- a/testlib/src/test_utils.c +++ b/testlib/src/test_utils.c @@ -17,101 +17,121 @@ #include #include #include -#include "CUnit/Basic.h" +#include #include "test_utils.h" int file_exists(const char file_path[]) { - // preconditions - assert(file_path); - int errno_safe = errno; - errno = 0; - // try and forgive... - FILE *file = fopen(file_path, "r"); - assert(file || (!file && (errno == ENOENT))); // either it exists or "No such file or directory" error code (see man errno). - errno = errno_safe; // fopen will set errno if the file does not exist - if (file) { - assert(0 == fclose(file)); - return 1; // existed - } - return 0; // did not exist + // preconditions + assert(file_path); + int errno_safe = errno; + errno = 0; + // try and forgive... + FILE *file = fopen(file_path, "r"); + assert(file || (!file && (errno == ENOENT))); // either it exists or "No such file or directory" error code (see man errno). + errno = errno_safe; // fopen will set errno if the file does not exist + if (file) { + assert(0 == fclose(file)); + return 1; // existed + } + return 0; // did not exist } void remove_file_if_exists(const char file_path[]) { - // we take the risk that between checking and removing, some undesired file access may happen and jeopardize the control logic... - if (file_exists(file_path)) { - assert(0 == unlink(file_path)); - } + // we take the risk that between checking and removing, some undesired file access may happen and jeopardize the control logic... + if (file_exists(file_path)) { + assert(0 == unlink(file_path)); + } +} + +static void print_current_char(int c) +{ + if (c < 0) + { + printf(" "); + } + else if (isprint(c)) + { + printf(" 0x%02x = '%c'", c, c); + } + else + { + printf(" 0x%02x = %s", c, ""); + } } void assert_lines(const char file[], const char *lines[], size_t n_lines) { - // preconditions - CU_ASSERT_PTR_NOT_NULL_FATAL(file); - CU_ASSERT_PTR_NOT_NULL_FATAL(lines); + // preconditions + CU_ASSERT_PTR_NOT_NULL_FATAL(file); + CU_ASSERT_PTR_NOT_NULL_FATAL(lines); - // file access may always fail - FILE *input = fopen(file, "r"); - if (!input) perror(file); - CU_ASSERT_PTR_NOT_NULL_FATAL(input); + // file access may always fail + FILE *input = fopen(file, "r"); + if (!input) perror(file); + CU_ASSERT_PTR_NOT_NULL_FATAL(input); - // process all lines and compare to the file content - size_t i = 0; - size_t n = 0; - for(i = 0; i < n_lines && n == 0; i++) { - const char *line = lines[i]; - CU_ASSERT_PTR_NOT_NULL(line); - if (line) { - size_t len = n = strlen(line); - CU_ASSERT(n > 0); - while (n > 0) { - int c = fgetc(input); - CU_ASSERT_FALSE(feof(input)); - CU_ASSERT_EQUAL(c, *line); - if (c != *line) { - printf("\nfile %s: line %zu, pos %zu = %d = '%c', expected = %d = '%c'\n", - file, i+1, len-n+1, c, isprint(c) ? c : '.', *line, isprint(*line) ? *line : '.'); - break; - } - line++; - n--; - } - } - } - CU_ASSERT_FALSE(feof(input)); - (void)fgetc(input); - CU_ASSERT_TRUE(feof(input)); - CU_ASSERT_EQUAL(i, n_lines); - CU_ASSERT_EQUAL(n, 0); + // process all lines and compare to the file content + size_t i = 0; + size_t n = 0; + for(i = 0; i < n_lines && n == 0; i++) { + const char *exp_line = lines[i]; + // allow NULL lines to allow for empty files: fix -pedantic warning "ISO C forbids zero-size array" + if (exp_line) { + size_t len = n = strlen(exp_line); + CU_ASSERT(n > 0); + while (n > 0) { + int exp_c = *exp_line; + int act_c = fgetc(input); + CU_ASSERT_FALSE(feof(input)); + CU_ASSERT_EQUAL(act_c, exp_c); + if (act_c != exp_c) { + printf("\nfile %s: line %zu, pos %zu: expected =", file, i+1, len-n+1); + print_current_char(exp_c); + printf(", actual ="); + print_current_char(act_c); + printf("\n"); + break; + } + exp_line++; + n--; + } + } + } + CU_ASSERT_FALSE(feof(input)); + (void)fgetc(input); + CU_ASSERT_TRUE(feof(input)); + CU_ASSERT_EQUAL(i, n_lines); + CU_ASSERT_EQUAL(n, 0); - // successfully reached the end... - int fclose_result = fclose(input); - CU_ASSERT(0 == fclose_result); - - // print actual versus expected in case of error - if (n != 0 || i != n_lines) { - printf("---- EXPECTED ----\n"); - for(int i = 0; i < n_lines; i++) { - const char *p = lines[i]; - while(p && *p) { - putchar(*p); - p++; - } - } - printf("---- ACTUAL (%s) ----\n", file); - FILE* fd = fopen(file, "r"); - int last = 0; - while(fd && !feof(fd)) { - int c = fgetc(fd); - if (c != EOF) { - last = c; - putchar(c); - } - } - if (fd) fclose(fd); - if (last != '\n') putchar('\n'); - printf("---- END ----\n"); - } + // successfully reached the end... + int fclose_result = fclose(input); + CU_ASSERT(0 == fclose_result); + // print actual versus expected in case of error + if (n != 0 || i != n_lines) { + printf("---- EXPECTED ----\n"); + for(int i = 0; i < n_lines; i++) { + const char *p = lines[i]; + while(p && *p) { + putchar(*p); + p++; + } + } + printf("---- ACTUAL (%s) ----\n", file); + FILE* fd = fopen(file, "r"); + int last = 0; + while(fd && !feof(fd)) { + int c = fgetc(fd); + if (c != EOF) { + last = c; + putchar(c); + } + } + if (fd) fclose(fd); + if (last != '\n') putchar('\n'); + printf("---- END ----\n"); + } + } diff --git a/testlib/tests/tests.c b/testlib/tests/tests.c index b9e00c8..894c072 100644 --- a/testlib/tests/tests.c +++ b/testlib/tests/tests.c @@ -13,7 +13,7 @@ */ #include #include -#include "CUnit/Basic.h" +#include #include "test_utils.h" #ifndef TARGET // must be given by the make file --> see test target @@ -34,137 +34,138 @@ // setup & teardown static int setup(void) { - remove_file_if_exists(OUTFILE); - remove_file_if_exists(ERRFILE); - remove_file_if_exists(EMPTYFILE); - remove_file_if_exists(NONEMPTYFILE); - remove_file_if_exists(NONEMPTYFILE_NONLEND); - // do nothing - return 0; // success + remove_file_if_exists(OUTFILE); + remove_file_if_exists(ERRFILE); + remove_file_if_exists(EMPTYFILE); + remove_file_if_exists(NONEMPTYFILE); + remove_file_if_exists(NONEMPTYFILE_NONLEND); + // do nothing + return 0; // success } static int teardown(void) { - // do nothing - return 0; // success + // do nothing + return 0; // success } // tests static void test_remove_file_that_exists(void) { - // ** arrange ** + // ** arrange ** - // create a file - FILE *file = fopen(OUTFILE, "w"); - CU_ASSERT_PTR_NOT_NULL(file); - CU_ASSERT_EQUAL(fclose(file), 0); - errno = 0; + // create a file + FILE *file = fopen(OUTFILE, "w"); + CU_ASSERT_PTR_NOT_NULL(file); + CU_ASSERT_EQUAL(fclose(file), 0); + errno = 0; - // ** act ** - remove_file_if_exists(OUTFILE); + // ** act ** + remove_file_if_exists(OUTFILE); - // ** assert ** + // ** assert ** - // make sure the file is removed - CU_ASSERT_EQUAL(errno, 0); - file = fopen(OUTFILE, "r"); - CU_ASSERT_TRUE(!file && errno == ENOENT); - // cleanup gracefully - if (file) CU_ASSERT_EQUAL(fclose(file), 0); - errno = 0; + // make sure the file is removed + CU_ASSERT_EQUAL(errno, 0); + file = fopen(OUTFILE, "r"); + CU_ASSERT_TRUE(!file && errno == ENOENT); + // cleanup gracefully + if (file) CU_ASSERT_EQUAL(fclose(file), 0); + errno = 0; } static void test_remove_file_that_does_not_exist(void) { - // ** arrange ** - remove_file_if_exists(OUTFILE); - // the file is now supposed to not exist any more --> see test_remove_file_that_exists test result + // ** arrange ** + remove_file_if_exists(OUTFILE); + // the file is now supposed to not exist any more --> see test_remove_file_that_exists test result - // ** act ** + // ** act ** - // call with a not existing file - remove_file_if_exists(OUTFILE); - // must not fail in any internal assertion + // call with a not existing file + remove_file_if_exists(OUTFILE); + // must not fail in any internal assertion + + // ** assert ** - // ** assert ** - - // make sure the file is removed - CU_ASSERT_EQUAL(errno, 0); - FILE *file = fopen(OUTFILE, "r"); - CU_ASSERT_TRUE(!file && errno == ENOENT); - // cleanup gracefully - if (file) CU_ASSERT_EQUAL(fclose(file), 0); - errno = 0; + // make sure the file is removed + CU_ASSERT_EQUAL(errno, 0); + FILE *file = fopen(OUTFILE, "r"); + CU_ASSERT_TRUE(!file && errno == ENOENT); + // cleanup gracefully + if (file) CU_ASSERT_EQUAL(fclose(file), 0); + errno = 0; } static void test_assert_lines_empty_file(void) { - // ** arrange ** + // ** arrange ** - // empty file - remove_file_if_exists(EMPTYFILE); - FILE *file = fopen(EMPTYFILE, "w"); - CU_ASSERT_PTR_NOT_NULL_FATAL(file); - CU_ASSERT_EQUAL(fclose(file), 0); - const char *lines[] = {}; + // empty file + remove_file_if_exists(EMPTYFILE); + FILE *file = fopen(EMPTYFILE, "w"); + CU_ASSERT_PTR_NOT_NULL_FATAL(file); + CU_ASSERT_EQUAL(fclose(file), 0); + const char *lines[] = { NULL }; - // ** act ** - assert_lines(EMPTYFILE, lines, sizeof(lines)/sizeof(*lines)); + // ** act ** + assert_lines(EMPTYFILE, lines, sizeof(lines)/sizeof(*lines)); + + // ** assert ** - // ** assert ** - - // no assertions should have happened within assert_lines(...) + // no assertions should have happened within assert_lines(...) } static void test_assert_lines_non_empty_file(void) { - // ** arrange ** + // ** arrange ** - // reference file - remove_file_if_exists(NONEMPTYFILE); - FILE *file = fopen(NONEMPTYFILE, "w"); - CU_ASSERT_PTR_NOT_NULL_FATAL(file); - CU_ASSERT_EQUAL(fprintf(file, "LINE1\n"), 6); - CU_ASSERT_EQUAL(fprintf(file, "LINE2\n"), 6); - CU_ASSERT_EQUAL(fclose(file), 0); - const char *lines[] = { "LINE1\n", "LINE2\n"}; + // reference file + remove_file_if_exists(NONEMPTYFILE); + FILE *file = fopen(NONEMPTYFILE, "w"); + CU_ASSERT_PTR_NOT_NULL_FATAL(file); + CU_ASSERT_EQUAL(fprintf(file, "LINE1\n"), 6); + CU_ASSERT_EQUAL(fprintf(file, "LINE2\n"), 6); + CU_ASSERT_EQUAL(fclose(file), 0); + const char *lines[] = { "LINE1\n", "LINE2\n"}; - // ** act ** - assert_lines(NONEMPTYFILE, lines, sizeof(lines)/sizeof(*lines)); + // ** act ** + assert_lines(NONEMPTYFILE, lines, sizeof(lines)/sizeof(*lines)); + + // ** assert ** - // ** assert ** - - // no assertions should have happened within assert_lines(...) + // no assertions should have happened within assert_lines(...) } static void test_assert_lines_no_newline_at_the_end(void) { - // ** arrange ** + // ** arrange ** - // reference file - remove_file_if_exists(NONEMPTYFILE_NONLEND); - FILE *file = fopen(NONEMPTYFILE_NONLEND, "w"); - CU_ASSERT_PTR_NOT_NULL_FATAL(file); - CU_ASSERT_EQUAL(fprintf(file, "LINE1\n"), 6); - CU_ASSERT_EQUAL(fprintf(file, "LINE2"), 5); - CU_ASSERT_EQUAL(fclose(file), 0); - const char *lines[] = { "LINE1\n", "LINE2"}; + // reference file + remove_file_if_exists(NONEMPTYFILE_NONLEND); + FILE *file = fopen(NONEMPTYFILE_NONLEND, "w"); + CU_ASSERT_PTR_NOT_NULL_FATAL(file); + CU_ASSERT_EQUAL(fprintf(file, "LINE1\n"), 6); + CU_ASSERT_EQUAL(fprintf(file, "LINE2"), 5); + CU_ASSERT_EQUAL(fclose(file), 0); + const char *lines[] = { "LINE1\n", "LINE2"}; - // ** act ** - assert_lines(NONEMPTYFILE_NONLEND, lines, sizeof(lines)/sizeof(*lines)); + // ** act ** + assert_lines(NONEMPTYFILE_NONLEND, lines, sizeof(lines)/sizeof(*lines)); + + // ** assert ** - // ** assert ** - - // no assertions should have happened within assert_lines(...) + // no assertions should have happened within assert_lines(...) } /** * @brief Registers and runs the tests. + * @returns success (==0) or error (!= 0) */ int main(void) { - TestMainBasic("PROGC Test Lib", setup, teardown - , test_remove_file_that_exists - , test_remove_file_that_does_not_exist - , test_assert_lines_empty_file - , test_assert_lines_non_empty_file - , test_assert_lines_no_newline_at_the_end - ); + TestMainBasic("PROGC Test Lib", setup, teardown + , test_remove_file_that_exists + , test_remove_file_that_does_not_exist + , test_assert_lines_empty_file + , test_assert_lines_non_empty_file + , test_assert_lines_no_newline_at_the_end + ); }