改造前:全仓 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),与产品代码无关。
108 lines
4.7 KiB
PowerShell
108 lines
4.7 KiB
PowerShell
<#
|
||
.SYNOPSIS
|
||
跑 BakNRet 的 Pester 测试套件(tests/BakNRet.Tests.ps1)。
|
||
|
||
.DESCRIPTION
|
||
Pester 从哪儿来,按优先级:
|
||
1. 仓库内的 .tools\modules(由 tools/Install-TestDependencies.ps1 放的本地副本,已 gitignore);
|
||
2. 机器上已安装的 Pester 5+。
|
||
|
||
两者都没有时给出一条明确的安装命令并以退出码 2 结束,而不是抛一堆看不懂的错。
|
||
|
||
为什么显式要求 Pester 5.0+:3.4.0 没有 `Should -Be`,本套件会直接语法错误。
|
||
本脚本只把 .tools\modules 临时加进 PSModulePath,**不会**去改机器上的全局模块。
|
||
|
||
.EXAMPLE
|
||
pwsh -File .\tests\Run-Pester.ps1
|
||
|
||
.EXAMPLE
|
||
pwsh -File .\tests\Run-Pester.ps1 -Verbosity Minimal
|
||
#>
|
||
|
||
[CmdletBinding()]
|
||
param(
|
||
[ValidateSet('Detailed', 'Normal', 'Minimal', 'None')]
|
||
[string]$Verbosity = 'Detailed',
|
||
|
||
[string[]]$Tag,
|
||
|
||
# 默认跑 tests/ 下所有 *.Tests.ps1(Pester 按这个命名约定发现)
|
||
[string]$TestPath
|
||
)
|
||
|
||
$ErrorActionPreference = 'Stop'
|
||
|
||
# 默认值不能写在 param() 里:Windows PowerShell 5.1 在带 [CmdletBinding()] 的脚本上,
|
||
# 参数绑定阶段还没有给 $PSScriptRoot 赋值,默认值表达式会拿到空串(实测:带
|
||
# [CmdletBinding()] -> 空串,不带 -> 正常;PowerShell 7 两种都正常)。所以默认值
|
||
# 一律在这里补 —— 这也是本仓库对 -BackupDir / -ConfigPath 一直在用的写法。
|
||
if (-not $TestPath) { $TestPath = $PSScriptRoot }
|
||
|
||
$projectRoot = Split-Path -Parent $PSScriptRoot
|
||
$localModules = Join-Path $projectRoot '.tools\modules'
|
||
if (Test-Path -LiteralPath $localModules) {
|
||
$env:PSModulePath = $localModules + [System.IO.Path]::PathSeparator + $env:PSModulePath
|
||
}
|
||
|
||
$pester = Get-Module -ListAvailable Pester |
|
||
Where-Object { [version]$_.Version -ge [version]'5.0.0' } |
|
||
Sort-Object { [version]$_.Version } -Descending |
|
||
Select-Object -First 1
|
||
|
||
if (-not $pester) {
|
||
$installed = @(Get-Module -ListAvailable Pester | ForEach-Object { $_.Version.ToString() })
|
||
|
||
Write-Host ''
|
||
Write-Host '找不到 Pester 5.0+,无法运行 Pester 套件。' -ForegroundColor Red
|
||
if ($installed.Count -gt 0) {
|
||
Write-Host ("已安装的版本:{0}(3.x 没有 Should -Be,本套件会语法错误)" -f ($installed -join '、')) -ForegroundColor Yellow
|
||
}
|
||
Write-Host ''
|
||
Write-Host '两种拿到 Pester 5+ 的方式(任选其一):' -ForegroundColor Cyan
|
||
Write-Host ' A. 只装到仓库里(推荐,不动机器上的全局模块):' -ForegroundColor Cyan
|
||
Write-Host ' .\tools\Install-TestDependencies.ps1' -ForegroundColor Gray
|
||
Write-Host ' B. 装到当前用户:' -ForegroundColor Cyan
|
||
Write-Host ' Install-Module Pester -Scope CurrentUser -MinimumVersion 5.0.0' -ForegroundColor Gray
|
||
Write-Host ''
|
||
Write-Host '零依赖的替代方案:.\tests\Run-Tests.ps1(不需要 Pester)' -ForegroundColor Cyan
|
||
Write-Host ''
|
||
exit 2
|
||
}
|
||
|
||
Import-Module $pester.Path -Force
|
||
Write-Host ("Pester {0} ({1})" -f $pester.Version, $pester.ModuleBase) -ForegroundColor DarkGray
|
||
Write-Host ("测试文件:{0}" -f $TestPath) -ForegroundColor DarkGray
|
||
|
||
$configuration = New-PesterConfiguration
|
||
$configuration.Run.Path = $TestPath
|
||
$configuration.Run.PassThru = $true
|
||
$configuration.Run.Exit = $false
|
||
$configuration.Output.Verbosity = $Verbosity
|
||
if ($Tag) { $configuration.Filter.Tag = $Tag }
|
||
|
||
# 关掉 Pester 的 TestRegistry:它会去写注册表(HKCU 下的测试键),
|
||
# 在受限环境 / 沙箱里会被拒绝,于是**所有**容器都以
|
||
# "Was not able to registry key for TestRegistry" 失败。
|
||
# 本套件不用 TestRegistry(只用临时目录),关掉它不影响任何用例。
|
||
$configuration.TestRegistry.Enabled = $false
|
||
|
||
$result = Invoke-Pester -Configuration $configuration
|
||
|
||
# 容器级失败(发现阶段的语法错误、Describe 外的异常)不会进 FailedCount,
|
||
# 只会在输出里出现一行 "Container failed" —— 不显式检查就会把"根本没跑起来"
|
||
# 报成"全部通过"。这里把它也当成失败。
|
||
$failedContainers = @($result.Containers | Where-Object { $_.Result -eq 'Failed' })
|
||
|
||
Write-Host ''
|
||
if ($result.FailedCount -gt 0 -or $failedContainers.Count -gt 0) {
|
||
Write-Host ("Pester 测试通过 {0} 项,失败 {1} 项,跳过 {2} 项,容器级失败 {3} 个" -f `
|
||
$result.PassedCount, $result.FailedCount, $result.SkippedCount, $failedContainers.Count) -ForegroundColor Red
|
||
foreach ($container in $failedContainers) {
|
||
Write-Host (" 容器失败:{0}" -f $container.Item) -ForegroundColor Red
|
||
}
|
||
exit 1
|
||
}
|
||
|
||
Write-Host ("Pester 测试全部通过:{0} 项(跳过 {1} 项)" -f $result.PassedCount, $result.SkippedCount) -ForegroundColor Green
|
||
exit 0
|