diff --git a/tools/android/exercise-final-progression.ps1 b/tools/android/exercise-final-progression.ps1 index de61fbd..e77922a 100644 --- a/tools/android/exercise-final-progression.ps1 +++ b/tools/android/exercise-final-progression.ps1 @@ -256,7 +256,7 @@ function Collect([int]$Stage) { } $state=Save "stage-$Stage-collected"; $board=Board $state $Stage Check "stage-$Stage-direct-collected-not-counted" ($board.groups.Count-eq1-and$board.collectedBallIds.Count-eq$board.balls.Count-and$board.countedBallIds.Count-eq0) 'Every ball directly dragged or merged; no injected or automatic count' - if($board.balls.Count-ge6){$board=ZoomOut $Stage $board} + if($board.balls.Count-ge6-and$board.camera.distance-lt15){$board=ZoomOut $Stage $board} return $board } function CountRemaining([int]$Stage) { diff --git a/tools/android/test-final-collect-framing.ps1 b/tools/android/test-final-collect-framing.ps1 new file mode 100644 index 0000000..22ba6e2 --- /dev/null +++ b/tools/android/test-final-collect-framing.ps1 @@ -0,0 +1,49 @@ +param([Parameter(Mandatory)][string]$EvidenceDir,[Parameter(Mandatory)][string]$EnteredFixture,[Parameter(Mandatory)][string]$CollectedFixture,[string]$ProgressionSource=(Join-Path $PSScriptRoot 'exercise-final-progression.ps1')) +$ErrorActionPreference='Stop' +New-Item -ItemType Directory $EvidenceDir -Force|Out-Null +$checks=[Collections.Generic.List[object]]::new();$script:inputs=[Collections.Generic.List[object]]::new() +function Record($Id,$Pass,$Actual){$checks.Add(@{id=$Id;passed=[bool]$Pass;actual=$Actual})} +function Clone($Value){return $Value|ConvertTo-Json -Depth 30|ConvertFrom-Json} +function Load($Path,$Name){ + $a=[Management.Automation.Language.Parser]::ParseFile($Path,[ref]$null,[ref]$null) + $f=$a.Find({param($n)$n-is[Management.Automation.Language.FunctionDefinitionAst]-and$n.Name-eq$Name},$true) + if(!$f){throw "Missing production function $Name"} + $body=$f.Extent.Text.Replace("function $Name","function global:$Name").Replace('$PSScriptRoot',"'$PSScriptRoot'") + . ([scriptblock]::Create($body)) + Record "$Name-production-body" ((Get-Command $Name).ScriptBlock.Ast.Extent.Text-ceq$body) $Path +} +function Check($Id,$Pass,$Actual){if(!$Pass){throw "$Id : $Actual"}} +function Start-Sleep {} +function pwsh {$script:inputs.Add('native-pinch-leaf');$global:LASTEXITCODE=0} +function Step {} +function global:MergeReal {throw 'Unexpected merge after complete direct collection'} +$commands=[Collections.Generic.List[object]]::new() +$entered=Get-Content $EnteredFixture -Raw|ConvertFrom-Json +$collected=Get-Content $CollectedFixture -Raw|ConvertFrom-Json +$script:current=$null;$script:noIncrease=$false +function Save([string]$Name){ + if($Name-eq'stage-16-count-initial'){return Clone $entered} + if($Name-eq'stage-16-zoom-out-state'-and!$script:noIncrease){(Board $script:current 16).camera.distance=15} + return Clone $script:current +} +try{ + Load (Join-Path $PSScriptRoot 'final-common.ps1') Same + foreach($n in @('Board','Counts','ZoomOut','Collect')){Load $ProgressionSource $n} + Record 'actual-fixture-is-collected-six-at-maximum-distance' ((Board $collected 16).camera.distance-eq15-and(Board $collected 16).groups.Count-eq1-and(Board $collected 16).collectedBallIds.Count-eq6-and(Board $collected 16).countedBallIds.Count-eq0) 'Root actual last native merge output; no fabricated completion' + foreach($kind in @('actual-maximum','counterfactual-below-maximum','counterfactual-pinch-no-increase')){ + $script:current=Clone $collected;$script:inputs.Clear();$script:noIncrease=$kind-eq'counterfactual-pinch-no-increase' + if($kind-ne'actual-maximum'){(Board $script:current 16).camera.distance=8} + $before=Clone $script:current;$value=$null;$errorText=$null + try{$value=Collect 16}catch{$errorText=$_.Exception.Message} + if($kind-eq'actual-maximum'){ + $pass=!$errorText-and$script:inputs.Count-eq0-and(Same $value (Board $before 16))-and(Same $before $script:current) + }elseif($kind-eq'counterfactual-below-maximum'){ + $expected=Clone $before;(Board $expected 16).camera=(Board $script:current 16).camera + $pass=!$errorText-and$script:inputs.Count-eq5-and$value.camera.distance-gt8-and(Same $value (Board $script:current 16))-and(Same $expected $script:current) + }else{$pass=$errorText-match'pinch-preserves-board'-and$null-eq$value-and$script:inputs.Count-eq5} + Record "Collect-$kind" $pass @{error=$errorText;nativePinchLeaves=$script:inputs.Count;returnedBoard=$value;scope='Offline actual save replay; below15 input-leaf/camera controls counterfactual, no native success claim'} + } +}catch{Record 'evaluation' $false $_.Exception.Message} +$passed=$checks.Count-gt0-and@($checks|Where-Object passed -ne $true).Count-eq0 +@{passed=$passed;scope='Production Collect/ZoomOut actual distance15 regression; mocked native leaves; initial entered and final collected saves replay completed actual work, not progression proof';progressionSha256=(Get-FileHash $ProgressionSource).Hash;fixtures=@($EnteredFixture,$CollectedFixture|ForEach-Object {@{path=$_;sha256=(Get-FileHash $_).Hash}});checks=$checks.ToArray()}|ConvertTo-Json -Depth 25|Set-Content (Join-Path $EvidenceDir 'collect-framing-result.json') +if(!$passed){exit 1};exit 0