_TESTS/PSLocalBase.Revalidation-3ecc2c1.Tests.ps1
|
# Restored independent review regressions for commit 3ecc2c1. # In-memory databases only. Failures describe unresolved review findings. $ErrorActionPreference = 'Stop' Import-Module (Join-Path (Split-Path $PSScriptRoot -Parent) 'PSLocalBase.psd1') -Force $script:passed = 0 $script:failed = 0 function Check-Review([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() } } Check-Review 'V01 - dropIndex respects JSON field casing' { param($db) [void]$db.collection('users').createIndex('email') [void]$db.collection('users').createIndex('Email', @{ unique = $true }) [void]$db.collection('users').add(@{ Email = 'same' }, 'u1') [void]$db.collection('users').dropIndex('email') $blocked = $false try { [void]$db.collection('users').add(@{ Email = 'same' }, 'u2') } catch [System.InvalidOperationException] { $blocked = $true } $indexes = $db.query("SELECT name FROM sqlite_master WHERE type='index' AND name LIKE 'idx_%';") if (-not $blocked -or $indexes.Count -ne 1) { throw "Email UNIQUE lost: blocked=$blocked indexes=$($indexes.Count)" } } Check-Review 'V02 - old hash32 compatibility verifies the indexed expression' { param($db) $p1 = 'a.a_a_a_a_a_a_a_a.a.a.a.a.a_a.a_a_a.a' $p2 = 'a_a.a.a.a_a.a_a.a.a.a_a_a.a.a.a_a.a_a' $clean = $p1.Replace('.', '_') $oldName = "idx_users__${clean}_43CEB4E2" [void]$db.collection('users').create() [void]$db.query("CREATE UNIQUE INDEX ""$oldName"" ON users(json_extract(doc,'`$.$p1'));") [void]$db.collection('users').createIndex($p2, @{ unique = $true }) $insert = 'INSERT INTO users(key,doc) VALUES(?,json_set(''{}'',?,?,?,?));' [void]$db.query($insert, @('u1', "`$.$p1", 'one', "`$.$p2", 'same')) $blocked = $false try { [void]$db.query($insert, @('u2', "`$.$p1", 'two', "`$.$p2", 'same')) } catch [System.InvalidOperationException] { $blocked = $true } $indexes = $db.query("SELECT name FROM sqlite_master WHERE type='index' AND name LIKE 'idx_%';") if (-not $blocked -or $indexes.Count -ne 2) { throw "Second UNIQUE missing: blocked=$blocked indexes=$($indexes.Count)" } } Check-Review 'V03 - Decimal 1 preserves a distinct adjacent Double' { param($db) $next = [double]::Parse('1.0000000000000002', [Globalization.CultureInfo]::InvariantCulture) $db.collection('items').doc('one').set(@{ values = @($next) }) $db.collection('items').doc('one').update(@{ values = [PSLocalBase]::ArrayRemove([decimal]1) }) $actual = @($db.collection('items').doc('one').get().values) if ($actual.Count -ne 1 -or [double]$actual[0] -ne $next) { throw "Distinct value removed: count=$($actual.Count)" } } Check-Review 'V04 - sum honors union or explicitly rejects it' { param($db) $db.collection('a').doc('one').set(@{ n = 10 }) $db.collection('b').doc('two').set(@{ n = 20 }) try { $actual = $db.collection('a').union($db.collection('b')).sum('n') } catch [System.InvalidOperationException] { if ($_.Exception.Message -match 'composite|union|aggregate') { return }; throw } if ($actual -ne 30) { throw "Union sum=$actual instead of 30" } } Check-Review 'V05 - sum honors pagination or explicitly rejects it' { param($db) $db.collection('a').doc('one').set(@{ n = 10 }) $db.collection('a').doc('two').set(@{ n = 20 }) try { $actual = $db.collection('a').orderBy('n').limit(1).sum('n') } catch [System.InvalidOperationException] { if ($_.Exception.Message -match 'limit|pagination|aggregate') { return }; throw } if ($actual -ne 10) { throw "Paged sum=$actual instead of 10" } } Check-Review 'V06 - composite createIndex rejects before schema mutation' { param($db) $db.collection('a').doc('one').set(@{ n = 10 }) [void]$db.collection('b').create() $blocked = $false try { [void]$db.collection('a').union($db.collection('b')).createIndex('n') } catch [System.InvalidOperationException] { $blocked = $_.Exception.Message -match 'composite|union' } $indexes = $db.query("SELECT name FROM sqlite_master WHERE type='index' AND name LIKE 'idx_%';") if (-not $blocked -or $indexes.Count -ne 0) { throw "Rejected=$blocked indexes=$($indexes.Count)" } } Check-Review 'V07 - group upsert rejects before creating wildcard schema' { param($db) $db.collection('audit_a').doc('one').set(@{ n = 1 }) $blocked = $false try { [void]$db.collectionGroup('audit_*').upsert(@{ n = 2 }, 'new') } catch [System.InvalidOperationException] { $blocked = $_.Exception.Message -match 'composite|collectionGroup' } if (-not $blocked -or $db.collectionExists('audit_*')) { throw "Rejected=$blocked wildcard table=$($db.collectionExists('audit_*'))" } } Check-Review 'V08 - populated right branch is preserved or rejected' { param($db) $db.collection('customers').doc('c').set(@{ name = 'Alice' }) $db.collection('orders').doc('o').set(@{ customer = 'c' }) $db.collection('archive').doc('a').set(@{ customer = 'c' }) foreach ($method in @('union', 'unionAll')) { $blocked = $false try { $rows = @($db.collection('orders').$method($db.collection('archive').populate('customer', 'customers')).get()) } catch [System.InvalidOperationException] { $blocked = $_.Exception.Message -match 'populate.*not supported' } if (-not $blocked) { $populated = @($rows | Where-Object { $_.customer -isnot [string] -and $_.customer.name -eq 'Alice' }) if ($populated.Count -ne 1) { throw "$method discarded right-branch population" } } } } Check-Review 'V09 - documented bare delete retains table and indexes' { param($db) [void]$db.collection('users').createIndex('name', @{ unique = $true }) $db.collection('users').doc('u1').set(@{ name = 'Alice' }) $before = $db.query("SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='users';").name -join ',' $db.collection('users').delete() $after = $db.query("SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='users';").name -join ',' if (-not $db.collectionExists('users') -or $before -cne $after) { throw 'Bare delete dropped table/indexes despite SECURITY truncate claim' } } Check-Review 'C01 - failed UNIQUE upgrade preserves schema and outer transaction' { param($db) [void]$db.collection('users').createIndex('email') [void]$db.collection('users').add(@{ email = 'same' }, 'u1') [void]$db.collection('users').add(@{ email = 'same' }, 'u2') $before = $db.query("SELECT name FROM sqlite_master WHERE type='index' AND name LIKE 'idx_%';").name -join ',' $db.beginTransaction() $db.collection('other').doc('one').set(@{ n = 1 }) $blocked = $false try { [void]$db.collection('users').createIndex('email', @{ unique = $true }) } catch [System.InvalidOperationException] { $blocked = $true } $after = $db.query("SELECT name FROM sqlite_master WHERE type='index' AND name LIKE 'idx_%';").name -join ',' if (-not $blocked -or $before -cne $after -or -not $db.InTransaction) { throw 'Schema/transaction changed after failed upgrade' } $db.rollback() if ($db.collectionExists('other')) { throw 'Outer rollback failed' } } Check-Review 'C02 - explicit BLOB rejection leaves connection usable' { param($db) foreach ($sql in @("SELECT X'0041FF80' AS value;", "SELECT X'' AS value;")) { $blocked = $false try { [void]$db.query($sql) } catch [System.NotSupportedException] { $blocked = $true } if (-not $blocked -or $db.query('SELECT 1 AS n;')[0].n -ne 1) { throw 'BLOB or later query contract failed' } } } Write-Host "Revalidation 3ecc2c1: passed=$script:passed; failed=$script:failed" if ($script:failed -gt 0) { exit 1 } |