Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion Scripts/PesterInterface.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,21 @@ Describe 'PesterInterface' {
$baseMock.Data = @('pester')
Expand-TestCaseName $baseMock | Should -Be 'Array TestCase pester'
}
It 'Works with Array testcase - placeholder only' {
$baseMock.Name = '<_>'
$baseMock.Data = @('pester')
Expand-TestCaseName $baseMock | Should -Be 'pester'
}
It 'Works with Array testcase - PSCustomObject' {
$baseMock.Name = 'Using PropertyName: Returns <Emoji> (<Description>)'
$baseMock.Data = [pscustomobject]@{ Emoji = '🦒' ; Description = 'giraffe' }
Expand-TestCaseName $baseMock | Should -Be 'Using PropertyName: Returns 🦒 (giraffe)'
}
It 'Works with Array testcase - PSCustomObject Property' {
$baseMock.Name = 'Using _.PropertyName: Returns <_.Emoji> (<_.Description>)'
$baseMock.Data = [pscustomobject]@{ Emoji = '🦒' ; Description = 'giraffe' }
Expand-TestCaseName $baseMock | Should -Be 'Using _.PropertyName: Returns 🦒 (giraffe)'
}
It 'Works with Single Hashtable testcase' {
$baseMock.Name = 'Array TestCase <Name>'
$baseMock.Data = @{Name = 'pester' }
Expand All @@ -118,11 +133,47 @@ Describe 'PesterInterface' {
$baseMock.Data = @{Name = 'pester'; Data = 'aCoolTest' }
Expand-TestCaseName $baseMock | Should -Be 'Array aCoolTest TestCase pester'
}

It 'Works with Multiple Hashtable testcase - Property syntax' {
$baseMock.Name = 'Using _.PropertyName: Returns <_.Emoji> (<_.Description>)'
$baseMock.Data = @{ Emoji = '🦒' ; Description = 'giraffe' }
Expand-TestCaseName $baseMock | Should -Be 'Using _.PropertyName: Returns 🦒 (giraffe)'
}
It "Works with Multiple Hashtable testcase - dot-navigation" {
$baseMock.Name = 'A <animal.emoji> (<Name>) goes <Animal.Sound>'
$baseMock.Data = @{ Name = "cow"; Animal = @{ Sound = "Mooo"; Emoji = "🐄"}}
Expand-TestCaseName $baseMock | Should -Be 'A 🐄 (cow) goes Mooo'
}
It 'Works with Pester.Block' {
$Block = Import-Clixml $Mocks/Block.clixml
Expand-TestCaseName $Block | Should -Be 'Describe Nested Foreach giraffe'
}
It 'Works with Variable defined in Before-Block' -Skip {
$baseMock.Name = '<banana> <giraffe>'
# TODO dont know how to test this and get this case working
#$baseMock.BeforeAll = { $banana = '🍌' }
#$baseMock.BeforeEach = { $giraffe = '🦒' }
Expand-TestCaseName $baseMock | Should -Be '🍌 🦒'
}
It 'Works with Escaping in Single Quotes' {
$baseMock.Name = 'x: `<<_>`>'
$baseMock.Data = @(1)
Expand-TestCaseName $baseMock | Should -Be 'x: <1>'
}
It 'Works with Escaping in Single Quotes 2' {
$baseMock.Name = 'When x `< 4, x: <_>'
$baseMock.Data = @(1)
Expand-TestCaseName $baseMock | Should -Be 'When x < 4, x: 1'
}
It 'Works with Escaping in Double Quotes' {
$baseMock.Name = "x: ``<<_>``>"
$baseMock.Data = @(1)
Expand-TestCaseName $baseMock | Should -Be 'x: <1>'
}
It 'Works with Escaping in Double Quotes 2' {
$baseMock.Name = "When x ``< 4, x: <_>"
$baseMock.Data = @(1)
Expand-TestCaseName $baseMock | Should -Be 'When x < 4, x: 1'
}
}

Context 'Get-DurationString' {
Expand Down
51 changes: 48 additions & 3 deletions Scripts/PesterTestPlugin.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,62 @@ function Expand-TestCaseName {
process {
[String]$Name = $Test.Name.ToString()

$Data = Merge-TestData $Test
$Data = ([Hashtable] (Merge-TestData $Test))

$flatData = @{}
foreach ($DataItem in $Data) {
$flatData += Flatten-Object $DataItem
}

# Array value was stored as _ by Merge-TestData
$Data.GetEnumerator().ForEach{
$Name = $Name -replace ('<{0}>' -f $PSItem.Key), $PSItem.Value
$placeholders = [regex]::Matches($Name, '(^<|[^`]<)([_\.]?[^>]*)>')
foreach ($placeholder in $placeholders) {
$match = $placeholder.Groups[2].Value
$replacement = ""
if($match.StartsWith("_.")) {
$replacement = $null -ne $flatData[$match] ? $flatData[$match] : $flatData[$match.Trim("_.")]
} else {
$replacement = $null -ne $flatData[$match] ? $flatData[$match] : $flatData["_." + $match]
}
$Name = $Name -replace "<(_\.)?$match>", $replacement
}

$Name = $Name -replace '`', ''

return $Name
}
}

# Inspired by https://gist.github.com/SP3269/fb5b0784bf2cede11ac3a1fa6d5ee1de
function Flatten-Object ( $object, [string] $prefix = "" ) {
[CmdletBinding()]

$result = @{}

if ($null -eq $object) {
return @{$prefix = "null" }
}

$point = $prefix -eq "" ? "" : "."

switch -Regex ($object.GetType().Name) {
'^(Boolean|String|Int32|Int64|Float|Double|.*\[\])$' {
$result += @{$prefix = $object }
}
"Hashtable" {
$object.GetEnumerator() | ForEach-Object {
$result += Flatten-Object $PSItem.Value ($prefix + $point + $PSItem.Key)
}
}
"PSCustomObject" {
$(Get-Member -InputObject $object -MemberType NoteProperty).GetEnumerator() | ForEach-Object {
$result += Flatten-Object ($object | Select-Object -ExpandProperty $PSItem.Name) ($prefix + $point + $PSItem.Name)
}
}
}
return $result
}

function New-TestItemId {
<#
.SYNOPSIS
Expand Down
226 changes: 226 additions & 0 deletions sample/Tests/DataDriven.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
BeforeDiscovery {
$script:arrayOfHashtables = @(
@{ Emoji = '🌵' ; Description = 'cactus' }
@{ Emoji = '🦒' ; Description = 'giraffe' }
@{ Emoji = '🍎' ; Description = 'apple' }
@{ Emoji = '🐧' ; Description = 'penguin' }
@{ Emoji = '😊' ; Description = 'smiling face with smiling eyes' }
)

$script:arrayOfObjects = @(
[pscustomobject]@{ Emoji = '🌵' ; Description = 'cactus' }
[System.Object]@{ Emoji = '🦒' ; Description = 'giraffe' }
[pscustomobject]@{ Emoji = '🍎' ; Description = 'apple' }
[pscustomobject]@{ Emoji = '🐧' ; Description = 'penguin' }
[pscustomobject]@{ Emoji = '😊' ; Description = 'smiling face with smiling eyes' }
)
}

Describe 'Issue 247' {
Describe 'Template expansion' {
Context 'Array of hashtables' {
It 'Using PropertyName: Returns <Emoji> (<Description>)' -ForEach $arrayOfHashtables {}
It 'Using _.PropertyName: Returns <_.Emoji> (<_.Description>)' -ForEach $arrayOfHashtables {}
}
Context 'Array of objects' {
It 'Using PropertyName: Returns <Emoji> (<Description>)' -ForEach $arrayOfObjects {}
It 'Using _.PropertyName: Returns <_.Emoji> (<_.Description>)' -ForEach $arrayOfObjects {}
}
}
}

Describe 'Pester Documentation V5' {
BeforeAll {
Get-Module PesterDemoFunctions | Remove-Module
New-Module PesterDemoFunctions -ScriptBlock {
$emojis = @(
@{ Name = 'apple'; Symbol = '🍎'; Kind = 'Fruit' }
@{ Name = 'beaming face with smiling eyes'; Symbol = '😁'; Kind = 'Face' }
@{ Name = 'cactus'; Symbol = '🌵'; Kind = 'Plant' }
@{ Name = 'giraffe'; Symbol = '🦒'; Kind = 'Animal' }
@{ Name = 'pencil'; Symbol = '✏️'; Kind = 'Item' }
@{ Name = 'penguin'; Symbol = '🐧'; Kind = 'Animal' }
@{ Name = 'pensive'; Symbol = '😔'; Kind = 'Face' }
@{ Name = 'slightly smiling face'; Symbol = '🙂'; Kind = 'Face' }
@{ Name = 'smiling face with smiling eyes'; Symbol = '😊'; Kind = 'Face' }
) | ForEach-Object { [PSCustomObject]$_ }

function Get-Emoji ([string]$Name = '*') {
$script:emojis | Where-Object Name -like $Name | ForEach-Object Symbol
}

function Get-EmojiKind {
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string]$Emoji
)
process {
$script:emojis | Where-Object Symbol -eq $Emoji | Foreach-Object Kind
}
}

$fruitBasket = [System.Collections.ArrayList]@('🍎', '🍌', '🥝', '🥑', '🍇', '🍐')

function Get-FruitBasket {
$script:fruitBasket
}

function Remove-FruitBasket {
param(
[Parameter(Mandatory = $true)]
[string]$Item
)
$script:fruitBasket.Remove($Item)
}

function Reset-FruitBasket {
$script:fruitBasket = [System.Collections.ArrayList]@('🍎', '🍌', '🥝', '🥑', '🍇', '🍐')
}
} | Import-Module
}
Context "Using -ForEach & -TestCases with hashtable" {
Describe "Get-Emoji" {
It "Returns <expected> (<name>)" -ForEach @(
@{ Name = "cactus"; Expected = '🌵' }
@{ Name = "giraffe"; Expected = '🦒' }
@{ Name = "apple"; Expected = '🍎' }
@{ Name = "pencil"; Expected = '✏️' }
@{ Name = "penguin"; Expected = '🐧' }
@{ Name = "smiling face with smiling eyes"; Expected = '😊' }
) {
Get-Emoji -Name $name | Should -Be $expected
}
}
Describe "Get-Emoji <name>" -ForEach @(
@{ Name = "cactus"; Symbol = '🌵'; Kind = 'Plant' }
@{ Name = "giraffe"; Symbol = '🦒'; Kind = 'Animal' }
) {
It "Returns <symbol>" {
Get-Emoji -Name $name | Should -Be $symbol
}

It "Has kind <kind>" {
Get-Emoji -Name $name | Get-EmojiKind | Should -Be $kind
}
}
Describe "Get-Emoji <name>" -ForEach @(
@{
Name = "cactus";
Symbol = '🌵';
Kind = 'Plant'
Runes = @(
@{ Index = 0; Rune = 127797 }
)
}
@{
Name = "pencil"
Symbol = '✏️'
Kind = 'Item'
Runes = @(
@{ Index = 0; Rune = 9999 }
@{ Index = 1; Rune = 65039 }
)
}
) {
It "Returns <symbol>" {
Get-Emoji -Name $name | Should -Be $symbol
}

It "Has kind <kind>" {
Get-Emoji -Name $name | Get-EmojiKind | Should -Be $kind
}

Context "Runes (each character in multibyte emoji)" {
It "Has rune <rune> on index <index>" -ForEach $runes {
$actual = @((Get-Emoji -Name $name).EnumerateRunes())
$actual[$index].Value | Should -Be $rune
}
}
}
}
Context 'Using -ForEach & -TestCases with an array' {
Describe "Get-FruitBasket" {
It "Contains <_>" -ForEach '🍎', '🍌', '🥝', '🥑', '🍇', '🍐' {
Get-FruitBasket | Should -Contain $_
}

Context "Fruit <_>" -ForEach '🍎', '🍌', '🥝', '🥑', '🍇', '🍐' {
It "Contains <_> by default" {
Get-FruitBasket | Should -Contain $_
}

It "Can remove <_> from the basket" {
Remove-FruitBasket -Item $_
Get-FruitBasket | Should -Not -Contain $_
}
}
AfterAll {
Reset-FruitBasket
}
}
}
Context 'Using <> templates' {
BeforeAll {
$script:apple = '🍎'
}

Describe "<apple>" {
It "<apple> <animal>" -ForEach @(
@{ Animal = "🐛" }
@{ Animal = "🐶" }
) {}
}
Describe "<banana>" {
BeforeAll {
$script:banana = '🍌'
}

BeforeEach {
$script:giraffe = '🦒'
}

It "<banana> <giraffe> <animal>" {}
}
Describe "Animals " {
It "<_>" -ForEach @("🐛", "🐶") {}
}
}
Context 'Using dot-navigation in <> template' {
Describe "Animals" {
It "A <animal.emoji> (<name>) goes <animal.sound>" -ForEach @(
@{
Name = "cow"
Animal = @{
Sound = "Mooo"
Emoji = "🐄"
}
}
@{
Name = "fox"
Animal = @{
Sound = "Ring-ding-ding-ding-dingeringeding!"
Emoji = "🦊"
}
}
) {}
}
}
Context 'Escaping' {
Describe 'with single quoted string' {
Describe "Fruit <_>" -ForEach "🍎", "🍐" {
It 'Getting <_> returns $null' {}
}
Describe 'When x `< 4, x: <_>' -ForEach @(1..4) {
It 'x: `<<_>`>' {}
}
}
Describe 'with double quoted string' {
Describe "Fruit <_>" -ForEach "🍎", "🍐" {
It "Getting <_> returns `$null" {}
}
Describe "When x ``< 4, x: <_>" -ForEach @(1..4) {
It "x: ``<<_>``>" {}
}
}
}
}