Skip to content

Commit

Permalink
Validating examples
Browse files Browse the repository at this point in the history
  • Loading branch information
Gijsreyn committed Nov 14, 2024
1 parent f792228 commit ca1d97a
Show file tree
Hide file tree
Showing 2 changed files with 271 additions and 5 deletions.
8 changes: 4 additions & 4 deletions resources/Help/Microsoft.VSCode.Dsc/VSCodeExtension.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The `VSCodeExtension` DSC Resource allows you to install, update, and remove Vis
$params = @{
Name = 'ms-python.python'
}
Invoke-DscResource -Name VSCodeExtension -Method Set -Property $params -ModuleName Microsoft.VSCode.Dsc
Invoke-DscResource -ModuleName Microsoft.VSCode.Dsc -Name VSCodeExtension -Method Set -Property $params
```

### EXAMPLE 2
Expand All @@ -46,7 +46,7 @@ $params = @{
Name = 'ms-python.python'
Version = '2021.5.842923320'
}
Invoke-DscResource -Name VSCodeExtension -Method Set -Property $params -ModuleName Microsoft.VSCode.Dsc
Invoke-DscResource -ModuleName Microsoft.VSCode.Dsc -Name VSCodeExtension -Method Set -Property $params
```

### EXAMPLE 3
Expand All @@ -57,7 +57,7 @@ $params = @{
Name = 'ms-python.python'
Exist = $false
}
Invoke-DscResource -Name VSCodeExtension -Method Set -Property $params -ModuleName Microsoft.VSCode.Dsc
Invoke-DscResource -ModuleName Microsoft.VSCode.Dsc -Name VSCodeExtension -Method Set -Property $params
```

### EXAMPLE 4
Expand All @@ -68,5 +68,5 @@ $params = @{
Name = 'ms-python.python'
Insiders = $true
}
Invoke-DscResource -Name VSCodeExtension -Method Set -Property $params -ModuleName Microsoft.VSCode.Dsc
Invoke-DscResource -ModuleName Microsoft.VSCode.Dsc -Name VSCodeExtension -Method Set -Property $params
```
268 changes: 267 additions & 1 deletion tests/QA/module.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,157 @@ param (
Write-Verbose ("repoRootPath: $repoRootPath") -Verbose
Write-Verbose ("modules: $($modules.Count)") -Verbose

#region Functions
function Get-MarkdownHeadings {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string]$FilePath
)

$fileContent = Get-Content -Path $FilePath

$headings = @()

# Use pattern to capture all headings
$headingPattern = '^(#+)\s+(.*)'

foreach ($line in $fileContent) {
if ($line -match $headingPattern) {
$level = $matches[1].Length
$text = $matches[2]

$heading = [PSCustomObject]@{
Level = $level
Text = $text
}

$headings += $heading
}
}

return $headings
}

function Get-MdCodeBlock {
[CmdletBinding()]
[OutputType([CodeBlock])]
param (
[Parameter(Mandatory, ValueFromPipeline, Position = 0)]
[string[]]
[SupportsWildcards()]
$Path,

[Parameter()]
[string]
$BasePath = '.',

[Parameter()]
[string]
$Language
)

process {
foreach ($unresolved in $Path) {
foreach ($file in (Resolve-Path -Path $unresolved).Path) {
$file = (Resolve-Path -Path $file).Path
$BasePath = (Resolve-Path -Path $BasePath).Path
$escapedRoot = [regex]::Escape($BasePath)
$relativePath = $file -replace "$escapedRoot\\", ''


# This section imports files referenced by PyMdown snippet syntax
# Example: --8<-- "abbreviations.md"
# Note: This function only supports very basic snippet syntax.
# See https://facelessuser.github.io/pymdown-extensions/extensions/snippets/ for documentation on the Snippets PyMdown extension
$lines = [System.IO.File]::ReadAllLines($file, [System.Text.Encoding]::UTF8) | ForEach-Object {
if ($_ -match '--8<-- "(?<file>[^"]+)"') {
$snippetPath = Join-Path -Path $BasePath -ChildPath $Matches.file
if (Test-Path -Path $snippetPath) {
Get-Content -Path $snippetPath
} else {
Write-Warning "Snippet not found: $snippetPath"
}
} else {
$_
}
}


$lineNumber = 0
$code = $null
$state = [MdState]::Undefined
$content = [System.Text.StringBuilder]::new()

foreach ($line in $lines) {
$lineNumber++
switch ($state) {
'Undefined' {
if ($line -match '^\s*```(?<lang>\w+)?' -and ([string]::IsNullOrWhiteSpace($Language) -or $Matches.lang -eq $Language)) {
$state = [MdState]::InCodeBlock
$code = [CodeBlock]@{
Source = $relativePath
Language = $Matches.lang
LineNumber = $lineNumber
}
} elseif (($inlineMatches = [regex]::Matches($line, '(?<!`)`(#!(?<lang>\w+) )?(?<code>[^`]+)`(?!`)'))) {
if (-not [string]::IsNullOrWhiteSpace($Language) -and $inlineMatch.Groups.lang -ne $Language) {
continue
}
foreach ($inlineMatch in $inlineMatches) {
[CodeBlock]@{
Source = $relativePath
Language = $inlineMatch.Groups.lang
Content = $inlineMatch.Groups.code
LineNumber = $lineNumber
Position = $inlineMatch.Index
Inline = $true
}
}
}
}

'InCodeBlock' {
if ($line -match '^\s*```') {
$state = [MdState]::Undefined
$code.Content = $content.ToString()
$code
$code = $null
$null = $content.Clear()
} else {
$null = $content.AppendLine($line)
}
}
}
}
}
}
}
}
#endRegion Functions

#region Enum
enum MdState {
Undefined
InCodeBlock
}
#endRegion Enum
class CodeBlock {
[string] $Source
[string] $Language
[string] $Content
[int] $LineNumber
[int] $Position
[bool] $Inline

[string] ToString() {
return '{0}:{1}:{2}' -f $this.Source, $this.LineNumber, $this.Language
}
}
#region Classes

#endRegion Classes

BeforeDiscovery {
$moduleResources = [System.Collections.ArrayList]@()

Expand Down Expand Up @@ -86,13 +237,39 @@ Describe 'Module tests' {
$moduleResource = $_
$moduleImport = Import-PowerShellDataFile -Path $moduleResource.ModulePath.Replace('.psm1', '.psd1')

# For the resources
$resources = [System.Collections.ArrayList]@()

# For the code blocks to capture in the examples
$codeBlocks = [System.Collections.ArrayList]@()

foreach ($resource in $moduleImport.DscResourcesToExport) {
$helpFile = Join-Path $repoRootPath 'resources' 'Help' $moduleResource.ModuleName "$resource.md"

$resources += @{
moduleName = $moduleResource.ModuleName
resource = $resource
HelpFile = Join-Path $repoRootPath 'resources' 'Help' $moduleResource.ModuleName "$resource.md"
helpFile = $helpFile
CodeBlock = Get-MdCodeBlock -Path $helpFile -Language 'powershell' -ErrorAction SilentlyContinue
}

$blocks = Get-MdCodeBlock -Path $helpFile -Language 'powershell' -ErrorAction SilentlyContinue
if (-not $blocks) {
$codeBlocks += @{
moduleName = $moduleResource.ModuleName
resource = $resource
content = 'No code block found'
language = 'powershell'
}
}

foreach ($block in $blocks) {
$codeBlocks += @{
moduleName = $moduleResource.ModuleName
resource = $resource
content = $block.Content
language = $block.Language
}
}
}

Expand All @@ -117,5 +294,94 @@ Describe 'Module tests' {
$file = Get-Item -Path $helpFile -ErrorAction SilentlyContinue
$file.Length | Should -BeGreaterThan 0
}

It '[<moduleName>] Should have a help file for [<resource>] resource with heading 1' -TestCases $resources {
param (
[string] $moduleName,
[string] $resource,
[string] $helpFile
)

$headings = Get-MarkdownHeadings -FilePath $helpFile -ErrorAction SilentlyContinue

$h1 = $headings | Where-Object { $_.Level -eq 1 -and $_.Text -eq $moduleName }
$h1 | Should -Not -BeNullOrEmpty
}

It '[<moduleName>] Should have a help file for [<resource>] resource with heading 2 matching SYNOPSIS' -TestCases $resources {
param (
[string] $moduleName,
[string] $resource,
[string] $helpFile
)

$headings = Get-MarkdownHeadings -FilePath $helpFile -ErrorAction SilentlyContinue

$h2 = $headings | Where-Object { $_.Level -eq 2 -and $_.Text -eq 'SYNOPSIS' }
$h2 | Should -Not -BeNullOrEmpty
}

It '[<moduleName>] Should have a help file for [<resource>] resource with heading 2 matching DESCRIPTION' -TestCases $resources {
param (
[string] $moduleName,
[string] $resource,
[string] $helpFile
)

$headings = Get-MarkdownHeadings -FilePath $helpFile -ErrorAction SilentlyContinue

$h2 = $headings | Where-Object { $_.Level -eq 2 -and $_.Text -eq 'DESCRIPTION' }
$h2 | Should -Not -BeNullOrEmpty
}

It '[<moduleName>] Should have a help file for [<resource>] resource with heading 2 matching PARAMETERS' -TestCases $resources {
param (
[string] $moduleName,
[string] $resource,
[string] $helpFile
)

$headings = Get-MarkdownHeadings -FilePath $helpFile -ErrorAction SilentlyContinue

$h2 = $headings | Where-Object { $_.Level -eq 2 -and $_.Text -eq 'PARAMETERS' }
$h2 | Should -Not -BeNullOrEmpty
}

It '[<moduleName>] Should have a help file for [<resource>] resource with heading 2 matching EXAMPLES' -TestCases $resources {
param (
[string] $moduleName,
[string] $resource,
[string] $helpFile
)

$headings = Get-MarkdownHeadings -FilePath $helpFile -ErrorAction SilentlyContinue

$h2 = $headings | Where-Object { $_.Level -eq 2 -and $_.Text -eq 'EXAMPLES' }
$h2 | Should -Not -BeNullOrEmpty
}

It '[<moduleName>] Should have a help file for [<resource>] with 1 example' -TestCases $resources {
param (
[string] $moduleName,
[string] $resource,
[string] $helpFile
)

$headings = Get-MarkdownHeadings -FilePath $helpFile -ErrorAction SilentlyContinue

$h3 = $headings | Where-Object { $_.Level -eq 3 -and $_.Text -eq 'EXAMPLE 1' }
$h3 | Should -Not -BeNullOrEmpty
}

It '[<moduleName>] Should have at least a PowerShell coding example with Invoke-DscResource' -TestCases $codeBlocks {
param (
[string] $ModuleName,
[string] $Content,
[string] $Language
)

$Content | Should -Match "Invoke-DscResource -ModuleName $ModuleName -Name $ResourceName"
}
}
}

0 comments on commit ca1d97a

Please sign in to comment.