diff --git a/.jenkins.d/10-build.sh b/.jenkins.d/10-build.sh index 7f885fb..f0df3eb 100755 --- a/.jenkins.d/10-build.sh +++ b/.jenkins.d/10-build.sh @@ -27,7 +27,7 @@ fi # Configure/build in debug mode with tests if [[ $JOB_NAME == *"code-coverage" ]]; then - COVERAGE="" # TODO add code coverage support + COVERAGE="--with-coverage" elif ! has OSX-10.9 $NODE_LABELS && ! has OSX-10.11 $NODE_LABELS; then ASAN="--with-sanitizer=address" fi diff --git a/.jenkins.d/30-coverage.sh b/.jenkins.d/30-coverage.sh index fc3cbc0..7637b61 100755 --- a/.jenkins.d/30-coverage.sh +++ b/.jenkins.d/30-coverage.sh @@ -6,11 +6,27 @@ source "$JDIR"/util.sh set -x -# TODO add code coverage support -if false && [[ $JOB_NAME == *"code-coverage" ]]; then +if [[ $JOB_NAME == *"code-coverage" ]]; then gcovr --object-directory=build \ --output=build/coverage.xml \ - --filter="$PWD/(core|tools)" \ + --exclude="$PWD/tests" \ --root=. \ --xml + + # Generate also a detailed HTML output, but using lcov (better results) + lcov --quiet \ + --capture --no-external \ + --directory . \ + --rc lcov_branch_coverage=1 \ + --output-file build/coverage-with-tests.info + + lcov --quiet \ + --remove build/coverage-with-tests.info "$PWD/tests/*" \ + --rc lcov_branch_coverage=1 \ + --output-file build/coverage.info + + genhtml --legend \ + --rc genhtml_branch_coverage=1 \ + build/coverage.info \ + --output-directory build/coverage fi diff --git a/.waf-tools/coverage.py b/.waf-tools/coverage.py new file mode 100644 index 0000000..ce92883 --- /dev/null +++ b/.waf-tools/coverage.py @@ -0,0 +1,22 @@ +# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +from waflib import TaskGen, Logs + +def options(opt): + opt.add_option('--with-coverage', action='store_true', default=False, dest='with_coverage', + help='''Set compiler flags for gcc to enable code coverage information''') + +def configure(conf): + if conf.options.with_coverage: + if not conf.options.debug: + conf.fatal("Code coverage flags require debug mode compilation (add --debug)") + conf.check_cxx(cxxflags=['-fprofile-arcs', '-ftest-coverage', '-fPIC'], + linkflags=['-fprofile-arcs'], uselib_store='GCOV', mandatory=True) + +@TaskGen.feature('cxx','cc') +@TaskGen.after('process_source') +def add_coverage(self): + if getattr(self, 'use', ''): + self.use += ' GCOV' + else: + self.use = 'GCOV' diff --git a/tests/global-configuration-fixture.cpp b/tests/global-configuration-fixture.cpp new file mode 100644 index 0000000..35ceeed --- /dev/null +++ b/tests/global-configuration-fixture.cpp @@ -0,0 +1,83 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2014-2017, Regents of the University of California. + * + * This file is part of ndn-tools (Named Data Networking Essential Tools). + * See AUTHORS.md for complete list of ndn-tools authors and contributors. + * + * ndn-tools 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. + * + * ndn-tools 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 + * ndn-tools, e.g., in COPYING.md file. If not, see . + */ + +#include +#include + +#include "test-common.hpp" + +namespace ndn { +namespace tools { +namespace tests { + +class GlobalConfigurationFixture : boost::noncopyable +{ +public: + GlobalConfigurationFixture() + { + if (getenv("HOME") != nullptr) { + m_home = getenv("HOME"); + } + if (getenv("NDN_CLIENT_PIB") != nullptr) { + m_pib = getenv("NDN_CLIENT_PIB"); + } + if (getenv("NDN_CLIENT_TPM") != nullptr) { + m_tpm = getenv("NDN_CLIENT_TPM"); + } + + boost::filesystem::path dir(TMP_TESTS_PATH); + dir /= "test-home"; + setenv("HOME", dir.generic_string().c_str(), 1); + + if (exists(dir)) { + remove_all(dir); + } + + setenv("NDN_CLIENT_PIB", ("pib-sqlite3:" + dir.string()).c_str(), 1); + setenv("NDN_CLIENT_TPM", ("tpm-file:" + dir.string()).c_str(), 1); + create_directories(dir); + } + + ~GlobalConfigurationFixture() + { + if (!m_home.empty()) { + setenv("HOME", m_home.c_str(), 1); + } + if (!m_pib.empty()) { + setenv("NDN_CLIENT_PIB", m_pib.c_str(), 1); + } + if (!m_tpm.empty()) { + setenv("NDN_CLIENT_TPM", m_tpm.c_str(), 1); + } + } + +private: + std::string m_home; + std::string m_pib; + std::string m_tpm; +}; + +BOOST_GLOBAL_FIXTURE(GlobalConfigurationFixture) +#if (BOOST_VERSION >= 105900) +; +#endif // BOOST_VERSION >= 105900 + +} // namespace tests +} // namespace tools +} // namespace ndn diff --git a/wscript b/wscript index 07a7524..42cb690 100644 --- a/wscript +++ b/wscript @@ -9,7 +9,8 @@ import os def options(opt): opt.load(['compiler_cxx', 'gnu_dirs']) - opt.load(['default-compiler-flags', 'sanitizers', 'sphinx_build', 'boost'], + opt.load(['default-compiler-flags', 'coverage', 'sanitizers', 'boost', + 'sphinx_build'], tooldir=['.waf-tools']) opt.add_option('--with-tests', action='store_true', default=False, @@ -33,6 +34,9 @@ def configure(conf): boost_libs += ' unit_test_framework' conf.check_boost(lib=boost_libs) + # Loading "late" to prevent tests from being compiled with profiling flags + conf.load('coverage') + conf.recurse('tools') conf.load('sanitizers')