mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 13:26:10 +01:00
139 lines
4.0 KiB
C++
139 lines
4.0 KiB
C++
#include <algorithm>
|
|
#include <array>
|
|
#include <cassert>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <numeric>
|
|
#include <regex>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
std::string escape_arg(const std::string& arg) {
|
|
if (arg.empty() == false &&
|
|
arg.find_first_of(" \t\n\v\"") == arg.npos) {
|
|
return arg;
|
|
}
|
|
|
|
std::string escaped;
|
|
escaped.push_back('"');
|
|
for (auto it = arg.begin(); ; ++it) {
|
|
int num_backslashes = 0;
|
|
|
|
while (it != arg.end() && *it == '\\') {
|
|
++it;
|
|
++num_backslashes;
|
|
}
|
|
|
|
if (it == arg.end()) {
|
|
escaped.append(num_backslashes * 2, '\\');
|
|
break;
|
|
} else if (*it == '"') {
|
|
escaped.append(num_backslashes * 2 + 1, '\\');
|
|
escaped.push_back(*it);
|
|
} else {
|
|
escaped.append(num_backslashes, '\\');
|
|
escaped.push_back(*it);
|
|
}
|
|
}
|
|
escaped.push_back('"');
|
|
|
|
return escaped;
|
|
}
|
|
|
|
|
|
void create_empty_file(std::string const& path) {
|
|
std::ofstream ofs(path);
|
|
ofs << '\n';
|
|
}
|
|
|
|
const std::string separator = "--sep--";
|
|
const std::string logfile_prefix = "--log-file=";
|
|
|
|
bool starts_with(std::string const& str, std::string const& pref) {
|
|
return str.find(pref) == 0;
|
|
}
|
|
|
|
int parse_log_file_arg(std::string const& arg) {
|
|
assert(starts_with(arg, logfile_prefix) && "Attempting to parse incorrect arg!");
|
|
auto fname = arg.substr(logfile_prefix.size());
|
|
create_empty_file(fname);
|
|
std::regex regex("MemoryChecker\\.(\\d+)\\.log", std::regex::icase);
|
|
std::smatch match;
|
|
if (std::regex_search(fname, match, regex)) {
|
|
return std::stoi(match[1]);
|
|
} else {
|
|
throw std::domain_error("Couldn't find desired expression in string: " + fname);
|
|
}
|
|
}
|
|
|
|
std::string catch_path(std::string path) {
|
|
auto start = path.find("catch");
|
|
// try capitalized instead
|
|
if (start == std::string::npos) {
|
|
start = path.find("Catch");
|
|
}
|
|
if (start == std::string::npos) {
|
|
throw std::domain_error("Couldn't find Catch's base path");
|
|
}
|
|
auto end = path.find_first_of("\\/", start);
|
|
return path.substr(0, end);
|
|
}
|
|
|
|
std::string windowsify_path(std::string path) {
|
|
for (auto& c : path) {
|
|
if (c == '/') {
|
|
c = '\\';
|
|
}
|
|
}
|
|
return path;
|
|
}
|
|
|
|
void exec_cmd(std::string const& cmd, int log_num, std::string const& path) {
|
|
std::array<char, 128> buffer;
|
|
#if defined(_WIN32)
|
|
// cmd has already been escaped outside this function.
|
|
auto real_cmd = "OpenCppCoverage --export_type binary:cov-report" + std::to_string(log_num)
|
|
+ ".bin --quiet " + "--sources " + escape_arg(path) + " --cover_children -- " + cmd;
|
|
std::cout << "=== Marker ===: Cmd: " << real_cmd << '\n';
|
|
std::shared_ptr<FILE> pipe(_popen(real_cmd.c_str(), "r"), _pclose);
|
|
#else // Just for testing, in the real world we will always work under WIN32
|
|
(void)log_num; (void)path;
|
|
std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
|
|
#endif
|
|
|
|
if (!pipe) {
|
|
throw std::runtime_error("popen() failed!");
|
|
}
|
|
while (!feof(pipe.get())) {
|
|
if (fgets(buffer.data(), 128, pipe.get()) != nullptr) {
|
|
std::cout << buffer.data();
|
|
}
|
|
}
|
|
}
|
|
|
|
// argv should be:
|
|
// [0]: our path
|
|
// [1]: "--log-file=<path>"
|
|
// [2]: "--sep--"
|
|
// [3]+: the actual command
|
|
|
|
int main(int argc, char** argv) {
|
|
std::vector<std::string> args(argv, argv + argc);
|
|
auto sep = std::find(begin(args), end(args), separator);
|
|
assert(sep - begin(args) == 2 && "Structure differs from expected!");
|
|
|
|
auto num = parse_log_file_arg(args[1]);
|
|
|
|
auto cmdline = std::accumulate(++sep, end(args), std::string{}, [] (const std::string& lhs, const std::string& rhs) {
|
|
return lhs + ' ' + escape_arg(rhs);
|
|
});
|
|
|
|
try {
|
|
return exec_cmd(cmdline, num, windowsify_path(catch_path(args[0])));
|
|
} catch (std::exception const& ex) {
|
|
std::cerr << "Helper failed with: '" << ex.what() << "'\n";
|
|
return 12;
|
|
}
|
|
}
|