diff --git a/Makefile.am b/Makefile.am --- a/Makefile.am +++ b/Makefile.am @@ -73,3 +73,37 @@ stowinstall: $(MAKE) $(AM_MAKEFLAGS) install prefix=/usr/local/stow/libksba + +# Coverage targets + +if HAVE_GCOV + +.PHONY: clean-gcda +clean-gcda: + @echo Removing old coverage results + -find -name '*.gcda' -print | xargs -r rm + -find -name '*.gcno' -print | xargs -r rm + +.PHONY: coverage-html generate-coverage-html clean-coverage-html +#coverage-html: clean-gcda +coverage-html: + $(MAKE) $(AM_MAKEFLAGS) -k check + $(MAKE) $(AM_MAKEFLAGS) generate-coverage-html + +generate-coverage-html: + @echo Collecting coverage data with lcov + $(LCOV) --gcov-tool $(GCOV) -b src --directory $(builddir)/src --capture --output-file coverage.info.src --no-checksum --compat-libtool --rc lcov_branch_coverage=1 + $(LCOV) --gcov-tool $(GCOV) -b tests --directory $(builddir)/tests --capture --output-file coverage.info.tests --no-checksum --compat-libtool --rc lcov_branch_coverage=1 + $(LCOV) -a coverage.info.src -a coverage.info.tests --output-file coverage.info --no-checksum --rc lcov_branch_coverage=1 + $(LCOV) --remove coverage.info "/usr*" -o coverage.info --rc lcov_branch_coverage=1 + $(LCOV) --remove coverage.info "/opt*" -o coverage.info --rc lcov_branch_coverage=1 + $(LCOV) --remove coverage.info "*/tests/*" -o coverage.info --rc lcov_branch_coverage=1 + LANG=C $(GENHTML) --prefix $(builddir)/src --output-directory coveragereport --title "Code Coverage" --legend --show-details coverage.info --rc lcov_branch_coverage=1 + +clean-coverage-html: clean-gcda + -$(LCOV) --directory $(builddir)/src -z + -$(LCOV) --directory $(builddir)/test -z + -rm -rf coverage.info coveragereport + +clean-local: clean-coverage-html +endif # HAVE_GCOV diff --git a/README.GIT b/README.GIT --- a/README.GIT +++ b/README.GIT @@ -47,3 +47,7 @@ maintainer should also make sure that the required version of automake et al. are properly indicated at the top of configure.ac and take care to copy the files and not merely use symlinks. + +In order to generate coverage information, compile with --enable-gcov. +You need to install lcov for this. Running "make coverage-html" will +generate a coverage report in coveragereport/index.html. diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -127,6 +127,12 @@ AC_PROG_YACC AX_PROG_BISON([have_bison=yes],[have_bison=no]) +# gcov coverage reporting +AC_CHECK_PROGS(GCOV, [gcov], gcov) +AC_TDD_GCOV +AC_SUBST(COVERAGE_CFLAGS) +AC_SUBST(COVERAGE_LDFLAGS) + AC_C_INLINE # We need to compile and run a program on the build machine. diff --git a/m4/Makefile.am b/m4/Makefile.am --- a/m4/Makefile.am +++ b/m4/Makefile.am @@ -1,5 +1,5 @@ EXTRA_DIST = autobuild.m4 gnupg-typedef.m4 gpg-error.m4 libgcrypt.m4 \ - libtool.m4 ax_prog_bison.m4 + libtool.m4 ax_prog_bison.m4 gcov.m4 diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,7 +36,7 @@ DISTCLEANFILES = asn1-tables.c AM_CPPFLAGS = -I$(top_builddir)/gl -I$(top_srcdir)/gl -AM_CFLAGS = $(GPG_ERROR_CFLAGS) +AM_CFLAGS = $(GPG_ERROR_CFLAGS) $(COVERAGE_CFLAGS) if HAVE_LD_VERSION_SCRIPT @@ -82,7 +82,8 @@ libksba_la_LDFLAGS = $(no_undefined) $(export_symbols) $(extra_ltoptions) \ $(libksba_version_script_cmd) -version-info \ - @LIBKSBA_LT_CURRENT@:@LIBKSBA_LT_REVISION@:@LIBKSBA_LT_AGE@ + @LIBKSBA_LT_CURRENT@:@LIBKSBA_LT_REVISION@:@LIBKSBA_LT_AGE@ \ + $(COVERAGE_LDFLAGS) libksba_la_INCLUDES = -I$(top_srcdir)/lib libksba_la_DEPENDENCIES = $(srcdir)/libksba.vers $(ksba_deps) libksba_la_LIBADD = $(ksba_res) @LTLIBOBJS@ @GPG_ERROR_LIBS@ diff --git a/src/reader.c b/src/reader.c --- a/src/reader.c +++ b/src/reader.c @@ -407,6 +407,41 @@ } r->nread += *nread; } + else if (r->type == READER_TYPE_FD) + { + ssize_t n; + + if (r->eof) + return gpg_error (GPG_ERR_EOF); + + if (!length) + { + *nread = 0; + return 0; + } + + n = read (r->u.fd, buffer, length); + if (n > 0) + { + r->nread += n; + *nread = n; + } + else + { + *nread = 0; + + if (n < 0) + { + r->error = errno; + return gpg_error_from_errno (errno); + } + else + { + r->eof = 1; + return gpg_error (GPG_ERR_EOF); + } + } + } else return gpg_error (GPG_ERR_BUG); diff --git a/tests/Makefile.am b/tests/Makefile.am --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -39,10 +39,10 @@ BUILT_SOURCES = oidtranstbl.h CLEANFILES = oidtranstbl.h -TESTS = cert-basic t-crl-parser t-dnparser t-oid +TESTS = cert-basic t-crl-parser t-dnparser t-oid t-reader -AM_CFLAGS = $(GPG_ERROR_CFLAGS) -AM_LDFLAGS = -no-install +AM_CFLAGS = $(GPG_ERROR_CFLAGS) $(COVERAGE_CFLAGS) +AM_LDFLAGS = -no-install $(COVERAGE_LDFLAGS) noinst_HEADERS = t-common.h noinst_PROGRAMS = $(TESTS) t-cms-parser t-crl-parser t-dnparser t-ocsp diff --git a/tests/t-reader.c b/tests/t-reader.c new file mode 100644 --- /dev/null +++ b/tests/t-reader.c @@ -0,0 +1,201 @@ +/* t-dnparser.c - basic tests for the reader object + * Copyright (C) 2017 g10 Code GmbH + * + * This file is part of KSBA. + * + * KSBA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * KSBA 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, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../src/ksba.h" +#include "t-common.h" + +void +test_fd(const char* path) +{ + int fd = open (path, O_RDONLY); + gpg_error_t err = 0; + ksba_reader_t reader; + ksba_cert_t cert; + + if (fd < 0) + { + perror ("open() failed"); + exit (1); + } + + if ((err = ksba_reader_new (&reader))) + { + fprintf (stderr, "ksba_reader_new() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + if ((err = ksba_reader_set_fd (reader, fd))) + { + fprintf (stderr, "ksba_reader_set_fd() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + if ((err = ksba_cert_new (&cert))) + { + fprintf (stderr, "ksba_cert_new() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + if ((err = ksba_cert_read_der (cert, reader))) + { + fprintf(stderr, "ksba_cert_read_der() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + ksba_cert_release (cert); + ksba_reader_release (reader); + close (fd); +} + +void +test_file(const char* path) +{ + FILE* fd = fopen (path, "r"); + gpg_error_t err = 0; + ksba_reader_t reader; + ksba_cert_t cert; + + if (!fd) + { + perror ("fopen() failed"); + exit (1); + } + + if ((err = ksba_reader_new (&reader))) + { + fprintf (stderr, "ksba_reader_new() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + if ((err = ksba_reader_set_file (reader, fd))) + { + fprintf (stderr, "ksba_reader_set_fd() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + if ((err = ksba_cert_new (&cert))) + { + fprintf (stderr, "ksba_cert_new() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + if ((err = ksba_cert_read_der (cert, reader))) + { + fprintf(stderr, "ksba_cert_read_der() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + ksba_cert_release (cert); + ksba_reader_release (reader); + fclose (fd); +} + +void +test_mem(const char* path) +{ + int fd = open (path, O_RDONLY); + gpg_error_t err = 0; + ksba_reader_t reader; + ksba_cert_t cert; + char *mem = NULL; + struct stat st; + + if (fd < 0) + { + perror ("fopen() failed"); + exit (1); + } + + if (fstat (fd, &st)) + { + fprintf (stderr, "fstat() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + if ((mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == NULL) + { + fprintf (stderr, "fstat() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + if ((err = ksba_reader_new (&reader))) + { + fprintf (stderr, "ksba_reader_new() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + if ((err = ksba_reader_set_mem (reader, mem, st.st_size))) + { + fprintf (stderr, "ksba_reader_set_mem() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + if ((err = ksba_cert_new (&cert))) + { + fprintf (stderr, "ksba_cert_new() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + if ((err = ksba_cert_read_der (cert, reader))) + { + fprintf(stderr, "ksba_cert_read_der() failed: %s\n", gpg_strerror (err)); + exit (1); + } + + ksba_cert_release (cert); + ksba_reader_release (reader); + munmap (mem, st.st_size); + close (fd); +} + +int +main (int argc, char **argv) +{ + if (argc == 1) + { + test_fd ("cert_g10code_test1.der"); + test_file ("cert_g10code_test1.der"); + test_mem ("cert_g10code_test1.der"); + } + else + { + for (int i = 1; i < argc; ++i) + { + test_fd (argv[i]); + test_file (argv[i]); + test_mem (argv[i]); + } + } + + return 0; +}