Wait for actual native board UI before fixture assertions
This commit is contained in:
@@ -64,14 +64,46 @@ function FixtureState($Board,[string]$Type,[int]$Stage){
|
||||
if($Type-eq'free'){$state.latestFreePlay=Clone $Board}else{$state.puzzleStates=@($state.puzzleStates|Where-Object stageId -ne $Stage)+@(Clone $Board)}
|
||||
return $state
|
||||
}
|
||||
function BoardScreen([string]$Path){
|
||||
Add-Type -AssemblyName System.Drawing;$image=[Drawing.Bitmap]::new($Path)
|
||||
$pixels=[Collections.Generic.List[object]]::new();$gold=0;$world=0
|
||||
try{
|
||||
if($image.Width-eq2400-and$image.Height-eq1080){
|
||||
foreach($point in @(@(80,70),@(380,70),@(80,140),@(380,140))){
|
||||
$pixel=$image.GetPixel($point[0],$point[1]);$pixels.Add(@{x=$point[0];y=$point[1];r=$pixel.R;g=$pixel.G;b=$pixel.B})
|
||||
if($pixel.R-ge230-and$pixel.G-ge185-and$pixel.G-le210-and$pixel.B-ge60-and$pixel.B-le90){$gold++}
|
||||
}
|
||||
foreach($x in @(600,1200,1800)){foreach($y in @(300,500,700)){
|
||||
$pixel=$image.GetPixel($x,$y);$pixels.Add(@{x=$x;y=$y;r=$pixel.R;g=$pixel.G;b=$pixel.B})
|
||||
if($pixel.R-gt20-or$pixel.G-gt20-or$pixel.B-gt20){$world++}
|
||||
}}
|
||||
}
|
||||
return @{ready=$gold-eq4-and$world-ge3;width=$image.Width;height=$image.Height;goldCorners=$gold;nonblackWorldSamples=$world;pixels=$pixels.ToArray()}
|
||||
}finally{$image.Dispose()}
|
||||
}
|
||||
function WaitBoard([string]$Name){
|
||||
$observations=[Collections.Generic.List[object]]::new();$ready=$false;$state=$null
|
||||
try{
|
||||
for($attempt=0;$attempt-lt30;$attempt++){
|
||||
$stepName="$Name-board-ready-$attempt";Step $stepName @() 500
|
||||
$png=Join-Path $EvidenceDir "$stepName.png";$screen=BoardScreen $png
|
||||
$state=Save "$stepName-save";$savePath=Join-Path $EvidenceDir "$stepName-save.json"
|
||||
$observations.Add(@{attempt=$attempt;utc=[DateTime]::UtcNow.ToString('o');png=$png;pngSha256=(Get-FileHash -LiteralPath $png).Hash;screen=$screen;save=$savePath;saveSha256=(Get-FileHash -LiteralPath $savePath).Hash})
|
||||
if($screen.ready){$ready=$true;break}
|
||||
}
|
||||
Check "$Name-board-ui-ready" $ready 'Actual 2400x1080 board: four golden Home-button corners and nonblack world samples; unchanged pulled save alone is never entry proof; at most 30 observations at 500ms intervals'
|
||||
Copy-Item -LiteralPath $observations[-1].save -Destination (Join-Path $EvidenceDir "$Name-entered.json")
|
||||
return $state
|
||||
}finally{@{ready=$ready;finishedUtc=[DateTime]::UtcNow.ToString('o');observations=$observations.ToArray()}|ConvertTo-Json -Depth 8|Set-Content -LiteralPath (Join-Path $EvidenceDir "$Name-board-readiness.json") -Encoding utf8}
|
||||
}
|
||||
function LoadFixture([string]$Name,$State,[string]$Type,[int]$Stage){
|
||||
Adb @('shell','am','force-stop',$package)|Out-Null
|
||||
$path=Join-Path $EvidenceDir "$Name-injected.json";$State|ConvertTo-Json -Depth 20|Set-Content -LiteralPath $path -Encoding utf8
|
||||
@{name=$Name;origin='Actual Fresh30/thirty-completed.json; explicitly labelled injected boundary case';originalFile=$originalPath;originalSha256=(Get-FileHash -LiteralPath $originalPath).Hash;fixtureSha256=(Get-FileHash -LiteralPath $path).Hash;changedFields=@('puzzleStates','latestFreePlay');preservedFields=@('schemaVersion','completedStageIds','seenTutorialIds');utc=[DateTime]::UtcNow.ToString('o')}|ConvertTo-Json -Depth 5|Set-Content -LiteralPath (Join-Path $EvidenceDir "$Name-origin.json")
|
||||
Adb @('push',$path,$remote)|Out-Null;Adb @('push',$path,($remote+'.bak'))|Out-Null
|
||||
StartHome "$Name-home"
|
||||
if($Type-eq'free'){Step "$Name-enter-free" @('shell','input','tap','1200','810') 1500}else{SelectStage "$Name-enter-puzzle" $Stage}
|
||||
return Save "$Name-entered"
|
||||
if($Type-eq'free'){Step "$Name-enter-free" @('shell','input','tap','1200','810') 0}else{SelectStage "$Name-enter-puzzle" $Stage}
|
||||
return WaitBoard $Name
|
||||
}
|
||||
function PreservesOtherSlots([string]$Name,$Before,$After,[string]$Type,[int]$Stage){
|
||||
Check "$Name-progress-preserved" ((Same $Before.completedStageIds $After.completedStageIds)-and(Same $Before.seenTutorialIds $After.seenTutorialIds)-and$After.schemaVersion-eq1) 'Completion/unlock/tutorial/schema unchanged'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
param([Parameter(Mandatory)][string]$EvidenceDir,[string]$FinalSource=(Join-Path $PSScriptRoot 'exercise-final.ps1'),[string]$PlaygroundSource=(Join-Path $PSScriptRoot 'exercise-playground.ps1'),[string]$PreservationFixtureDir)
|
||||
param([Parameter(Mandatory)][string]$EvidenceDir,[string]$FinalSource=(Join-Path $PSScriptRoot 'exercise-final.ps1'),[string]$PlaygroundSource=(Join-Path $PSScriptRoot 'exercise-playground.ps1'),[string]$PreservationFixtureDir,[string]$BoardReadyPng,[string]$HomePng)
|
||||
$ErrorActionPreference='Stop'
|
||||
New-Item -ItemType Directory -Path $EvidenceDir -Force|Out-Null
|
||||
$checks=[Collections.Generic.List[object]]::new()
|
||||
@@ -128,6 +128,64 @@ exit ([int]$env:PLAYGROUND_CONTROL_TOUCH_EXIT)
|
||||
$friends=@(BlueFriends $path);$expectedCount=if($kind-eq'two-blue-friends'){2}else{0}
|
||||
Probe "actual-live-steering-vision-$kind" ($friends.Count-eq$expectedCount) @{friends=$friends;expectedCount=$expectedCount;scope='Synthetic semantic control, not native screenshot verdict'}
|
||||
}
|
||||
$boardReader=$gestureAst.Find({param($node)$node-is[Management.Automation.Language.FunctionDefinitionAst]-and$node.Name-eq'BoardScreen'},$true)
|
||||
$boardWait=$gestureAst.Find({param($node)$node-is[Management.Automation.Language.FunctionDefinitionAst]-and$node.Name-eq'WaitBoard'},$true)
|
||||
Probe 'actual-board-readiness-functions-present' ($null-ne$boardReader-and$null-ne$boardWait) 'Actual suite screen predicate and bounded wait'
|
||||
if($boardReader-and$boardWait){
|
||||
. ([scriptblock]::Create($boardReader.Extent.Text));. ([scriptblock]::Create($boardWait.Extent.Text))
|
||||
foreach($kind in @('board','home','black','black-with-ui','partial-ui','wrong-size')){
|
||||
$width=if($kind-eq'wrong-size'){1200}else{2400};$height=if($kind-eq'wrong-size'){540}else{1080}
|
||||
$bitmap=[Drawing.Bitmap]::new($width,$height);$graphics=[Drawing.Graphics]::FromImage($bitmap)
|
||||
try{
|
||||
$background=if($kind-in@('black','black-with-ui')){[Drawing.Color]::Black}else{[Drawing.Color]::FromArgb(147,211,223)}
|
||||
$graphics.Clear($background)
|
||||
if($kind-in@('board','black-with-ui','partial-ui','wrong-size')){
|
||||
$brush=[Drawing.SolidBrush]::new([Drawing.Color]::FromArgb(245,196,72))
|
||||
try{$graphics.FillRectangle($brush,58,59,$(if($kind-eq'partial-ui'){100}else{365}),99)}finally{$brush.Dispose()}
|
||||
}
|
||||
$path=Join-Path $EvidenceDir "readiness-$kind.png";$bitmap.Save($path,[Drawing.Imaging.ImageFormat]::Png)
|
||||
}finally{$graphics.Dispose();$bitmap.Dispose()}
|
||||
$screen=BoardScreen $path
|
||||
Probe "actual-board-screen-$kind" ($screen.ready-eq($kind-eq'board')) $screen
|
||||
}
|
||||
if($BoardReadyPng-and$HomePng){
|
||||
foreach($control in @(@{name='actual-free';path=$BoardReadyPng;expected=$true},@{name='actual-home';path=$HomePng;expected=$false})){
|
||||
$screen=BoardScreen $control.path
|
||||
Probe "actual-board-screen-$($control.name)" ($screen.ready-eq$control.expected) @{path=$control.path;sha256=(Get-FileHash -LiteralPath $control.path).Hash;screen=$screen;scope='Actual captured PNG replay; no live native readiness claim'}
|
||||
}
|
||||
}
|
||||
}
|
||||
# Execute the actual LoadFixture path with capture/save transport doubles only; no ADB.
|
||||
$load=$gestureAst.Find({param($node)$node-is[Management.Automation.Language.FunctionDefinitionAst]-and$node.Name-eq'LoadFixture'},$true)
|
||||
. ([scriptblock]::Create($load.Extent.Text))
|
||||
function Adb([string[]]$Arguments){}
|
||||
function StartHome([string]$Name){}
|
||||
function SelectStage([string]$Name,[int]$Stage){Step "$Name-stage" @() 0}
|
||||
function Step([string]$Name,[string[]]$Arguments=@(),[int]$Delay=500){
|
||||
$controlSteps.Add(@{name=$Name;delay=$Delay})
|
||||
if($Name-like'*-board-ready-*'){
|
||||
$capture=if($controlHomeOnly-or$controlAttempt-eq0){$controlHome}else{$controlBoard}
|
||||
Copy-Item -LiteralPath $capture -Destination (Join-Path $EvidenceDir "$Name.png")
|
||||
$script:controlAttempt++
|
||||
}
|
||||
}
|
||||
function Save([string]$Name){Copy-Item -LiteralPath $originalPath -Destination (Join-Path $EvidenceDir "$Name.json");return Clone $original}
|
||||
$originalPath=Join-Path $EvidenceDir 'readiness-original.json'
|
||||
if($PreservationFixtureDir){Copy-Item -LiteralPath (Join-Path $PreservationFixtureDir 'safe-free-injected.json') -Destination $originalPath;$original=Get-Content -LiteralPath $originalPath -Raw|ConvertFrom-Json}else{$original|ConvertTo-Json -Depth 20|Set-Content -LiteralPath $originalPath}
|
||||
$originalHash=(Get-FileHash -LiteralPath $originalPath).Hash
|
||||
$controlBoard=if($BoardReadyPng){$BoardReadyPng}else{Join-Path $EvidenceDir 'readiness-board.png'}
|
||||
$controlHome=if($HomePng){$HomePng}else{Join-Path $EvidenceDir 'readiness-home.png'}
|
||||
foreach($type in @('free','puzzle')){foreach($controlHomeOnly in @($false,$true)){
|
||||
$script:controlAttempt=0;$controlSteps=[Collections.Generic.List[object]]::new();$accepted=$false;$message=$null
|
||||
$label="readiness-$type-$(if($controlHomeOnly){'timeout'}else{'home-to-board'})"
|
||||
try{$loaded=LoadFixture $label $original $type 1;$accepted=$true}catch{$message=$_.Exception.Message}
|
||||
$polls=@($controlSteps|Where-Object name -like '*-board-ready-*')
|
||||
$reportPath=Join-Path $EvidenceDir "$label-board-readiness.json";$report=if(Test-Path -LiteralPath $reportPath){Get-Content -LiteralPath $reportPath -Raw|ConvertFrom-Json}else{$null}
|
||||
$expectedPolls=if($controlHomeOnly){30}else{2}
|
||||
Probe "actual-entry-$type-$(if($controlHomeOnly){'home-timeout-rejects-unchanged-save'}else{'waits-for-ui-despite-unchanged-save'})" ($accepted-eq!$controlHomeOnly-and$polls.Count-eq$expectedPolls-and@($polls|Where-Object delay -ne 500).Count-eq0-and$report.observations.Count-eq$expectedPolls-and$report.ready-eq!$controlHomeOnly) @{accepted=$accepted;polls=$polls.Count;observations=$report.observations.Count;error=$message;scope='Actual suite LoadFixture/WaitBoard, transport doubles replay actual PNGs and unchanged JSON; no native run'}
|
||||
$enteredPath=Join-Path $EvidenceDir "$label-entered.json"
|
||||
Probe "actual-entry-$type-$(if($controlHomeOnly){'timeout'}else{'ready'})-raw-save-preserved" ($report.observations.Count-eq$expectedPolls-and@($report.observations|Where-Object saveSha256 -ne $originalHash).Count-eq0-and$(if($accepted){(Get-FileHash -LiteralPath $enteredPath).Hash-eq$originalHash-and(Same $loaded $original)}else{!(Test-Path -LiteralPath $enteredPath)})) @{original=$originalPath;sha256=$originalHash;observations=$report.observations.Count;enteredExists=(Test-Path -LiteralPath $enteredPath)}
|
||||
}}
|
||||
}
|
||||
}catch{Probe 'control-execution' $false $_.Exception.Message}
|
||||
$passed=$checks.Count-gt0-and@($checks|Where-Object passed -ne $true).Count-eq0
|
||||
|
||||
Reference in New Issue
Block a user