Skip to content

Instantly share code, notes, and snippets.

@wsmelton
Last active October 29, 2020 00:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wsmelton/24bad5e8fbe4ca8f47b9bdb7f25e556d to your computer and use it in GitHub Desktop.
Save wsmelton/24bad5e8fbe4ca8f47b9bdb7f25e556d to your computer and use it in GitHub Desktop.
Pester 5 File Integrity Tests using 5.1 version of Pester

Introduction

This tests is written to show a pattern of how iteration will work in Pester 5.1 (as of Oct 23, 2020 is still in beta).

References

The File Integrity test source came from one of Chrissy LeMaire's module kbupdate. You can find the source version here.

The function included in this test, Get-FileEncoding, was sourced from Frank Richard's post.

Pattern

The ForEach can be used with the Describe and Context blocks in your tests. The Describe block you would execute code prior in order to provide the object (as I did for $allFiles). The Context is a bit different because a major change in Pester 5 was code that is to be run prior to a Context or It block has to be done within a BeforeAll or BeforeEach block.

When you iterate over the objects and you want to reference the object in the description of the Describe, Context or It block you can use <_>. Within code such as BeforeAll you would use the same $_ that we use in PowerShell piping. I use the later for setting variables in the BeforeAll block such as $name and $fullName.

Pester Should Syntax

A major thing ot remember when you are converting your scripts, or writing new ones for Pester 5, is the syntax for Should statement is no being enforced. Previously we could just do $true | Should Be $true but that will now error with the following:

RuntimeException: Legacy Should syntax (without dashes) is not supported in Pester 5. Please refer to migration guide at: http://pester.dev/docs/migrations/v3-to-v4

Instead you must use proper parameter syntax as $true | Should -Be $true (notice the dash).

$moduleRoot = (Resolve-Path "$PSScriptRoot\..").Path
$allFiles = Get-ChildItem -Path $moduleRoot -Recurse -Filter "*.ps1" |
Where-Object FullName -NotLike "$moduleRoot\tests\*" |
Where-Object FullName -NotLike "$moduleRoot\Build.ps1"
Describe "Verifying module PS1 files" -Foreach $allFiles {
BeforeAll {
$name = $_.Name
$fullName = $_.FullName
$file = $_
$bandCommands = @('Write-Host','Get-WmiObject','Write-Debug')
$tokens, $parseErrors = $null
$ast = [System.Management.Automation.Language.Parser]::ParseFile($fullName, [ref]$tokens, [ref]$parseErrors)
function Get-FileEncoding {
[CmdletBinding()]
Param (
[Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
[string]$Path
)
[byte[]]$byte = Get-Content -Encoding byte -ReadCount 4 -TotalCount 4 -Path $Path
#Write-Host Bytes: $byte[0] $byte[1] $byte[2] $byte[3]
# EF BB BF (UTF8)
if ( $byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf )
{ Write-Output 'UTF8' }
# FE FF (UTF-16 Big-Endian)
elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff)
{ Write-Output 'Unicode UTF-16 Big-Endian' }
# FF FE (UTF-16 Little-Endian)
elseif ($byte[0] -eq 0xff -and $byte[1] -eq 0xfe)
{ Write-Output 'Unicode UTF-16 Little-Endian' }
# 00 00 FE FF (UTF32 Big-Endian)
elseif ($byte[0] -eq 0 -and $byte[1] -eq 0 -and $byte[2] -eq 0xfe -and $byte[3] -eq 0xff)
{ Write-Output 'UTF32 Big-Endian' }
# FE FF 00 00 (UTF32 Little-Endian)
elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff -and $byte[2] -eq 0 -and $byte[3] -eq 0)
{ Write-Output 'UTF32 Little-Endian' }
# 2B 2F 76 (38 | 38 | 2B | 2F)
elseif ($byte[0] -eq 0x2b -and $byte[1] -eq 0x2f -and $byte[2] -eq 0x76 -and ($byte[3] -eq 0x38 -or $byte[3] -eq 0x39 -or $byte[3] -eq 0x2b -or $byte[3] -eq 0x2f) )
{ Write-Output 'UTF7' }
# F7 64 4C (UTF-1)
elseif ( $byte[0] -eq 0xf7 -and $byte[1] -eq 0x64 -and $byte[2] -eq 0x4c )
{ Write-Output 'UTF-1' }
# DD 73 66 73 (UTF-EBCDIC)
elseif ($byte[0] -eq 0xdd -and $byte[1] -eq 0x73 -and $byte[2] -eq 0x66 -and $byte[3] -eq 0x73)
{ Write-Output 'UTF-EBCDIC' }
# 0E FE FF (SCSU)
elseif ( $byte[0] -eq 0x0e -and $byte[1] -eq 0xfe -and $byte[2] -eq 0xff )
{ Write-Output 'SCSU' }
# FB EE 28 (BOCU-1)
elseif ( $byte[0] -eq 0xfb -and $byte[1] -eq 0xee -and $byte[2] -eq 0x28 )
{ Write-Output 'BOCU-1' }
# 84 31 95 33 (GB-18030)
elseif ($byte[0] -eq 0x84 -and $byte[1] -eq 0x31 -and $byte[2] -eq 0x95 -and $byte[3] -eq 0x33)
{ Write-Output 'GB-18030' }
else
{ Write-Output 'ASCII' }
}
}
Context "Validating <_>" {
It "<_> Should have UTF8 encoding" {
Get-FileEncoding -Path $fullName | Should -Be 'UTF8'
}
It "<_> Should have no trailing space" {
($file | Select-String "\s$" | Where-Object { $_.Line.Trim().Length -gt 0 } | Measure-Object).Count | Should -BeExactly 0
}
It "<_> Should have no syntax errors" {
$parseErrors | Should -BeNullOrEmpty
}
}
Context "Verify <_> does not contain unapproved code" {
It "<_> should not contain unapproved commands"{
$tokens | Where-Object Text -in $bandCommands | Should -BeNullOrEmpty -Because "These are commands that should be utilized in this module"
}
It "<_> should not contain any aliases" {
$tokens | Where-Object TokenFlags -eq CommandName | Where-Object { Test-Path "alias:\$($_.Text)" } | Measure-Object | Select-Object -ExpandProperty Count | Should -BeExactly 0
}
It "<_> should not contain special character aliases" {
$tokens | Where-Object TokenFlags -eq 'BinaryPrecedenceMultiply, BinaryOperator, CommandName, CanConstantFold' | Where-Object { Test-Path "alias:\$($_.Text)" } | Measure-Object | Select-Object -ExpandProperty Count | Should -BeExactly 0
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment