Flux git-text in-arbore: git_sync.ps1 + teste, txt2vcx in-place, filemap pjx/dbf
- git_sync.ps1 nou: conversie recursiva bin->text in arbore (staging temp, incremental, orfani, RoundtripExempt, DbfList cu date, anti-dialog cfg) - vfp_filemap.ps1: mapari .pjx->.pj2 si .dbf->.db2 - txt2vcx.ps1: CacheRoot implicit = ProjectRoot (text in-arbore) + cfg anti-dialog in staging - test_roundtrip.ps1: parametrizat per proiect, restaurare din backup temp (nu git checkout) - test_git_sync.ps1 nou: incremental, orfani, esec partial, protectie binar, scutire roundtrip - CLAUDE.md: fluxul nou documentat Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,40 +1,49 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Teste standalone (fara Pester) pentru fluxul bin<->text VFP (FoxBin2Prg) si scriptul
|
||||
de write-back txt2vcx.ps1. Implicit ruleaza pe ROAGEST.
|
||||
de write-back txt2vcx.ps1. Parametrizat per proiect (implicit 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.
|
||||
- fidelity : esantion din FIECARE tip convertit, auto-descoperit din arborele proiectului.
|
||||
vcx/scx -> roundtrip complet bin->text1->bin->text2 (comparare pe octeti);
|
||||
frx/mnx/lbx/dbc/pjx/dbf -> doar validare bin->text (exit code + timeout + text nevid).
|
||||
Totul in temp, nimic scris in proiect.
|
||||
- edit : editare reala via txt2vcx.ps1 pe fixture-uri cunoscute (implicit ROAGEST);
|
||||
daca fixture-ul lipseste in proiect, se sare (warn). Restaurarea binarelor
|
||||
se face din backup temp (NU git checkout - binarele sunt git-ignored dupa migrare).
|
||||
- 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.
|
||||
test multi-fisier. Textul stricat ruleaza DOAR in cache temp, niciodata in arbore.
|
||||
- smoke : fidelity pe cate un .vcx din proiectele frate (-SmokeProjects).
|
||||
- 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.
|
||||
Restaurare: orice binar atins de write-back e copiat in backup temp INAINTE si restaurat
|
||||
la final (in finally), cu asertie byte-identic fata de original. Cache-ul text implicit e
|
||||
un director temporar creat pentru rulare (decuplat de arborele proiectului).
|
||||
|
||||
Exit 1 daca orice Assert a esuat, CU EXCEPTIA celor marcate warn-only (mnx/frx in Faza A).
|
||||
Exit 1 daca orice Assert a esuat, CU EXCEPTIA celor marcate warn-only.
|
||||
|
||||
.PARAMETER ProjectRoot
|
||||
Radacina proiectului principal testat (implicit ROAGEST).
|
||||
|
||||
.PARAMETER CacheRoot
|
||||
Cache-ul text al proiectului principal.
|
||||
Cache-ul text folosit de teste. Gol (implicit) => director temporar creat/sters de test,
|
||||
ca sa nu se scrie niciodata text in arborele proiectului.
|
||||
|
||||
.PARAMETER Phase
|
||||
all | fidelity | edit | negative | smoke
|
||||
|
||||
.PARAMETER SmokeProjects
|
||||
Lista proiectelor frate pentru faza smoke.
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$ProjectRoot = 'D:\ROA\ROAGEST',
|
||||
[string]$CacheRoot = 'D:\ROA\_vfp_textcache\roagest',
|
||||
[string]$CacheRoot = '',
|
||||
[ValidateSet('all','fidelity','edit','negative','smoke')]
|
||||
[string]$Phase = 'all'
|
||||
[string]$Phase = 'all',
|
||||
[string[]]$SmokeProjects = @('D:\ROA\ROAIMOB','D:\ROA\ROAACNPRO')
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
@@ -45,7 +54,8 @@ $txt2vcx = 'D:\ROA\UTIL\foxbin2prg\txt2vcx.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 --
|
||||
$script:BackupRoot = Join-Path $env:TEMP ("fb2p_test_backup_{0}_{1}" -f $PID, ([Guid]::NewGuid().ToString('N').Substring(0,8)))
|
||||
$script:Backups = @{} # cheie: cale binar (lower) -> info backup, pt restaurare la final
|
||||
|
||||
function Assert([bool]$cond, [string]$msg) {
|
||||
if ($cond) { Write-Host " PASS: $msg" -ForegroundColor Green }
|
||||
@@ -76,10 +86,13 @@ function Test-BytesEqual([byte[]]$a, [byte[]]$b) {
|
||||
}
|
||||
|
||||
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.
|
||||
# Watchdog obligatoriu - FoxBin2Prg poate afisa un MessageBox modal nativ VFP la text stricat;
|
||||
# fara asta, faza negativa ar ramane agatata la infinit intr-o rulare automata.
|
||||
param([string]$InputFile, [string]$Recompile = '', [int]$TimeoutSeconds = 60)
|
||||
# cfg in dir-ul input-ului: DontShowErrors suprima MessageBox-ul propriu FoxBin2Prg (ca in git_sync)
|
||||
$cfgLines = [System.Collections.Generic.List[string]]@('DontShowErrors: 1','ShowProgressbar: 0')
|
||||
if ([IO.Path]::GetExtension($InputFile).ToLower() -eq '.dbf') { $cfgLines.Add('DBF_Conversion_Support: 4') }
|
||||
Set-Content -LiteralPath (Join-Path (Split-Path -Parent $InputFile) 'foxbin2prg.cfg') -Value $cfgLines -Encoding Ascii
|
||||
if ($Recompile) {
|
||||
$r = Invoke-FoxBin2PrgSafe -ExePath $exe -ExeArgs @($InputFile,'','','','1','0','1','',$Recompile) -TimeoutSeconds $TimeoutSeconds
|
||||
} else {
|
||||
@@ -94,21 +107,73 @@ function Get-FileHashBytes([string]$path) {
|
||||
return (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash
|
||||
}
|
||||
|
||||
# --- Faza A: fidelitate pura (bin->text1->bin->text2, doar in temp) ---
|
||||
function Get-RelPath([string]$Root, [string]$Full) {
|
||||
return $Full.Substring($Root.TrimEnd('\').Length).TrimStart('\')
|
||||
}
|
||||
|
||||
# --- Auto-descoperire: un esantion mic non-COMUN de tipul cerut, cu memo companion ---
|
||||
function Find-SampleBinary {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$ProjRoot,
|
||||
[Parameter(Mandatory)][string]$Ext,
|
||||
[bool]$RequireMemo = $true,
|
||||
[int]$MaxBytes = 500000
|
||||
)
|
||||
if (-not (Test-Path -LiteralPath $ProjRoot)) { return $null }
|
||||
$memoExt = $script:VfpFileMap[$Ext][0]
|
||||
Get-ChildItem -LiteralPath $ProjRoot -Recurse -File -Filter ("*" + $Ext) -ErrorAction SilentlyContinue |
|
||||
Where-Object {
|
||||
$_.FullName -notmatch '(?i)\\COMUN\\' -and
|
||||
$_.Length -le $MaxBytes -and $_.Length -gt 0 -and
|
||||
(-not $RequireMemo -or (Test-Path -LiteralPath ([IO.Path]::ChangeExtension($_.FullName, $memoExt))))
|
||||
} |
|
||||
Sort-Object Length |
|
||||
Select-Object -First 1
|
||||
}
|
||||
|
||||
# --- Backup/restore binare din temp (inlocuieste git checkout - binarele sunt git-ignored) ---
|
||||
function Backup-ProjectBinary([string]$fullBin) {
|
||||
$key = $fullBin.ToLower()
|
||||
if ($script:Backups.ContainsKey($key)) { return }
|
||||
$ext = [IO.Path]::GetExtension($fullBin).ToLower()
|
||||
$memoExt = $script:VfpFileMap[$ext][0]
|
||||
$dir = Split-Path $fullBin -Parent
|
||||
$base = [IO.Path]::GetFileNameWithoutExtension($fullBin)
|
||||
$memoEntry = Get-ChildItem -LiteralPath $dir -Filter ($base + $memoExt) -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
$memoFull = if ($memoEntry) { $memoEntry.FullName } else { [IO.Path]::ChangeExtension($fullBin, $memoExt) }
|
||||
$bdir = Join-Path $script:BackupRoot ([Guid]::NewGuid().ToString('N').Substring(0,8))
|
||||
New-Item -ItemType Directory -Force -Path $bdir | Out-Null
|
||||
$binBak = Join-Path $bdir (Split-Path $fullBin -Leaf)
|
||||
Copy-Item -LiteralPath $fullBin -Destination $binBak -Force
|
||||
$memoBak = $null
|
||||
if (Test-Path -LiteralPath $memoFull) {
|
||||
$memoBak = Join-Path $bdir (Split-Path $memoFull -Leaf)
|
||||
Copy-Item -LiteralPath $memoFull -Destination $memoBak -Force
|
||||
}
|
||||
$script:Backups[$key] = @{ BinFull=$fullBin; BinBak=$binBak; MemoFull=$memoFull; MemoBak=$memoBak; OrigHash=(Get-FileHashBytes $fullBin) }
|
||||
}
|
||||
|
||||
function Restore-ProjectBinaries {
|
||||
foreach ($k in @($script:Backups.Keys)) {
|
||||
$b = $script:Backups[$k]
|
||||
Copy-Item -LiteralPath $b.BinBak -Destination $b.BinFull -Force
|
||||
if ($b.MemoBak) { Copy-Item -LiteralPath $b.MemoBak -Destination $b.MemoFull -Force }
|
||||
$now = Get-FileHashBytes $b.BinFull
|
||||
Assert ($now -eq $b.OrigHash) "Restore: $(Split-Path $b.BinFull -Leaf) byte-identic cu originalul dupa restore"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Fidelitate: roundtrip complet bin->text1->bin->text2 (doar in temp) - pt vcx/scx ---
|
||||
function Test-FidelityRoundtrip {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$RelPath, # relativ la $ProjRoot, ex Clase\oavize.vcx
|
||||
[Parameter(Mandatory)][string]$RelPath,
|
||||
[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
|
||||
}
|
||||
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 } }
|
||||
$pair = $script:VfpFileMap[$ext]
|
||||
if (-not $pair) { AssertWarn $false "Faza A: extensie necunoscuta, sarit: $RelPath"; return }
|
||||
$memoExt = $pair[0]; $txtExt = $pair[1]
|
||||
$memoFull = [IO.Path]::ChangeExtension($full, $memoExt)
|
||||
@@ -123,8 +188,7 @@ function Test-FidelityRoundtrip {
|
||||
$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 }
|
||||
if ($WarnOnly) { AssertWarn $false "Faza A ($RelPath): Bin2Prg #1 a esuat (ErrorLevel=$rc1)"; return }
|
||||
Assert $false "Faza A ($RelPath): Bin2Prg #1 a esuat (ErrorLevel=$rc1)"
|
||||
return
|
||||
}
|
||||
@@ -149,262 +213,287 @@ function Test-FidelityRoundtrip {
|
||||
}
|
||||
}
|
||||
|
||||
# --- Faza B: editare reala prin txt2vcx.ps1, cu revert git ---
|
||||
# --- Validare bin->text (fara roundtrip) - pt frx/mnx/lbx/dbc/pjx/dbf (write-back nesuportat) ---
|
||||
function Test-BinToTextValid {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$RelPath,
|
||||
[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 = $script:VfpFileMap[$ext]
|
||||
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_valid_{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)
|
||||
Copy-Item -LiteralPath $full -Destination $bin1 -Force
|
||||
if (Test-Path -LiteralPath $memoFull) { Copy-Item -LiteralPath $memoFull -Destination (Join-Path $work ($baseName + $memoExt)) -Force }
|
||||
$rc = Invoke-Fb2p -InputFile $bin1
|
||||
$text1 = Join-Path $work ($baseName + $txtExt)
|
||||
$ok = ($rc -eq 0) -and (Test-Path -LiteralPath $text1) -and ((Get-Item -LiteralPath $text1).Length -gt 0)
|
||||
$msg = "Faza A ($RelPath): bin->text valid (exit=$rc, text nevid)"
|
||||
if ($WarnOnly) { AssertWarn $ok $msg } else { Assert $ok $msg }
|
||||
} finally {
|
||||
Remove-Item -Recurse -Force -LiteralPath $work -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
# specificatie per tip convertit: roundtrip doar vcx/scx; restul doar validare bin->text
|
||||
$script:FidelitySpec = @(
|
||||
@{ Ext='.vcx'; Roundtrip=$true; WarnOnly=$false; RequireMemo=$true }
|
||||
@{ Ext='.scx'; Roundtrip=$true; WarnOnly=$false; RequireMemo=$true }
|
||||
@{ Ext='.frx'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$true }
|
||||
@{ Ext='.mnx'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$true }
|
||||
@{ Ext='.lbx'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$true }
|
||||
@{ Ext='.dbc'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$true }
|
||||
@{ Ext='.pjx'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$true }
|
||||
@{ Ext='.dbf'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$false }
|
||||
)
|
||||
|
||||
function Invoke-FidelityForProject([string]$ProjRoot) {
|
||||
foreach ($s in $script:FidelitySpec) {
|
||||
$sample = Find-SampleBinary -ProjRoot $ProjRoot -Ext $s.Ext -RequireMemo $s.RequireMemo
|
||||
if (-not $sample) { AssertWarn $false "Faza A: niciun esantion $($s.Ext) in $ProjRoot, sarit"; continue }
|
||||
$rel = Get-RelPath $ProjRoot $sample.FullName
|
||||
Write-Host " esantion $($s.Ext): $rel ($([int]($sample.Length/1024)) KB)"
|
||||
if ($s.Roundtrip) { Test-FidelityRoundtrip -RelPath $rel -ProjRoot $ProjRoot -WarnOnly $s.WarnOnly }
|
||||
else { Test-BinToTextValid -RelPath $rel -ProjRoot $ProjRoot -WarnOnly $s.WarnOnly }
|
||||
}
|
||||
}
|
||||
|
||||
# --- Editare reala prin txt2vcx.ps1, cu backup/restore (nu git) ---
|
||||
function Test-EditRoundtrip {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$RelPath, # ex Clase\oavize.vcx
|
||||
[Parameter(Mandatory)][string]$RelPath,
|
||||
[Parameter(Mandatory)][string]$CaptionOld,
|
||||
[Parameter(Mandatory)][string]$CaptionNew,
|
||||
[Parameter(Mandatory)][string]$ProcedureMarker # ex "PROCEDURE Init"
|
||||
[Parameter(Mandatory)][string]$ProcedureMarker
|
||||
)
|
||||
$full = Join-Path $ProjectRoot $RelPath
|
||||
if (-not (Test-Path -LiteralPath $full)) { AssertWarn $false "Faza B: fixture lipsa in proiect, sarit: $RelPath"; return }
|
||||
$ext = [IO.Path]::GetExtension($RelPath).ToLower()
|
||||
$pair = $script:VfpFileMap[$ext]
|
||||
$memoExt = $pair[0]; $txtExt = $pair[1]
|
||||
$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)
|
||||
$base = [IO.Path]::GetFileNameWithoutExtension($RelPath)
|
||||
$relText = if ($relDir) { Join-Path $relDir ($base + $txtExt) } else { $base + $txtExt }
|
||||
|
||||
Write-Host "-- Faza B: $RelPath --"
|
||||
& $vcx2txt -Source (Join-Path $ProjectRoot $RelPath) -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null
|
||||
Backup-ProjectBinary $full
|
||||
$origHash = $script:Backups[$full.ToLower()].OrigHash
|
||||
|
||||
& $vcx2txt -Source $full -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)
|
||||
$text = $script:Enc.GetString([IO.File]::ReadAllBytes($cacheText))
|
||||
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)
|
||||
if ($idx -ge 0) {
|
||||
$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 }
|
||||
Assert ((Get-FileHashBytes $full) -ne $origHash) "Faza B ($RelPath): binarul din proiect a fost rescris (hash diferit de original)"
|
||||
$bakStray = Join-Path (Join-Path $ProjectRoot $relDir) ($base + '.bak')
|
||||
Assert (-not (Test-Path -LiteralPath $bakStray)) "Faza B ($RelPath): fara .bak lasat in proiect"
|
||||
|
||||
$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
|
||||
# binarul e restaurat din backup in finally-ul global
|
||||
}
|
||||
|
||||
# ============================== MAIN ==============================
|
||||
$ownCache = $false
|
||||
if ([string]::IsNullOrWhiteSpace($CacheRoot)) {
|
||||
$CacheRoot = Join-Path $env:TEMP ("fb2p_test_cache_{0}_{1}" -f $PID, ([Guid]::NewGuid().ToString('N').Substring(0,8)))
|
||||
$ownCache = $true
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $CacheRoot)) { New-Item -ItemType Directory -Force -Path $CacheRoot | Out-Null }
|
||||
New-Item -ItemType Directory -Force -Path $script:BackupRoot | Out-Null
|
||||
|
||||
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 }
|
||||
# fixture-uri de editare cunoscute (implicit ROAGEST); se sar automat daca lipsesc in proiect
|
||||
$editFixtures = @(
|
||||
@{ Rel='Clase\oavize.vcx'; Old='Lb_titlu_alb_b121.Caption = "Date aviz"'; New='Lb_titlu_alb_b121.Caption = "Atentie-diacritice-ok"'; Marker='PROCEDURE Init' }
|
||||
@{ Rel='Ferestre\fundal.scx'; Old='Caption = ""'; New='Caption = "test"'; Marker='PROCEDURE Show' }
|
||||
)
|
||||
|
||||
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
|
||||
Write-Host "`n--- FAZA A: fidelitate (esantion din fiecare tip convertit) ---"
|
||||
Invoke-FidelityForProject $ProjectRoot
|
||||
}
|
||||
|
||||
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'
|
||||
Write-Host "`n--- FAZA B: editare reala (write-back) ---"
|
||||
foreach ($fx in $editFixtures) {
|
||||
Test-EditRoundtrip -RelPath $fx.Rel -CaptionOld $fx.Old -CaptionNew $fx.New -ProcedureMarker $fx.Marker
|
||||
}
|
||||
}
|
||||
|
||||
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" }
|
||||
Write-Host "`n--- FAZA C: smoke pe proiecte frate ---"
|
||||
foreach ($sp in $SmokeProjects) {
|
||||
if (-not (Test-Path -LiteralPath $sp)) { AssertWarn $false "Faza C: proiect lipsa $sp, sarit"; continue }
|
||||
$s = Find-SampleBinary -ProjRoot $sp -Ext '.vcx'
|
||||
if ($s) { Test-FidelityRoundtrip -RelPath (Get-RelPath $sp $s.FullName) -ProjRoot $sp }
|
||||
else { AssertWarn $false "Faza C: niciun .vcx in $sp, 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')
|
||||
$vcxSample = Find-SampleBinary -ProjRoot $ProjectRoot -Ext '.vcx'
|
||||
if (-not $vcxSample) {
|
||||
AssertWarn $false "Faza D: niciun .vcx in $ProjectRoot, faza sarita"
|
||||
} else {
|
||||
$vcxRel = Get-RelPath $ProjectRoot $vcxSample.FullName
|
||||
$vcxFull = $vcxSample.FullName
|
||||
$vcxDir = Split-Path $vcxRel -Parent
|
||||
$vcxBase = [IO.Path]::GetFileNameWithoutExtension($vcxRel)
|
||||
$vcxRelText = if ($vcxDir) { Join-Path $vcxDir ($vcxBase + '.vc2') } else { $vcxBase + '.vc2' }
|
||||
Write-Host " esantion negativ .vcx: $vcxRel"
|
||||
Backup-ProjectBinary $vcxFull
|
||||
$origVcxHash = Get-FileHashBytes $vcxFull # baseline curent (independent de backup) pt asertii "neatins"
|
||||
|
||||
# (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)
|
||||
& $vcx2txt -Source $vcxFull -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null
|
||||
$cacheText = Join-Path $CacheRoot $vcxRelText
|
||||
Assert (Test-Path -LiteralPath $cacheText) "Faza D: text esantion generat pentru $vcxRel"
|
||||
$origBytes = [IO.File]::ReadAllBytes($cacheText)
|
||||
|
||||
# (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
|
||||
# (a) text stricat: adauga o clasa neinchisa -> recompilare esueaza (doar in cache temp)
|
||||
$text = $script:Enc.GetString($origBytes)
|
||||
$brokenSuffix = "`r`nDEFINE CLASS _brokenzzz AS Custom`r`n"
|
||||
[IO.File]::WriteAllBytes($cacheText, $script:Enc.GetBytes($text + $brokenSuffix))
|
||||
& $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
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (a): txt2vcx exit != 0 pe text stricat (DEFINE CLASS neinchis)"
|
||||
Assert ((Get-FileHashBytes $vcxFull) -eq $origVcxHash) "Faza D (a): binarul esantion neatins in proiect"
|
||||
[IO.File]::WriteAllBytes($cacheText, $origBytes)
|
||||
|
||||
# (b) fisier text gol
|
||||
[IO.File]::WriteAllBytes($cacheText, [byte[]]@())
|
||||
& $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (b): txt2vcx exit != 0 pe fisier text gol"
|
||||
Assert ((Get-FileHashBytes $vcxFull) -eq $origVcxHash) "Faza D (b): binarul esantion neatins in proiect"
|
||||
[IO.File]::WriteAllBytes($cacheText, $origBytes)
|
||||
|
||||
# (guard) staleness: binar mai nou decat textul -> refuz fara -Force
|
||||
$origMtime = (Get-Item -LiteralPath $vcxFull).LastWriteTime
|
||||
(Get-Item -LiteralPath $vcxFull).LastWriteTime = (Get-Date).AddDays(1)
|
||||
try {
|
||||
[IO.File]::WriteAllBytes($cacheText, $origBytes)
|
||||
& $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard staleness): refuz fara -Force cand binarul e mai nou"
|
||||
Assert ((Get-FileHashBytes $vcxFull) -eq $origVcxHash) "Faza D (guard staleness): binar neatins"
|
||||
} finally {
|
||||
(Get-Item -LiteralPath $vcxFull).LastWriteTime = $origMtime
|
||||
}
|
||||
|
||||
# (guard) binar tinta lipsa -> refuz PERMANENT (si cu -Force)
|
||||
$missingCacheText = Join-Path $CacheRoot $(if ($vcxDir) { Join-Path $vcxDir '_nu_exista_deloc.vc2' } else { '_nu_exista_deloc.vc2' })
|
||||
New-Item -ItemType Directory -Force -Path (Split-Path $missingCacheText -Parent) | Out-Null
|
||||
[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
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard binar lipsa): refuz chiar si cu -Force"
|
||||
} finally { Remove-Item -LiteralPath $missingCacheText -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
# (guard) cale text in afara CacheRoot -> refuz
|
||||
$outsideText = Join-Path $env:TEMP ('_outside_' + [Guid]::NewGuid().ToString('N').Substring(0,8) + '.vc2')
|
||||
[IO.File]::WriteAllBytes($outsideText, $origBytes)
|
||||
try {
|
||||
& $txt2vcx -TextFile $outsideText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard cale in afara CacheRoot): refuz"
|
||||
} finally { Remove-Item -LiteralPath $outsideText -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
# (guard) extensie nesuportata (.mn2)
|
||||
$unsupported = Join-Path $CacheRoot $(if ($vcxDir) { Join-Path $vcxDir '_fake.mn2' } else { '_fake.mn2' })
|
||||
[IO.File]::WriteAllBytes($unsupported, $script:Enc.GetBytes("* fake mn2`r`n"))
|
||||
try {
|
||||
& $txt2vcx -TextFile $unsupported -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard extensie nesuportata .mn2): refuz"
|
||||
} finally { Remove-Item -LiteralPath $unsupported -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
# (guard) COMUN fara -AllowComun -> refuz (-DryRun, zero scrieri)
|
||||
$comunText = Join-Path $CacheRoot 'COMUN\clase\_fake.vc2'
|
||||
New-Item -ItemType Directory -Force -Path (Split-Path $comunText -Parent) | Out-Null
|
||||
[IO.File]::WriteAllBytes($comunText, $origBytes)
|
||||
try {
|
||||
& $txt2vcx -TextFile $comunText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -DryRun
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard COMUN, fara -AllowComun): refuz"
|
||||
} finally { Remove-Item -Recurse -Force -LiteralPath (Split-Path $comunText -Parent) -ErrorAction SilentlyContinue }
|
||||
|
||||
# (guard) folder-foxbin2prg -> refuz necondiționat (-DryRun)
|
||||
$fb2pCache = Join-Path $env:TEMP ('_fb2pguard_' + [Guid]::NewGuid().ToString('N').Substring(0,8))
|
||||
New-Item -ItemType Directory -Force -Path $fb2pCache | Out-Null
|
||||
$fb2pText = Join-Path $fb2pCache 'fake.vc2'
|
||||
[IO.File]::WriteAllBytes($fb2pText, $origBytes)
|
||||
try {
|
||||
& $txt2vcx -TextFile $fb2pText -ProjectRoot 'D:\ROA\UTIL\foxbin2prg' -CacheRoot $fb2pCache -DryRun
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard folder-foxbin2prg): refuz necondiționat"
|
||||
} finally { Remove-Item -Recurse -Force -LiteralPath $fb2pCache -ErrorAction SilentlyContinue }
|
||||
|
||||
# (-DryRun caz valid): nimic modificat in proiect, exit 0
|
||||
[IO.File]::WriteAllBytes($cacheText, $origBytes)
|
||||
& $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -DryRun
|
||||
Assert ($LASTEXITCODE -eq 0) "Faza D (-DryRun, caz valid): exit 0"
|
||||
Assert ((Get-FileHashBytes $vcxFull) -eq $origVcxHash) "Faza D (-DryRun, caz valid): binar neatins in proiect"
|
||||
|
||||
# --- multi-fisier: un scx valid (scris) + vcx stricat (refuzat) in aceeasi rulare ---
|
||||
$scxSample = Find-SampleBinary -ProjRoot $ProjectRoot -Ext '.scx'
|
||||
if ($scxSample) {
|
||||
$scxRel = Get-RelPath $ProjectRoot $scxSample.FullName
|
||||
$scxFull = $scxSample.FullName
|
||||
$scxDir = Split-Path $scxRel -Parent
|
||||
$scxBase = [IO.Path]::GetFileNameWithoutExtension($scxRel)
|
||||
$scxRelText = if ($scxDir) { Join-Path $scxDir ($scxBase + '.sc2') } else { $scxBase + '.sc2' }
|
||||
Backup-ProjectBinary $scxFull
|
||||
$scxOrigMtime = (Get-Item -LiteralPath $scxFull).LastWriteTime
|
||||
|
||||
& $vcx2txt -Source $scxFull -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null
|
||||
$scxCacheText = Join-Path $CacheRoot $scxRelText
|
||||
$scxText = $script:Enc.GetString([IO.File]::ReadAllBytes($scxCacheText))
|
||||
$m = [regex]::Match($scxText, "(?m)^\tPROCEDURE \w+\r?\n")
|
||||
if ($m.Success) {
|
||||
$pos = $m.Index + $m.Length
|
||||
$scxText = $scxText.Substring(0,$pos) + "`t`t* test multi`r`n" + $scxText.Substring($pos)
|
||||
[IO.File]::WriteAllBytes($scxCacheText, $script:Enc.GetBytes($scxText))
|
||||
}
|
||||
[IO.File]::WriteAllBytes($cacheText, $script:Enc.GetBytes($text + $brokenSuffix))
|
||||
|
||||
& $txt2vcx -TextFile @($scxCacheText, $cacheText) -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
Assert ($LASTEXITCODE -eq 1) "Faza D (multi-fisier): exit agregat = 1 (unul din doua a esuat)"
|
||||
Assert ((Get-FileHashBytes $vcxFull) -eq $origVcxHash) "Faza D (multi-fisier): vcx stricat neatins in proiect"
|
||||
Assert (((Get-Item -LiteralPath $scxFull).LastWriteTime) -ne $scxOrigMtime) "Faza D (multi-fisier): scx valid a fost scris in proiect (mtime schimbat)"
|
||||
[IO.File]::WriteAllBytes($cacheText, $origBytes)
|
||||
} else {
|
||||
AssertWarn $false "Faza D (multi-fisier): niciun .scx in $ProjectRoot, sarit"
|
||||
}
|
||||
}
|
||||
|
||||
# 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--- Cleanup final: restore binare din backup + curatare temp ---"
|
||||
Restore-ProjectBinaries
|
||||
if ($ownCache -and (Test-Path -LiteralPath $CacheRoot)) { Remove-Item -Recurse -Force -LiteralPath $CacheRoot -ErrorAction SilentlyContinue }
|
||||
if (Test-Path -LiteralPath $script:BackupRoot) { Remove-Item -Recurse -Force -LiteralPath $script:BackupRoot -ErrorAction SilentlyContinue }
|
||||
}
|
||||
|
||||
Write-Host "`n=== REZULTAT ==="
|
||||
|
||||
Reference in New Issue
Block a user