diff --git a/build.ps1 b/build.ps1
index 4eb4ed477..2256e018e 100644
--- a/build.ps1
+++ b/build.ps1
@@ -202,6 +202,7 @@ if ($Clean) {
, ("$PSScriptRoot/src/schemas/JUnit4/*.xsd", "$PSScriptRoot/bin/schemas/JUnit4/")
, ("$PSScriptRoot/src/schemas/NUnit25/*.xsd", "$PSScriptRoot/bin/schemas/NUnit25/")
, ("$PSScriptRoot/src/schemas/NUnit3/*.xsd", "$PSScriptRoot/bin/schemas/NUnit3/")
+ , ("$PSScriptRoot/src/schemas/Cobertura/*.dtd", "$PSScriptRoot/bin/schemas/Cobertura/")
, ("$PSScriptRoot/src/schemas/JaCoCo/*.dtd", "$PSScriptRoot/bin/schemas/JaCoCo/")
, ("$PSScriptRoot/src/csharp/Pester/bin/$Configuration/net452/Pester.dll", "$PSScriptRoot/bin/bin/net452/")
, ("$PSScriptRoot/src/csharp/Pester/bin/$Configuration/net452/Pester.pdb", "$PSScriptRoot/bin/bin/net452/")
diff --git a/publish/filesToPublish.ps1 b/publish/filesToPublish.ps1
index 56fba4967..2397f8142 100644
--- a/publish/filesToPublish.ps1
+++ b/publish/filesToPublish.ps1
@@ -10,6 +10,7 @@
'bin/netstandard2.0/Pester.pdb'
'en-US/about_Pester.help.txt'
'en-US/about_PesterConfiguration.help.txt'
+ 'schemas/Cobertura/coverage-loose.dtd'
'schemas/JaCoCo/report.dtd'
'schemas/JUnit4/junit_schema_4.xsd'
'schemas/NUnit25/nunit_schema_2.5.xsd'
diff --git a/src/csharp/Pester/CodeCoverageConfiguration.cs b/src/csharp/Pester/CodeCoverageConfiguration.cs
index ffcc3e10f..0309046ed 100644
--- a/src/csharp/Pester/CodeCoverageConfiguration.cs
+++ b/src/csharp/Pester/CodeCoverageConfiguration.cs
@@ -41,7 +41,7 @@ public static CodeCoverageConfiguration ShallowClone(CodeCoverageConfiguration c
public CodeCoverageConfiguration() : base("CodeCoverage configuration.")
{
Enabled = new BoolOption("Enable CodeCoverage.", false);
- OutputFormat = new StringOption("Format to use for code coverage report. Possible values: JaCoCo, CoverageGutters", "JaCoCo");
+ OutputFormat = new StringOption("Format to use for code coverage report. Possible values: JaCoCo, CoverageGutters, Cobertura", "JaCoCo");
OutputPath = new StringOption("Path relative to the current directory where code coverage report is saved.", "coverage.xml");
OutputEncoding = new StringOption("Encoding of the output file.", "UTF8");
Path = new StringArrayOption("Directories or files to be used for code coverage, by default the Path(s) from general settings are used, unless overridden here.", new string[0]);
diff --git a/src/en-US/about_PesterConfiguration.help.txt b/src/en-US/about_PesterConfiguration.help.txt
index 5057e0042..76f3e437d 100644
--- a/src/en-US/about_PesterConfiguration.help.txt
+++ b/src/en-US/about_PesterConfiguration.help.txt
@@ -95,7 +95,7 @@ SECTIONS AND OPTIONS
Type: bool
Default value: $false
- OutputFormat: Format to use for code coverage report. Possible values: JaCoCo, CoverageGutters
+ OutputFormat: Format to use for code coverage report. Possible values: JaCoCo, CoverageGutters, Cobertura
Type: string
Default value: 'JaCoCo'
diff --git a/src/functions/Coverage.Plugin.ps1 b/src/functions/Coverage.Plugin.ps1
index 809e058c6..bf507a034 100644
--- a/src/functions/Coverage.Plugin.ps1
+++ b/src/functions/Coverage.Plugin.ps1
@@ -145,11 +145,11 @@
$configuration = $run.PluginConfiguration.Coverage
- if ($configuration.OutputFormat -in 'JaCoCo', 'CoverageGutters') {
- [xml] $jaCoCoReport = [xml] (Get-JaCoCoReportXml -CommandCoverage $breakpoints -TotalMilliseconds $totalMilliseconds -CoverageReport $coverageReport -Format $configuration.OutputFormat)
- }
- else {
- throw "CodeCoverage.CoverageFormat '$($configuration.OutputFormat)' is not valid, please review your configuration."
+ $coverageXmlReport = switch ($configuration.OutputFormat) {
+ 'JaCoCo' { [xml](Get-JaCoCoReportXml -CommandCoverage $breakpoints -TotalMilliseconds $totalMilliseconds -CoverageReport $coverageReport -Format 'JaCoCo') }
+ 'CoverageGutters' { [xml](Get-JaCoCoReportXml -CommandCoverage $breakpoints -TotalMilliseconds $totalMilliseconds -CoverageReport $coverageReport -Format 'CoverageGutters') }
+ 'Cobertura' { [xml](Get-CoberturaReportXml -CoverageReport $coverageReport -TotalMilliseconds $totalMilliseconds) }
+ default { throw "CodeCoverage.CoverageFormat '$($configuration.OutputFormat)' is not valid, please review your configuration." }
}
$settings = [Xml.XmlWriterSettings] @{
@@ -163,7 +163,7 @@
$stringWriter = [Pester.Factory]::CreateStringWriter()
$xmlWriter = [Xml.XmlWriter]::Create($stringWriter, $settings)
- $jaCocoReport.WriteContentTo($xmlWriter)
+ $coverageXmlReport.WriteContentTo($xmlWriter)
$xmlWriter.Flush()
$stringWriter.Flush()
@@ -216,7 +216,7 @@
}
function Resolve-CodeCoverageConfiguration {
- $supportedFormats = 'JaCoCo', 'CoverageGutters'
+ $supportedFormats = 'JaCoCo', 'CoverageGutters', 'Cobertura'
if ($PesterPreference.CodeCoverage.OutputFormat.Value -notin $supportedFormats) {
throw (Get-StringOptionErrorMessage -OptionPath 'CodeCoverage.OutputFormat' -SupportedValues $supportedFormats -Value $PesterPreference.CodeCoverage.OutputFormat.Value)
}
diff --git a/src/functions/Coverage.ps1 b/src/functions/Coverage.ps1
index 8548c3162..ddb6e7613 100644
--- a/src/functions/Coverage.ps1
+++ b/src/functions/Coverage.ps1
@@ -231,12 +231,12 @@ function Get-CodeCoverageFilePaths {
$testsPattern = "*$($PesterPreference.Run.TestExtension.Value)"
[string[]] $filteredFiles = @(foreach ($file in (& $SafeCommands['Get-ChildItem'] -LiteralPath $Paths -File -Recurse:$RecursePaths)) {
- if (('.ps1', '.psm1') -contains $file.Extension -and ($IncludeTests -or $file.Name -notlike $testsPattern)) {
- $file.FullName
- }
- })
+ if (('.ps1', '.psm1') -contains $file.Extension -and ($IncludeTests -or $file.Name -notlike $testsPattern)) {
+ $file.FullName
+ }
+ })
- $uniqueFiles = & $SafeCommands['New-Object'] -TypeName 'System.Collections.Generic.HashSet[string]' -ArgumentList (,$filteredFiles)
+ $uniqueFiles = & $SafeCommands['New-Object'] -TypeName 'System.Collections.Generic.HashSet[string]' -ArgumentList (, $filteredFiles)
return $uniqueFiles
}
@@ -452,6 +452,14 @@ function IsIgnoredCommand {
return $true
}
+ if ($PSVersionTable.PSVersion.Major -ge 5) {
+ if ($Command -is [System.Management.Automation.Language.CommandExpressionAst] -and
+ $Command.Expression[0] -is [System.Management.Automation.Language.BaseCtorInvokeMemberExpressionAst]) {
+ # Calls to inherited "base(...)" constructor does not trigger breakpoint or tracer hit, ignore.
+ return $true
+ }
+ }
+
return $false
}
@@ -804,9 +812,10 @@ function Get-JaCoCoReportXml {
return [string]::Empty
}
- $now = & $SafeCommands['Get-Date']
- $nineteenSeventy = & $SafeCommands['Get-Date'] -Date "01/01/1970"
- [long] $endTime = [math]::Floor((New-TimeSpan -start $nineteenSeventy -end $now).TotalMilliseconds)
+ # Report uses unix epoch time format (milliseconds since midnight 1/1/1970 UTC)
+ $nineteenSeventy = & $SafeCommands['New-Object'] 'System.DateTime' -ArgumentList @(1970, 1, 1, 0, 0, 0, [System.DateTimeKind]::Utc)
+ $now = [DateTime]::Now.ToUniversalTime()
+ [long] $endTime = [math]::Floor(($now - $nineteenSeventy).TotalMilliseconds)
[long] $startTime = [math]::Floor($endTime - $TotalMilliseconds)
$folderGroups = $CommandCoverage | & $SafeCommands["Group-Object"] -Property {
@@ -1028,6 +1037,226 @@ function Get-JaCoCoReportXml {
return $xml
}
+function Get-CoberturaReportXml {
+ param (
+ [parameter(Mandatory = $true)]
+ [object] $CoverageReport,
+ [parameter(Mandatory = $true)]
+ [long] $TotalMilliseconds
+ )
+
+ if ($null -eq $CoverageReport -or $CoverageReport.NumberOfCommandsAnalyzed -eq 0) {
+ return [string]::Empty
+ }
+
+ # Report uses unix epoch time format (milliseconds since midnight 1/1/1970 UTC)
+ $nineteenSeventy = & $SafeCommands['New-Object'] 'System.DateTime' -ArgumentList @(1970, 1, 1, 0, 0, 0, [System.DateTimeKind]::Utc)
+ $now = [DateTime]::Now.ToUniversalTime()
+ [long] $endTime = [math]::Floor(($now - $nineteenSeventy).TotalMilliseconds)
+ [long] $startTime = [math]::Floor($endTime - $TotalMilliseconds)
+
+ $commonRoot = Get-CommonParentPath -Path $CoverageReport.AnalyzedFiles
+
+ $allLines = [System.Collections.Generic.List[object]]@()
+ $allLines.AddRange($CoverageReport.MissedCommands)
+ $allLines.AddRange($CoverageReport.HitCommands)
+ $packages = @{}
+ foreach ($command in $allLines) {
+ $package = & $SafeCommands["Split-Path"] $command.File -Parent
+ if (!$packages[$package]) {
+ $packages[$package] = @{
+ Classes = @{}
+ }
+ }
+
+ $class = $command.File
+ if (!$packages[$package].Classes[$class]) {
+ $packages[$package].Classes[$class] = @{
+ Methods = @{}
+ Lines = @{}
+ }
+ }
+
+ if (!$packages[$package].Classes[$class].Lines[$command.Line]) {
+ $packages[$package].Classes[$class].Lines[$command.Line] = [ordered]@{ number = $command.Line ; hits = 0 }
+ }
+ $packages[$package].Classes[$class].Lines[$command.Line].hits += $command.HitCount
+
+ $method = $command.Function
+ if (!$method) {
+ continue
+ }
+
+ if (!$packages[$package].Classes[$class].Methods[$method]) {
+ $packages[$package].Classes[$class].Methods[$method] = @{}
+ }
+
+ if (!$packages[$package].Classes[$class].Methods[$method][$command.Line]) {
+ $packages[$package].Classes[$class].Methods[$method][$command.Line] = [ordered]@{ number = $command.Line ; hits = 0 }
+ }
+ $packages[$package].Classes[$class].Methods[$method][$command.Line].hits += $command.HitCount
+ }
+
+ $packages = foreach ($packageGroup in $packages.GetEnumerator()) {
+ $classGroups = $packageGroup.Value.Classes
+ $classes = foreach ($classGroup in $classGroups.GetEnumerator()) {
+ $methodGroups = $classGroup.Value.Methods
+ $methods = foreach ($methodGroup in $methodGroups.GetEnumerator()) {
+ $lines = ([object[]]$methodGroup.Value.Values) | New-LineNode
+ $coveredLines = foreach ($line in $lines) { if (0 -lt $line.attributes.hits) { $line } }
+
+ $method = [ordered]@{
+ name = 'method'
+ attributes = [ordered]@{
+ name = $methodGroup.Name
+ signature = '()'
+ }
+ children = [ordered]@{
+ lines = $lines | & $SafeCommands["Sort-Object"] { [int]$_.attributes.number }
+ }
+ totalLines = $lines.Length
+ coveredLines = $coveredLines.Length
+ }
+
+ $method
+ }
+
+ $lines = ([object[]]$classGroup.Value.Lines.Values) | New-LineNode
+ $coveredLines = foreach ($line in $lines) { if (0 -lt $line.attributes.hits) { $line } }
+
+ $lineRate = Get-LineRate -CoveredLines $coveredLines.Length -TotalLines $lines.Length
+ $filename = $classGroup.Name.Substring($commonRoot.Length).Replace('\', '/').TrimStart('/')
+
+ $class = [ordered]@{
+ name = 'class'
+ attributes = [ordered]@{
+ name = (& $SafeCommands["Split-Path"] $classGroup.Name -Leaf)
+ filename = $filename
+ 'line-rate' = $lineRate
+ 'branch-rate' = 1
+ }
+ children = [ordered]@{
+ methods = $methods | & $SafeCommands["Sort-Object"] { $_.attributes.name }
+ lines = $lines | & $SafeCommands["Sort-Object"] { [int]$_.attributes.number }
+ }
+ totalLines = $lines.Length
+ coveredLines = $coveredLines.Length
+ }
+
+ $class
+ }
+
+ $totalLines = ($classes.totalLines | & $SafeCommands["Measure-Object"] -Sum).Sum
+ $coveredLines = ($classes.coveredLines | & $SafeCommands["Measure-Object"] -Sum).Sum
+ $lineRate = Get-LineRate -CoveredLines $coveredLines -TotalLines $totalLines
+ $packageName = $packageGroup.Name.Substring($commonRoot.Length).Replace('\', '/').TrimStart('/')
+
+ $package = [ordered]@{
+ name = 'package'
+ attributes = [ordered]@{
+ name = $packageName
+ 'line-rate' = $lineRate
+ 'branch-rate' = 0
+ }
+ children = [ordered]@{
+ classes = $classes | & $SafeCommands["Sort-Object"] { $_.attributes.name }
+ }
+ totalLines = $totalLines
+ coveredLines = $coveredLines
+ }
+
+ $package
+ }
+
+ $totalLines = ($packages.totalLines | & $SafeCommands["Measure-Object"] -Sum).Sum
+ $coveredLines = ($packages.coveredLines | & $SafeCommands["Measure-Object"] -Sum).Sum
+ $lineRate = Get-LineRate -CoveredLines $coveredLines -TotalLines $totalLines
+
+ $coverage = [ordered]@{
+ name = 'coverage'
+ attributes = [ordered]@{
+ 'lines-valid' = $totalLines
+ 'lines-covered' = $coveredLines
+ 'line-rate' = $lineRate
+ 'branches-valid' = 0
+ 'branches-covered' = 0
+ 'branch-rate' = 1
+ timestamp = $startTime
+ version = 0.1
+ }
+ children = [ordered]@{
+ sources = [ordered]@{
+ name = 'source'
+ value = $commonRoot.Replace('\', '/')
+ }
+ packages = $packages | & $SafeCommands["Sort-Object"] { $_.attributes.name }
+ }
+ }
+
+ $xmlDeclaration = ''
+ $docType = ''
+ $coverageXml = ConvertTo-XmlElement -Node $coverage
+ $document = "$xmlDeclaration`n$docType`n$($coverageXml.OuterXml)"
+
+ $document
+}
+
+function New-LineNode {
+ param(
+ [parameter(Mandatory = $true, ValueFromPipeline = $true)] [object] $LineObject
+ )
+
+ process {
+ [ordered]@{
+ name = 'line'
+ attributes = $LineObject
+ }
+ }
+}
+
+function Get-LineRate {
+ param(
+ [parameter(Mandatory = $true)] [int] $CoveredLines,
+ [parameter(Mandatory = $true)] [int] $TotalLines
+ )
+
+ [double]$denominator = if ($TotalLines) { $TotalLines } else { 1 }
+
+ $CoveredLines / $denominator
+}
+
+function ConvertTo-XmlElement {
+ param(
+ [parameter(Mandatory = $true)] [object] $Node
+ )
+
+ $element = ([xml]"<$($Node.name)/>").DocumentElement
+ if ($node.attributes) {
+ $attributes = $node.attributes
+ foreach ($attr in $attributes.GetEnumerator()) {
+ $element.SetAttribute($attr.Name, $attr.Value)
+ }
+ }
+ if ($node.children) {
+ $children = $node.children
+ foreach ($child in $children.GetEnumerator()) {
+ $childElement = ([xml]"<$($child.Name)/>").DocumentElement
+ foreach ($value in $child.Value) {
+ $childXml = ConvertTo-XmlElement $value
+ $importedChildXml = $childElement.OwnerDocument.ImportNode($childXml, $true)
+ $null = $childElement.AppendChild($importedChildXml)
+ }
+ $importedChild = $element.OwnerDocument.ImportNode($childElement, $true)
+ $null = $element.AppendChild($importedChild)
+ }
+ }
+ if ($node.value) {
+ $element.InnerText = $node.value
+ }
+
+ $element
+}
+
function Add-XmlElement {
param (
[parameter(Mandatory = $true)] [System.Xml.XmlNode] $Parent,
@@ -1036,14 +1265,23 @@ function Add-XmlElement {
)
$element = $Parent.AppendChild($Parent.OwnerDocument.CreateElement($Name))
if ($Attributes) {
- foreach ($key in $Attributes.Keys) {
- $attribute = $element.Attributes.Append($Parent.OwnerDocument.CreateAttribute($key))
- $attribute.Value = $Attributes.$key
- }
+ Add-XmlAttribute -Element $element -Attributes $Attributes
}
return $element
}
+function Add-XmlAttribute {
+ param(
+ [parameter(Mandatory = $true)] [System.Xml.XmlNode] $Element,
+ [parameter(Mandatory = $true)] [System.Collections.IDictionary] $Attributes
+ )
+
+ foreach ($key in $Attributes.Keys) {
+ $attribute = $Element.Attributes.Append($Element.OwnerDocument.CreateAttribute($key))
+ $attribute.Value = $Attributes.$key
+ }
+}
+
function Add-JaCoCoCounter {
param (
[parameter(Mandatory = $true)] [ValidateSet('Instruction', 'Line', 'Method', 'Class')] [string] $Type,
diff --git a/src/schemas/Cobertura/coverage-loose.dtd b/src/schemas/Cobertura/coverage-loose.dtd
new file mode 100644
index 000000000..35c8272d2
--- /dev/null
+++ b/src/schemas/Cobertura/coverage-loose.dtd
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tst/functions/Coverage.Tests.ps1 b/tst/functions/Coverage.Tests.ps1
index 3a41303a6..3fffafa32 100644
--- a/tst/functions/Coverage.Tests.ps1
+++ b/tst/functions/Coverage.Tests.ps1
@@ -52,9 +52,16 @@ InPesterModuleScope {
if ($PSVersionTable.PSVersion.Major -ge 5) {
Add-Content -Path $testScriptPath -Value @'
- class MyClass
+ class MyBaseClass {
+ MyBaseClass()
+ {
+ 'I am the constructor of base class.'
+ }
+ }
+
+ class MyClass : MyBaseClass
{
- MyClass()
+ MyClass() : base()
{
'I am the constructor.'
}
@@ -79,11 +86,18 @@ InPesterModuleScope {
# Before that, let's just create equivalent commands to above class with exact same line numbers
Add-Content -Path $testScriptPath -Value @'
+ #class MyBaseClass {
+ function MyBaseClass
+ {
+ 'I am the constructor of base class.'
+ }
+ #}
+
#class MyClass
#{
function MyClass
{
- 'I am the constructor.'
+ MyBaseClass # calls the base constructor
}
function MethodOne
@@ -131,7 +145,9 @@ InPesterModuleScope {
# Path deliberately duplicated to make sure the code doesn't produce multiple breakpoints for the same commands
$breakpoints = Enter-CoverageAnalysis -CodeCoverage $testScriptPath, $testScriptPath, $testScript2Path, $testScript3Path -UseBreakpoints $UseBreakpoints
- @($breakpoints).Count | Should -Be 18 -Because 'it has the proper number of breakpoints defined'
+ # Output breakpoints so we can compare between PS Versions, when we have a failure on older systems.
+ Write-Host "Before All: Defined breakpoints (using profiler based code coverage: $(-not $UseBreakpoints)):`n$($breakpoints | Format-Table Class, Function, StartLine, StartColumn, Ast | Out-String)"
+ @($breakpoints).Count | Should -Be 19 -Because 'it has the proper number of breakpoints defined."'
$sb = {
$null = & $testScriptPath
@@ -153,11 +169,11 @@ InPesterModuleScope {
}
It 'Reports the proper number of executed commands' {
- $coverageReport.NumberOfCommandsExecuted | Should -Be 15
+ $coverageReport.NumberOfCommandsExecuted | Should -Be 16
}
It 'Reports the proper number of analyzed commands' {
- $coverageReport.NumberOfCommandsAnalyzed | Should -Be 18
+ $coverageReport.NumberOfCommandsAnalyzed | Should -Be 19
}
It 'Reports the proper number of analyzed files' {
@@ -175,7 +191,7 @@ InPesterModuleScope {
}
It 'Reports the proper number of hit commands' {
- $coverageReport.HitCommands.Count | Should -Be 15
+ $coverageReport.HitCommands.Count | Should -Be 16
}
It 'Reports the correct hit command' {
@@ -186,7 +202,8 @@ InPesterModuleScope {
$coverageReport.HitCommands[0].Class | Should -BeNullOrEmpty
# Classes have been introduced in PowerShell 5.0
if ($PSVersionTable.PSVersion.Major -ge 5) {
- $coverageReport.HitCommands[9].Class | Should -Be 'MyClass'
+ $coverageReport.HitCommands[9].Class | Should -Be 'MyBaseClass'
+ $coverageReport.HitCommands[10].Class | Should -Be 'MyClass'
$coverageReport.MissedCommands[2].Class | Should -Be 'MyClass'
}
else {
@@ -198,7 +215,8 @@ InPesterModuleScope {
It 'Reports the correct function names' {
$coverageReport.HitCommands[0].Function | Should -Be 'NestedFunction'
$coverageReport.HitCommands[2].Function | Should -Be 'FunctionOne'
- $coverageReport.HitCommands[9].Function | Should -Be 'MyClass'
+ $coverageReport.HitCommands[9].Function | Should -Be 'MyBaseClass'
+ $coverageReport.HitCommands[10].Function | Should -Be 'MyClass'
$coverageReport.MissedCommands[2].Function | Should -Be 'MethodTwo'
}
@@ -237,24 +255,29 @@ InPesterModuleScope {
-
+
-
+
-
+
+
+
+
+
+
-
-
-
+
+
+
@@ -278,14 +301,15 @@ InPesterModuleScope {
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -295,13 +319,14 @@ InPesterModuleScope {
-
-
-
+
+
+
-
+
@@ -324,9 +349,9 @@ InPesterModuleScope {
-
-
-
+
+
+
')
@@ -370,24 +395,29 @@ InPesterModuleScope {
-
+
-
+
-
+
+
+
+
+
+
-
-
-
+
+
+
@@ -411,14 +441,15 @@ InPesterModuleScope {
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -428,9 +459,9 @@ InPesterModuleScope {
-
-
-
+
+
+
@@ -457,14 +488,118 @@ InPesterModuleScope {
-
-
-
+
+
+
')
}
+ It 'Cobertura report must be correct' {
+ [String]$coberturaReportXml = Get-CoberturaReportXml -TotalMilliseconds 10000 -CoverageReport $coverageReport
+ $coberturaReportXml = $coberturaReportXml -replace 'timestamp="[0-9]*"', 'timestamp=""'
+ $coberturaReportXml = $coberturaReportXml -replace "$([System.Environment]::NewLine)", ''
+ $coberturaReportXml = $coberturaReportXml.Replace($root, 'CommonRoot')
+ $coberturaReportXml = $coberturaReportXml.Replace($root.Replace('\', '/'), 'CommonRoot')
+ (Clear-WhiteSpace $coberturaReportXml) | Should -Be (Clear-WhiteSpace '
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ')
+ }
+
It 'JaCoCo returns empty string when there are 0 analyzed commands' {
$coverageReport = [PSCustomObject] @{ NumberOfCommandsAnalyzed = 0 }
[String]$jaCoCoReportXml = Get-JaCoCoReportXml -CommandCoverage @{} -TotalMilliseconds 10000 -CoverageReport $coverageReport -Format "CoverageGutters"
@@ -472,6 +607,13 @@ InPesterModuleScope {
$jaCoCoReportXml | Should -Be ([String]::Empty)
}
+ It 'Cobertura returns empty string when there are 0 analyzed commands' {
+ $coverageReport = [PSCustomObject] @{ NumberOfCommandsAnalyzed = 0 }
+ [String]$coberturaReportXml = Get-CoberturaReportXml -CoverageReport $coverageReport -TotalMilliseconds 10000
+ $coberturaReportXml | Should -Not -Be $null
+ $coberturaReportXml | Should -Be ([String]::Empty)
+ }
+
It 'Reports the right line numbers' {
$coverageReport.HitCommands[$coverageReport.NumberOfCommandsExecuted - 1].Line | Should -Be 1
$coverageReport.HitCommands[$coverageReport.NumberOfCommandsExecuted - 1].StartLine | Should -Be 1
@@ -642,7 +784,7 @@ InPesterModuleScope {
BeforeAll {
$breakpoints = Enter-CoverageAnalysis -CodeCoverage @{Path = "$(Join-Path -Path $root -ChildPath *.ps1)"; Function = '*' }
- @($breakpoints).Count | Should -Be 13 -Because 'it has the proper number of breakpoints defined'
+ @($breakpoints).Count | Should -Be 14 -Because 'it has the proper number of breakpoints defined'
if ($UseBreakpoints) {
& $testScriptPath
@@ -657,11 +799,11 @@ InPesterModuleScope {
}
It 'Reports the proper number of executed commands' {
- $coverageReport.NumberOfCommandsExecuted | Should -Be 10
+ $coverageReport.NumberOfCommandsExecuted | Should -Be 11
}
It 'Reports the proper number of analyzed commands' {
- $coverageReport.NumberOfCommandsAnalyzed | Should -Be 13
+ $coverageReport.NumberOfCommandsAnalyzed | Should -Be 14
}
It 'Reports the proper number of analyzed files' {
@@ -678,7 +820,7 @@ InPesterModuleScope {
}
It 'Reports the proper number of hit commands' {
- $coverageReport.HitCommands.Count | Should -Be 10
+ $coverageReport.HitCommands.Count | Should -Be 11
}
It 'Reports the correct hit command' {
@@ -747,7 +889,7 @@ InPesterModuleScope {
$breakpoints = Enter-CoverageAnalysis -CodeCoverage @{Path = $testScriptPath; Class = '*' }
- @($breakpoints).Count | Should -Be 3 -Because 'it has the proper number of breakpoints defined'
+ @($breakpoints).Count | Should -Be 4 -Because 'it has the proper number of breakpoints defined'
if ($UseBreakpoints) {
& $testScriptPath
@@ -762,11 +904,11 @@ InPesterModuleScope {
}
It 'Reports the proper number of executed commands' {
- $coverageReport.NumberOfCommandsExecuted | Should -Be 2
+ $coverageReport.NumberOfCommandsExecuted | Should -Be 3
}
It 'Reports the proper number of analyzed commands' {
- $coverageReport.NumberOfCommandsAnalyzed | Should -Be 3
+ $coverageReport.NumberOfCommandsAnalyzed | Should -Be 4
}
It 'Reports the proper number of missed commands' {
@@ -774,7 +916,7 @@ InPesterModuleScope {
}
It 'Reports the proper number of hit commands' {
- $coverageReport.HitCommands.Count | Should -Be 2
+ $coverageReport.HitCommands.Count | Should -Be 3
}
AfterAll {