<# .SYNOPSIS Tests statiques d'integrite T-STAT-02 a T-STAT-04 (Docs/Migration/03_Plan_Migration_Tests.md). .DESCRIPTION -Modules : Content/Modules 5.5 identique a 4.27 (liste et MD5). -Env : environnement de developpement identique au manifeste du lot L0. -Ref427 : arbre 4.27 inchange depuis l'empreinte de reference. -InitRef427 : cree l'empreinte de reference 4.27 (a faire une seule fois, en L0). Code de sortie 1 si un test echoue. .EXAMPLE .\Tools\CheckIntegrity.ps1 -Modules -Env -Ref427 #> param( [switch]$Modules, [switch]$Env, [switch]$Ref427, [switch]$InitRef427, [string]$ProjectRoot = (Split-Path $PSScriptRoot -Parent), [string]$Root427 = 'D:\Game\LifePlay-master 4.27', [string]$BackupRoot = 'D:\Game\LifePlay_Backup_5.5' ) $ErrorActionPreference = 'Stop' $refCsv = Join-Path $ProjectRoot 'Docs\Migration\etat\L0_ref427.csv' $failed = 0 function Hash-Tree([string]$Base, [string[]]$Rel) { foreach ($r in $Rel) { $p = Join-Path $Base $r if (-not (Test-Path $p)) { continue } Get-ChildItem $p -File -Recurse -Force | ForEach-Object { [pscustomobject]@{ Rel = $_.FullName.Substring($Base.TrimEnd('\').Length + 1); MD5 = (Get-FileHash $_.FullName -Algorithm MD5).Hash } } } } function Report([string]$Name, [object[]]$Diffs, [int]$Total) { if ($Diffs) { $script:failed++ "ECHEC $Name : $(@($Diffs).Count) ecart(s) sur $Total" $Diffs | Select-Object -First 20 | ForEach-Object { " $_" } } else { "OK $Name : $Total fichier(s) conformes" } } $refSet = @('Source', 'Config', 'LifePlay.uproject', 'Content\BPs', 'Content\Structs', 'Plugins\ModdingExtra\Source', 'Plugins\StreetMap\Source') if ($InitRef427) { if (Test-Path $refCsv) { throw "Empreinte deja presente : $refCsv (supprimer volontairement pour la refaire)" } Hash-Tree $Root427 $refSet | Export-Csv $refCsv -NoTypeInformation -Encoding UTF8 "Empreinte 4.27 ecrite : $refCsv" } if ($Modules) { $a = Hash-Tree $Root427 @('Content\Modules'); $b = Hash-Tree $ProjectRoot @('Content\Modules') $ha = @{}; $a | ForEach-Object { $ha[$_.Rel] = $_.MD5 } $hb = @{}; $b | ForEach-Object { $hb[$_.Rel] = $_.MD5 } $keys = @($ha.Keys) + @($hb.Keys) | Sort-Object -Unique $d = $keys | Where-Object { $ha[$_] -ne $hb[$_] } | ForEach-Object { if (-not $ha[$_]) { "en plus en 5.5 : $_" } elseif (-not $hb[$_]) { "absent en 5.5 : $_" } else { "different : $_" } } Report 'T-STAT-02 Modules = 4.27' $d $keys.Count } if ($Env) { $man = Join-Path $BackupRoot 'L0\manifest.csv' $rows = Import-Csv $man | Where-Object { $_.Rel -match '^(\.claude\\|\.mcp\.json$|Saved\\Backups\\|Saved\\SaveGames\\)' } $d = foreach ($r in $rows) { $p = Join-Path $ProjectRoot $r.Rel if (-not (Test-Path -LiteralPath $p)) { "absent : $($r.Rel)" } elseif ((Get-FileHash -LiteralPath $p -Algorithm MD5).Hash -ne $r.MD5) { # Les .sav changent quand on joue : signales mais non bloquants if ($r.Rel -like 'Saved\SaveGames\*') { Write-Host " (info) sauvegarde de jeu modifiee : $($r.Rel)" } else { "modifie : $($r.Rel)" } } } Report 'T-STAT-03 environnement = L0' $d @($rows).Count } if ($Ref427) { if (-not (Test-Path $refCsv)) { throw "Pas d'empreinte 4.27 : lancer -InitRef427 d'abord" } $ref = Import-Csv $refCsv $cur = @{}; Hash-Tree $Root427 $refSet | ForEach-Object { $cur[$_.Rel] = $_.MD5 } $d = @($ref | Where-Object { $cur[$_.Rel] -ne $_.MD5 } | ForEach-Object { "modifie ou absent : $($_.Rel)" }) $known = @{}; $ref | ForEach-Object { $known[$_.Rel] = 1 } $d += @($cur.Keys | Where-Object { -not $known[$_] } | ForEach-Object { "nouveau : $_" }) Report 'T-STAT-04 arbre 4.27 inchange' $d @($ref).Count } if ($failed) { exit 1 }