-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #833 from mull-project/mutate-diffs
Incremental mutation testing using GitDiffFilter
- Loading branch information
Showing
55 changed files
with
1,179 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
Incremental mutation testing | ||
============================ | ||
|
||
Normally, Mull looks for mutations in all files of a project. Depending on a | ||
project's size, a number of mutations can be very large, so running Mull | ||
against all of them might be a rather slow process. Speed aside, an analysis of | ||
a large mutation data sets can be very time consuming work to be done by a | ||
user. | ||
|
||
Incremental mutation testing is a feature that enables running Mull only on the | ||
mutations found in Git Diff changesets. Instead of analysing all files and | ||
functions, Mull only finds mutations in the source lines that are covered by | ||
a particular Git Diff changeset. | ||
|
||
Example: if a Git diff is created from a project's Git tree and the diff is only | ||
one line, Mull will only find mutations in that line and will skip everything | ||
else. | ||
|
||
To enable incremental mutation testing, two arguments have to be provided to | ||
Mull: ``-git-diff-ref=<branch or commit>`` and ``-git-project-root=<path>`` | ||
which is a path to a project's Git root path. | ||
|
||
An additional debug option ``-debug`` can be useful for a visualization of how | ||
exactly Mull whitelists or blacklists found source lines. | ||
|
||
**Note:** Incremental mutation testing is an experimental feature. Things might | ||
go wrong. If you encounter any issues, please report them on the | ||
`mull/issues <https://github.com/mull-project/mull/issues>`_ tracker. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#pragma once | ||
|
||
#include "mull/Diagnostics/Diagnostics.h" | ||
#include "mull/Filters/Filter.h" | ||
#include "mull/Filters/GitDiffReader.h" | ||
#include "mull/Filters/InstructionFilter.h" | ||
|
||
namespace mull { | ||
struct SourceLocation; | ||
class GitDiffFilter : public InstructionFilter { | ||
public: | ||
static GitDiffFilter *createFromGitDiff(Diagnostics &diagnostics, | ||
const std::string &gitProjectRoot, | ||
const std::string &gitDiffBranch); | ||
|
||
GitDiffFilter(Diagnostics &diagnostics, GitDiffInfo gitDiffInfo); | ||
|
||
std::string name() override; | ||
bool shouldSkip(llvm::Instruction *instruction) const override; | ||
|
||
private: | ||
Diagnostics &diagnostics; | ||
const GitDiffInfo gitDiffInfo; | ||
}; | ||
} // namespace mull |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#pragma once | ||
|
||
#include "mull/Diagnostics/Diagnostics.h" | ||
|
||
#include <map> | ||
#include <string> | ||
#include <vector> | ||
|
||
namespace mull { | ||
class Diagnostics; | ||
|
||
typedef std::pair<int, int> GitDiffSourceFileRange; | ||
typedef std::vector<GitDiffSourceFileRange> GitDiffSourceFileRanges; | ||
typedef std::map<std::string, GitDiffSourceFileRanges> GitDiffInfo; | ||
|
||
class GitDiffReader { | ||
public: | ||
GitDiffReader(Diagnostics &diagnostics, const std::string gitRepoPath); | ||
GitDiffInfo readGitDiff(const std::string &gitBranch); | ||
GitDiffInfo parseDiffContent(const std::string &diffContent); | ||
|
||
private: | ||
Diagnostics &diagnostics; | ||
const std::string gitRepoPath; | ||
}; | ||
} // namespace mull |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
#include "mull/Filters/GitDiffFilter.h" | ||
|
||
#include "mull/Diagnostics/Diagnostics.h" | ||
#include "mull/SourceLocation.h" | ||
#include "mull/Toolchain/Runner.h" | ||
|
||
#include "llvm/IR/InstIterator.h" | ||
#include <llvm/IR/DebugInfoMetadata.h> | ||
#include <llvm/IR/DebugLoc.h> | ||
#include <llvm/IR/Function.h> | ||
#include <llvm/Support/FileSystem.h> | ||
|
||
#include <iostream> | ||
#include <regex> | ||
#include <sstream> | ||
#include <unistd.h> | ||
|
||
using namespace mull; | ||
|
||
GitDiffFilter *GitDiffFilter::createFromGitDiff(Diagnostics &diagnostics, | ||
const std::string &gitProjectRoot, | ||
const std::string &gitDiffBranch) { | ||
mull::GitDiffReader gitDiffReader(diagnostics, gitProjectRoot); | ||
mull::GitDiffInfo gitDiffInfo = gitDiffReader.readGitDiff(gitDiffBranch); | ||
return new GitDiffFilter(diagnostics, gitDiffInfo); | ||
} | ||
|
||
GitDiffFilter::GitDiffFilter(Diagnostics &diagnostics, GitDiffInfo gitDiffInfo) | ||
: diagnostics(diagnostics), gitDiffInfo(gitDiffInfo) {} | ||
|
||
std::string GitDiffFilter::name() { | ||
return "Git Diff"; | ||
} | ||
|
||
bool GitDiffFilter::shouldSkip(llvm::Instruction *instruction) const { | ||
SourceLocation sourceLocation = SourceLocation::locationFromInstruction(instruction); | ||
if (sourceLocation.isNull()) { | ||
return true; | ||
} | ||
|
||
/// If no diff, then filtering out. | ||
if (gitDiffInfo.size() == 0) { | ||
std::stringstream debugMessage; | ||
debugMessage << "GitDiffFilter: git diff is empty. Skipping instruction: "; | ||
debugMessage << sourceLocation.filePath << ":"; | ||
debugMessage << sourceLocation.line << ":" << sourceLocation.column; | ||
diagnostics.debug(debugMessage.str()); | ||
return true; | ||
} | ||
|
||
/// If file is not in the diff, then filtering out. | ||
if (gitDiffInfo.count(sourceLocation.filePath) == 0) { | ||
std::stringstream debugMessage; | ||
debugMessage << "GitDiffFilter: the file is not present in the git diff. "; | ||
debugMessage << "Skipping instruction: "; | ||
debugMessage << sourceLocation.filePath << ":"; | ||
debugMessage << sourceLocation.line << ":" << sourceLocation.column; | ||
diagnostics.debug(debugMessage.str()); | ||
return true; | ||
} | ||
|
||
GitDiffSourceFileRanges ranges = gitDiffInfo.at(sourceLocation.filePath); | ||
for (auto &range : ranges) { | ||
int rangeEnd = range.first + range.second - 1; | ||
if (range.first <= sourceLocation.line && sourceLocation.line <= rangeEnd) { | ||
std::stringstream debugMessage; | ||
debugMessage << "GitDiffFilter: whitelisting instruction: "; | ||
debugMessage << sourceLocation.filePath << ":"; | ||
debugMessage << sourceLocation.line << ":" << sourceLocation.column; | ||
diagnostics.debug(debugMessage.str()); | ||
return false; | ||
} | ||
} | ||
|
||
std::stringstream debugMessage; | ||
debugMessage << "GitDiffFilter: skipping instruction: "; | ||
debugMessage << sourceLocation.filePath << ":"; | ||
debugMessage << sourceLocation.line << ":" << sourceLocation.column; | ||
diagnostics.debug(debugMessage.str()); | ||
|
||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
#include "mull/Filters/GitDiffReader.h" | ||
|
||
#include "mull/Diagnostics/Diagnostics.h" | ||
#include <mull/Path.h> | ||
#include "mull/Toolchain/Runner.h" | ||
|
||
#include <iostream> | ||
#include <regex> | ||
#include <sstream> | ||
|
||
using namespace mull; | ||
|
||
GitDiffReader::GitDiffReader(Diagnostics &diagnostics, const std::string gitRepoPath) | ||
: diagnostics(diagnostics), gitRepoPath(gitRepoPath) {} | ||
|
||
GitDiffInfo GitDiffReader::readGitDiff(const std::string &gitBranch) { | ||
/// The implementation is borrowed from the git-clang-format Python tool. | ||
/// https://opensource.apple.com/source/clang/clang-800.0.38/src/tools/clang/tools/clang-format/git-clang-format.auto.html | ||
Runner runner(diagnostics); | ||
|
||
std::vector<std::string> args = { "diff", "-U0", gitBranch }; | ||
|
||
ExecutionResult result = | ||
runner.runProgram("git", args, {}, 5000, true, gitRepoPath); | ||
if (result.exitStatus != 0) { | ||
diagnostics.warning( | ||
std::string("GitDiffReader: cannot get git diff information. Received output: ") + | ||
result.stderrOutput); | ||
return GitDiffInfo(); | ||
} | ||
|
||
const std::string diffContent = result.stdoutOutput; | ||
GitDiffInfo gitDiffInfo = parseDiffContent(diffContent); | ||
return gitDiffInfo; | ||
} | ||
|
||
GitDiffInfo GitDiffReader::parseDiffContent(const std::string &diffContent) { | ||
GitDiffInfo gitDiffInfo; | ||
if (diffContent.empty()) { | ||
return gitDiffInfo; | ||
} | ||
|
||
std::stringstream diffStream(diffContent); | ||
std::string currentLine; | ||
|
||
std::string currentFileName; | ||
|
||
while (std::getline(diffStream, currentLine, '\n')) { | ||
std::regex lineRegex("^\\+\\+\\+\\ [^/]+/(.*)"); | ||
std::regex rangeRegex("^@@ -[0-9,]+ \\+(\\d+)(,(\\d+))?"); | ||
std::smatch matches; | ||
|
||
if (std::regex_search(currentLine, matches, lineRegex)) { | ||
currentFileName = absoluteFilePath(this->gitRepoPath, matches[1].str()); | ||
continue; | ||
} | ||
|
||
if (std::regex_search(currentLine, matches, rangeRegex)) { | ||
const std::string startLineStr = matches[1].str(); | ||
int startLine = std::stoi(startLineStr); | ||
|
||
size_t lineCount = 1; | ||
const std::string lineCountStr = matches[3].str(); | ||
if (lineCountStr.size() > 0) { | ||
lineCount = std::stoi(lineCountStr); | ||
} | ||
if (lineCount > 0) { | ||
if (gitDiffInfo.count(currentFileName) == 0) { | ||
gitDiffInfo[currentFileName] = std::vector<GitDiffSourceFileRange>(); | ||
} | ||
gitDiffInfo[currentFileName].push_back(std::pair<int, int>(startLine, lineCount)); | ||
} | ||
} | ||
} | ||
return gitDiffInfo; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,4 +7,5 @@ | |
*.tmp | ||
*.profdata | ||
*.profraw | ||
**/Output/** | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.