_TESTS/PSLocalBase.Independent-c57b52c.Tests.ps1
|
# Independent evidence for the review of commit c57b52c. # Does not modify the engine or the existing test suites. In-memory databases only. $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() } } Check 'A01 - removing 1.0 must preserve its distinct adjacent Double' { param($db) $next = [double]::Parse('1.0000000000000002', [Globalization.CultureInfo]::InvariantCulture) $db.collection('numbers').doc('n').set(@{ values = @([double]1.0, $next) }) $before = $db.collection('numbers').doc('n').get() if (@($before.values).Count -ne 2 -or $before.values[0] -eq $before.values[1]) { throw 'Fixture did not preserve distinct doubles.' } $db.collection('numbers').doc('n').update(@{ values = [PSLocalBase]::ArrayRemove([double]1.0) }) $after = @($db.collection('numbers').doc('n').get().values) # PS 5.1 may deserialize the fractional JSON number as Decimal. Normalize # the assertion to Double instead of invoking asymmetric PS -eq coercion. if ($after.Count -ne 1 -or [double]$after[0] -ne $next) { throw "Expected one adjacent Double; remaining count=$($after.Count)." } } Check 'A02 - equality of exactly equal Int64 and Double at 2^53' { param($db) $db.collection('numbers').doc('n').set(@{ values = @([long]9007199254740992) }) $db.collection('numbers').doc('n').update(@{ values = [PSLocalBase]::ArrayRemove([double]9007199254740992) }) $after = @($db.collection('numbers').doc('n').get().values) if ($after.Count -ne 0) { throw "Equal numeric member was retained: $($after -join ',')." } } Check 'A03 - literal dotted and underscore legacy fields must remain independent' { param($db) [void]$db.collection('users').create() [void]$db.query('CREATE UNIQUE INDEX idx_users_profile_code ON users(json_extract(doc, ''$.profile_code''));') $db.collection('users').doc('u1').set(@{ profile_code = 'unique'; profile = @{ code = 'x' } }) [void]$db.collection('users').dropIndex('profile.code') $blocked = $false try { [void]$db.collection('users').add(@{ profile_code = 'unique' }, 'u2') } catch [System.InvalidOperationException] { $blocked = $true } if (-not $blocked) { throw 'An index for another JSON path was dropped; duplicate accepted.' } } Check 'A04 - numeric filter data must obey the documented debug privacy guarantee' { param($db) $db.collection('users').doc('u1').set(@{ pin = 735291 }) $db.config['debug'] = $true try { $captured = & { [void]$db.collection('users').where('pin', '=', 735291).get() } 6>&1 } finally { $db.config['debug'] = $false } if (($captured | Out-String) -match '735291') { throw 'Numeric filter value appeared in diagnostic output.' } } Check 'A05 - unsupported composite insert must reject before schema changes' { param($db) $db.collection('audit_a').doc('a').set(@{ value = 1 }) $rejected = $false try { [void]$db.collectionGroup('audit_*').add(@{ value = 2 }, 'new') } catch [System.InvalidOperationException] { $rejected = $true } if (-not $rejected -or $db.collectionExists('audit_*')) { throw "Rejected=$rejected; literal wildcard table exists=$($db.collectionExists('audit_*'))." } } Check 'C01 - matched unusual index name is dropped without interpreting its contents' { param($db) [void]$db.collection('users').create() $db.collection('victim').doc('v1').set(@{ value = 'keep' }) $hasher = [Security.Cryptography.SHA256]::Create() try { $hash = [BitConverter]::ToString($hasher.ComputeHash([Text.Encoding]::UTF8.GetBytes('users:email'))).Replace('-', '').Substring(0, 8) } finally { $hasher.Dispose() } # The suffix deliberately matches the current selector, unlike the old R03 fixture. $indexName = 'fixture"__email_probe]; DROP TABLE victim; --__email_' + $hash $quotedName = $indexName.Replace('"', '""') [void]$db.query("CREATE INDEX ""$quotedName"" ON users(key);") [void]$db.collection('users').dropIndex('email') $remaining = $db.query('SELECT name FROM sqlite_master WHERE type=''index'' AND name=?;', @($indexName)) if ($remaining.Count -ne 0) { throw 'Fixture was not selected: identifier quoting was not exercised.' } if (-not $db.collectionExists('victim') -or $db.collection('victim').doc('v1').get().value -cne 'keep') { throw 'Schema identifier was interpreted as SQL.' } } Check 'C02 - rejected composite writes must actually throw and retain all source documents' { param($db) $db.collection('a').doc('one').set(@{ value = 1 }) $db.collection('a').doc('two').set(@{ value = 2 }) [void]$db.collection('b').create() foreach ($operation in @('set', 'delete')) { $rejected = $false $query = $db.collection('a').doc('one').union($db.collection('b')) try { if ($operation -eq 'set') { $query.set(@(@{ value = 3 })) } else { $query.delete() } } catch [System.InvalidOperationException] { $rejected = $true } if (-not $rejected -or $db.collection('a').count() -ne 2 -or $db.collection('a').doc('one').get().value -ne 1) { throw "$operation was not rejected before mutation." } } } Write-Host "Independent c57b52c checks: passed=$script:passed; failed=$script:failed" if ($script:failed -gt 0) { exit 1 } |