param( [Parameter(Mandatory=$true)][string]$Executable, [Parameter(Mandatory=$true)][string]$OutputDirectory, [Parameter(Mandatory=$true)][string]$Account, [string]$ChatId='filehelper', [Parameter(Mandatory=$true)][long]$LocalId, [Parameter(Mandatory=$true)][int]$ExpectedCount ) $ErrorActionPreference='Stop' $exe=(Resolve-Path $Executable).Path if(Test-Path $OutputDirectory){throw 'Use a fresh evidence directory.'} $out=(New-Item -ItemType Directory $OutputDirectory).FullName $checks=New-Object System.Collections.Generic.List[object] function Check([string]$Name,[string[]]$Arguments,[int]$ExpectedExit=0){ $raw=(& $exe @Arguments 2> "$out\$Name.stderr.txt" | Out-String) $code=$LASTEXITCODE $raw | Set-Content "$out\$Name.json" -Encoding UTF8 $checks.Add(@{Stage=$Name;ExitCode=$code;ExpectedExit=$ExpectedExit}) if($code -ne $ExpectedExit){throw "$Name returned unexpected exit code."} return ($raw | ConvertFrom-Json) } try { $default=Check 'merged-default' @('db','merged','--account',$Account,'--chat',$ChatId,'--local-id',"$LocalId",'--timeout','60') if($default.record.count -ne $ExpectedCount){throw 'Unexpected record count.'} if($null -ne $default.record.title -or $null -ne $default.record.description -or @($default.record.messages | Where-Object {$null -ne $_.text -or $null -ne $_.senderName}).Count){throw 'Default output leaked record content.'} $full=Check 'merged-content.private' @('db','merged','--account',$Account,'--chat',$ChatId,'--local-id',"$LocalId",'--include-content','--timeout','60') if($full.record.count -ne $ExpectedCount -or $full.parent.LocalId -ne $LocalId){throw 'Selected record mismatch.'} if(@($full.record.messages | Where-Object {$_.dataType -ne 1 -or $null -eq $_.text -or !$_.senderName -or !$_.timestamp -or !$_.sourceServerId}).Count){throw 'Expected complete text-message metadata in this fixture.'} if(@($full.record.messages.path | Select-Object -Unique).Count -ne $ExpectedCount){throw 'Message paths are not unique.'} $metadata=Check 'database-readonly' @('db','query','--account',$Account,'--database',$full.database,'--timeout','60') if(!$metadata.metadata.WritesRejected){throw 'Database is not reported read-only.'} $invalid=Check 'invalid-id' @('db','merged','--account',$Account,'--chat',$ChatId,'--local-id','0','--timeout','30') 1 if($invalid.error -ne 'InvalidArgument'){throw 'Wrong invalid-ID error.'} $missing=Check 'missing-id' @('db','merged','--account',$Account,'--chat',$ChatId,'--local-id','9223372036854775807','--timeout','60') 1 if($missing.error -ne 'ControlNotFound'){throw 'Wrong missing-ID error.'} } catch { @{Message=$_.Exception.Message;Line=$_.InvocationInfo.ScriptLineNumber} | ConvertTo-Json | Set-Content "$out\error.json" -Encoding UTF8 } finally { $success=($checks.Count -eq 5 -and @($checks | Where-Object {$_.ExitCode -ne $_.ExpectedExit}).Count -eq 0 -and !(Test-Path "$out\error.json")) @{Success=$success;Checks=@($checks.ToArray());ProcessSessionId=[Diagnostics.Process]::GetCurrentProcess().SessionId;RecordCount=$ExpectedCount;SendsAttempted=0;BinarySha256=(Get-FileHash $exe -Algorithm SHA256).Hash} | ConvertTo-Json -Depth 6 | Set-Content "$out\summary.json" -Encoding UTF8 } if(!$success){exit 1}