xaizek / uncov (License: AGPLv3+) (since 2018-12-07)
Uncov(er) is a tool that collects and processes code coverage reports.
Commit aa075c155c07fed338b9401c15a9521eb341e23a

Generalize GcovImporter::runner_f
So that it's capable of returning output of the command.
Author: xaizek
Author date (UTC): 2022-04-08 10:43
Committer name: xaizek
Committer date (UTC): 2022-04-08 10:43
Parent(s): 9d7765ab3180b20fd362becee85ce86ba3a3f888
Signing key: 99DC5E4DB05F6BE2
Tree: 76322c765233210438de5a94826137afd23b8f9e
File Lines added Lines deleted
src/GcovImporter.cpp 1 1
src/GcovImporter.hpp 4 2
src/sub_commands.cpp 7 2
tests/GcovImporter.cpp 4 0
tests/TestUtils.cpp 9 0
tests/TestUtils.hpp 8 0
tests/sub_commands.cpp 64 37
File src/GcovImporter.cpp changed (mode: 100644) (index ef661b8..86dc01c)
... ... GcovImporter::importAsFiles(std::vector<fs::path> gcnoFiles)
311 311
312 312 TempDir tempDir("gcovi"); TempDir tempDir("gcovi");
313 313 std::string tempDirPath = tempDir; std::string tempDirPath = tempDir;
314 getRunner()(std::move(cmd), tempDirPath);
314 (void)getRunner()(std::move(cmd), tempDirPath);
315 315
316 316 for (fs::recursive_directory_iterator it(tempDirPath), end; for (fs::recursive_directory_iterator it(tempDirPath), end;
317 317 it != end; ++it) { it != end; ++it) {
File src/GcovImporter.hpp changed (mode: 100644) (index 25260ad..865a8c1)
... ... class GcovImporter
86 86 { {
87 87 /** /**
88 88 * @brief Accepts comand to be run at specified directory. * @brief Accepts comand to be run at specified directory.
89 *
90 * When @p from is `-`, should return the output.
89 91 */ */
90 using runner_f = void(std::vector<std::string> &&cmd,
91 const std::string &dir);
92 using runner_f = std::string(std::vector<std::string> &&cmd,
93 const std::string &from);
92 94
93 95 public: public:
94 96 /** /**
File src/sub_commands.cpp changed (mode: 100644) (index dfddf96..33a34d8)
... ... public:
882 882 "make a dangling commit if working directory is dirty"); "make a dangling commit if working directory is dirty");
883 883
884 884 auto runner = [this](std::vector<std::string> &&cmd, auto runner = [this](std::vector<std::string> &&cmd,
885 const std::string &dir) {
886 std::string output = readProc(std::move(cmd), dir, CatchStderr{});
885 const std::string &from) {
886 const bool stdOut = (from == "-");
887 const std::string dir = (stdOut ? "." : from);
888 std::string output = readProc(std::move(cmd), dir,
889 CatchStderr{!stdOut});
890
887 891 if (verbose) { if (verbose) {
888 892 std::cout << output; std::cout << output;
889 893 } }
894 return (stdOut ? output : std::string());
890 895 }; };
891 896 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
892 897 } }
File tests/GcovImporter.cpp changed (mode: 100644) (index d4ba1ff..e134e09)
... ... TEST_CASE("Plain text format parsed and binning is performed", "[GcovImporter]")
64 64 << "file:" << relPath.string() << '\n' << "file:" << relPath.string() << '\n'
65 65 << "lcount:1,1\n" << "lcount:1,1\n"
66 66 << "lcount:2,0\n"; << "lcount:2,0\n";
67
68 return std::string();
67 69 }; };
68 70 auto prevRunner = GcovImporter::setRunner(runner); auto prevRunner = GcovImporter::setRunner(runner);
69 71 BOOST_SCOPE_EXIT_ALL(prevRunner) { BOOST_SCOPE_EXIT_ALL(prevRunner) {
 
... ... TEST_CASE("JSON format is parsed", "[GcovImporter]")
108 110 } }
109 111 ] ]
110 112 })"); })");
113
114 return std::string();
111 115 }; };
112 116 auto prevRunner = GcovImporter::setRunner(runner); auto prevRunner = GcovImporter::setRunner(runner);
113 117 BOOST_SCOPE_EXIT_ALL(prevRunner) { BOOST_SCOPE_EXIT_ALL(prevRunner) {
File tests/TestUtils.cpp changed (mode: 100644) (index 38a7d0e..4bd7e88)
21 21 #include <boost/iostreams/filtering_streambuf.hpp> #include <boost/iostreams/filtering_streambuf.hpp>
22 22 #include <boost/range.hpp> #include <boost/range.hpp>
23 23
24 #include <algorithm>
24 25 #include <fstream> #include <fstream>
25 26 #include <ostream> #include <ostream>
27 #include <string>
26 28
27 29 #include "Settings.hpp" #include "Settings.hpp"
28 30 #include "app.hpp" #include "app.hpp"
 
... ... makeGz(const std::string &path, const std::string &contents)
102 104
103 105 std::basic_ostream<char>(&out) << contents; std::basic_ostream<char>(&out) << contents;
104 106 } }
107
108 void
109 removeChars(std::string &str, char c)
110 {
111 auto newEnd = std::remove(str.begin(), str.end(), c);
112 str.erase(newEnd, str.end());
113 }
File tests/TestUtils.hpp changed (mode: 100644) (index 6d26b16..30d815b)
... ... std::string getDbPath(const Repository &repo);
161 161 */ */
162 162 void makeGz(const std::string &path, const std::string &contents); void makeGz(const std::string &path, const std::string &contents);
163 163
164 /**
165 * @brief Removes all occurances of a character @p c in a string @p str.
166 *
167 * @param str String for the operation.
168 * @param c Character to remove.
169 */
170 void removeChars(std::string &str, char c);
171
164 172 #endif // UNCOV__TESTS__TESTUTILS_HPP__ #endif // UNCOV__TESTS__TESTUTILS_HPP__
File tests/sub_commands.cpp changed (mode: 100644) (index d79f9d4..8b67086)
... ... TEST_CASE("Empty coverage data is imported",
1062 1062 BuildHistory bh(db); BuildHistory bh(db);
1063 1063
1064 1064 auto runner = [](std::vector<std::string> &&cmd, auto runner = [](std::vector<std::string> &&cmd,
1065 const std::string &/*dir*/) {
1065 const std::string &/*from*/) {
1066 1066 REQUIRE(cmd.size() == 4U); REQUIRE(cmd.size() == 4U);
1067 return std::string();
1067 1068 }; };
1068 1069 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1069 1070
 
... ... TEST_CASE("Coverage file is discovered",
1097 1098 std::ofstream{gcnoFile}; std::ofstream{gcnoFile};
1098 1099
1099 1100 auto runner = [&gcnoFile](std::vector<std::string> &&cmd, auto runner = [&gcnoFile](std::vector<std::string> &&cmd,
1100 const std::string &/*dir*/) {
1101 const std::string &/*from*/) {
1101 1102 REQUIRE(cmd.size() == 5U); REQUIRE(cmd.size() == 5U);
1102 1103 CHECK(boost::ends_with(cmd[4], gcnoFile)); CHECK(boost::ends_with(cmd[4], gcnoFile));
1104 return std::string();
1103 1105 }; };
1104 1106 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1105 1107
 
... ... TEST_CASE("Unexecuted files can be excluded",
1127 1129 BuildHistory bh(db); BuildHistory bh(db);
1128 1130
1129 1131 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1130 const std::string &/*dir*/) {
1132 const std::string &/*from*/) {
1133 return std::string();
1131 1134 }; };
1132 1135 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1133 1136
 
... ... TEST_CASE("new-gcovi --prefix", "[subcommands][new-gcovi-subcommand]")
1155 1158 BuildHistory bh(db); BuildHistory bh(db);
1156 1159
1157 1160 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1158 const std::string &dir) {
1159 std::ofstream{dir + "/subdir#file.gcov"}
1161 const std::string &from) {
1162 std::ofstream{from + "/subdir#file.gcov"}
1160 1163 << "file:file.cpp\n"; << "file:file.cpp\n";
1164 return std::string();
1161 1165 }; };
1162 1166 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1163 1167
 
... ... TEST_CASE("Executed files can be excluded",
1186 1190 BuildHistory bh(db); BuildHistory bh(db);
1187 1191
1188 1192 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1189 const std::string &dir) {
1190 std::ofstream{dir + "/subdir#file.gcov"}
1193 const std::string &from) {
1194 std::ofstream{from + "/subdir#file.gcov"}
1191 1195 << "file:subdir/file.cpp\n"; << "file:subdir/file.cpp\n";
1196 return std::string();
1192 1197 }; };
1193 1198 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1194 1199
 
... ... TEST_CASE("Gcov file is found and parsed",
1217 1222 BuildHistory bh(db); BuildHistory bh(db);
1218 1223
1219 1224 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1220 const std::string &dir) {
1225 const std::string &from) {
1226 std::string json = R"({
1227 "current_working_directory": "./",
1228 "files": [{
1229 "file": "test-file1.cpp",
1230 "lines": [
1231 { "line_number": 2, "count": 1 },
1232 { "line_number": 4, "count": 1 }
1233 ]
1234 }]
1235 })";
1236
1221 1237 GcovInfo gcovInfo; GcovInfo gcovInfo;
1222 if (gcovInfo.hasJsonFormat()) {
1223 makeGz(dir + "/test-file1.gcno.gcov.json.gz", R"({
1224 "current_working_directory": "./",
1225 "files": [{
1226 "file": "test-file1.cpp",
1227 "lines": [
1228 { "line_number": 2, "count": 1 },
1229 { "line_number": 4, "count": 1 }
1230 ]
1231 }]
1232 })");
1238 if (from == "-") {
1239 removeChars(json, '\n');
1240 return json;
1241 } else if (gcovInfo.hasJsonFormat()) {
1242 makeGz(from + "/test-file1.gcno.gcov.json.gz", json);
1233 1243 } else { } else {
1234 std::ofstream{dir + "/test-file1.gcov"}
1244 std::ofstream{from + "/test-file1.gcov"}
1235 1245 << "file:test-file1.cpp\n" << "file:test-file1.cpp\n"
1236 1246 << "lcount:2,1\n" << "lcount:2,1\n"
1237 1247 << "lcount:4,1\n"; << "lcount:4,1\n";
1238 1248 } }
1249
1250 return std::string();
1239 1251 }; };
1240 1252 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1241 1253
 
... ... TEST_CASE("Gcov file with broken format causes an exception",
1260 1272 BuildHistory bh(db); BuildHistory bh(db);
1261 1273
1262 1274 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1263 const std::string &dir) {
1275 const std::string &from) {
1276 std::string json = R"({
1277 "files": [{
1278 "file": "test-file1.cpp",
1279 "lines": [ { "line_number": 2, "count": 0 }, ]
1280 }]
1281 })";
1282
1264 1283 GcovInfo gcovInfo; GcovInfo gcovInfo;
1265 if (gcovInfo.hasJsonFormat()) {
1266 makeGz(dir + "/test-file1.gcno.gcov.json.gz", R"({
1267 "files": [{
1268 "file": "test-file1.cpp",
1269 "lines": [ { "line_number": 2, "count": 0 }, ]
1270 }]
1271 })");
1284 if (from == "-") {
1285 removeChars(json, '\n');
1286 return json;
1287 } else if (gcovInfo.hasJsonFormat()) {
1288 makeGz(from + "/test-file1.gcno.gcov.json.gz", json);
1272 1289 } else { } else {
1273 std::ofstream{dir + "/test-file1.gcov"}
1290 std::ofstream{from + "/test-file1.gcov"}
1274 1291 << "file:test-file1.cpp\n" << "file:test-file1.cpp\n"
1275 1292 << "lcount:2\n"; << "lcount:2\n";
1276 1293 } }
1294
1295 return std::string();
1277 1296 }; };
1278 1297 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1279 1298
 
... ... TEST_CASE("Modified source file is captured",
1305 1324 std::ofstream{sourceFile} << "int f() { return 666; }"; std::ofstream{sourceFile} << "int f() { return 666; }";
1306 1325
1307 1326 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1308 const std::string &/*dir*/) {
1327 const std::string &/*from*/) {
1328 return std::string();
1309 1329 }; };
1310 1330 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1311 1331
 
... ... TEST_CASE("Untracked source file is captured",
1340 1360 std::ofstream{untrackedFile}; std::ofstream{untrackedFile};
1341 1361
1342 1362 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1343 const std::string &/*dir*/) {
1363 const std::string &/*from*/) {
1364 return std::string();
1344 1365 }; };
1345 1366 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1346 1367
 
... ... TEST_CASE("Untracked source file is rejected without capture",
1377 1398 std::ofstream{untrackedFile}; std::ofstream{untrackedFile};
1378 1399
1379 1400 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1380 const std::string &/*dir*/) {
1401 const std::string &/*from*/) {
1402 return std::string();
1381 1403 }; };
1382 1404 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1383 1405
 
... ... TEST_CASE("Unmatched source fails build addition",
1409 1431 std::ofstream{sourceFile} << "int f() { return 666; }"; std::ofstream{sourceFile} << "int f() { return 666; }";
1410 1432
1411 1433 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1412 const std::string &/*dir*/) {
1434 const std::string &/*from*/) {
1435 return std::string();
1413 1436 }; };
1414 1437 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1415 1438
 
... ... TEST_CASE("new-gcovi --help", "[subcommands][new-gcovi-subcommand]")
1431 1454 BuildHistory bh(db); BuildHistory bh(db);
1432 1455
1433 1456 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1434 const std::string &/*dir*/) {
1457 const std::string &/*from*/) {
1458 return std::string();
1435 1459 }; };
1436 1460 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1437 1461
 
... ... TEST_CASE("new-gcovi --ref-name", "[subcommands][new-gcovi-subcommand]")
1457 1481 BuildHistory bh(db); BuildHistory bh(db);
1458 1482
1459 1483 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1460 const std::string &/*dir*/) {
1484 const std::string &/*from*/) {
1485 return std::string();
1461 1486 }; };
1462 1487 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1463 1488
 
... ... TEST_CASE("new-gcovi --capture-worktree can be noop",
1486 1511 BuildHistory bh(db); BuildHistory bh(db);
1487 1512
1488 1513 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1489 const std::string &/*dir*/) {
1514 const std::string &/*from*/) {
1515 return std::string();
1490 1516 }; };
1491 1517 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1492 1518
 
... ... TEST_CASE("new-gcovi --verbose", "[subcommands][new-gcovi-subcommand]")
1517 1543 std::ofstream{untrackedFile}; std::ofstream{untrackedFile};
1518 1544
1519 1545 auto runner = [](std::vector<std::string> &&/*cmd*/, auto runner = [](std::vector<std::string> &&/*cmd*/,
1520 const std::string &/*dir*/) {
1546 const std::string &/*from*/) {
1547 return std::string();
1521 1548 }; };
1522 1549 GcovImporter::setRunner(runner); GcovImporter::setRunner(runner);
1523 1550
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/uncov

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/uncov

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master