_TESTS/PSLocalBase.Issues31-32.Tests.ps1
|
$ErrorActionPreference='Stop' Import-Module (Join-Path (Split-Path $PSScriptRoot -Parent) 'PSLocalBase.psd1') -Force $script:passed=0; $script:failed=0 function Check([string]$Name,[scriptblock]$Body) { $db=New-LocalBase try { & $Body $db; $script:passed++; Write-Host "[PASS] $Name" } catch { $script:failed++; Write-Host "[FAIL] ${Name}: $($_.Exception.Message)" } finally {$db.close()} } function Seed($db) { foreach($n in 1..3) {$db.collection('a').doc("a$n").set(@{n=$n;profile=@{name="a$n"};flag=$true;items=@($n)})} foreach($n in 4..5) {$db.collection('b').doc("b$n").set(@{n=$n;profile=@{name="b$n"};flag=$false;items=@($n)})} } Check '#31 global pagination on both union operators' { param($db); Seed $db foreach($kind in @('union','unionAll')) { $q=if($kind -eq 'union') {$db.collection('a').union($db.collection('b'))}else{$db.collection('a').unionAll($db.collection('b'))} $page=$q.orderBy('n').skip(2).limit(2) if((@($page.get()).n -join ',') -ne '3,4' -or $page.count() -ne 2) {throw "$kind paged incorrect rows"} $projection=@($q.select('profile.name').get() | ForEach-Object {$_.'profile.name'} | Sort-Object) if(($projection -join ',') -ne 'a1,a2,a3,b4,b5') {throw "$kind lost nested values"} } } Check '#31 branch-local limits remain separate from global limits and clones' { param($db); Seed $db $left=$db.collection('a').orderBy('n','desc').skip(1).limit(1) $right=$db.collection('b').orderBy('n','desc').limit(1) $q=$left.unionAll($right) if((@($q.orderBy('n').get()).n -join ',') -ne '2,5' -or $q.count() -ne 2) {throw 'Branch-local paging lost or applied globally'} $page=$q.clone().orderBy('n','desc').skip(1).limit(1) if(@($page.get())[0].n -ne 2 -or $page.count() -ne 1 -or $q.count() -ne 2) {throw 'Global page changed branch plan or source'} $leftEmpty=$db.collection('a').limit(0).unionAll($db.collection('b')) if($leftEmpty.count() -ne 2) {throw 'LHS limit(0) became a global limit'} } Check '#31 branch projection preserves bool and array types' { param($db); Seed $db $q=$db.collection('a').select('n','flag','items').unionAll($db.collection('b').select('n','flag','items')) $rows=@($q.orderBy('n').get()) if($rows.Count -ne 5 -or $rows[0].flag -isnot [bool] -or $rows[4].flag -isnot [bool] -or @($rows[0].items).Count -ne 1) {throw 'Branch projection changed JSON types'} } Check '#31 filters after union target the complete result' { param($db); Seed $db $q=$db.collection('a').where('n','>',1).unionAll($db.collection('b')).where('n','>',4) if((@($q.get()).n -join ',') -ne '5' -or $q.count() -ne 1) {throw 'Composite filter did not cover both branches'} } Check '#32 complete NUL strings and Unicode match the PowerShell oracle' { param($db) $names=@('a',"a`0tail","`0a","a`0",'',"`0",'a_b','a%b','a*b','a?b','a\b',([string][char]233),([string][char]201)) for($i=0;$i -lt $names.Count;$i++) {$db.collection('patterns').doc("p$i").set(@{name=$names[$i]})} foreach($pattern in @('a',"a`0tail","*`0*","?`0*",'*','?',"`0",'a_b','a%*','a`*b','a\b',([string][char]201))) { foreach($op in @('-like','-notlike')) { $expected=@(for($i=0;$i -lt $names.Count;$i++) {if(($op -eq '-like' -and $names[$i] -like $pattern) -or ($op -eq '-notlike' -and $names[$i] -notlike $pattern)) {"p$i"}}) | Sort-Object $actual=@($db.collection('patterns').where('name',$op,$pattern).get(@{keys=$true})).key | Sort-Object if(($expected -join ',') -cne ($actual -join ',')) {throw "$op differed from PowerShell for pattern length=$($pattern.Length)"} } } } Check '#32 deletion preserves nonmatching NUL documents and exact equality' { param($db) $tail="a`0tail" $db.collection('items').doc('a').set(@{name='a'}) $db.collection('items').doc('tail').set(@{name=$tail}) if(@($db.collection('items').where('name','=',$tail).get()).Count -ne 1) {throw 'NUL equality fixture invalid'} $db.collection('items').where('name','-like','a').delete() if($db.collection('items').doc('tail').get().name -cne $tail -or $db.collection('items').count() -ne 1) {throw 'NUL document deleted or altered'} $db.collection('items').where('name','-notlike','a').delete() if($db.collection('items').count() -ne 0) {throw 'Negated match did not delete the intended NUL document'} $db.collection('numeric').doc('one').set(@{name='1';flag=$true}) $db.collection('numeric').doc('tail').set(@{name="1`0tail";flag=$false}) foreach($pattern in @(1,$true)) { if(@($db.collection('numeric').where('name','-like',$pattern).get()).Count -ne 1) {throw 'Typed pattern bypassed full-string matching'} } if(@($db.collection('numeric').where('flag','-like',$true).get()).Count -ne 1) {throw 'JSON boolean pattern normalization changed'} } Check '#32 SQL LIKE stays distinct and matcher survives GC on multiple connections' { param($db) $db.collection('items').doc('a').set(@{name='a_b'}) $db.collection('items').doc('b').set(@{name='aXb'}) if(@($db.collection('items').where('name','LIKE','a_b').get()).Count -ne 2) {throw 'SQL LIKE contract changed'} [GC]::Collect(); [GC]::WaitForPendingFinalizers() for($i=0;$i -lt 20;$i++) {if(@($db.collection('items').where('name','-like','a_b').get()).Count -ne 1) {throw 'Matcher changed after GC'} } $other=New-LocalBase try {$other.collection('items').doc('one').set(@{name="a`0b"}); if(@($other.collection('items').where('name','-like',"a`0b").get()).Count -ne 1) {throw 'Matcher missing on second connection'}} finally {$other.close()} } Write-Host "Issues31-32: passed=$script:passed; failed=$script:failed" if($script:failed -gt 0) {exit 1} |