PSSAToJunit.psm1

function ConvertTo-PSSAJunitXml {
    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    param (
        [Parameter( Mandatory, ValueFromPipeline = $true )]
        [AllowNull()]
        [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
        $PSScriptAnalyzerResult,

        [Parameter()]
        [String]
        $TestName,

        [Parameter()]
        [ValidateSet("Information", "Warning", "Error")]
        [System.String[]]
        $Severity
    )

    begin {
        try {
            if (!$TestName) {
                $TestName = "PSScriptAnalyzer"
            }
            if (!$Severity) {
                $Severity = @("Warning", "Error")
            }

            $TestSuites = Get-TestSuite -Severity $Severity
        }
        catch {
            Write-Error "Error occurred while initializing variables: $_"
            return
        }
    }

    process {
        try {
            if ($PSScriptAnalyzerResult) {
                foreach ($Result in $PSScriptAnalyzerResult) {
                    if ($Result.RuleName -in $TestSuites.Keys) {
                        $TestSuites[$Result.RuleName].FailedTests += @{
                            ScriptName = $Result.ScriptName
                            Message    = $Result.Message
                            Line       = $Result.Line
                            ScriptPath = $Result.ScriptPath
                        }
                    }
                }
            }
        }
        catch {
            Write-Error "Error occurred while processing results: $_"
            return
        }
    }

    end {
        try {
            [System.Xml.XmlDocument]$JunitXml = ConvertTo-JunitXml -TestSuites $TestSuites -TestName $TestName
            Return $JunitXml
        }
        catch {
            Write-Error "Error occurred while converting to JUnit XML: $_"
            return
        }
    }
}
function Export-PSSAJunitXml {
    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    param (
        [Parameter(Mandatory, ValueFromPipeline = $true)]
        [System.Xml.XmlDocument]
        $InputXml,

        [Parameter()]
        [System.IO.FileInfo]
        $FilePath
    )

    begin {
        if (!$FilePath) {
            $FilePath = Join-Path -Path $PWD -ChildPath "PSScriptAnalyzerResults.xml"
        }
    }

    process {
        try {
            $InputXml.Save($FilePath)
        }
        catch {
            Write-Error "Error saving file: $_"
        }
    }

    end {
        if (Test-Path $FilePath) {
            Write-Debug "File created at: $FilePath"
        }
        else {
            Write-Error "File not created"
        }
    }
}
function ConvertTo-JunitXml {
    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    param (
        [Parameter(Mandatory)]
        [System.Collections.Hashtable]
        $TestSuites,

        [Parameter(Mandatory)]
        [String]
        $TestName
    )

    try {
        [System.Xml.XmlDocument]$JunitXml = Get-ParentXml -TestRunName $TestName

        foreach ($TestSuite in $TestSuites.GetEnumerator()) {
            [System.Xml.XmlDocument]$TestSuiteXml = Get-TestSuiteXml -TestSuiteName $TestSuite.Name

            foreach ($FailedTest in $TestSuite.Value.FailedTests) {
                [Hashtable]$GetTestCaseXmlArgs = @{
                    TestCaseName    = $FailedTest.ScriptName
                    TestCaseMessage = $FailedTest.Message
                    TestCasePath    = $FailedTest.ScriptPath
                    Line            = $FailedTest.Line
                }
                [System.Xml.XmlDocument]$TestCaseXml = Get-TestCaseXml @GetTestCaseXmlArgs

                $TestCaseRoot = $TestCaseXml.DocumentElement
                $ImportedNode = $TestSuiteXml.ImportNode($TestCaseRoot, $true)
                $TestSuiteXml.DocumentElement.AppendChild($ImportedNode) | Out-Null

                $TestSuiteXml.testsuite.tests = [int]($TestSuiteXml.testsuite.tests) + 1
                $TestSuiteXml.testsuite.failures = [int]($TestSuiteXml.testsuite.failures) + 1
            }

            if (![int]$TestSuiteXml.testsuite.failures) {
                $TestSuiteXml.testsuite.tests = 1
                $TestSuiteXml.testsuite.failures = 0

            }

            $TestSuiteRoot = $TestSuiteXml.DocumentElement
            $ImportedNode = $JunitXml.ImportNode($TestSuiteRoot, $true)
            $JunitXml.DocumentElement.AppendChild($ImportedNode) | Out-Null

            $JunitXml.testsuites.tests = [int]$JunitXml.testsuites.tests + [int]($TestSuiteXml.testsuite.tests)
            $JunitXml.testsuites.failures = [int]($JunitXml.testsuites.failures) + [int]($TestSuiteXml.testsuite.failures)
        }

        Return $JunitXml
    }
    catch {
        Write-Error "An error occurred while converting to JUnit XML: $_"
    }
}
function Get-ParentXml {
    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    param (
        [Parameter(Mandatory)]
        [String]
        $TestRunName
    )

    return [System.Xml.XmlDocument]@"
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<testsuites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="junit_schema_4.xsd" name="$TestRunName" tests="0" errors="0" failures="0" disabled="0" time="0">
</testsuites>
"@

}
function Get-TestCaseXml {
    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    param (
        [Parameter()]
        [String]
        $TestCaseName,

        [Parameter()]
        [String]
        $Severity,

        [Parameter()]
        [String]
        $TestCaseMessage,

        [Parameter()]
        [String]
        $TestCasePath,

        [Parameter()]
        [Int]
        $Line
    )

    return [System.Xml.XmlDocument]@"
<testcase id="" name="$TestCaseName" time="0.001">
    <failure message="$TestCasePath">
$($Severity.ToUpper()): $TestCaseMessage
File: $TestCasePath
Line: $Line
    </failure>
</testcase>
"@

}

function Get-TestSuite {
    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param (
        [Parameter()]
        [ValidateSet("Information", "Warning", "Error")]
        [System.String[]]
        $Severity
    )

    try {
        $ScriptAnalyzerRules = Get-ScriptAnalyzerRule -Severity $Severity
    }
    catch {
        Write-Error "Failed to retrieve ScriptAnalyzer rules: $_"
        return
    }

    $TestSuites = @{}
    foreach ($Rule in $ScriptAnalyzerRules) {
        $TestSuites[$Rule.RuleName] = @{
            Name        = $Rule.RuleName
            Severity    = $Rule.Severity
            Description = $Rule.Description
            FailedTests = @()
        }
    }

    return $TestSuites
}
function Get-TestSuiteXml {
    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    param (
        [Parameter(Mandatory)]
        [String]
        $TestSuiteName
    )

    return [System.Xml.XmlDocument]@"
<testsuite name="$TestSuiteName" tests="0" errors="0" failures="0" hostname="" id="0" skipped="0" disabled="0" package="" time="0">
</testsuite>
"@

}