├── PesterMatchArray.psd1 ├── Publish.ps1 ├── PesterMatchArray.psm1 ├── appveyor.yml ├── RunPester.ps1 ├── Examples.ps1 ├── LICENSE ├── .vscode └── tasks.json ├── PesterMatchArray.Tests.ps1 ├── README.md └── PesterMatchArray.ps1 /PesterMatchArray.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuartleeks/PesterMatchArray/HEAD/PesterMatchArray.psd1 -------------------------------------------------------------------------------- /Publish.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [Parameter(Mandatory=$true)] 3 | [string]$powershellGalleryKey 4 | ) 5 | Publish-Module -NuGetApiKey $powershellGalleryKey -Path ./ -------------------------------------------------------------------------------- /PesterMatchArray.psm1: -------------------------------------------------------------------------------- 1 | Push-Location $PSScriptRoot 2 | [System.Diagnostics.Debug]::WriteLine("PoshHump:in psm1") 3 | . .\PesterMatchArray.ps1 4 | Pop-Location -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | image: WMF 5 3 | install: 4 | - ps: >- 5 | Get-PackageProvider -Name NuGet -Force 6 | 7 | Install-Module -Name Pester -Force 8 | 9 | build_script: 10 | - ps: Invoke-Pester -EnableExit -------------------------------------------------------------------------------- /RunPester.ps1: -------------------------------------------------------------------------------- 1 | function GetLineNumber($stackTrace){ 2 | if($stackTrace -match "at line: (\d*)"){ 3 | $matches[1]; 4 | } else { 5 | $null 6 | } 7 | } 8 | function GetFileName($stackTrace){ 9 | if($stackTrace -match "at line: (?:\d*) in (.*)\n"){ 10 | $matches[1]; 11 | } else { 12 | $null 13 | } 14 | } 15 | function FormatResult ($result){ 16 | process { 17 | $lineNumber = GetLineNumber $_.StackTrace 18 | $file = GetFileName $_.StackTrace | Resolve-Path -Relative 19 | $collapsedMessage = $_.FailureMessage -replace "`n"," " 20 | $testDescription = "$($_.Describe):$($_.Name)" 21 | "$file;$lineNumber;${testDescription}:$collapsedMessage" 22 | } 23 | } 24 | Write-Output "Running tests..." 25 | $results = Invoke-Pester -PassThru # can use -Quiet to suppress the default Pester output 26 | $results.TestResult | ?{ -not $_.Passed} | FormatResult 27 | Write-Output "Done" -------------------------------------------------------------------------------- /Examples.ps1: -------------------------------------------------------------------------------- 1 | $here = Split-Path -Parent $MyInvocation.MyCommand.Path 2 | Import-Module "$here\PesterMatchArray.psm1" -Force 3 | 4 | Describe "MatchArrayOrdered examples" { 5 | It "single item arrays match" { 6 | ,@("a") | Should MatchArrayOrdered @("a") 7 | } 8 | It "arrays with the same contents match" { 9 | ,@("a", 1) | Should MatchArrayOrdered @("a",1) 10 | } 11 | It "arrays with the same contents in different orders do not match" { 12 | ,@("a", 1) | Should Not MatchArrayOrdered @(1,"a") 13 | } 14 | } 15 | 16 | Describe "MatchArrayUnordered examples" { 17 | It "single item arrays match" { 18 | ,@("a") | Should MatchArrayUnordered @("a") 19 | } 20 | It "arrays with the same contents match" { 21 | ,@("a", 1) | Should MatchArrayUnordered @("a",1) 22 | } 23 | It "arrays with the same contents in different orders match" { 24 | ,@("a", 1) | Should MatchArrayUnordered @(1,"a") 25 | } 26 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Stuart Leeks 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | { 9 | "version": "0.1.0", 10 | "command": "powershell", 11 | "isShellCommand": true, 12 | "showOutput": "silent", 13 | "suppressTaskName": true, 14 | "tasks": [ 15 | { 16 | "taskName": "Test", 17 | "isTestCommand": true, 18 | "args": [ 19 | // weird as it seems, we're passing these as separate params as otherwise 20 | // VSCode will put them in quotes and then PowerShell no longer recognises 21 | // them as switches! 22 | "-ExecutionPolicy", "RemoteSigned", 23 | "-Command", "${workspaceRoot}\\RunPester.ps1" 24 | ], 25 | "problemMatcher": { 26 | "owner": "pester", 27 | "pattern": { 28 | "regexp": "(.+);(.+);(.*)", 29 | "file": 1, 30 | "line": 2, 31 | "message": 3 32 | } 33 | } 34 | }, 35 | { 36 | "taskName": "Package", 37 | "isBuildCommand": true, 38 | "args": [ 39 | "-ExecutionPolicy", "RemoteSigned", 40 | "-Command", "${workspaceRoot}\\BuildPackage.ps1" 41 | ] 42 | } 43 | ] 44 | } -------------------------------------------------------------------------------- /PesterMatchArray.Tests.ps1: -------------------------------------------------------------------------------- 1 | $here = Split-Path -Parent $MyInvocation.MyCommand.Path 2 | $sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") 3 | . "$here\$sut" 4 | 5 | Describe "MatchArrayUnordered" { 6 | It "returns true for matching single item arrays" { 7 | , @("a") | Should MatchArrayUnordered @("a") 8 | } 9 | It "returns true for matching single item and single item array" { 10 | "a" | Should MatchArrayUnordered @("a") 11 | } 12 | It "returns true for matching single item array and single item" { 13 | , (@("a")) | Should MatchArrayUnordered "a" 14 | } 15 | It "returns true for arrays with the same contents" { 16 | , @("a", 1) | Should MatchArrayUnordered @("a", 1) 17 | } 18 | It "returns true for arrays with the same contents in different orders" { 19 | , (@("a", 1)) | Should MatchArrayUnordered @(1, "a") 20 | } 21 | 22 | It "returns false if arrays differ in content" { 23 | , (@(1)) | Should Not MatchArrayUnordered @(2) 24 | } 25 | It "returns false if arrays differ in length" { 26 | , (@(1)) | Should Not MatchArrayUnordered @(1, 1) 27 | } 28 | It "returns false if arrays differ in the number of each item" { 29 | , (@(1, 1, 2)) | Should Not MatchArrayUnordered @(1, 2, 2) 30 | } 31 | } 32 | 33 | 34 | Describe "MatchArrayOrdered" { 35 | It "returns true for matching single item arrays" { 36 | , @("a") | Should MatchArrayOrdered @("a") 37 | } 38 | It "returns true for matching single item and single item array" { 39 | "a" | Should MatchArrayOrdered @("a") 40 | } 41 | It "returns true for matching single item array and single item" { 42 | , @("a") | Should MatchArrayOrdered "a" 43 | } 44 | It "returns true for arrays with the same contents in the same order" { 45 | , @("a", 1) | Should MatchArrayOrdered @("a", 1) 46 | } 47 | It "returns false for arrays with the same contents in different orders" { 48 | , @("a", 1) | Should Not MatchArrayOrdered @(1, "a") 49 | } 50 | 51 | It "returns false if arrays differ in content" { 52 | , @(1) | Should Not MatchArrayOrdered @(2) 53 | } 54 | It "returns false if arrays differ in length" { 55 | , @(1) | Should Not MatchArrayOrdered @(1, 1) 56 | } 57 | It "returns false if arrays differ in the number of each item" { 58 | , (@(1, 1, 2)) | Should Not MatchArrayOrdered @(1, 2, 2) 59 | } 60 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ***This repo is now archived as the functionality exists directly in Pester: https://pester.dev/docs/usage/assertions#be*** 2 | 3 | # PesterMatchArray 4 | This module provides additional assertions for [Pester](https://github.com/pester/Pester) to help with testing array contents 5 | 6 | Also see [PesterMatchHashtable](https://github.com/stuartleeks/PesterMatchHashtable) for hashtable assertions. 7 | 8 | [![Build status](https://ci.appveyor.com/api/projects/status/6huvvr4ujptbkk52/branch/master?svg=true)](https://ci.appveyor.com/project/stuartleeks/pestermatcharray/branch/master) 9 | 10 | ## Installation 11 | 12 | ### PowerShell Gallery 13 | 14 | You can install [PesterMatchArray](https://www.powershellgallery.com/packages/PesterMatchArray/) via the [PowerShell Gallery](https://www.powershellgallery.com/) 15 | 16 | ```powershell 17 | Install-Module -Name PesterMatchArray 18 | ``` 19 | 20 | ## Examples 21 | Because Pester works with the pipeline to give a nice syntax for tests, 22 | and PowerShell uses the pipeline to pass sequences through functions/cmdlets, 23 | the syntax for assertions of arrays with Pester is a little bit unintuitive. 24 | In particular, note the comma at the start of the assertion examples below. 25 | 26 | ### MatchArrayOrdered 27 | MatchArrayOrdered compares two arrays. They are deemed to match if they have the same contents in the same order. 28 | 29 | ```powershell 30 | Describe "MatchArrayOrdered examples" { 31 | It "single item arrays match" { 32 | ,@("a") | Should MatchArrayOrdered @("a") 33 | } 34 | It "arrays with the same contents match" { 35 | ,@("a", 1) | Should MatchArrayOrdered @("a",1) 36 | } 37 | It "arrays with the same contents in different orders do not match" { 38 | ,@("a", 1) | Should Not MatchArrayOrdered @(1,"a") 39 | } 40 | } 41 | ``` 42 | 43 | ### MatchArrayUnordered 44 | MatchArrayUnordered compares two arrays. They are deemed to match if they have the same contents regardless of the order of the items. 45 | 46 | ```powershell 47 | Describe "MatchArrayUnordered examples" { 48 | It "single item arrays match" { 49 | ,@("a") | Should MatchArrayUnordered @("a") 50 | } 51 | It "arrays with the same contents match" { 52 | ,@("a", 1) | Should MatchArrayUnordered @("a",1) 53 | } 54 | It "arrays with the same contents in different orders match" { 55 | ,@("a", 1) | Should MatchArrayUnordered @(1,"a") 56 | } 57 | } 58 | ``` 59 | 60 | ## Release Notes 61 | 62 | ### Version 0.3.1 31st July 2017 63 | Pushed to PowerShell Gallery 64 | 65 | Fix #4 (BUG: arrays with the same items in different quantities do not fail unordered assertion) 66 | 67 | ### Version 0.3.0 27th July 2017 68 | Pushed to PowerShell Gallery 69 | 70 | Updated to work with Pester v4 (tested on 4.0.5 pre-release) 71 | 72 | ### Version 0.2.1 26th November 2015 73 | Pushed to PowerShell Gallery 74 | 75 | Initial version of PesterMatchArray that is split out from other projects 76 | 77 | ## Future 78 | * Wrap up to publish to chocolatey, psget 79 | -------------------------------------------------------------------------------- /PesterMatchArray.ps1: -------------------------------------------------------------------------------- 1 | function PesterMatchArrayUnordered($ActualValue, $ExpectedValue, [switch] $Negate) { 2 | $message = FindMismatchedValueUnordered $ActualValue $ExpectedValue 3 | $success = $message -eq $null; 4 | 5 | if ($success) { 6 | if ($Negate) { 7 | #expecting failure 8 | $success = $false 9 | $message = "Expected: ${ActualValue} to not match the expression ${ExpectedValue}" 10 | } 11 | # else - we can just return success 12 | } 13 | else { 14 | if ($Negate) { 15 | # expecting failure 16 | $success = $true 17 | $message = "" 18 | } 19 | # else - we can just return failure 20 | } 21 | return New-Object psobject -Property @{ 22 | Succeeded = $success 23 | FailureMessage = $message 24 | } 25 | } 26 | function FindMismatchedValueUnordered($ActualValue, $ExpectedValue) { 27 | $ActualValue = @($ActualValue) 28 | $ExpectedGroups = $ExpectedValue | Group-Object | Sort-Object -Property Name 29 | $ActualGroups = $ActualValue | Group-Object | Sort-Object -Property Name 30 | for ($i = 0; $i -lt $ExpectedGroups.Length; $i++) { 31 | if ( ($i -ge $ActualGroups.Length) ` 32 | -or (-not($ActualGroups[$i].Name -eq $ExpectedGroups[$i].Name))) { 33 | return "Expected: {$ExpectedValue}. Actual: {$ActualValue}. Actual is missing item: $($ExpectedGroups[$i].Name)" 34 | } 35 | if (-not($ActualGroups[$i].Count -eq $ExpectedGroups[$i].Count)) { 36 | return "Expected: {$ExpectedValue}. Actual: {$ActualValue}. Actual has $($ActualGroups[$i].Count) of item '$($ExpectedGroups[$i].Name)', expected $($ExpectedGroups[$i].Count)" 37 | } 38 | } 39 | for ($i = 0; $i -lt $ActualGroups.Length; $i++) { 40 | # check for items in actual not in expected 41 | if ( ($i -ge $ExpectedGroups.Length) ` 42 | -or (-not($ExpectedGroups[$i].Name -eq $ActualGroups[$i].Name))) { 43 | return "Expected: {$ExpectedValue}. Actual: {$ActualValue}. Expected doesn't have item: $($ActualGroups[$i].Name)" 44 | } 45 | } 46 | if ($ActualValue.Length -ne $ExpectedValue.Length) { 47 | return "Lengths differ. Expected length $($ExpectedValue.Length). Actual length $($ActualValue.Length) "; 48 | } 49 | return $null; 50 | } 51 | 52 | Add-AssertionOperator -Name MatchArrayUnordered ` 53 | -Test $function:PesterMatchArrayUnordered 54 | 55 | ################################################################################################### 56 | function PesterMatchArrayOrdered($ActualValue, $ExpectedValue, [switch] $Negate) { 57 | 58 | $message = FindMismatchedValueOrdered $ActualValue $ExpectedValue 59 | $success = $message -eq $null; 60 | 61 | if ($success) { 62 | if ($Negate) { 63 | #expecting failure 64 | $success = $false 65 | $message = "Expected: ${ActualValue} to not match the expression ${ExpectedValue}" 66 | } 67 | # else - we can just return success 68 | } 69 | else { 70 | if ($Negate) { 71 | # expecting failure 72 | $success = $true 73 | $message = "" 74 | } 75 | # else - we can just return failure 76 | } 77 | return New-Object psobject -Property @{ 78 | Succeeded = $success 79 | FailureMessage = $message 80 | } 81 | } 82 | 83 | function FindMismatchedValueOrdered($value, $expectedMatch) { 84 | $value = @($value) 85 | for ($i = 0; $i -lt $expectedMatch.Length -and $i -lt $value.Length; $i++) { 86 | if (-not($value[$i] -eq $expectedMatch[$i])) { 87 | return "Differs at index $i. Expected: {$expectedMatch}. Actual: {$value}." 88 | } 89 | } 90 | if ($value.Length -ne $expectedMatch.Length) { 91 | return "Lengths differ - Expected length $($expectedMatch.Length), actual length $($value.Length)"; 92 | } 93 | return $null; 94 | } 95 | 96 | Add-AssertionOperator -Name MatchArrayOrdered ` 97 | -Test $function:PesterMatchArrayOrdered 98 | --------------------------------------------------------------------------------