Skip to content

Commit

Permalink
Added link back to Stryker issue that started this
Browse files Browse the repository at this point in the history
  • Loading branch information
rajbos committed Oct 4, 2019
1 parent 13f6896 commit b2527ef
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 5 deletions.
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
# Stryker.MultipleProjectRunner
Runs Stryker for multiple .NET Core projects and aggregates the results
Runs Stryker for multiple .NET Core projects and aggregates the results, based on [this GitHub conversation](https://github.com/stryker-mutator/stryker-net/issues/740).

TL;DR: Stryker cannot run for an entire solution with multiple test projects (YET), so we need to help it a little and run each project by itself and then join the results.

### Note
This is a first draft and could use some more error handling 😄.


## Requirements
* Install dotnet core
* Install global dotnet core tool for Stryker: `dotnet tool install -g dotnet-stryker`
* `Git Clone` this repository somewhere
* Update the datafile with your files. See `DATAFILE` below
* `git clone` or `download` this repository somewhere
* Update the datafile with your files. See `DATAFILE` below.

## Running this script
Just call the script. It creates an Output directory from your starting path and will save all output files there
Expand All @@ -31,8 +36,8 @@ In the datafile the following properties should be set:
|jsonReportsPath|`D:\Source\SolutionFolder\Stryker.Output\`|Output folder|
|projectsToTest|see below|Array of projects to run|

### ProjectsToTest
The projectsToTest property is an array of items
### ProjectsToTest array
The projectsToTest property is an array of items with these properties:
|Property|Example|Description|
|---|---|---|
|csProjPath|`D:\Source\SolutionFolder\src\ProjectFolder\project.csproj`|FilePath of the project file to mutate|
Expand Down
138 changes: 138 additions & 0 deletions Run Stryker.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
function RunForOneAssembly ($csprojPath, $testPath, $solutionPath, $outputPath) {
Write-Host "csprojPath: " $csprojPath
Write-Host "Moving to test directory: $testPath"

Set-Location $testPath

Write-Host "Calling Stryker"
dotnet stryker --project-file "$csprojPath" --solution-path $solutionPath --reporters "['json', 'progress']"

if( -not $? ){
Write-Host "Error in running Stryker, exiting the script"
# write error output to Azure DevOps
Write-Host "##vso[task.complete result=Failed;]Error"
exit;
}

$searchPath = Split-Path -Path $testPath
Write-Host "Searching for json files in this path: $searchPath"
# find all json result files and use the most recent one
$files = Get-ChildItem -Path "$searchPath" -Filter "*.json" -Recurse -ErrorAction SilentlyContinue -Force
$file = $files | Sort-Object {$_.LastWriteTime} | Select-Object -last 1

# get the name and the timestamp of the file
$orgReportFilePath=$file.FullName
$splitted = $splitted = $orgReportFilePath.split("\")
$dateTimeStamp = $splitted[$splitted.Length - 3]
$fileName = $splitted[$splitted.Length - 1]
Write-Host "Last file filename: $orgReportFilePath has timestamp: $dateTimeStamp"

# create a new filename to use in the output
New-Item $outputPath -ItemType "directory" -Force
$newFileName = "$outputPath" + $dateTimeStamp + "_"+ $fileName
Write-Host "Copy the report file to '$newFileName'"
# write the new file out to the report directory
Copy-Item "$orgReportFilePath" "$newFileName"
}

function JoinStykerJsonFile ($additionalFile, $joinedFileName) {
# Stryker report json files object is not an array :-(, so we cannot join them and have to do it manually
$report = (Get-Content $joinedFileName | Out-String)
$additionalContent = (Get-Content $additionalFile | Out-String)

$searchString = '"files": {'
$searchStringLength = $searchString.Length
$startCopy = $additionalContent.IndexOf($searchString)
$offSet = 9
$copyText = $additionalContent.Substring($startCopy+$searchStringLength, $additionalContent.Length-$offSet-$startCopy-$searchStringLength)

# save the first part of the report file
$startCopy = $report.Substring(0, $report.Length-$offSet)
# add in the new copy text
$startCopy = $startCopy + ",`r`n" + $copyText
# add in the end of the file again
$fileEnding = $report.Substring($report.Length-$offSet, $offSet)
$startCopy = $startCopy + $fileEnding

# save the new file to disk
Set-Content -Path $joinedFileName -Value $startCopy
}

function JoinJsonWithHtmlFile ($joinedJsonFileName, $reportFileName, $emptyReportFileName, $reportTitle) {
$report = (Get-Content $emptyReportFileName | Out-String)
$Json = (Get-Content $joinedJsonFileName | Out-String)

$report = $report.Replace("##REPORT_JSON##", $Json)
$report = $report.Replace("##REPORT_TITLE##", $reportTitle)
# hardcoded link to the package from the npm CDN
$report = $report.Replace("<script>##REPORT_JS##</script>", '<script defer src="https://www.unpkg.com/mutation-testing-elements"></script>')

Set-Content -Path $reportFileName -Value $report
}

function JoinAllJsonFiles ($joinedFileName) {
$files = Get-ChildItem -Filter "*.json" -Exclude $joinedFileName -Recurse -ErrorAction SilentlyContinue -Force
Write-Host "Found $($files.Count) json files to join"
$firstFile = $true
foreach ($file in $files) {
if ($true -eq $firstFile) {
# copy the first file as is
Copy-Item $file.FullName "$joinedFileName"
$firstFile = $false
continue
}

JoinStykerJsonFile $file.FullName $joinedFileName
}
Write-Host "Joined $($files.Count) files to the new json file: $joinedFileName"
}

# save where we started
$startDir = Get-Location
Write-Host "Starting at: " $startDir
try {
# load the data file
$strykerDataFilePath = "$startDir\Stryker.data.json"
$strykerData = (Get-Content $strykerDataFilePath | Out-String | ConvertFrom-Json)

# check for errors
if( -not $?) {
exit;
}

# clear the output path
Write-Host "Deleting previous json files from $($strykerData.jsonReportsPath)"
Get-ChildItem -Path "$($strykerData.jsonReportsPath)" -Include *.json -File -Recurse | ForEach-Object { $_.Delete()}

# mutate all projects in the data file
$counter = 1
foreach ($project in $strykerData.projectsToTest) {
Write-Host "Running mutation for project $($counter) of $($strykerData.projectsToTest.Length)"

RunForOneAssembly $project.csprojPath $project.testPath $strykerData.solutionPath $strykerData.jsonReportsPath
$counter++
}

# check for errors
if( -not $?) {
exit;
}

# Join all the json files
Set-Location "$startDir\Output"
$joinedJsonFileName = "mutation-report.json"

JoinAllJsonFiles $joinedJsonFileName

# join the json with the html template for the final output
$reportFileName = "StrykerReport.html"
$emptyReportFileName = "$startDir\StrykerReportEmpty.html"
$reportTitle = "Stryker Mutation Testing"
JoinJsonWithHtmlFile $joinedJsonFileName $reportFileName $emptyReportFileName $reportTitle

Write-Host "Created new report file: $startDir\Output\$reportFileName"
}
finally {
# change back to the starting directory
Set-Location $startDir
}
14 changes: 14 additions & 0 deletions StrykerReportEmpty.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<script>##REPORT_JS##</script>
</head>
<body>
<mutation-test-report-app title-postfix="##REPORT_TITLE##"></mutation-test-report-app>

<script>
document.querySelector('mutation-test-report-app').report =
##REPORT_JSON##;
</script>
</body>
</html>

0 comments on commit b2527ef

Please sign in to comment.