<# .SYNOPSIS Teste standalone (fara Pester) pentru fluxul bin<->text VFP (FoxBin2Prg) si scriptul de write-back txt2vcx.ps1. Implicit ruleaza pe ROAGEST. .DESCRIPTION Faze: - fidelity : roundtrip pur bin->text1->bin->text2 (doar in temp, fara scriere in proiect), pentru .vcx/.scx (blocant) si .mnx/.frx (warn-only - read-only in flux). - edit : editare reala pe copie de proiect (ROAGEST), via txt2vcx.ps1, cu revert git. - negative : text stricat, fisier gol, guard-uri (staleness, binar lipsa, cale in afara cache-ului, extensie nesuportata, COMUN, folder-foxbin2prg, -DryRun), test multi-fisier (unul valid + unul stricat in aceeasi rulare). - smoke : Faza A (fidelity) pe cate un .vcx mic non-COMUN din ROAIMOB si ROAACNPRO. - all : toate cele de mai sus, in ordine. Precondita: git status --porcelain trebuie sa fie gol PENTRU FISIERELE TINTA (nu tot repo-ul) inainte de a incepe. La final (in finally), git checkout -- pe orice binar atins + refresh cache, indiferent de rezultat. Exit 1 daca orice Assert a esuat, CU EXCEPTIA celor marcate warn-only (mnx/frx in Faza A). .PARAMETER ProjectRoot Radacina proiectului principal testat (implicit ROAGEST). .PARAMETER CacheRoot Cache-ul text al proiectului principal. .PARAMETER Phase all | fidelity | edit | negative | smoke #> [CmdletBinding()] param( [string]$ProjectRoot = 'D:\ROA\ROAGEST', [string]$CacheRoot = 'D:\ROA\_vfp_textcache\roagest', [ValidateSet('all','fidelity','edit','negative','smoke')] [string]$Phase = 'all' ) $ErrorActionPreference = 'Stop' $exe = 'D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE' $vcx2txt = 'D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1' $txt2vcx = 'D:\ROA\UTIL\foxbin2prg\txt2vcx.ps1' . (Join-Path $PSScriptRoot 'vfp_filemap.ps1') $script:Failures = @() $script:Enc = [Text.Encoding]::GetEncoding(1252) $script:TouchedProjectFiles = New-Object System.Collections.Generic.List[string] # cai relative la ProjectRoot, pt cleanup git checkout -- function Assert([bool]$cond, [string]$msg) { if ($cond) { Write-Host " PASS: $msg" -ForegroundColor Green } else { Write-Host " FAIL: $msg" -ForegroundColor Red; $script:Failures += $msg } } function AssertWarn([bool]$cond, [string]$msg) { if ($cond) { Write-Host " PASS(warn-only): $msg" -ForegroundColor Green } else { Write-Warning " WARN (non-blocant): $msg" } } function Normalize-Crlf([byte[]]$bytes) { $out = New-Object System.Collections.Generic.List[byte] for ($i = 0; $i -lt $bytes.Length; $i++) { if ($bytes[$i] -eq 0x0D) { if ($i + 1 -lt $bytes.Length -and $bytes[$i+1] -eq 0x0A) { continue } $out.Add(0x0A) | Out-Null } else { $out.Add($bytes[$i]) | Out-Null } } return $out.ToArray() } function Test-BytesEqual([byte[]]$a, [byte[]]$b) { $na = Normalize-Crlf $a; $nb = Normalize-Crlf $b if ($na.Length -ne $nb.Length) { return $false } for ($i = 0; $i -lt $na.Length; $i++) { if ($na[$i] -ne $nb[$i]) { return $false } } return $true } function Invoke-Fb2p { # Watchdog obligatoriu - vezi nota din txt2vcx.ps1: FoxBin2Prg poate afisa un # MessageBox modal nativ VFP (necontrolat de cDontShowErrors) la text stricat; # fara asta, Faza D (negativ) ar putea ramane agatata la infinit intr-o rulare automata. param([string]$InputFile, [string]$Recompile = '', [int]$TimeoutSeconds = 60) if ($Recompile) { $r = Invoke-FoxBin2PrgSafe -ExePath $exe -ExeArgs @($InputFile,'','','','1','0','1','',$Recompile) -TimeoutSeconds $TimeoutSeconds } else { $r = Invoke-FoxBin2PrgSafe -ExePath $exe -ExeArgs @($InputFile,'','','','1','0','1') -TimeoutSeconds $TimeoutSeconds } if ($r.TimedOut) { Write-Warning "Invoke-Fb2p: timeout pe '$InputFile' - tratat ca ESEC." } return $r.ExitCode } function Get-FileHashBytes([string]$path) { if (-not (Test-Path -LiteralPath $path)) { return $null } return (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash } # --- Faza A: fidelitate pura (bin->text1->bin->text2, doar in temp) --- function Test-FidelityRoundtrip { param( [Parameter(Mandatory)][string]$RelPath, # relativ la $ProjRoot, ex Clase\oavize.vcx [Parameter(Mandatory)][string]$ProjRoot, [bool]$WarnOnly = $false ) $full = Join-Path $ProjRoot $RelPath if (-not (Test-Path -LiteralPath $full)) { AssertWarn $false "Faza A: fisier lipsa, sarit: $RelPath" return } $ext = [IO.Path]::GetExtension($full).ToLower() $pair = $null foreach ($k in $script:VfpFileMap.Keys) { if ($k -eq $ext) { $pair = $script:VfpFileMap[$k]; break } } if (-not $pair) { AssertWarn $false "Faza A: extensie necunoscuta, sarit: $RelPath"; return } $memoExt = $pair[0]; $txtExt = $pair[1] $memoFull = [IO.Path]::ChangeExtension($full, $memoExt) $work = Join-Path $env:TEMP ("fb2p_fidelity_{0}_{1}" -f $PID, ([Guid]::NewGuid().ToString('N').Substring(0,8))) New-Item -ItemType Directory -Force -Path $work | Out-Null try { $baseName = [IO.Path]::GetFileNameWithoutExtension($full) $bin1 = Join-Path $work ($baseName + $ext); $memo1 = Join-Path $work ($baseName + $memoExt) Copy-Item -LiteralPath $full -Destination $bin1 -Force if (Test-Path -LiteralPath $memoFull) { Copy-Item -LiteralPath $memoFull -Destination $memo1 -Force } $rc1 = Invoke-Fb2p -InputFile $bin1 $text1 = Join-Path $work ($baseName + $txtExt) if ($rc1 -ne 0 -or -not (Test-Path -LiteralPath $text1)) { AssertWarn (-not $WarnOnly) "Faza A ($RelPath): Bin2Prg #1 a esuat (ErrorLevel=$rc1)" if ($WarnOnly) { return } Assert $false "Faza A ($RelPath): Bin2Prg #1 a esuat (ErrorLevel=$rc1)" return } $stage2 = Join-Path $work 'stage2' New-Item -ItemType Directory -Force -Path $stage2 | Out-Null $text1copy = Join-Path $stage2 ($baseName + $txtExt) Copy-Item -LiteralPath $text1 -Destination $text1copy -Force $rc2 = Invoke-Fb2p -InputFile $text1copy -Recompile $ProjRoot $bin2 = Join-Path $stage2 ($baseName + $ext); $memo2 = Join-Path $stage2 ($baseName + $memoExt) if ($rc2 -ne 0 -or -not (Test-Path -LiteralPath $bin2) -or -not (Test-Path -LiteralPath $memo2)) { $ok = $false } else { $rc3 = Invoke-Fb2p -InputFile $bin2 $text2 = Join-Path $stage2 ($baseName + $txtExt) $ok = ($rc3 -eq 0) -and (Test-Path -LiteralPath $text2) -and (Test-BytesEqual ([IO.File]::ReadAllBytes($text1)) ([IO.File]::ReadAllBytes($text2))) } if ($WarnOnly) { AssertWarn $ok "Faza A ($RelPath): text1 == text2 dupa roundtrip complet" } else { Assert $ok "Faza A ($RelPath): text1 == text2 dupa roundtrip complet" } } finally { Remove-Item -Recurse -Force -LiteralPath $work -ErrorAction SilentlyContinue } } # --- Faza B: editare reala prin txt2vcx.ps1, cu revert git --- function Test-EditRoundtrip { param( [Parameter(Mandatory)][string]$RelPath, # ex Clase\oavize.vcx [Parameter(Mandatory)][string]$CaptionOld, [Parameter(Mandatory)][string]$CaptionNew, [Parameter(Mandatory)][string]$ProcedureMarker # ex "PROCEDURE Init" ) $ext = [IO.Path]::GetExtension($RelPath).ToLower() $pair = $script:VfpFileMap[$ext] $memoExt = $pair[0]; $txtExt = $pair[1] $relDir = Split-Path $RelPath -Parent $baseName = [IO.Path]::GetFileNameWithoutExtension($RelPath) # rezolva casing-ul REAL al memo-ului din proiect (poate fi .SCT/.VCT majuscul, vezi fundal.SCT) $memoEntry = Get-ChildItem -LiteralPath (Join-Path $ProjectRoot $relDir) -Filter ($baseName + $memoExt) -ErrorAction SilentlyContinue | Select-Object -First 1 $relMemo = if ($memoEntry) { Join-Path $relDir $memoEntry.Name } else { Join-Path $relDir ($baseName + $memoExt) } $relText = Join-Path $relDir ($baseName + $txtExt) Write-Host "-- Faza B: $RelPath --" & $vcx2txt -Source (Join-Path $ProjectRoot $RelPath) -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null $cacheText = Join-Path $CacheRoot $relText Assert (Test-Path -LiteralPath $cacheText) "Faza B ($RelPath): cache text regenerat" $bytes = [IO.File]::ReadAllBytes($cacheText) $text = $script:Enc.GetString($bytes) Assert ($text.Contains($CaptionOld)) "Faza B ($RelPath): linia Caption originala gasita" $text = $text.Replace($CaptionOld, $CaptionNew) $marker = "`t" + $ProcedureMarker + "`r`n" $idx = $text.IndexOf($marker) Assert ($idx -ge 0) "Faza B ($RelPath): marker '$ProcedureMarker' gasit" $insertPos = $idx + $marker.Length $text = $text.Substring(0,$insertPos) + "`t`t* test roundtrip`r`n" + $text.Substring($insertPos) [IO.File]::WriteAllBytes($cacheText, $script:Enc.GetBytes($text)) $script:TouchedProjectFiles.Add($RelPath) | Out-Null $script:TouchedProjectFiles.Add($relMemo) | Out-Null & $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot $rc = $LASTEXITCODE Assert ($rc -eq 0) "Faza B ($RelPath): txt2vcx.ps1 exit 0" Push-Location $ProjectRoot try { $porcelain = (git status --porcelain -- $RelPath $relMemo) -join "`n" $lines = $porcelain -split "`n" | Where-Object { $_.Trim() -ne '' } Assert ($lines.Count -eq 2) "Faza B ($RelPath): git status arata exact 2 fisiere modificate ($($lines.Count) gasite)" $untracked = git status --porcelain | Where-Object { $_ -match '^\?\?' -and $_ -match [regex]::Escape((Split-Path $RelPath -Parent)) } Assert (-not $untracked -or ($untracked | Where-Object { $_ -match '\.bak$' }).Count -eq 0) "Faza B ($RelPath): fara fisiere .bak untracked" } finally { Pop-Location } $regenText = $script:Enc.GetString([IO.File]::ReadAllBytes($cacheText)) Assert ($regenText.Contains($CaptionNew)) "Faza B ($RelPath): textul regenerat contine Caption editat" Assert ($regenText.Contains('* test roundtrip')) "Faza B ($RelPath): textul regenerat contine comentariul adaugat" if ($RelPath -match 'oavize') { Assert ($regenText.Contains($CaptionNew)) "Faza B ($RelPath) [assert diacritice]: string cu diacritice supravietuieste roundtrip-ului byte-identic" } Push-Location $ProjectRoot try { git checkout -- $RelPath $relMemo } finally { Pop-Location } & $vcx2txt -Source (Join-Path $ProjectRoot $RelPath) -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null } # ============================== MAIN ============================== Write-Host "=== test_roundtrip.ps1 -- ProjectRoot=$ProjectRoot CacheRoot=$CacheRoot Phase=$Phase ===" # Precondita: git status curat pentru fisierele tinta cunoscute dinainte $knownTargets = @('Clase\oavize.vcx','Clase\oavize.vct','Ferestre\fundal.scx','Ferestre\fundal.SCT') Push-Location $ProjectRoot try { $pre = (git status --porcelain -- $knownTargets) -join "`n" if ($pre.Trim() -ne '') { throw "Precondita esuata: fisierele tinta nu sunt curate in git:`n$pre" } } finally { Pop-Location } try { if ($Phase -eq 'all' -or $Phase -eq 'fidelity') { Write-Host "`n--- FAZA A: fidelitate (roundtrip pur) ---" Test-FidelityRoundtrip -RelPath 'Clase\oavize.vcx' -ProjRoot $ProjectRoot # inlocuieste atentie.vcx (gol, fara clase reale - vezi deviere raportata) Test-FidelityRoundtrip -RelPath 'Ferestre\fundal.scx' -ProjRoot $ProjectRoot Test-FidelityRoundtrip -RelPath 'Meniuri\achi_transfer.mnx' -ProjRoot $ProjectRoot -WarnOnly $true Test-FidelityRoundtrip -RelPath 'Rapoarte\fisa.frx' -ProjRoot $ProjectRoot -WarnOnly $true } if ($Phase -eq 'all' -or $Phase -eq 'edit') { Write-Host "`n--- FAZA B: editare reala (ROAGEST) ---" Test-EditRoundtrip -RelPath 'Clase\oavize.vcx' ` -CaptionOld 'Lb_titlu_alb_b121.Caption = "Date aviz"' ` -CaptionNew 'Lb_titlu_alb_b121.Caption = "Atentie-diacritice-ok"' ` -ProcedureMarker 'PROCEDURE Init' Test-EditRoundtrip -RelPath 'Ferestre\fundal.scx' ` -CaptionOld 'Caption = ""' ` -CaptionNew 'Caption = "test"' ` -ProcedureMarker 'PROCEDURE Show' } if ($Phase -eq 'all' -or $Phase -eq 'smoke') { Write-Host "`n--- FAZA C: smoke pe siblings ---" if (Test-Path 'D:\ROA\ROAIMOB\Clase\onom_imob.vcx') { Test-FidelityRoundtrip -RelPath 'Clase\onom_imob.vcx' -ProjRoot 'D:\ROA\ROAIMOB' } else { AssertWarn $false "Faza C: onom_imob.vcx lipsa in ROAIMOB, sarit" } if (Test-Path 'D:\ROA\ROAACNPRO\Clase\ofundal_facturare.vcx') { Test-FidelityRoundtrip -RelPath 'Clase\ofundal_facturare.vcx' -ProjRoot 'D:\ROA\ROAACNPRO' } else { AssertWarn $false "Faza C: ofundal_facturare.vcx lipsa in ROAACNPRO, sarit" } } if ($Phase -eq 'all' -or $Phase -eq 'negative') { Write-Host "`n--- FAZA D: negativ + guard-uri + multi-fisier ---" & $vcx2txt -Source (Join-Path $ProjectRoot 'Clase\oavize.vcx') -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null $cacheText = Join-Path $CacheRoot 'Clase\oavize.vc2' $origBytes = [IO.File]::ReadAllBytes($cacheText) $origVcxHash = Get-FileHashBytes (Join-Path $ProjectRoot 'Clase\oavize.vcx') $origVctHash = Get-FileHashBytes (Join-Path $ProjectRoot 'Clase\oavize.vct') # (a) text stricat: sterge un ENDPROC $work = Join-Path $env:TEMP ("fb2p_negD_{0}" -f ([Guid]::NewGuid().ToString('N').Substring(0,8))) New-Item -ItemType Directory -Force -Path $work | Out-Null $corruptText = Join-Path $work 'oavize.vc2' $text = $script:Enc.GetString($origBytes) $text2 = $text -replace "(?s)(PROCEDURE do_cauta_altele.*?)\r?\n\s*ENDPROC", '$1' Assert ($text2 -ne $text) "Faza D (a): am reusit sa sterg un ENDPROC din textul de test" [IO.File]::WriteAllBytes($corruptText, $script:Enc.GetBytes($text2)) # txt2vcx cere ca fisierul sa fie sub CacheRoot -> copiem in cache temporar sub un nume separat $corruptCacheText = Join-Path $CacheRoot 'Clase\_test_corrupt.vc2' Copy-Item -LiteralPath $corruptText -Destination $corruptCacheText -Force # simulam ca tinta e oavize (acelasi binar), redenumind local -- de fapt txt2vcx mapeaza dupa numele fisierului text, # deci pentru acest test punem textul corupt chiar in oavize.vc2 din cache (e restaurat mai jos) Copy-Item -LiteralPath $corruptText -Destination $cacheText -Force Remove-Item -LiteralPath $corruptCacheText -Force -ErrorAction SilentlyContinue & $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot $rcA = $LASTEXITCODE Assert ($rcA -ne 0) "Faza D (a): txt2vcx.ps1 exit != 0 pe text stricat (ENDPROC lipsa)" Assert ((Get-FileHashBytes (Join-Path $ProjectRoot 'Clase\oavize.vcx')) -eq $origVcxHash) "Faza D (a): oavize.vcx neatins in proiect" Assert ((Get-FileHashBytes (Join-Path $ProjectRoot 'Clase\oavize.vct')) -eq $origVctHash) "Faza D (a): oavize.vct neatins in proiect" [IO.File]::WriteAllBytes($cacheText, $origBytes) # (b) fisier text gol (0 bytes) [IO.File]::WriteAllBytes($cacheText, [byte[]]@()) & $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot $rcB = $LASTEXITCODE Assert ($rcB -ne 0) "Faza D (b): txt2vcx.ps1 exit != 0 pe fisier text gol" Assert ((Get-FileHashBytes (Join-Path $ProjectRoot 'Clase\oavize.vcx')) -eq $origVcxHash) "Faza D (b): oavize.vcx neatins in proiect" [IO.File]::WriteAllBytes($cacheText, $origBytes) # --- Test guard-uri --- # staleness: dam mtime-ul binarului in viitor -> refuz fara -Force $vcxPath = Join-Path $ProjectRoot 'Clase\oavize.vcx' $origMtime = (Get-Item -LiteralPath $vcxPath).LastWriteTime (Get-Item -LiteralPath $vcxPath).LastWriteTime = (Get-Date).AddDays(1) try { [IO.File]::WriteAllBytes($cacheText, $origBytes) # text neschimbat, dar staleness trebuie sa refuze oricum & $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot $rcStale = $LASTEXITCODE Assert ($rcStale -ne 0) "Faza D (guard staleness): refuz fara -Force cand binarul e mai nou decat cache-ul" Assert ((Get-FileHashBytes $vcxPath) -eq $origVcxHash) "Faza D (guard staleness): oavize.vcx neatins" } finally { (Get-Item -LiteralPath $vcxPath).LastWriteTime = $origMtime } # binar tinta lipsa -> refuz PERMANENT (si cu -Force) $missingCacheText = Join-Path $CacheRoot 'Clase\_nu_exista_deloc.vc2' [IO.File]::WriteAllBytes($missingCacheText, $script:Enc.GetBytes("* fake`r`nDEFINE CLASS x AS y`r`nENDDEFINE`r`n")) try { & $txt2vcx -TextFile $missingCacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force $rcMissing = $LASTEXITCODE Assert ($rcMissing -ne 0) "Faza D (guard binar lipsa): refuz chiar si cu -Force" } finally { Remove-Item -LiteralPath $missingCacheText -Force -ErrorAction SilentlyContinue } # cale text in afara CacheRoot -> eroare dura $outsideText = Join-Path $env:TEMP 'oavize_outside.vc2' [IO.File]::WriteAllBytes($outsideText, $origBytes) try { & $txt2vcx -TextFile $outsideText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot $rcOutside = $LASTEXITCODE Assert ($rcOutside -ne 0) "Faza D (guard cale in afara CacheRoot): refuz" } finally { Remove-Item -LiteralPath $outsideText -Force -ErrorAction SilentlyContinue } # extensie nesuportata (.mn2) $unsupported = Join-Path $CacheRoot 'Clase\_fake.mn2' [IO.File]::WriteAllBytes($unsupported, $script:Enc.GetBytes("* fake mn2`r`n")) try { & $txt2vcx -TextFile $unsupported -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot $rcUnsup = $LASTEXITCODE Assert ($rcUnsup -ne 0) "Faza D (guard extensie nesuportata .mn2): refuz" } finally { Remove-Item -LiteralPath $unsupported -Force -ErrorAction SilentlyContinue } # guard COMUN (cu -DryRun, refuz inainte de staging, zero scrieri) $comunCandidate = Get-ChildItem -Path (Join-Path $CacheRoot 'comun\clase') -Filter '*.vc2' -ErrorAction SilentlyContinue | Select-Object -First 1 if ($comunCandidate) { & $txt2vcx -TextFile $comunCandidate.FullName -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -DryRun $rcComun = $LASTEXITCODE Assert ($rcComun -ne 0) "Faza D (guard COMUN, fara -AllowComun): refuz" } else { AssertWarn $false "Faza D (guard COMUN): niciun candidat .vc2 gasit sub cache\comun\clase, sarit" } # guard folder-foxbin2prg (cu -DryRun) $fb2pFakeCache = Join-Path $CacheRoot 'UTIL_foxbin2prg_fake' New-Item -ItemType Directory -Force -Path $fb2pFakeCache | Out-Null $fb2pFakeText = Join-Path $fb2pFakeCache 'fake.vc2' [IO.File]::WriteAllBytes($fb2pFakeText, $origBytes) try { & $txt2vcx -TextFile $fb2pFakeText -ProjectRoot 'D:\ROA\UTIL\foxbin2prg' -CacheRoot $fb2pFakeCache -DryRun $rcFb2p = $LASTEXITCODE Assert ($rcFb2p -ne 0) "Faza D (guard folder-foxbin2prg): refuz necondiționat" } finally { Remove-Item -Recurse -Force -LiteralPath $fb2pFakeCache -ErrorAction SilentlyContinue } # -DryRun pe caz valid: nimic modificat in proiect, exit reflecta staging-ul (0 = OK) [IO.File]::WriteAllBytes($cacheText, $origBytes) & $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -DryRun $rcDry = $LASTEXITCODE Assert ($rcDry -eq 0) "Faza D (-DryRun, caz valid): exit 0" Assert ((Get-FileHashBytes $vcxPath) -eq $origVcxHash) "Faza D (-DryRun, caz valid): oavize.vcx neatins in proiect" # --- Test multi-fisier: un .vc2 valid (fundal.scx) + unul stricat (oavize) in aceeasi rulare --- & $vcx2txt -Source (Join-Path $ProjectRoot 'Ferestre\fundal.scx') -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null $fundalCacheText = Join-Path $CacheRoot 'Ferestre\fundal.sc2' $fundalOrigBytes = [IO.File]::ReadAllBytes($fundalCacheText) $fundalOrigVcxHash = Get-FileHashBytes (Join-Path $ProjectRoot 'Ferestre\fundal.scx') $fundalText = $script:Enc.GetString($fundalOrigBytes).Replace('Caption = ""', 'Caption = "multi-test"') [IO.File]::WriteAllBytes($fundalCacheText, $script:Enc.GetBytes($fundalText)) $corruptOavizeText = $script:Enc.GetString($origBytes) -replace "(?s)(PROCEDURE do_cauta_altele.*?)\r?\n\s*ENDPROC", '$1' [IO.File]::WriteAllBytes($cacheText, $script:Enc.GetBytes($corruptOavizeText)) $script:TouchedProjectFiles.Add('Ferestre\fundal.scx') | Out-Null $script:TouchedProjectFiles.Add('Ferestre\fundal.SCT') | Out-Null & $txt2vcx -TextFile @($fundalCacheText, $cacheText) -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot $rcMulti = $LASTEXITCODE Assert ($rcMulti -eq 1) "Faza D (multi-fisier): exit code agregat = 1 (unul din doua a esuat)" Assert ((Get-FileHashBytes $vcxPath) -eq $origVcxHash) "Faza D (multi-fisier): oavize.vcx (cel stricat) neatins in proiect" $fundalVcxHash = Get-FileHashBytes (Join-Path $ProjectRoot 'Ferestre\fundal.scx') Assert ($fundalVcxHash -ne $fundalOrigVcxHash) "Faza D (multi-fisier): fundal.scx (cel valid) A FOST scris in proiect" # cleanup multi-fisier Push-Location $ProjectRoot try { git checkout -- 'Ferestre\fundal.scx' 'Ferestre\fundal.SCT' } finally { Pop-Location } [IO.File]::WriteAllBytes($cacheText, $origBytes) & $vcx2txt -Source (Join-Path $ProjectRoot 'Clase\oavize.vcx') -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null & $vcx2txt -Source (Join-Path $ProjectRoot 'Ferestre\fundal.scx') -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null Remove-Item -Recurse -Force -LiteralPath $work -ErrorAction SilentlyContinue } } finally { Write-Host "`n--- Cleanup final: git checkout -- pe fisierele atinse + refresh cache ---" Push-Location $ProjectRoot try { $toRevert = $script:TouchedProjectFiles | Sort-Object -Unique foreach ($f in $toRevert) { $status = git status --porcelain -- $f if ($status) { git checkout -- $f 2>$null } } } finally { Pop-Location } & $vcx2txt -Source (Join-Path $ProjectRoot 'Clase\oavize.vcx') -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null & $vcx2txt -Source (Join-Path $ProjectRoot 'Ferestre\fundal.scx') -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null } Write-Host "`n=== REZULTAT ===" if ($script:Failures.Count -eq 0) { Write-Host "TOATE testele au trecut (Phase=$Phase)." -ForegroundColor Green exit 0 } else { Write-Host "$($script:Failures.Count) test(e) esuate:" -ForegroundColor Red $script:Failures | ForEach-Object { Write-Host " - $_" -ForegroundColor Red } exit 1 }