Templates/Sampler/tests/QA/module.tests.ps1
$here = Split-Path -Parent $MyInvocation.MyCommand.Path # Convert-path required for PS7 or Join-Path fails $ProjectPath = "$here\..\.." | Convert-Path $ProjectName = (Get-ChildItem $ProjectPath\*\*.psd1 | Where-Object { ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and $(try { Test-ModuleManifest $_.FullName -ErrorAction Stop }catch{$false}) } ).BaseName $SourcePath = (Get-ChildItem $ProjectPath\*\*.psd1 | Where-Object { ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and $(try { Test-ModuleManifest $_.FullName -ErrorAction Stop }catch { $false }) } ).Directory.FullName $mut = Import-Module -Name $ProjectName -ErrorAction Stop -PassThru -Force $allModuleFunctions = &$mut {Get-Command -Module $args[0] -CommandType Function } $ProjectName Describe 'Changelog Management' -Tag 'Changelog' { It 'Changelog has been updated' -skip:( !([bool](Get-Command git -EA SilentlyContinue) -and [bool](&(Get-Process -id $PID).Path -NoProfile -Command 'git rev-parse --is-inside-work-tree 2>$null')) ) { # Get the list of changed files compared with master $HeadCommit = &git rev-parse HEAD $MasterCommit = &git rev-parse origin/master $filesChanged = &git @('diff', "$MasterCommit...$HeadCommit", '--name-only') if ($HeadCommit -ne $MasterCommit) { # if we're not testing same commit (i.e. master..master) $filesChanged.Where{ (Split-Path $_ -Leaf) -match '^changelog' } | Should -Not -BeNullOrEmpty } } It 'Changelog format compliant with keepachangelog format' -skip:(![bool](Get-Command git -EA SilentlyContinue)) { { Get-ChangelogData (Join-Path $ProjectPath 'CHANGELOG.md') -ErrorAction Stop } | Should -Not -Throw } } Describe 'General module control' -Tags 'FunctionalQuality' { It 'imports without errors' { { Import-Module -Name $ProjectName -Force -ErrorAction Stop } | Should -Not -Throw Get-Module $ProjectName | Should -Not -BeNullOrEmpty } It 'Removes without error' { { Remove-Module -Name $ProjectName -ErrorAction Stop } | Should -not -Throw Get-Module $ProjectName | Should -beNullOrEmpty } } if (Get-Command Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue) { $scriptAnalyzerRules = Get-ScriptAnalyzerRule } else { if ($ErrorActionPreference -ne 'Stop') { Write-Warning "ScriptAnalyzer not found!" } else { Throw "ScriptAnalyzer not found!" } } foreach ($function in $allModuleFunctions) { $functionFile = Get-ChildItem -path $SourcePath -Recurse -Include "$($function.Name).ps1" Describe "Quality for $($function.Name)" -Tags 'TestQuality' { It "$($function.Name) has a unit test" { Get-ChildItem "tests\" -recurse -include "$($function.Name).Tests.ps1" | Should Not BeNullOrEmpty } if ($scriptAnalyzerRules) { It "Script Analyzer for $($functionFile.FullName)" { $PSSAResult = (Invoke-ScriptAnalyzer -Path $functionFile.FullName) $Report = $PSSAResult | Format-Table -AutoSize | Out-String -Width 110 $PSSAResult | Should -BeNullOrEmpty -Because ` "some rule triggered.`r`n`r`n $Report" } } } Describe "Help for $($function.Name)" -Tags 'helpQuality' { $AbstractSyntaxTree = [System.Management.Automation.Language.Parser]:: ParseInput((Get-Content -raw $functionFile.FullName), [ref]$null, [ref]$null) $AstSearchDelegate = { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] } $ParsedFunction = $AbstractSyntaxTree.FindAll( $AstSearchDelegate, $true ) | ? Name -eq $function.Name $FunctionHelp = $ParsedFunction.GetHelpContent() It 'Has a SYNOPSIS' { $FunctionHelp.Synopsis | should not BeNullOrEmpty } It 'Has a Description, with length > 40' { $FunctionHelp.Description.Length | Should beGreaterThan 40 } It 'Has at least 1 example' { $FunctionHelp.Examples.Count | Should beGreaterThan 0 $FunctionHelp.Examples[0] | Should match ([regex]::Escape($function.Name)) $FunctionHelp.Examples[0].Length | Should BeGreaterThan ($function.Name.Length + 10) } $parameters = $ParsedFunction.Body.ParamBlock.Parameters.name.VariablePath.Foreach{ $_.ToString() } foreach ($parameter in $parameters) { It "Has help for Parameter: $parameter" { $FunctionHelp.Parameters.($parameter.ToUpper()) | Should Not BeNullOrEmpty $FunctionHelp.Parameters.($parameter.ToUpper()).Length | Should BeGreaterThan 25 } } } } |