Tests/LMFilterValidation.Tests.ps1
|
BeforeAll { Import-Module $Module -Force # Dot source the validation functions for unit testing . "$PSScriptRoot/../Private/Test-LMFilterField.ps1" . "$PSScriptRoot/../Private/Format-LMFilter-v1.ps1" . "$PSScriptRoot/../Private/Format-LMFilter.ps1" } Describe 'Filter Field Validation' { Context 'Valid Filters - String Format' { It 'Should accept valid device filter with correct field names' { { Format-LMFilter -Filter "displayName -eq 'test' -and deviceType -eq '0'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } It 'Should accept valid alert filter with severity and cleared fields' { { Format-LMFilter -Filter "severity -eq 'Error' -and cleared -eq 'false'" -ResourcePath "/alert/alerts" -ErrorAction Stop } | Should -Not -Throw } It 'Should accept valid device group filter with fullPath field' { { Format-LMFilter -Filter "fullPath -eq 'test' -and disableAlerting -eq 'false'" -ResourcePath "/device/groups" -ErrorAction Stop } | Should -Not -Throw } It 'Should accept property-based filter (customProperties)' { { Format-LMFilter -Filter "customProperties -contains 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } It 'Should accept property-based filter (systemProperties)' { { Format-LMFilter -Filter "systemProperties -contains 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } It 'Should accept multiple valid operators (-ne, -gt, -lt, -ge, -le, -notcontains)' { { Format-LMFilter -Filter "id -ne '0'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw { Format-LMFilter -Filter "id -gt '100'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw { Format-LMFilter -Filter "id -lt '1000'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw { Format-LMFilter -Filter "id -ge '100'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw { Format-LMFilter -Filter "id -le '1000'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw { Format-LMFilter -Filter "name -notcontains 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } } Context 'Valid Filters - Hashtable Format' { It 'Should accept valid hashtable filter with correct fields' { { Format-LMFilter -Filter @{displayName="test"; deviceType="0"} -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } It 'Should accept hashtable filter with single field' { { Format-LMFilter -Filter @{name="test"} -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } It 'Should accept hashtable filter with multiple valid fields' { { Format-LMFilter -Filter @{displayName="test"; name="test"; id="123"} -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } } Context 'Invalid Filters - Case Sensitivity' { It 'Should reject lowercase field name and suggest correct casing' { { Format-LMFilter -Filter "displayname -eq 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Throw -ExpectedMessage "*displayName*" } It 'Should reject mixed case typo in field name' { { Format-LMFilter -Filter "DisplayName -eq 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Throw -ExpectedMessage "*displayName*" } It 'Should reject all uppercase field name' { { Format-LMFilter -Filter "DISPLAYNAME -eq 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Throw } } Context 'Invalid Filters - Completely Wrong Field Names' { It 'Should reject completely invalid field name in string filter' { { Format-LMFilter -Filter "invalidField -eq 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Throw -ExpectedMessage "*Invalid filter field*" } It 'Should reject completely invalid field name in hashtable filter' { { Format-LMFilter -Filter @{badFieldName="test"} -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Throw -ExpectedMessage "*Invalid filter field*" } It 'Should reject invalid field even when mixed with valid fields' { { Format-LMFilter -Filter "displayName -eq 'test' -and badField -eq 'value'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Throw -ExpectedMessage "*Invalid filter field*" } It 'Should reject multiple invalid fields and list them all' { { Format-LMFilter -Filter "badField1 -eq 'test' -and badField2 -eq 'value'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Throw -ExpectedMessage "*Invalid filter field*" } } Context 'Invalid Filters - Wrong Endpoint Fields' { It 'Should reject device field when used on alert endpoint' { { Format-LMFilter -Filter "deviceType -eq '0'" -ResourcePath "/alert/alerts" -ErrorAction Stop } | Should -Throw -ExpectedMessage "*Invalid filter field*" } It 'Should reject alert field when used on device endpoint' { { Format-LMFilter -Filter "severity -eq 'Error'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Throw -ExpectedMessage "*Invalid filter field*" } } Context 'Error Messages' { It 'Should provide helpful error message with field name' { try { Format-LMFilter -Filter "badField -eq 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } catch { $_.Exception.Message | Should -Match "Invalid filter field" $_.Exception.Message | Should -Match "badField" } } It 'Should suggest valid fields in error message' { try { Format-LMFilter -Filter "invalidField -eq 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } catch { $_.Exception.Message | Should -Match "Valid fields for this endpoint include" } } It 'Should suggest similar field for typos' { try { Format-LMFilter -Filter "displayname -eq 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } catch { $_.Exception.Message | Should -Match "Did you mean.*displayName" } } } Context 'Configuration Loading' { It 'Should load validation config successfully' { $ConfigPath = "$PSScriptRoot/../Private/LMFilterValidationConfig.psd1" $ConfigPath | Should -Exist $Config = Import-PowerShellDataFile -Path $ConfigPath $Config | Should -Not -BeNullOrEmpty $Config.Keys.Count | Should -BeGreaterThan 0 } It 'Should have device endpoint in config' { $ConfigPath = "$PSScriptRoot/../Private/LMFilterValidationConfig.psd1" $Config = Import-PowerShellDataFile -Path $ConfigPath $Config.ContainsKey('/device/devices') | Should -Be $true } It 'Should have alert endpoint in config' { $ConfigPath = "$PSScriptRoot/../Private/LMFilterValidationConfig.psd1" $Config = Import-PowerShellDataFile -Path $ConfigPath $Config.ContainsKey('/alert/alerts') | Should -Be $true } It 'Should have device group endpoint in config' { $ConfigPath = "$PSScriptRoot/../Private/LMFilterValidationConfig.psd1" $Config = Import-PowerShellDataFile -Path $ConfigPath $Config.ContainsKey('/device/groups') | Should -Be $true } It 'Should have displayName in device fields' { $ConfigPath = "$PSScriptRoot/../Private/LMFilterValidationConfig.psd1" $Config = Import-PowerShellDataFile -Path $ConfigPath $Config['/device/devices'] | Should -Contain 'displayName' } It 'Should have severity in alert fields' { $ConfigPath = "$PSScriptRoot/../Private/LMFilterValidationConfig.psd1" $Config = Import-PowerShellDataFile -Path $ConfigPath $Config['/alert/alerts'] | Should -Contain 'severity' } } Context 'Multiple Endpoints' { It 'Should validate correctly for device endpoint' { { Format-LMFilter -Filter "displayName -eq 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } It 'Should validate correctly for alert endpoint' { { Format-LMFilter -Filter "severity -eq 'Error'" -ResourcePath "/alert/alerts" -ErrorAction Stop } | Should -Not -Throw } It 'Should validate correctly for device group endpoint' { { Format-LMFilter -Filter "fullPath -eq 'test'" -ResourcePath "/device/groups" -ErrorAction Stop } | Should -Not -Throw } It 'Should validate correctly for collector endpoint' { { Format-LMFilter -Filter "description -eq 'test'" -ResourcePath "/setting/collector/collectors" -ErrorAction Stop } | Should -Not -Throw } It 'Should validate correctly for dashboard endpoint' { { Format-LMFilter -Filter "name -eq 'test'" -ResourcePath "/dashboard/dashboards" -ErrorAction Stop } | Should -Not -Throw } } Context 'Special Cases' { It 'Should handle filters with quoted values containing special characters' { { Format-LMFilter -Filter "displayName -eq 'test-device.example.com'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } It 'Should handle filters with AND logical operator' { { Format-LMFilter -Filter "displayName -eq 'test' -and deviceType -eq '0'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } It 'Should handle filters with OR logical operator' { { Format-LMFilter -Filter "displayName -eq 'test' -or displayName -eq 'test2'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } It 'Should handle complex filters with multiple conditions' { { Format-LMFilter -Filter "displayName -eq 'test' -and deviceType -eq '0' -or name -eq 'test'" -ResourcePath "/device/devices" -ErrorAction Stop } | Should -Not -Throw } } } Describe 'Filter Validation Config Generator' { Context 'Build-LMFilterValidationConfig Script' { It 'Should exist in root directory' { "$PSScriptRoot/../Build-LMFilterValidationConfig.ps1" | Should -Exist } It 'Should be a valid PowerShell script' { $ScriptContent = Get-Content "$PSScriptRoot/../Build-LMFilterValidationConfig.ps1" -Raw { [scriptblock]::Create($ScriptContent) } | Should -Not -Throw } } Context 'Generated Config File' { It 'Should exist in Private directory' { "$PSScriptRoot/../Private/LMFilterValidationConfig.psd1" | Should -Exist } It 'Should be a valid PowerShell data file' { { Import-PowerShellDataFile "$PSScriptRoot/../Private/LMFilterValidationConfig.psd1" -ErrorAction Stop } | Should -Not -Throw } It 'Should contain hashtable structure' { $Config = Import-PowerShellDataFile "$PSScriptRoot/../Private/LMFilterValidationConfig.psd1" $Config | Should -BeOfType [hashtable] } It 'Should have multiple endpoints configured' { $Config = Import-PowerShellDataFile "$PSScriptRoot/../Private/LMFilterValidationConfig.psd1" $Config.Keys.Count | Should -BeGreaterThan 10 } It 'Should have arrays of field names for each endpoint' { $Config = Import-PowerShellDataFile "$PSScriptRoot/../Private/LMFilterValidationConfig.psd1" foreach ($endpoint in $Config.Keys) { # PowerShell data files with single items may be strings, so ensure it's an array $fields = @($Config[$endpoint]) $fields | Should -Not -BeNullOrEmpty $fields.Count | Should -BeGreaterThan 0 } } } } |