tests/VisualEffects.Unit.Tests.ps1
#Requires -Modules @{ModuleName='Pester'; MaximumVersion='5.99.99'} [Diagnostics.CodeAnalysis.SuppressMessageAttribute('AvoidDeprecatedCommands', '', Justification = 'Test-Json is skipped in PowerShell 5')] [CmdletBinding()] param () BeforeDiscovery { # Get the module path and name, even if we are in nested sub-directories $manifestPath = $PSScriptRoot -replace '(\w+)\\Tests\b.*', '$1\$1.psd1' $moduleName = $manifestPath -replace '.*\\|\.psd1' $modulePath = $PSScriptRoot -replace '\\Tests\b.*' Get-Module $moduleName | Remove-Module # Importing module to build test cases in Discovery Import-Module $manifestPath -Force $legacyPowerShell = $PSEdition -ne 'Core' $definitionFiles = Get-ChildItem "$modulePath\Definitions\*.json" $presetFiles = Get-ChildItem "$modulePath\Presets\*.json" } BeforeAll { # Get the module path and name, even if we are in nested sub-directories $manifestPath = $PSScriptRoot -replace '(\w+)\\Tests\b.*', '$1\$1.psd1' $moduleName = $manifestPath -replace '.*\\|\.psd1' $modulePath = $PSScriptRoot -replace '\\Tests\b.*' # Mock function to track when Set() made a change function MockFunction {[CmdletBinding()]param()} Mock MockFunction {} Mock Get-VisualEffectInstance { $result = [pscustomobject]@{ Name = $Name Enabled = $effectEnabled Description = "Some description about $Name" } $result | Add-Member -MemberType ScriptMethod -Name Set -Value { if ($this.Enabled -ne $args[0]) {MockFunction} } $result } -ModuleName $moduleName # Splat variable for repeated use of Should -Invoke (in module scope) $onceInModule = @{ ModuleName = $moduleName Exactly = $true } } Describe 'JSON files' { It 'Definition file <_.Name> should conform to its schema' -Skip:$legacyPowerShell -ForEach $definitionFiles { $schema = "$($_.DirectoryName)\Schema\$($_.BaseName)-Schema.json" Test-Json -Path $_.FullName -SchemaFile $schema -ErrorAction SilentlyContinue | Should -BeTrue } It 'Preset file <_.Name> should conform to its schema' -Skip:$legacyPowerShell -ForEach $presetFiles { $schema = "$($_.DirectoryName)\Schema\Presets-Schema.json" Test-Json -Path $_.FullName -SchemaFile $schema -ErrorAction SilentlyContinue | Should -BeTrue } } Describe 'Classes and enums' { It 'EffectName enum should match effect definitions' -ForEach @(, $definitionFiles) { $effects = $_ | Get-Content -Raw | ConvertFrom-Json $enum = InModuleScope $moduleName {[Enum]::GetNames([EffectName])} compare $effects.List.Name $enum -PassThru | Should -BeNullOrEmpty } It 'EffectNamePreset enum should match preset definitions' -Foreach @(, $presetFiles) { $enum = InModuleScope $moduleName {[Enum]::GetNames([EffectPreset])} compare $_.BaseName $enum -PassThru | Should -BeNullOrEmpty } } Describe 'Get-VisualEffect' { Context 'When a Visual Effect Does Not Exist' { It 'The parameter filter for enums picks this up and throws' { {Get-VisualEffect -Name 'NotExist'} | Should -Throw '*Cannot convert value "NotExist" to type "EffectName"*' } } Context 'When a single Visual Effect is requested by param' { It 'Get-VisualEffectInstance mock should be called once by name' { Get-VisualEffect -Name 'Animation' | Out-Null Should -Invoke @onceInModule Get-VisualEffectInstance -ParameterFilter {$Name -eq 'Animation'} } } Context 'When a single Visual Effect is requested by pipeline' { It 'Get-VisualEffectInstance mock should be called once by name' { 'Animation' | Get-VisualEffect | Out-Null Should -Invoke @onceInModule Get-VisualEffectInstance -ParameterFilter {$Name -eq 'Animation'} } } Context 'When multiple Visual Effects are requested by param' { BeforeEach { Get-VisualEffect -Name 'Animation', 'CursorShadow' | Out-Null } It 'Get-VisualEffectInstance should be called once for <_>' -ForEach @('Animation', 'CursorShadow') { Should -Invoke @onceInModule Get-VisualEffectInstance -ParameterFilter {$Name -eq $_} } } Context 'When multiple Visual Effects are requested by pipeline' { BeforeEach { 'Animation', 'CursorShadow' | Get-VisualEffect | Out-Null } It 'Get-VisualEffectInstance should be called once for <_>' -ForEach @('Animation', 'CursorShadow') { Should -Invoke @onceInModule Get-VisualEffectInstance -ParameterFilter {$Name -eq $_} } } } Describe 'Set-VisualEffect' { BeforeAll { Mock Set-ItemProperty {} -ModuleName $moduleName -ParameterFilter {$Name -eq 'VisualFXSetting'} } Context 'When a Visual Effect Does Not Exist' { It 'The parameter filter for enums picks this up and throws' { {Set-VisualEffect -Name 'NotExist' -Enabled $true} | Should -Throw '*Cannot convert value "NotExist" to type "EffectName"*' } } Context 'When a single Visual Effect is enabled by param and it is currently disabled' { BeforeEach { # Ensure the Get Method on mocked Get-VisualEffectInstance returns false $effectEnabled = $false Set-VisualEffect -Name 'Animation' -Enabled $true | Out-Null } It 'Get-VisualEffectInstance mock should be called once by name' { Should -Invoke @onceInModule Get-VisualEffectInstance -ParameterFilter {$Name -eq 'Animation'} } It 'MockFunction should be called once' { Should -Invoke MockFunction -Exactly } It 'VisualFXSetting should be set' { Should -Invoke @onceInModule Set-ItemProperty } } Context 'When a single Visual Effect is enabled by pipeline and it is currently disabled' { BeforeEach { $effectEnabled = $false 'Animation' | Set-VisualEffect -Enabled $true | Out-Null } It 'Get-VisualEffectInstance mock should be called once by name' { Should -Invoke @onceInModule Get-VisualEffectInstance -ParameterFilter {$Name -eq 'Animation'} } It 'MockFunction should be called once' { Should -Invoke MockFunction -Exactly } It 'VisualFXSetting should be set' { Should -Invoke @onceInModule Set-ItemProperty } } Context 'When multiple Visual Effects are enabled by pipeline and they are currently disabled' { BeforeEach { $effectEnabled = $false 'Animation', 'CursorShadow' | Set-VisualEffect -Enabled $true | Out-Null } It 'Get-VisualEffectInstance should be called once for <_>' -ForEach @('Animation', 'CursorShadow') { Should -Invoke @onceInModule Get-VisualEffectInstance -ParameterFilter {$Name -eq $_} } It 'MockFunction should be called twice' { Should -Invoke MockFunction -Exactly -Times 2 } It 'VisualFXSetting should be set' { Should -Invoke @onceInModule Set-ItemProperty } } Context 'Running in -WhatIf mode' { BeforeAll { # Using BeforeAll and -Scope Context so we only see the WhatIf message once Set-VisualEffect -Name 'Animation' -Enabled $true -WhatIf } It 'Get-VisualEffectInstance mock should be called once by name' { Should -Invoke @onceInModule Get-VisualEffectInstance -Scope Context -ParameterFilter { $Name -eq 'Animation' } } It 'MockFunction should not be called' { Should -Invoke MockFunction -Times 0 -Scope Context } It 'VisualFXSetting should not be set' { Should -Invoke Set-ItemProperty -ModuleName $moduleName -Times 0 -Scope Context } } Context 'When a single Visual Effect is enabled by param and it is currently enabled' { BeforeEach { # Ensure the Get Method on mocked Get-VisualEffectInstance returns true $effectEnabled = $true Set-VisualEffect -Name 'Animation' -Enabled $true | Out-Null } It 'Get-VisualEffectInstance mock should be called once by name' { Should -Invoke @onceInModule Get-VisualEffectInstance -ParameterFilter {$Name -eq 'Animation'} } It 'MockFunction should not be called' { Should -Invoke MockFunction -Times 0 } It 'VisualFXSetting should not be set' { Should -Invoke Set-ItemProperty -ModuleName $moduleName -Times 0 } } Context 'When a single Visual Effect is enabled by pipeline and it is currently enabled' { BeforeEach { $effectEnabled = $true 'Animation' | Set-VisualEffect -Enabled $true | Out-Null } It 'Get-VisualEffectInstance mock should be called once by name' { Should -Invoke @onceInModule Get-VisualEffectInstance -ParameterFilter {$Name -eq 'Animation'} } It 'MockFunction should not be called' { Should -Invoke MockFunction -Times 0 } It 'VisualFXSetting should not be set' { Should -Invoke Set-ItemProperty -ModuleName $moduleName -Times 0 } } Context 'When multiple Visual Effects are enabled by pipeline and they are currently enabled' { BeforeEach { $effectEnabled = $true 'Animation', 'CursorShadow' | Set-VisualEffect -Enabled $true | Out-Null } It 'Get-VisualEffectInstance should be called once for <_>' -ForEach @('Animation', 'CursorShadow') { Should -Invoke @onceInModule Get-VisualEffectInstance -ParameterFilter {$Name -eq $_} } It 'MockFunction should not be called' { Should -Invoke MockFunction -Times 0 } It 'VisualFXSetting should not be set' { Should -Invoke Set-ItemProperty -ModuleName $moduleName -Times 0 } } } Describe 'Get-VisualEffectPreset' { BeforeDiscovery { $presets = Get-VisualEffectPreset } It 'There are at least 2 presets' -Foreach @(, $presets) { $_.Count | Should -BeGreaterOrEqual 2 } Context 'Preset <_.Name>' -ForEach $presets { It 'Has a <Attribute> property' -ForEach @( @{Attribute = 'Name'; Value = $_.Name} @{Attribute = 'Description'; Value = $_.Description} @{Attribute = 'Settings'; Value = $_.Settings} ) { $Value | Should -Not -BeNullOrEmpty } It 'Setting <_.Name> has an Enabled property' -ForEach $_.Settings { $_.Enabled | Should -BeOfType [bool] } } } Describe 'Set-VisualEffectPreset' { BeforeAll { # Local Mocks Mock Set-VisualEffect {} -ModuleName $moduleName $testPreset = Get-VisualEffectPreset | select -First 1 } Context 'When a Preset is applied' { It 'There should be settings found' { $testPreset.Settings.Count | Should -BeGreaterThan 5 } It 'Set-VisualEffect mock should be called for each setting' { Set-VisualEffectPreset -Name $testPreset.Name Should -Invoke Set-VisualEffect -ModuleName $moduleName -Exactly $testPreset.Settings.Count } } } |