Tests/Find-Jev.Tests.ps1
|
BeforeAll { Import-Module (Join-Path $PSScriptRoot '..' 'Jev.psd1') -Force } AfterAll { Remove-Module Jev -Force -ErrorAction SilentlyContinue } Describe 'Find-Jev comparative search' { BeforeEach { Mock -ModuleName Jev Invoke-JevDecision { param($State, $Questions) $State | Should -Be 'Which entry explains the failure?' $Questions.Count | Should -Be 1 $Questions.match.type | Should -Be 'choice' $Questions.match.criteria['none'] | Should -Not -BeNullOrEmpty [pscustomobject]@{ answers = [ordered]@{ match = [pscustomobject]@{ type = 'choice'; choice = 'candidate002' } } } } } It 'compares all strings in one request and returns the exact selected line' { $lines = @('Process started.', 'Payment key expired.', 'Checkout failed.') $results = @($lines | Find-Jev 'Which entry explains the failure?') $results.Count | Should -Be 1 $results[0] | Should -Be 'Payment key expired.' $results[0] | Should -BeOfType [string] Should -Invoke Invoke-JevDecision -ModuleName Jev -Exactly 1 -Scope It -ParameterFilter { $Questions.match.criteria.Count -eq 4 -and $Questions.match.criteria['candidate001'] -eq 'Process started.' -and $Questions.match.criteria['candidate002'] -eq 'Payment key expired.' -and $Questions.match.criteria['candidate003'] -eq 'Checkout failed.' } } It 'returns nothing when Jev selects none fits' { Mock -ModuleName Jev Invoke-JevDecision { [pscustomobject]@{ answers = @{ match = @{ choice = 'none' } } } } $results = @(@('Healthy.', 'No errors.') | Find-Jev 'Which entry explains the failure?') $results.Count | Should -Be 0 Should -Invoke Invoke-JevDecision -ModuleName Jev -Exactly 1 -Scope It } It 'serializes object candidates but returns the original object without changes' { $first = [pscustomobject]@{ Id = 1; Message = 'Process started.' } $second = [pscustomobject]@{ Id = 2; Message = 'Payment key expired.'; match = 'Existing value' } $results = @(@($first, $second) | Find-Jev 'Which entry explains the failure?') $results.Count | Should -Be 1 [object]::ReferenceEquals($results[0], $second) | Should -BeTrue $second.match | Should -Be 'Existing value' @($second.PSObject.Properties.Name) | Should -Be @('Id', 'Message', 'match') Should -Invoke Invoke-JevDecision -ModuleName Jev -Exactly 1 -Scope It -ParameterFilter { ($Questions.match.criteria['candidate002'] | ConvertFrom-Json).Message -eq 'Payment key expired.' } } It 'preserves dictionary and dotnet object identity and accepts dictionary responses' { $dictionary = [ordered]@{ Id = 1; Message = 'Payment key expired.' } $version = [version] '2.8.0' Mock -ModuleName Jev Invoke-JevDecision { @{ answers = @{ match = @{ choice = 'candidate001' } } } } $dictionaryResult = @(@($dictionary, $version) | Find-Jev 'Which entry explains the failure?') [object]::ReferenceEquals($dictionaryResult[0], $dictionary) | Should -BeTrue Mock -ModuleName Jev Invoke-JevDecision { @{ answers = @{ match = @{ choice = 'candidate002' } } } } $versionResult = @(@($dictionary, $version) | Find-Jev 'Which entry explains the failure?') [object]::ReferenceEquals($versionResult[0], $version) | Should -BeTrue $versionResult[0] | Should -BeOfType [version] } It 'keeps identical candidates separate and returns the selected original' { $first = [pscustomobject]@{ Message = 'Same text.' } $second = [pscustomobject]@{ Message = 'Same text.' } $results = @(@($first, $second) | Find-Jev 'Which entry explains the failure?') [object]::ReferenceEquals($results[0], $second) | Should -BeTrue Should -Invoke Invoke-JevDecision -ModuleName Jev -Exactly 1 -Scope It -ParameterFilter { $Questions.match.criteria.Count -eq 3 } } It 'accepts a single named candidate and preserves a named array as one candidate' { Mock -ModuleName Jev Invoke-JevDecision { param($State, $Questions) $Questions.match.criteria.Count | Should -Be 2 ($Questions.match.criteria['candidate001'] | ConvertFrom-Json).Count | Should -Be 2 [pscustomobject]@{ answers = @{ match = @{ choice = 'candidate001' } } } } $candidate = @('First field.', 'Second field.') $results = @(Find-Jev -State $candidate 'Which entry explains the failure?') $results.Count | Should -Be 1 [object]::ReferenceEquals($results[0], $candidate) | Should -BeTrue ($results[0] -is [object[]]) | Should -BeTrue Should -Invoke Invoke-JevDecision -ModuleName Jev -Exactly 1 -Scope It } It 'evaluates a single piped candidate rather than automatically returning it' { Mock -ModuleName Jev Invoke-JevDecision { param($State, $Questions) $Questions.match.criteria.Count | Should -Be 2 [pscustomobject]@{ answers = @{ match = @{ choice = 'none' } } } } @('Healthy.' | Find-Jev 'Which entry explains the failure?').Count | Should -Be 0 Should -Invoke Invoke-JevDecision -ModuleName Jev -Exactly 1 -Scope It } It 'makes no request for empty input' { @(@() | Find-Jev 'Which entry explains the failure?').Count | Should -Be 0 Should -Invoke Invoke-JevDecision -ModuleName Jev -Exactly 0 -Scope It } It 'accepts 254 candidates plus the none choice in one request' { $results = @(1..254 | Find-Jev 'Which entry explains the failure?') $results | Should -Be @(2) $results[0] | Should -BeOfType [int] Should -Invoke Invoke-JevDecision -ModuleName Jev -Exactly 1 -Scope It -ParameterFilter { $Questions.match.criteria.Count -eq 255 } } It 'rejects 255 candidates before making a request' { { 1..255 | Find-Jev 'Which entry explains the failure?' } | Should -Throw '*at most 254*' Should -Invoke Invoke-JevDecision -ModuleName Jev -Exactly 0 -Scope It } It 'rejects an unknown selection rather than silently returning no match' { Mock -ModuleName Jev Invoke-JevDecision { [pscustomobject]@{ answers = @{ match = @{ choice = 'candidate999' } } } } { @('First.', 'Second.') | Find-Jev 'Which entry explains the failure?' } | Should -Throw '*unknown candidate*' } It 'rejects a missing answer: <Case>' -TestCases @( @{ Case = 'answers'; Response = [pscustomobject]@{ model = 'test' } } @{ Case = 'match'; Response = [pscustomobject]@{ answers = @{} } } @{ Case = 'choice'; Response = [pscustomobject]@{ answers = @{ match = @{ confidence = 0.9 } } } } @{ Case = 'null choice'; Response = [pscustomobject]@{ answers = @{ match = @{ choice = $null } } } } ) { param($Case, $Response) Mock -ModuleName Jev Invoke-JevDecision { $Response } { @('First.', 'Second.') | Find-Jev 'Which entry explains the failure?' } | Should -Throw '*Jev did not return*' } It 'propagates request failures and emits no selected candidate' { Mock -ModuleName Jev Invoke-JevDecision { throw 'API unavailable.' } $emitted = [System.Collections.Generic.List[object]]::new() { @('First.', 'Second.') | Find-Jev 'Which entry explains the failure?' | ForEach-Object { $emitted.Add($_) } } | Should -Throw '*API unavailable*' $emitted.Count | Should -Be 0 } } |