tests/cases/31-ps12exe-args.ps1
|
# ps12exe 参数与预处理:PSD 命令行参数、#_pragma 求值、嵌套 #_if、const-eval 回退。 $deps = $script:CoreCompileDeps Add-Test @{ Name = 'ps12exe.args.psd' Group = 'ps12exe' Deps = $deps Build = @{ Name = 'psd' Output = 'psd.exe' InputText = @' param([hashtable]$Config, [int]$N = 0) "Type=$($Config.GetType().Name) a=$($Config.a) x=$($Config.x) N=$N" '@ } Run = { param($ctx) $psdExe = Copy-BuildAs -BuildPath $ctx.Builds['psd'] -WorkDir $ctx.WorkDir -Name 'psd.exe' $out = (Invoke-ExeCaptureMergedOutput -ExePath $psdExe -Arguments @('-Config', "@{a='b'}", '-N', "[int]'42'")).Output Assert-Match $out 'Type=Hashtable' "PSD 参数未按哈希表解析:$out" Assert-Match $out 'a=b' "PSD 参数 a 丢失:$out" Assert-Match $out 'N=42' "PSD 安全类型转换失败:$out" $bad = (Invoke-ExeCaptureMergedOutput -ExePath $psdExe -Arguments @('-Config', "@{x=1+1}")).Output Assert-NotMatch $bad 'x=2' "PSD 参数被当作 PowerShell 求值了:$bad" } } Add-Test @{ Name = 'ps12exe.pragma.eval' Group = 'ps12exe' Deps = $deps Run = { param($ctx) $script:GuestMode = $false $script:Params = @{} $script:ParamList = @{ App = @{ ParameterType = [hashtable] } Os = @{ ParameterType = [hashtable] } Build = @{ ParameterType = [hashtable] } Resources = @{ ParameterType = [hashtable] } Signing = @{ ParameterType = [hashtable] } } $script:i18nWarnings = [System.Collections.Generic.List[string]]::new() function Write-I18n { param($PipeLineType, $Mid, $FormatArgs, $Category) if ($PipeLineType -eq 'Error') { throw "PragmaError:$Mid" } if ($PipeLineType -eq 'Warning') { $script:i18nWarnings.Add($Mid) } } . (Join-Path $ctx.RepoRoot 'src/ReadScriptFile.ps1') function Get-ParamByPath($Params, [string]$Path) { $cur = $Params foreach ($seg in ($Path -split '\.')) { $cur = $cur[$seg] } $cur } function Invoke-PragmaTest([string]$pragma, [bool]$guest, [string]$expect, [string]$assertParam = 'Resources.Icon') { $script:GuestMode = $guest $script:Params = @{} $rejected = $false try { [void](Preprocessor @($pragma) "C:\compiled\main.ps1") } catch { $rejected = $true; $Error.Clear() } $actual = if ($rejected) { 'REJECTED' } else { Get-ParamByPath $script:Params $assertParam } if ($expect -eq 'REJECTED') { Assert-True $rejected "pragma 应被拒绝:[$pragma] guest=$guest 得到:$actual" } else { Assert-False $rejected "pragma 应能求值:[$pragma] guest=$guest 被拒绝" Assert-Equal $expect "$actual" "pragma 值不符:[$pragma] guest=$guest" } } $userProfileFoo = Join-Path $env:USERPROFILE 'foo.ico' $pwshSource = (Get-Command pwsh).Source $secretFile = Join-Path $ctx.WorkDir 'pragma-secret.txt' [System.IO.File]::WriteAllText($secretFile, 'secret-value', [System.Text.UTF8Encoding]::new($false)) $env:PRAGMA_SECRET = $secretFile Invoke-PragmaTest '#_pragma Resources.Icon $(Join-Path $env:USERPROFILE "foo.ico")' $false $userProfileFoo Invoke-PragmaTest '#_pragma Resources.Icon $(Join-Path $env:USERPROFILE "foo.ico")' $true $userProfileFoo Invoke-PragmaTest '#_pragma Resources.Icon $((Get-Command pwsh).Source)' $false $pwshSource Invoke-PragmaTest '#_pragma Resources.Icon $((Join-Path $env:USERPROFILE "Foo.ico").ToLower())' $false (Join-Path $env:USERPROFILE 'foo.ico') Invoke-PragmaTest '#_pragma Resources.Icon $((Get-Item C:\Windows).Delete())' $false 'REJECTED' Invoke-PragmaTest '#_pragma Resources.Icon $(Remove-Item C:\x -Recurse)' $false 'REJECTED' Invoke-PragmaTest '#_pragma Resources.Icon $(Get-Content $env:PRAGMA_SECRET)' $false 'secret-value' Invoke-PragmaTest '#_pragma Resources.Icon $(Get-Content $env:PRAGMA_SECRET)' $true 'REJECTED' Invoke-PragmaTest '#_pragma Resources.Icon $PSScriptRoot/foo.ico' $false 'C:\compiled/foo.ico' Invoke-PragmaTest '#_pragma Resources.Title "prefix$(Split-Path $PSScriptRoot -Leaf)suffix"' $false 'prefixcompiledsuffix' 'Resources.Title' Invoke-PragmaTest '#_pragma Signing.Certificate C:\cert.pfx' $false 'C:\cert.pfx' 'Signing.Certificate' Invoke-PragmaTest '#_pragma Resources.meta.deep C:\deep\v' $false 'C:\deep\v' 'Resources.meta.deep' $script:i18nWarnings.Clear() $script:GuestMode = $false $script:Params = @{} [void](Preprocessor @('#_pragma notTable.key value') "C:\compiled\main.ps1") Assert-True ($script:i18nWarnings -contains 'UnknownPragma') "非哈希表根的嵌套 pragma 未告警:$($script:i18nWarnings -join ',')" Remove-Item Env:\PRAGMA_SECRET -ErrorAction SilentlyContinue } } Add-Test @{ Name = 'ps12exe.pragma.nested-if' Group = 'ps12exe' Deps = $deps Run = { param($ctx) $script:GuestMode = $false $script:Params = @{} $script:ParamList = @{ App = @{ ParameterType = [hashtable] }; Os = @{ ParameterType = [hashtable] }; Build = @{ ParameterType = [hashtable] }; Resources = @{ ParameterType = [hashtable] }; Signing = @{ ParameterType = [hashtable] } } $script:i18nWarnings = [System.Collections.Generic.List[string]]::new() function Write-I18n { param($PipeLineType, $Mid, $FormatArgs, $Category) if ($PipeLineType -eq 'Error') { throw "PragmaError:$Mid" } if ($PipeLineType -eq 'Warning') { $script:i18nWarnings.Add($Mid) } } . (Join-Path $ctx.RepoRoot 'src/ReadScriptFile.ps1') $result = Preprocessor @( '#_if PSEXE' 'outer-true' '#_if PSScript' 'inner-false' '#_else' 'inner-true' '#_endif' 'outer-tail' '#_else' 'outer-false' '#_endif' ) 'C:\compiled\main.ps1' $text = $result -join "`n" foreach ($expected in @('outer-true', 'inner-true', 'outer-tail')) { Assert-Match $text ([regex]::Escape($expected)) "嵌套 #_if 丢掉了 $expected" } foreach ($unexpected in @('inner-false', 'outer-false')) { Assert-NotMatch $text ([regex]::Escape($unexpected)) "嵌套 #_if 保留了 $unexpected" } Assert-True ($script:i18nWarnings -contains 'PreprocessNestedIfDeadCode') "嵌套 #_if 未告警死代码:$($script:i18nWarnings -join ', ')" } } Add-Test @{ Name = 'ps12exe.branch-bang-warnings' Group = 'ps12exe' Deps = $deps Run = { param($ctx) $script:GuestMode = $false $script:Params = @{} $script:i18nWarnings = [System.Collections.Generic.List[string]]::new() function Write-I18n { param($PipeLineType, $Mid, $FormatArgs, $Category) if ($PipeLineType -eq 'Warning') { $script:i18nWarnings.Add($Mid) } } . (Join-Path $ctx.RepoRoot 'src/ReadScriptFile.ps1') function Get-WarningCount([string]$Mid) { @($script:i18nWarnings | Where-Object { $_ -eq $Mid }).Count } # PSEXE 分支会编译进 EXE,其中的普通代码必须带 #_!!;而 PSScript 分支中的 #_!! 在直接运行时会变成注释。 [void](Preprocessor @( '#_if PSEXE' '$needsBang = 1' '#_!! $escaped = 2' '# comment' '#_else' '$direct = 3' '#_!! $wrongBang = 4' '#_endif' ) 'C:\compiled\main.ps1') Assert-Equal 1 (Get-WarningCount 'PreprocessPsexeBranchCode') "PSEXE 分支中的普通代码未告警:$($script:i18nWarnings -join ', ')" Assert-Equal 1 (Get-WarningCount 'PreprocessPsscriptBranchBang') "PSScript 上下文中的 #_!! 未告警:$($script:i18nWarnings -join ', ')" # 嵌套时只有所有外层分支都在编译期选中的行才进入 EXE:内层 PSEXE 仍处于直接运行宿主。 $script:i18nWarnings.Clear() [void](Preprocessor @( '#_if PSScript' '#_if PSEXE' '$inner = 1' '#_!! $innerBang = 2' '#_endif' '#_endif' ) 'C:\compiled\main.ps1') Assert-Equal 0 (Get-WarningCount 'PreprocessPsexeBranchCode') '嵌套在未选中的 PSScript 分支中的 PSEXE 不应要求 #_!!' Assert-Equal 1 (Get-WarningCount 'PreprocessPsscriptBranchBang') '嵌套在未选中的 PSScript 分支中的 #_!! 应告警' } } Add-Test @{ Name = 'ps12exe.const-eval.unit' Group = 'ps12exe' Deps = $deps Run = { param($ctx) function Write-I18n { param($PipeLineType, $Mid, $FormatArgs, $Category) } $noConsole = $false $architecture = 'anycpu' $requireAdmin = $false $isCoreTarget = $false $AstAnalyzeResult = @{ IsConst = $true } $noConstEval = $false $constEvalTimeout = $true . (Join-Path $ctx.RepoRoot 'src/ConstProgramCheck.ps1') Assert-False $AstAnalyzeResult.IsConst 'Build.ConstEval.Timeout 未把 IsConst 置回 $false(issue 63)' $AstAnalyzeResult = @{ IsConst = $true } $noConstEval = $true $constEvalTimeout = $false . (Join-Path $ctx.RepoRoot 'src/ConstProgramCheck.ps1') Assert-False $AstAnalyzeResult.IsConst 'Build.ConstEval.Enabled=0 未跳过常量求值(issue 63)' } } Add-Test @{ Name = 'ps12exe.const-eval.fallback-e2e' Group = 'ps12exe' Deps = $deps Build = @{ Name = 'fallback' Output = 'const-fallback-e2e.exe' InputText = @' #_pragma Build.ConstEval.Timeout 1 'const-fallback-e2e-ok' '@ } Run = { param($ctx) $r = Invoke-ExeCaptureMergedOutput -ExePath $ctx.Builds['fallback'] Assert-Match $r.Output 'const-fallback-e2e-ok' "const-eval 回退产出了坏 exe(issue 63):$($r.Output)" } } |