src/Report.psm1
|
using module ./BranchCoverage.psm1 using module ./BranchData.psm1 using module ./FunctionCoverage.psm1 using module ./FunctionData.psm1 using module ./LineCoverage.psm1 using module ./LineData.psm1 using module ./SourceFile.psm1 using module ./Tokens.psm1 <# .SYNOPSIS Represents a trace file, that is a coverage report. #> class Report { <# .SYNOPSIS The source file list. #> [ValidateNotNull()] [SourceFile[]] $SourceFiles <# .SYNOPSIS The test name. #> [ValidateNotNull()] [string] $TestName <# .SYNOPSIS Creates a new report. .PARAMETER TestName The test name. #> Report([string] $TestName) { $this.SourceFiles = @() $this.TestName = $TestName } <# .SYNOPSIS Creates a new report. .PARAMETER TestName The test name. .PARAMETER SourceFiles The source file list. #> Report([string] $TestName, [SourceFile[]] $SourceFiles) { $this.SourceFiles = $SourceFiles $this.TestName = $TestName } <# .SYNOPSIS Parses the specified coverage data in LCOV format. .PARAMETER Coverage The coverage data. .OUTPUTS The resulting coverage report. #> static [Report] Parse([string] $Coverage) { $offset = 0 $report = [Report]::new("") $sourceFile = [SourceFile] "" $sourceFile.Branches = [BranchCoverage]::new() $sourceFile.Functions = [FunctionCoverage]::new() $sourceFile.Lines = [LineCoverage]::new() foreach ($line in $Coverage -split "\r?\n") { $offset++ if ([string]::IsNullOrWhiteSpace($line)) { continue } $parts = $line.Trim() -split ":" if (($parts.Count -lt 2) -and ($parts[0] -ne [Tokens]::EndOfRecord)) { throw [FormatException] "Invalid token format at line #$offset." } $data = ($parts[1..$parts.Count] -join ":") -split "," $token = $parts[0] switch -CaseSensitive ($token) { ([Tokens]::TestName) { if ([string]::IsNullOrWhiteSpace($report.TestName)) { $report.TestName = $data[0] } break } ([Tokens]::BranchData) { if ($data.Count -lt 4) { throw [FormatException] "Invalid branch data at line #$offset." } $sourceFile.Branches.Data += [BranchData]@{ BlockNumber = $data[1] BranchNumber = $data[2] LineNumber = $data[0] Taken = $data[3] -eq "-" ? 0 : $data[3] } break } ([Tokens]::BranchesFound) { $sourceFile.Branches.Found = $data[0] break } ([Tokens]::BranchesHit) { $sourceFile.Branches.Hit = $data[0] break } ([Tokens]::FunctionData) { if ($data.Count -lt 2) { throw [FormatException] "Invalid function data at line #$offset." } $items = $sourceFile.Functions.Data.Where{ $_.FunctionName -eq $data[1] } foreach ($item in $items) { $item.ExecutionCount = $data[0] } break } ([Tokens]::FunctionsFound) { $sourceFile.Functions.Found = $data[0] break } ([Tokens]::FunctionsHit) { $sourceFile.Functions.Hit = $data[0] break } ([Tokens]::FunctionName) { if ($data.Count -lt 2) { throw [FormatException] "Invalid function name at line #$offset." } $sourceFile.Functions.Data += [FunctionData]@{ FunctionName = $data[1]; LineNumber = $data[0] } break } ([Tokens]::LineData) { if ($data.Count -lt 2) { throw [FormatException] "Invalid line data at line #$offset." } $sourceFile.Lines.Data += [LineData]@{ Checksum = $data.Count -ge 3 ? $data[2] : "" ExecutionCount = $data[1] LineNumber = $data[0] } break } ([Tokens]::LinesFound) { $sourceFile.Lines.Found = $data[0] break } ([Tokens]::LinesHit) { $sourceFile.Lines.Hit = $data[0] break } ([Tokens]::SourceFile) { $sourceFile = [SourceFile] $data[0] $sourceFile.Branches = [BranchCoverage]::new() $sourceFile.Functions = [FunctionCoverage]::new() $sourceFile.Lines = [LineCoverage]::new() break } ([Tokens]::EndOfRecord) { $report.SourceFiles += $sourceFile break } default { throw [FormatException] "Unknown token at line #$offset." } } } if (-not $report.SourceFiles) { throw [FormatException] "The coverage data is empty or invalid." } return $report } <# .SYNOPSIS Returns a string representation of this object. .OUTPUTS The string representation of this object. #> [string] ToString() { return @( $this.TestName ? @("$([Tokens]::TestName):$($this.TestName)") : @() $this.SourceFiles.ForEach{ [string] $_ } ) -join "`n" } } |