Commit b7df87cc authored by Sebastian Wolf's avatar Sebastian Wolf

Rewrite CodeCoverage

parent 997a6107
Pipeline #1169 failed with stages
in 12 minutes
......@@ -4,8 +4,7 @@
CXX = g++
COMPATIBILITY = -std=c++11
STRICT_WARNINGS = TRUE
DEBUG += -D XERUS_TEST_COVERAGE # Enable coverage tests
ACTIVATE_CODE_COVERAGE = TRUE # Enable coverage tests
DEBUG += -D _GLIBCXX_ASSERTIONS # Activate GLIBCXX assertions
DEBUG += -g # Adds debug symbols
......
......@@ -24,7 +24,7 @@ TEST_NAME = XerusTest
# ------------------------------------------------------------------------------------------------------
# Extract Xerus version from VERSION file
# Extract Xerus version from VERSION file and the git repository
# ------------------------------------------------------------------------------------------------------
VERSION_STRING = $(shell git describe --tags --always 2>/dev/null || cat VERSION)
......@@ -101,9 +101,9 @@ include makeIncludes/optimization.mk
# ------------------------------------------------------------------------------------------------------
# Set additional compiler options
# ------------------------------------------------------------------------------------------------------
ifdef ACTIVATE_CODE_COVERAGE
DEBUG += -D XERUS_TEST_COVERAGE
endif
# ------------------------------------------------------------------------------------------------------
# Convinience variables
......@@ -225,7 +225,7 @@ endif
$(TEST_NAME): $(MINIMAL_DEPS) $(UNIT_TEST_OBJECTS) $(TEST_OBJECTS) build/libxerus.a build/libxerus_misc.a
$(CXX) -D XERUS_UNITTEST $(FLAGS) $(UNIT_TEST_OBJECTS) $(TEST_OBJECTS) build/libxerus.a build/libxerus_misc.a $(SUITESPARSE) $(LAPACK_LIBRARIES) $(ARPACK_LIBRARIES) $(BLAS_LIBRARIES) $(CALLSTACK_LIBS) -o $(TEST_NAME)
$(CXX) -D XERUS_UNITTEST $(FLAGS) $(UNIT_TEST_OBJECTS) $(TEST_OBJECTS) build/libxerus.a build/libxerus_misc.a $(SUITESPARSE) $(LAPACK_LIBRARIES) $(ARPACK_LIBRARIES) $(BLAS_LIBRARIES) $(BOOST_LIBS) $(CALLSTACK_LIBS) -o $(TEST_NAME)
build/print_boost_version: src/print_boost_version.cpp
@$(CXX) -o $@ $<
......@@ -233,8 +233,16 @@ build/print_boost_version: src/print_boost_version.cpp
printBoostVersion: build/print_boost_version
@build/print_boost_version
ifdef ACTIVATE_CODE_COVERAGE
test:
mkdir -p build
$(MAKE) $(TEST_NAME) 2>&1 >/dev/null | grep "‘EnumMarker’ is deprecated" > build/required_tests.txt
./$(TEST_NAME) all
else
test: $(TEST_NAME)
./$(TEST_NAME) all
endif
test_python2: build/libxerus.so build/python2/xerus.so
......@@ -297,7 +305,7 @@ endif
# Build and execution rules for tutorials
build/.tutorialObjects/%: %.cpp $(MINIMAL_DEPS) build/libxerus.a build/libxerus_misc.a
mkdir -p $(dir $@)
$(CXX) -I include $< build/libxerus.a build/libxerus_misc.a $(SUITESPARSE) $(LAPACK_LIBRARIES) $(ARPACK_LIBRARIES) $(BLAS_LIBRARIES) $(CALLSTACK_LIBS) $(FLAGS) -MMD -o $@
$(CXX) -I include $< build/libxerus.a build/libxerus_misc.a $(SUITESPARSE) $(LAPACK_LIBRARIES) $(ARPACK_LIBRARIES) $(BLAS_LIBRARIES) $(BOOST_LIBS) $(CALLSTACK_LIBS) $(FLAGS) -MMD -o $@
# Build rule for the preCompileHeader
......
......@@ -65,7 +65,7 @@ COMPILE_THREADS = 8 # Number of threads to use during link t
# When performing tests it is useful to ensure that all of the code in covered. This is ensured by
# a set of macros including REQUIRE_TEST to mark lines that need to be tested. With the following
# definition this coverage is tested.
# DEBUG += -D XERUS_TEST_COVERAGE # Enable coverage tests
# ACTIVATE_CODE_COVERAGE = TRUE # Enable coverage tests
# You can add all kind of debuging options. In the following are some examples
......@@ -134,7 +134,7 @@ LAPACK_LIBRARIES = -llapacke -llapack # Standard Lapack +
SUITESPARSE = -lcholmod -lspqr
# Uncomment or add the approriate boost libraries
BOOST_LIBS = -lboost_filesystem
BOOST_LIBS = -lboost_filesystem -lboost_system
# (optional) Uncomment if needed, iterative eigenvalue solver ARPACK-ng, see https://github.com/opencollab/arpack-ng
# ARPACK_LIBRARIES = -larpack
......
......@@ -24,6 +24,8 @@
#pragma once
#include "codeCoverage.h"
/**
* @def XERUS_CHECK(condition, level, message)
* @brief Checks whether @a condition is true and calls XERUS_LOG(level, message) otherwise.
......@@ -45,22 +47,13 @@
* @brief Executes @a expression only if the compilation was without XERUS_DISABLE_RUNTIME_CHECKS set.
*/
#ifdef XERUS_TEST_COVERAGE
#include "../test/test.h"
#else
#define XERUS_REQUIRE_TEST (void)0
#endif
#ifndef XERUS_DISABLE_RUNTIME_CHECKS
#include "namedLogger.h"
#include "callStack.h"
#include "containerOutput.h"
#ifdef XERUS_TEST_COVERAGE
#define XERUS_CHECK(condition, level, message) XERUS_REQUIRE_TEST; if(XERUS_IS_LOGGING(level) && !(condition)) { XERUS_LOG(level, #condition " failed msg: " << message); } else void(0)
#else
#define XERUS_CHECK(condition, level, message) if(XERUS_IS_LOGGING(level) && !(condition)) { XERUS_LOG(level, #condition " failed msg: " << message); } else void(0)
#endif
#define XERUS_CHECK(condition, level, message) XERUS_REQUIRE_TEST; if(XERUS_IS_LOGGING(level) && !(condition)) { XERUS_LOG(level, #condition " failed msg: " << message); } else void(0)
#define XERUS_REQUIRE(condition, message) XERUS_CHECK(condition, error, message)
......@@ -85,11 +78,11 @@
#define XERUS_IF_NO_CHECK(expression)
#else
#define XERUS_CHECK(condition, level, message) void(0)
#define XERUS_CHECK(condition, level, message) XERUS_REQUIRE_TEST; void(0)
#define XERUS_REQUIRE(condition, message) void(0)
#define XERUS_REQUIRE(condition, message) XERUS_REQUIRE_TEST; void(0)
#define XERUS_INTERNAL_CHECK(condition, msg) void(0)
#define XERUS_INTERNAL_CHECK(condition, msg) XERUS_REQUIRE_TEST; void(0)
#define XERUS_IF_CHECK(expression)
......
// Xerus - A General Purpose Tensor Library
// Copyright (C) 2014-2019 Benjamin Huber and Sebastian Wolf.
//
// Xerus is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// Xerus 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Xerus. If not, see <http://www.gnu.org/licenses/>.
//
// For further information on Xerus visit https://libXerus.org
// or contact us at contact@libXerus.org.
/**
* @file
* @brief Header file for the code-coverage functions.
*/
#pragma once
#include <string>
#include <map>
#include <unordered_set>
#ifdef XERUS_TEST_COVERAGE
#define S1(x) #x
#define S2(x) S1(x)
#define LOCATION __FILE__ ":" S2(__LINE__)
#define LOCATION_MARKED "@" LOCATION "@"
#define XERUS_CC_MARK_WARNING enum [[deprecated(LOCATION_MARKED)]] EnumMarker {}; [[maybe_unused]] EnumMarker trigger;
/**
* @def XERUS_REQUIRE_TEST
* @brief Marked position for the code-coverage test. Any not passed XERUS_REQUIRE_TEST macro will result in a warning.
* XERUS_REQUIRE_TEST is implied by any XERUS_REQUIRE(...) macro if test coverage is enabled.
*/
#define XERUS_REQUIRE_TEST \
do { \
static const char * const xerusCCLocalFunctionName = __PRETTY_FUNCTION__;\
\
struct xerus_test_a{ static void rt() {\
xerus::misc::CodeCoverage::register_test(LOCATION, xerusCCLocalFunctionName);\
} };\
using xerus_test_t = void (*)(); \
static xerus_test_t xerus_test_rtp __attribute__((section(".init_array"))) = &xerus_test_a::rt; \
(void) xerus_test_rtp; \
\
xerus::misc::CodeCoverage::covered(LOCATION, xerusCCLocalFunctionName); \
\
XERUS_CC_MARK_WARNING \
} while(false)
#else
#define XERUS_REQUIRE_TEST (void)0
#endif
namespace xerus { namespace misc { namespace CodeCoverage {
extern std::map<std::string, std::unordered_set<std::string>>* testsCovered;
extern std::map<std::string, std::unordered_set<std::string>>* testsRequiredInit;
void register_test(const std::string& _location, const std::string& _identifier);
void covered(const std::string& _location, const std::string& _identifier);
void print_code_coverage();
}}}
......@@ -28,6 +28,8 @@
#include <string>
#include <fstream>
// #include "standard.h"
namespace xerus { namespace misc {
///@brief Creates all directories in the @a _path of the file, if needed.
......@@ -46,6 +48,10 @@ namespace xerus { namespace misc {
std::string read_file(const std::string& _path);
/// @brief Resolves 'folder/..' occurences in pathnames.
std::string /*XERUS_warn_unused*/ normalize_pathname(const std::string& _name);
#if __cplusplus >= 201402L
///@brief Opens a reading filestream for the given @a _path.
......
......@@ -34,9 +34,6 @@ namespace xerus {
/// @brief Demangles the function and class names created by gcc into a more readable format.
std::string XERUS_warn_unused demangle_cxa(const std::string& _cxa);
/// @brief Resolves 'folder/..' occurences in pathnames.
std::string XERUS_warn_unused normalize_pathname(const std::string& _name);
///@brief: Explodes a string at positions indicated by _delim.
std::vector<std::string> explode(const std::string& _string, const char _delim);
......
......@@ -24,34 +24,14 @@
#pragma once
/**
* @def XERUS_REQUIRE_TEST
* @brief Marked position for the code-coverage test. Any not passed XERUS_REQUIRE_TEST macro will result in a warning.
* XERUS_REQUIRE_TEST is implied by any XERUS_REQUIRE(...) macro if test coverage is enabled.
*/
#include <map>
#include <string>
#include <functional>
#include "../misc/namedLogger.h"
#ifdef XERUS_TEST_COVERAGE
#define XERUS_REQUIRE_TEST \
do { \
static const char * xerus_test_fname = __PRETTY_FUNCTION__;\
struct xerus_test_a{ static void rt() {\
xerus::misc::internal::RequiredTest::register_test(xerus_test_fname, __FILE__, __LINE__);\
} };\
using xerus_test_t = void (*)();\
static xerus_test_t xerus_test_rtp __attribute__((section(".init_array"))) = &xerus_test_a::rt; \
(void)xerus_test_rtp; \
xerus::misc::internal::RequiredTest::increase_counter(xerus_test_fname, __FILE__, __LINE__); \
} while(false)
#else
#define XERUS_REQUIRE_TEST (void)0
#endif
#include "../misc/codeCoverage.h"
#define XERUS_PRINTCHECK std::cout << u8"\033[1;32m\u2713 \033[0m" << std::flush
#define XERUS_PRINTFAIL std::cout << u8"\033[1;31m\u2717 \033[0m" << std::flush
......@@ -108,24 +88,4 @@ namespace xerus { namespace misc {
UnitTest(std::string _group, std::string _name, std::function<void()> _f);
};
#endif
namespace internal {
#ifdef XERUS_TEST_COVERAGE
struct RequiredTest {
struct Identifier {
std::string functionName;
std::string filename;
size_t lineNumber;
Identifier(std::string _func, std::string _file, size_t _line);
bool operator<(const Identifier &_rhs) const;
};
// order of construction of global objects is random so the first one has to create the map
static std::map<Identifier, size_t> *tests;
static void register_test(std::string _functionName, std::string _fileName, size_t _lineNb);
static void increase_counter(std::string _functionName, std::string _fileName, size_t _lineNb);
};
#endif
}}}
}}
// Xerus - A General Purpose Tensor Library
// Copyright (C) 2014-2019 Benjamin Huber and Sebastian Wolf.
//
// Xerus is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// Xerus 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Xerus. If not, see <http://www.gnu.org/licenses/>.
//
// For further information on Xerus visit https://libXerus.org
// or contact us at contact@libXerus.org.
/**
* @file
* @brief Implementation of code coverage functions.
*/
#include <xerus/misc/codeCoverage.h>
#include <iostream>
#include <iomanip>
#include <chrono>
#include <signal.h>
#include <sstream>
#include <string>
#include <unordered_set>
#include <string.h> // for strsignal
#include <sys/stat.h>
#include <sys/mman.h> // For mlockall
#include <xerus/misc/standard.h>
#include <xerus/misc/exceptions.h>
#include <xerus/misc/stringUtilities.h>
#include <xerus/misc/fileUtilities.h>
#include <xerus/misc/random.h>
#include <xerus/misc/internal.h>
namespace xerus { namespace misc { namespace CodeCoverage {
std::map<std::string, std::unordered_set<std::string>>* testsCovered;
std::map<std::string, std::unordered_set<std::string>>* testsRequiredInit;
void register_test(const std::string& _location, const std::string& _identifier) {
// Initialization order is undefined, therefore the first one has to initialize.
if(!testsRequiredInit) { testsRequiredInit = new std::map<std::string, std::unordered_set<std::string>>; }
(*testsRequiredInit)[_location].insert(_identifier);
}
void covered(const std::string& _location, const std::string& _identifier) {
// Initialization order is undefined, therefore the first covered test has to initialize.
if(!testsCovered) { testsCovered = new std::map<std::string, std::unordered_set<std::string>>; }
(*testsCovered)[_location].insert(_identifier);
}
void print_code_coverage() {
const std::string unknownName("Function name not detected");
// Set the required test from init
// requiredTests[file][lineNumber][functionIdentifier]
std::map<std::string, std::map<size_t, std::map<std::string, bool>>> requiredTests;
for(const auto& localTests : *testsRequiredInit) {
const auto locationParts = misc::explode(localTests.first, ':');
REQUIRE(locationParts.size() == 2, "Error parsing the required tests.");
const auto file = xerus::misc::normalize_pathname(locationParts[0]);
const auto lineNumber = xerus::misc::from_string<size_t>(locationParts[1]);
for(const auto& identifier : localTests.second) {
requiredTests[file][lineNumber][identifier] = false;
}
}
// Load further required tests
const auto testLines = xerus::misc::explode(xerus::misc::read_file("build/required_tests.txt"), '\n');
for(const auto& line : testLines) {
const auto lineParts = xerus::misc::explode(line, '@');
REQUIRE(lineParts.size() == 3, "Error parsing the required tests.");
const auto locationParts = misc::explode(lineParts[1], ':');
REQUIRE(locationParts.size() == 2, "Error parsing the required tests.");
const auto file = xerus::misc::normalize_pathname(locationParts[0]);
const auto lineNumber = xerus::misc::from_string<size_t>(locationParts[1]);
if(requiredTests[file].count(lineNumber) == 0) {
requiredTests[file][lineNumber][unknownName] = false;
}
}
// Assing covered tests to required ones
for( const auto &test : *testsCovered ) {
const auto locationParts = misc::explode(test.first, ':');
REQUIRE(locationParts.size() == 2, "Error parsing the required tests.");
const auto file = xerus::misc::normalize_pathname(locationParts[0]);
const auto lineNumber = xerus::misc::from_string<size_t>(locationParts[1]);
for( const auto& identifier : test.second ) {
REQUIRE(requiredTests.count(file) > 0 && requiredTests.at(file).count(lineNumber) > 0 && (requiredTests.at(file).at(lineNumber).count(identifier) > 0 || requiredTests.at(file).at(lineNumber).count(unknownName) > 0), "Test for: " << file << ":" << lineNumber << "( " << identifier << " ) is not required???");
if(requiredTests.at(file).at(lineNumber).count(unknownName) > 0) {
requiredTests[file][lineNumber][unknownName] = true;
} else {
requiredTests[file][lineNumber][identifier] = true;
}
}
}
// Check which tests are covered and assamble per file statistics
std::map<std::string, std::pair<size_t, size_t>> perFileStats;
for( const auto &fileTests : requiredTests ) {
for( const auto &lineTests : fileTests.second ) {
for( const auto &test : lineTests.second ) {
perFileStats[fileTests.first].first++;
if(test.second) {
perFileStats[fileTests.first].second++;
} else {
std::cout << "\033[1;31m Missing test for \033[0m" << fileTests.first << ":" << lineTests.first << ": " << test.first << std::endl;
}
}
}
}
// Print statistics
uint64_t totalExisting=0, totalPerformed=0;
for ( const auto &file : perFileStats ) {
const std::pair<size_t, size_t>& fstats = file.second;
totalExisting += fstats.first;
totalPerformed += fstats.second;
if (fstats.first == fstats.second) {
std::cout << "File " << file.first << " :\033[1;32m " << fstats.second << " of " << fstats.first << " tests performed\033[0m" << std::endl;
} else {
std::cout << "File " << file.first << " :\033[1;31m " << fstats.second << " of " << fstats.first << " tests performed\033[0m" << std::endl;
}
}
std::cout << "In total: " << totalPerformed << " of " << totalExisting << " = " << 100*double(totalPerformed)/double(totalExisting) << "% covered" << std::endl;
}
}}} // namespaces
......@@ -24,6 +24,7 @@
#include <xerus/misc/fileUtilities.h>
#include <xerus/misc/internal.h>
#include <xerus/misc/stringUtilities.h>
#include <fstream>
#include <boost/filesystem.hpp>
......@@ -75,6 +76,27 @@ namespace xerus { namespace misc {
}
std::string normalize_pathname(const std::string &_name) {
std::vector<std::string> oldpath = explode(_name,'/');
std::vector<std::string *> newpath;
for (std::string &f : oldpath) {
if (f.empty()) { continue; }
if (f==".." && !newpath.empty() && *newpath.back() != "..") {
newpath.pop_back();
} else {
newpath.push_back(&f);
}
}
std::string ret;
for (std::string *f : newpath) {
ret += *f;
ret += '/';
}
if (!ret.empty()) { ret.pop_back(); }
return ret;
}
#if __cplusplus >= 201402L
......
......@@ -41,26 +41,7 @@ namespace xerus {
return "";
}
std::string normalize_pathname(const std::string &_name) {
std::vector<std::string> oldpath = explode(_name,'/');
std::vector<std::string *> newpath;
for (std::string &f : oldpath) {
if (f.empty()) { continue; }
if (f==".." && !newpath.empty() && *newpath.back() != "..") {
newpath.pop_back();
} else {
newpath.push_back(&f);
}
}
std::string ret;
for (std::string *f : newpath) {
ret += *f;
ret += '/';
}
if (!ret.empty()) { ret.pop_back(); }
return ret;
}
std::vector<std::string> explode(const std::string& _string, const char _delim) {
std::vector<std::string> result;
std::istringstream iss(_string);
......@@ -72,6 +53,7 @@ namespace xerus {
return result;
}
void replace(std::string& _string, const std::string& _search, const std::string& _replace) {
size_t pos = 0;
......@@ -81,6 +63,7 @@ namespace xerus {
}
}
std::string trim(const std::string& _string, const std::string& whitespace) {
const size_t strBegin = _string.find_first_not_of(whitespace);
if (strBegin == std::string::npos) {
......@@ -89,6 +72,7 @@ namespace xerus {
const size_t strEnd = _string.find_last_not_of(whitespace);
return _string.substr(strBegin, strEnd - strBegin + 1);
}
std::string reduce(const std::string& _string, const std::string& whitespace, const std::string& fill) {
// Trim first
......
......@@ -37,6 +37,7 @@
#include <xerus/misc/standard.h>
#include <xerus/misc/exceptions.h>
#include <xerus/misc/stringUtilities.h>
#include <xerus/misc/fileUtilities.h>
#include <xerus/misc/random.h>
#include <xerus/misc/internal.h>
......@@ -57,42 +58,6 @@ namespace xerus { namespace misc {
}
namespace internal {
#ifdef XERUS_TEST_COVERAGE
std::map<RequiredTest::Identifier, size_t> *RequiredTest::tests;
RequiredTest::Identifier::Identifier(std::string _func, std::string _file, size_t _line) : functionName(_func), filename(_file), lineNumber(_line) {}
bool RequiredTest::Identifier::operator<(const Identifier &_rhs) const {
if (functionName < _rhs.functionName) {
return true;
} else if (functionName == _rhs.functionName && lineNumber < _rhs.lineNumber) {
return true;
} else {
return false;
}
}
void RequiredTest::register_test(std::string _functionName, std::string _fileName, size_t _lineNb) {
if (!tests) {
tests = new std::map<Identifier, size_t>();
}
Identifier key = Identifier(_functionName, _fileName, _lineNb);
// std::cout << "registered " << _functionName << " (" << _fileName << ":" << _lineNb << ")" << std::endl;
if (tests->count(key) == 0) {
(*tests)[key] = 0;
}
}
void RequiredTest::increase_counter(std::string _functionName, std::string _fileName, size_t _lineNb) {
if (!tests) {
// this can happen if some function in the init section (ie. before main) use REQUIREs
tests = new std::map<Identifier, size_t>();
}
Identifier key = Identifier(_functionName, _fileName, _lineNb);
// std::cout << "encountered " << _functionName << " (" << _fileName << ":" << _lineNb << ")" << std::endl;
(*tests)[key] += 1;
}
#endif
bool test(const std::pair<std::string, std::function<void()>> &_t, uint64 _seed=0) {
std::cout << "| " << _t.first << " starting: " << std::flush;
......@@ -178,6 +143,7 @@ int main(int argc, char* argv[]) {
// Prevent swap usage
mlockall(MCL_CURRENT | MCL_FUTURE);
// TODO Is this code useful?
// perform required_test initializations
// pass address of xerus::misc::internal::catch_signals as the address of main cannot be taken as by ISO c++...
std::pair<uintptr_t, uintptr_t> requiredTestRange = xerus::misc::get_range_of_section(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(&xerus::misc::internal::catch_signals)), "required_tests");
......@@ -185,7 +151,7 @@ int main(int argc, char* argv[]) {
try {
(*p)();
} catch (...) {
std::cout << "required test initialization failed. required test listing will be wrong." << std::endl;
std::cout << "Required test initialization failed. Required test listing will be wrong." << std::endl;
break;
}
}
......@@ -291,45 +257,11 @@ int main(int argc, char* argv[]) {
std::cout << "-------------------------------------------------------------------------------" << std::endl;
#ifdef XERUS_TEST_COVERAGE
// check whether all REQUIRED_TESTs were tested
std::map<std::string, std::pair<size_t, size_t>> perFile;
if (xerus::misc::internal::RequiredTest::tests) {
for (auto &t : (*xerus::misc::internal::RequiredTest::tests)) {
std::string normPath = xerus::misc::normalize_pathname(t.first.filename);
std::pair<size_t, size_t> &pf = perFile[normPath];
pf.second += 1;
if (t.second == 0) {
std::cout << "\033[1;31m missing test for function \033[0m"
<< xerus::misc::demangle_cxa(t.first.functionName) << " (" << normPath << ":" << t.first.lineNumber << ")" << std::endl;
} else {
pf.first += 1;
}
}
uint64_t totalPerformed=0;
uint64_t totalExisting=0;
for (auto &f : perFile) {
std::pair<size_t, size_t> &fstats = f.second;
totalPerformed += fstats.first;
totalExisting += fstats.second;
if (fstats.first == fstats.second) {
std::cout << "file " << f.first << " :\033[1;32m " << fstats.first << " of " << fstats.second << " tests performed\033[0m" << std::endl;
} else {
std::cout << "file " << f.first << " :\033[1;31m " << fstats.first << " of " << fstats.second << " tests performed\033[0m" << std::endl;
}
}
std::cout << "In total: " << totalPerformed << " of " << totalExisting << " = " << 100*double(totalPerformed)/double(totalExisting) << "% covered" << std::endl;
}
xerus::misc::CodeCoverage::print_code_coverage();
#endif
// Destroy all stored tests to make memory-leak detection simpler
delete xerus::misc::UnitTest::tests;
#ifdef XERUS_TEST_COVERAGE
delete xerus::misc::internal::RequiredTest::tests;
#endif
return totalPassCount != totalCount;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment