改造前:全仓 6/6 个源文件在 5.1 上解析失败(README 却承诺支持 5.1)。原因是文件是无 BOM 的 UTF-8,而 5.1 没有 BOM 就按 ANSI 代码页解码源码,中文变乱码、全角问号吃掉引号,整块语法塌掉。 现在 28/28 个文件在 5.1 与 7 上都解析零错误,E2E 36 项在 5.1 上全绿。 顺带修掉一个被 5.1 掩盖的缺陷:带 [CmdletBinding()] 的脚本在 5.1 上,param() 默认值里 拿不到 $PSScriptRoot(实测为空串,7 上正常)。于是 Backup.ps1 / Restore.ps1 在 5.1 上不传 路径参数就报错退出 —— 而计划任务恰恰不传。E2E 之所以看不见,是因为它总是显式传路径。 8 处默认值全部移到 param() 之后的解析段,沿用本仓库对 -BackupDir 一直在用的写法。 新增三条可重放的约定,让编码不再是一次性动作: .gitattributes 接管行尾(本机 core.autocrlf=true,会把工作区改成 CRLF 制造伪 diff) .editorconfig 用 charset = utf-8-bom 锁住 BOM tools\Set-SourceEncoding.ps1 是规范化脚本,tools\Invoke-* 之外的任何改动之后都能重放 test.ps1 是唯一验收入口:Encode + Parse + Unit + Smoke + E2E,在 7 与 5.1 上各跑一遍 test.ps1 的 Encode 层直接检查"必须有 BOM"这条规则。加它的原因很实际:实测本仓库用的 编辑工具在保存时会悄悄去掉 BOM,而丢了 BOM 的文件只在 5.1 上出错、在 7 上完全正常, 没有这条检查就会一直漏过去。 已知未修(下一步处理):5.1 上 Unit 有 6 项、Smoke 有 1 项失败,全部源于测试夹具写 临时文件时没指定编码(5.1 的 Set-Content 默认 ANSI),与产品代码无关。
112 lines
3.4 KiB
PowerShell
112 lines
3.4 KiB
PowerShell
<#
|
||
.SYNOPSIS
|
||
BakNRet 测试用的极简断言运行器(零依赖,PS 5.1 / 7.x 通用)。
|
||
|
||
.DESCRIPTION
|
||
不用 Pester:本机只装了 3.4.0,缺少 `Should -Be` 这类 Pester 4+ 语法,
|
||
为跑几个测试去装 Pester 5 不划算。这里只需要 Test-Case + Assert-* 就够。
|
||
#>
|
||
|
||
$script:Passed = 0
|
||
$script:Failed = 0
|
||
$script:Failures = @()
|
||
|
||
function Reset-TestResult {
|
||
$script:Passed = 0
|
||
$script:Failed = 0
|
||
$script:Failures = @()
|
||
}
|
||
|
||
function Get-TestResult {
|
||
return [pscustomobject]@{
|
||
Passed = $script:Passed
|
||
Failed = $script:Failed
|
||
Failures = @($script:Failures)
|
||
}
|
||
}
|
||
|
||
function Test-Case {
|
||
param([string]$Name, [scriptblock]$Body)
|
||
|
||
try {
|
||
& $Body
|
||
$script:Passed++
|
||
Write-Host " [PASS] $Name" -ForegroundColor Green
|
||
} catch {
|
||
$script:Failed++
|
||
$script:Failures += "$Name —— $($_.Exception.Message)"
|
||
Write-Host " [FAIL] $Name" -ForegroundColor Red
|
||
Write-Host " $($_.Exception.Message)" -ForegroundColor DarkGray
|
||
}
|
||
}
|
||
|
||
function Assert-Equal {
|
||
param($Expected, $Actual, [string]$Because)
|
||
if ($Expected -ne $Actual) {
|
||
throw ("期望 [{0}],实际 [{1}]{2}" -f $Expected, $Actual, $(if ($Because) { "($Because)" } else { '' }))
|
||
}
|
||
}
|
||
|
||
function Assert-True {
|
||
param($Condition, [string]$Because)
|
||
if (-not $Condition) { throw ("断言为真失败{0}" -f $(if ($Because) { ":$Because" } else { '' })) }
|
||
}
|
||
|
||
function Assert-False {
|
||
param($Condition, [string]$Because)
|
||
if ($Condition) { throw ("断言为假失败{0}" -f $(if ($Because) { ":$Because" } else { '' })) }
|
||
}
|
||
|
||
function Assert-Null {
|
||
param($Value, [string]$Because)
|
||
if ($null -ne $Value) {
|
||
throw ("期望为 null,实际 [{0}]{1}" -f $Value, $(if ($Because) { "($Because)" } else { '' }))
|
||
}
|
||
}
|
||
|
||
function Assert-FileExists {
|
||
param([string]$Path, [string]$Because)
|
||
if (-not (Test-Path -LiteralPath $Path)) {
|
||
throw ("文件应当存在但不存在:{0}{1}" -f $Path, $(if ($Because) { "($Because)" } else { '' }))
|
||
}
|
||
}
|
||
|
||
function Assert-FileMissing {
|
||
param([string]$Path, [string]$Because)
|
||
if (Test-Path -LiteralPath $Path) {
|
||
throw ("文件不应存在但存在:{0}{1}" -f $Path, $(if ($Because) { "($Because)" } else { '' }))
|
||
}
|
||
}
|
||
|
||
function Assert-FileHashEqual {
|
||
param([string]$ExpectedPath, [string]$ActualPath)
|
||
Assert-FileExists $ExpectedPath
|
||
Assert-FileExists $ActualPath
|
||
$a = (Get-FileHash -LiteralPath $ExpectedPath -Algorithm SHA256).Hash
|
||
$b = (Get-FileHash -LiteralPath $ActualPath -Algorithm SHA256).Hash
|
||
if ($a -ne $b) { throw ("内容不一致:{0} vs {1}" -f $ExpectedPath, $ActualPath) }
|
||
}
|
||
|
||
function Write-TestSummary {
|
||
param([string]$Title = '测试')
|
||
|
||
Write-Host ""
|
||
Write-Host ("=" * 60)
|
||
if ($script:Failed -eq 0) {
|
||
Write-Host "$Title 全部通过:$($script:Passed) 项" -ForegroundColor Green
|
||
} else {
|
||
Write-Host "$Title 通过 $($script:Passed) 项,失败 $($script:Failed) 项" -ForegroundColor Red
|
||
foreach ($failure in $script:Failures) { Write-Host " - $failure" -ForegroundColor Red }
|
||
}
|
||
Write-Host ("=" * 60)
|
||
|
||
return $script:Failed
|
||
}
|
||
|
||
Export-ModuleMember -Function @(
|
||
'Reset-TestResult', 'Get-TestResult', 'Test-Case',
|
||
'Assert-Equal', 'Assert-True', 'Assert-False', 'Assert-Null',
|
||
'Assert-FileExists', 'Assert-FileMissing', 'Assert-FileHashEqual',
|
||
'Write-TestSummary'
|
||
)
|