Browse Source

Add support for Rust coverage via tarpaulin

merge-requests/413/head
doe300 4 years ago
parent
commit
d1fd1b7a8e
  1. 73
      src/coverage.cpp
  2. 11
      src/coverage.hpp

73
src/coverage.cpp

@ -1,4 +1,5 @@
#include "coverage.hpp"
#include "compile_commands.hpp"
#include "config.hpp"
#include "filesystem.hpp"
#include "json.hpp"
@ -114,9 +115,75 @@ static std::vector<Coverage::LineCoverage> extract_gcov(JSON &&json, const boost
return {};
}
std::vector<Coverage::LineCoverage> Coverage::analyze(const FileInfo &file_info) {
if(file_info.language_id == "cpp" || file_info.language_id == "c") {
return extract_gcov(run_gcov(file_info.build_path, file_info.object_path), file_info.source_path);
static Coverage::LineCoverage tarpaulin_extract_line(const JSON &line_json) {
auto line = static_cast<unsigned long>(line_json.integer("line")) - 1U /* in tarpaulin, line numbers start at 1 */;
auto stats = line_json.object_optional("stats");
if(!stats) {
return Coverage::LineCoverage(line, 0);
}
auto count = static_cast<unsigned long>(stats->integer_optional("Line").value_or(0));
// branch and conditionally coverage are not yet implemented in tarpaulin (as of version 0.20.1
return Coverage::LineCoverage(line, count);
}
static std::vector<Coverage::LineCoverage> tarpaulin_extract_lines(const std::vector<JSON> &lines_json) {
std::vector<Coverage::LineCoverage> lines;
lines.reserve(lines_json.size());
std::transform(lines_json.begin(), lines_json.end(), std::back_inserter(lines), tarpaulin_extract_line);
std::sort(lines.begin(), lines.end());
return lines;
}
static std::vector<Coverage::LineCoverage> extract_tarpaulin(JSON &&json, const boost::filesystem::path &source_file) {
auto traces = json.object_optional("traces");
if(!traces) {
return {};
}
auto file_traces = traces->array_optional(source_file.string());
if(!file_traces) {
return {};
}
return tarpaulin_extract_lines(*file_traces);
}
std::vector<Coverage::LineCoverage> Coverage::analyze(Project::Build &build, const boost::filesystem::path &file_path, const std::string &language_id) {
if(language_id == "cpp" || language_id == "c") {
CompileCommands commands(build.get_default_path());
boost::filesystem::path object_file;
for(const auto &command : commands.commands) {
if(command.file == file_path) {
auto values = command.parameter_values("-o");
if(!values.empty()) {
object_file = command.directory / values.front();
break;
}
}
}
if(object_file.empty()) {
Terminal::get().async_print(file_path.filename().string() + ": could not find the C/C++ object file", true);
return std::vector<Coverage::LineCoverage>{};
}
return extract_gcov(run_gcov(build.get_default_path(), object_file), file_path);
}
if(language_id == "rust" && dynamic_cast<Project::CargoBuild *>(&build)) {
auto tarpaulin_folder = filesystem::get_canonical_path(build.get_default_path() / ".." / "tarpaulin");
if(!boost::filesystem::exists(tarpaulin_folder) || !boost::filesystem::is_directory(tarpaulin_folder)) {
Terminal::get().async_print("Directory '" + tarpaulin_folder.string() + "' does not exist, you may need to generate the coverage report via: cargo tarpaulin", true);
return std::vector<Coverage::LineCoverage>{};
}
for(const auto &file : boost::filesystem::directory_iterator(tarpaulin_folder)) {
if(boost::filesystem::is_regular(file.path()) && file.path().extension().string() == ".json") {
return extract_tarpaulin(JSON(file.path()), file_path);
}
}
Terminal::get().async_print("No JSON coverage file found in '" + tarpaulin_folder.string() + "', you may need to generate the coverage report via: cargo tarpaulin", true);
return std::vector<Coverage::LineCoverage>{};
}
return {};
}

11
src/coverage.hpp

@ -1,6 +1,7 @@
#pragma once
#include "boost/filesystem.hpp"
#include "project_build.hpp"
#include <vector>
namespace Coverage {
@ -33,13 +34,5 @@ namespace Coverage {
std::vector<BranchCoverage> branches;
};
struct FileInfo {
boost::filesystem::path source_path;
boost::filesystem::path object_path;
boost::filesystem::path build_path;
std::string language_id;
};
std::vector<LineCoverage> analyze(const FileInfo &file_info);
std::vector<LineCoverage> analyze(Project::Build &build, const boost::filesystem::path &file_path, const std::string &language_id);
} // namespace Coverage

Loading…
Cancel
Save