style: 逐条修静态分析告警(706 → 44),并把 MaxDepth 这条假承诺删掉

修掉的:空 catch 5 处;名词白名单 7 处;default-value 开关、自带 -WhatIf、lab 的明文口令与 irm|iex 各挂抑制并写明理由。

MaxDepth:它是分析器拓出来的真 bug —— 参数声明了却从未使用,也就是配置里的 CatalogMaxDepth 是假的,前缀补全实际只查 1 层,而配置注释与 README 都承诺「向下找几层」。按确认过的原则处理:**先让文档不撒谎**,所以把整条链路去掉(配置默认值、三个函数的参数、70 处实参、配置注释),而不是留一个假旋钮。零行为变化。想真的支持多层补全时,那是一个独立决定。

剩下 3 条都是分析器的误判,而且我实测确认过其中一条:$sourcePath 被报「赋值后从未使用」,我照着改成 $null = 之后,Set-StrictMode -Version 3.0 下读未定义变量直接抛错,Security 套件的 BeforeAll 挂掉、4 条用例连带失败。恢复后才绿。

这一类误判有共同成因:静态分析看不到「在传给 Test-Case / It / Where-Object 的 scriptblock 里被使用」。所以我只对能证明是误判的挂抑制并写明理由,不为了数字好看去改代码。

验收:test.ps1 9/9 全绿(7 与 5.1)、100 个文件两版解析零错、Run-RealSmoke 4/4。
This commit is contained in:
Shuery committed 2026-09-27 10:16:10 +08:00
1 parent 3a3a57a6a1
commit 232a82cd3c
28 files changed
+108 -98

No files matched your search

+17 -17
View File
@@ -138,7 +138,7 @@ Describe '软件名录:Slot 形状(新契约)' {
}
It '一个软件多个 Slot:Kind=Multi,Slot 按名排序且说明被保留' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -NoCache
$catalog['pair'].Kind | Should -Be 'Multi'
@($catalog['pair'].Slots).Count | Should -Be 2
(@($catalog['pair'].Slots | ForEach-Object { $_.Name }) -join ',') | Should -Be 'A,B'
@@ -150,7 +150,7 @@ Describe '软件名录:Slot 形状(新契约)' {
It '每个 Slot 都是一个独立的归档项来源(Kind=slot / Origin=catalog)' {
$entry = ConvertFrom-BackupListLine -Line 'pair'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
@($resolved.Items).Count | Should -Be 2
(@($resolved.Items | ForEach-Object { $_.ArchivePath }) -join ',') | Should -Be 'A,B'
(@($resolved.Items | ForEach-Object { $_.Kind }) -join ',') | Should -Be 'slot,slot'
@@ -161,22 +161,22 @@ Describe '软件名录:Slot 形状(新契约)' {
}
It 'Slot 级排除写在 Slot 自己身上(相对本 Slot 的归档根)' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -NoCache
(@($catalog['slotex'].Slots[0].Exclude) -join '|') | Should -Be '!*Cache|logs\'
$entry = ConvertFrom-BackupListLine -Line 'slotex'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
(@($resolved.Items[0].Exclude) -join '|') | Should -Be '!*Cache|logs\'
$resolved.HasExcludeOverride | Should -BeFalse
}
It '数组里"当前不存在"的 Slot 仍然产出归档项(恢复要靠它还原回原位)' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -NoCache
$catalog['partial'].Kind | Should -Be 'Partial'
@($catalog['partial'].Missing) | Should -Contain $script:MissingDir
$entry = ConvertFrom-BackupListLine -Line 'partial'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
@($resolved.Items).Count | Should -Be 2
@($resolved.Items | ForEach-Object { $_.RealPath }) | Should -Contain $script:MissingDir
$resolved.Blocking | Should -BeNullOrEmpty # 源不存在不是致命错误
@@ -184,7 +184,7 @@ Describe '软件名录:Slot 形状(新契约)' {
It '文件 Slot:归档项是文件项(归档里就是名为 Slot 的文件)' {
$entry = ConvertFrom-BackupListLine -Line 'fileapp'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
@($resolved.Items).Count | Should -Be 1
$resolved.Items[0].IsFile | Should -BeTrue
$resolved.Items[0].ArchivePath | Should -Be 'Cfg'
@@ -193,13 +193,13 @@ Describe '软件名录:Slot 形状(新契约)' {
}
It '旧的裸字符串 / 字符串数组写法被拒绝(ERROR + 跳过)' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -NoCache
$catalog.ContainsKey('legacystr') | Should -BeFalse
$catalog.ContainsKey('legacyarr') | Should -BeFalse
}
It '旧的 @{ Dirs = @(...) } 写法不再展开,留下 Invalid 与原因' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -NoCache
$catalog.ContainsKey('legacydirs') | Should -BeTrue
$catalog['legacydirs'].Kind | Should -Be 'Invalid'
$catalog['legacydirs'].Error | Should -Not -BeNullOrEmpty
@@ -208,7 +208,7 @@ Describe '软件名录:Slot 形状(新契约)' {
It '多 Slot 的名录条目在清单里仍然按软件名命名归档' {
$entry = ConvertFrom-BackupListLine -Line 'pair'
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3) | Should -Be 'pair'
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:FormatCatalog) | Should -Be 'pair'
}
}
@@ -227,7 +227,7 @@ Describe '清单修饰符:新契约格式' {
It ':: 覆盖 Path:单 Slot 条目直接生效' {
$entry = ConvertFrom-BackupListLine -Line "solo :: $script:DirB"
$entry.Overrides.ContainsKey('Path') | Should -BeTrue
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
@($resolved.Items).Count | Should -Be 1
$resolved.Items[0].ArchivePath | Should -Be 'Only'
$resolved.Items[0].RealPath | Should -Be $script:DirB
@@ -236,7 +236,7 @@ Describe '清单修饰符:新契约格式' {
It ':: 覆盖遇到多 Slot 条目 -> Blocking(不知道给哪一个,绝不猜)' {
$entry = ConvertFrom-BackupListLine -Line "pair :: $script:DirB"
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
@($resolved.Items).Count | Should -Be 0
$resolved.Blocking | Should -Match '不能用一个'
}
@@ -246,7 +246,7 @@ Describe '清单修饰符:新契约格式' {
(@($entry.ExcludePatterns) -join '|') | Should -Be 'logs\|!*Cache'
(@($entry.Includes) -join '|') | Should -Be "Mods:$script:DirB"
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
$resolved.HasExcludeOverride | Should -BeTrue
$resolved.HasIncludeOverride | Should -BeTrue
@($resolved.Items | ForEach-Object { $_.ArchivePath }) | Should -Contain 'Mods'
@@ -261,13 +261,13 @@ Describe '清单修饰符:新契约格式' {
}
It ':encrypt / :!encrypt 覆盖名录里的加密默认值' {
$base = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'fileapp') -CatalogPath $script:FormatCatalog -MaxDepth 3
$base = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'fileapp') -CatalogPath $script:FormatCatalog
$base.Encrypt | Should -BeTrue # 名录里 Cfg Slot 标了 Encrypt
$off = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'fileapp :!encrypt') -CatalogPath $script:FormatCatalog -MaxDepth 3
$off = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'fileapp :!encrypt') -CatalogPath $script:FormatCatalog
$off.Encrypt | Should -BeFalse
$on = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'pair :encrypt') -CatalogPath $script:FormatCatalog -MaxDepth 3
$on = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'pair :encrypt') -CatalogPath $script:FormatCatalog
$on.Encrypt | Should -BeTrue
}
@@ -279,7 +279,7 @@ Describe '清单修饰符:新契约格式' {
# @pathname 对软件名条目也会改用真实路径命名
$entry = ConvertFrom-BackupListLine -Line 'pair @pathname'
$expected = Get-BakNRetBackupBaseName -RawPath $script:DirA
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3) | Should -Be $expected
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:FormatCatalog) | Should -Be $expected
}
It '同一行里重复写同类记号会累积(不静默丢掉前一条规则)' {
+43 -43
View File
@@ -407,24 +407,24 @@ Describe '归档命名' {
It '软件名条目:默认用软件名做归档名' {
$entry = ConvertFrom-BackupListLine -Line 'my-app'
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog -MaxDepth 3) | Should -Be 'my-app'
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog) | Should -Be 'my-app'
}
It '字面路径条目:仍用路径命名算法(现有清单无需改写)' {
$entry = ConvertFrom-BackupListLine -Line 'C:\Programs\FooClolor'
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog -MaxDepth 3) | Should -Be 'FooClolor_from_C_+Programs'
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog) | Should -Be 'FooClolor_from_C_+Programs'
}
It '@pathname 用名录里的真实路径命名,而不是软件名' {
$entry = ConvertFrom-BackupListLine -Line 'my-app @pathname'
$expected = Get-BakNRetBackupBaseName -RawPath $script:NamingApp
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog -MaxDepth 3) | Should -Be $expected
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog) | Should -Be $expected
}
It '名录里没有该名字:归档名退回可读目录名,并给出 Error' {
$entry = ConvertFrom-BackupListLine -Line 'no-such-thing'
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog -MaxDepth 3) | Should -Be 'no-such-thing'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:NamingCatalog -MaxDepth 3
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog) | Should -Be 'no-such-thing'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:NamingCatalog
$resolved.Error | Should -Not -BeNullOrEmpty
@($resolved.Items).Count | Should -Be 0
}
@@ -827,7 +827,7 @@ Describe '软件名录' {
}
It '名录解析:条目与 Slot 的字段集合就是新契约' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
$entry = $catalog['single']
(@($entry.PSObject.Properties.Name) -join ',') | Should -Be 'Name,Path,Description,Slots,Kind,Missing,Error,Raw'
$entry.Name | Should -Be 'single'
@@ -849,7 +849,7 @@ Describe '软件名录' {
}
It '一个软件多个 Slot:Kind=Multi,Slot 按名字排序' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
$catalog['multi'].Kind | Should -Be 'Multi'
@($catalog['multi'].Slots).Count | Should -Be 2
(@($catalog['multi'].Slots | ForEach-Object { $_.Name }) -join ',') | Should -Be 'Alpha,Zeta'
@@ -858,7 +858,7 @@ Describe '软件名录' {
}
It 'Kind:Single / Multi / Partial / Unresolved / Invalid' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
$catalog['single'].Kind | Should -Be 'Single'
$catalog['multi'].Kind | Should -Be 'Multi'
$catalog['partial'].Kind | Should -Be 'Partial'
@@ -873,7 +873,7 @@ Describe '软件名录' {
}
It '前缀补全:<名>_<后缀> 与 <名>-<后缀> 都会被补全' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
$catalog['legendary'].Slots[0].Resolved | Should -Be (Join-Path $script:CatRoot 'legendary_2.0.4')
$catalog['legendary'].Slots[0].Suffixed | Should -BeTrue
@@ -882,12 +882,12 @@ Describe '软件名录' {
}
It '不会把 Legendary 误配成 LegendarySomething' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
$catalog['legendary'].Slots[0].Resolved | Should -Not -Be (Join-Path $script:CatRoot 'LegendarySomething')
}
It '一个 Slot 命中多个候选目录:报 Error,绝不悄悄挑一棵树' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
$entry = $catalog['dupslot']
$entry.Error | Should -Match '只能对应一个目录'
$entry.Error | Should -Match 'dup_1'
@@ -897,14 +897,14 @@ Describe '软件名录' {
}
It '文件 Slot:Path 指向文件时 IsFile 为真,Encrypt 也带上' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
$slot = $catalog['fileslot'].Slots[0]
$slot.IsFile | Should -BeTrue
$slot.Encrypt | Should -BeTrue
}
It '%变量% 会在名录路径里展开' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
$catalog['envpath'].Slots[0].Resolved | Should -Be ([Environment]::ExpandEnvironmentVariables('%TEMP%'))
}
@@ -916,39 +916,39 @@ Describe '软件名录' {
}
It '读取结果按"路径 + 时间戳 + 长度 + 内容 MD5"缓存' {
$first = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3
$second = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3
$first = Get-BakNRetSoftwareCatalog -Path $script:CatFile
$second = Get-BakNRetSoftwareCatalog -Path $script:CatFile
[object]::ReferenceEquals($first, $second) | Should -BeTrue
$fresh = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
$fresh = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
[object]::ReferenceEquals($first, $fresh) | Should -BeFalse
}
It '名录文件内容变了以后缓存自动失效' {
$path = Write-ListFile -Path (Join-Path $script:CatRoot 'cache.psd1') -Content "@{ 'x' = @{ S = @{ Path = '$script:CatReal'; Description = 'one' } } }"
(Get-BakNRetSoftwareCatalog -Path $path -MaxDepth 3)['x'].Description | Should -Be 'one'
(Get-BakNRetSoftwareCatalog -Path $path)['x'].Description | Should -Be 'one'
Write-ListFile -Path $path -Content "@{ 'x' = @{ S = @{ Path = '$script:CatReal'; Description = 'two' } } }" | Out-Null
(Get-BakNRetSoftwareCatalog -Path $path -MaxDepth 3)['x'].Description | Should -Be 'two'
(Get-BakNRetSoftwareCatalog -Path $path)['x'].Description | Should -Be 'two'
}
It 'Includes:分文件维护的名录会被合并' {
Write-ListFile -Path (Join-Path $script:CatRoot 'Extra.psd1') -Content "@{ 'extra-app' = @{ S = @{ Path = '$script:CatReal' } } }" | Out-Null
$main = Write-ListFile -Path (Join-Path $script:CatRoot 'Main.psd1') -Content "@{ Includes = @('Extra.psd1'); 'main-app' = @{ S = @{ Path = '$script:CatReal' } } }"
$catalog = Get-BakNRetSoftwareCatalog -Path $main -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $main -NoCache
$catalog.ContainsKey('main-app') | Should -BeTrue
$catalog.ContainsKey('extra-app') | Should -BeTrue
}
It '旧的裸字符串 / 字符串数组 / 对象数组写法都会报 ERROR 并被跳过' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:LegacyFile -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:LegacyFile -NoCache
$catalog.ContainsKey('bare') | Should -BeFalse
$catalog.ContainsKey('arr') | Should -BeFalse
$catalog.ContainsKey('objarr') | Should -BeFalse
}
It '旧的 @{ Dirs = @(...) } 写法不再展开:留下 Invalid 条目和原因' {
$catalog = Get-BakNRetSoftwareCatalog -Path $script:LegacyFile -MaxDepth 3 -NoCache
$catalog = Get-BakNRetSoftwareCatalog -Path $script:LegacyFile -NoCache
$catalog.ContainsKey('dirstyle') | Should -BeTrue
$catalog['dirstyle'].Kind | Should -Be 'Invalid'
$catalog['dirstyle'].Error | Should -Not -BeNullOrEmpty
@@ -976,7 +976,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
It 'resolve 与归档项的字段集合就是新契约(旧字段已删除)' {
$entry = ConvertFrom-BackupListLine -Line 'single'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
(@($resolved.PSObject.Properties.Name) -join ',') | Should -Be 'IsName,CatalogEntry,BaseName,ArchiveFlavor,Direction,Items,Encrypt,ExcludePatterns,HasExcludeOverride,Includes,HasIncludeOverride,Source,Error,Blocking'
@($resolved.Items)[0].PSObject.Properties.Name | Should -Contain 'ArchivePath'
@($resolved.Items)[0].PSObject.Properties.Name | Should -Contain 'Origin'
@@ -985,7 +985,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
It '软件名条目:isName/CatalogEntry/BaseName/ArchiveFlavor/Source' {
$entry = ConvertFrom-BackupListLine -Line 'single'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
$resolved.IsName | Should -BeTrue
$resolved.BaseName | Should -Be 'single'
$resolved.ArchiveFlavor | Should -Be 'name'
@@ -997,7 +997,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
It '软件名条目:Items 来自 Slot(ArchivePath=Slot 名,Kind=slot,Origin=catalog)' {
$entry = ConvertFrom-BackupListLine -Line 'multi'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
@($resolved.Items).Count | Should -Be 2
(@($resolved.Items | ForEach-Object { $_.ArchivePath }) -join ',') | Should -Be 'Alpha,Zeta'
(@($resolved.Items | ForEach-Object { $_.Kind }) -join ',') | Should -Be 'slot,slot'
@@ -1009,7 +1009,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
It '字面路径条目:一个 path 项(ArchivePath 是末级名)' {
$entry = ConvertFrom-BackupListLine -Line 'C:\Programs\FooClolor'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
$resolved.IsName | Should -BeFalse
$resolved.ArchiveFlavor | Should -Be 'path'
@($resolved.Items).Count | Should -Be 1
@@ -1021,7 +1021,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
It '字面路径条目上的 @ Path= 覆盖目标路径,但归档名仍按原路径' {
$entry = ConvertFrom-BackupListLine -Line "C:\Programs\Foo @ Path='D:\Elsewhere'"
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
$resolved.Items[0].RealPath | Should -Be 'D:\Elsewhere'
$resolved.BaseName | Should -Be 'Foo_from_C_+Programs'
}
@@ -1029,7 +1029,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
It '名录里的路径不存在时仍给出 Items(恢复要靠它还原回原位)' {
$missingCatalog = Write-ListFile -Path (Join-Path $script:Sandbox 'catalog\Missing.psd1') -Content "@{ 'gone' = @{ S = @{ Path = 'C:\definitely-not-here-98765' } } }"
$entry = ConvertFrom-BackupListLine -Line 'gone'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $missingCatalog -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $missingCatalog
@($resolved.Items).Count | Should -Be 1
$resolved.Items[0].Exists | Should -BeFalse
$resolved.Items[0].RealPath | Should -Be 'C:\definitely-not-here-98765'
@@ -1037,7 +1037,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
It ':: 覆盖 Path:单 Slot 条目直接生效' {
$entry = ConvertFrom-BackupListLine -Line "single :: $script:CatOther"
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
@($resolved.Items).Count | Should -Be 1
$resolved.Items[0].ArchivePath | Should -Be 'Main'
$resolved.Items[0].RealPath | Should -Be $script:CatOther
@@ -1047,7 +1047,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
It ':: / @ Path= 覆盖遇到多 Slot 条目 -> Blocking(不猜是哪一个)' {
foreach ($line in @("multi :: $script:CatOther", "multi @ Path='$script:CatOther'")) {
$entry = ConvertFrom-BackupListLine -Line $line
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
@($resolved.Items).Count | Should -Be 0
$resolved.Blocking | Should -Match '不能用一个'
}
@@ -1055,14 +1055,14 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
It '条目级 :- 覆盖名录里的排除:HasExcludeOverride 为真' {
$entry = ConvertFrom-BackupListLine -Line 'single :- logs\,!*Cache'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
$resolved.HasExcludeOverride | Should -BeTrue
(@($resolved.ExcludePatterns) -join '|') | Should -Be 'logs\|!*Cache'
}
It '名录 Slot 的 Include 会追加成 include 项' {
$entry = ConvertFrom-BackupListLine -Line 'incapp'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
@($resolved.Items).Count | Should -Be 2
$include = @($resolved.Items | Where-Object { $_.Origin -eq 'include' })
$include.Count | Should -Be 1
@@ -1074,7 +1074,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
It '条目级 :+ / @ Include= 覆盖名录里的 Include' {
foreach ($line in @("incapp :+ Other:$script:CatOther", "incapp @ Include='Other:$script:CatOther'")) {
$entry = ConvertFrom-BackupListLine -Line $line
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
$resolved.HasIncludeOverride | Should -BeTrue
(@($resolved.Items | ForEach-Object { $_.ArchivePath }) -join ',') | Should -Be 'A,Other'
@($resolved.Items)[1].RealPath | Should -Be $script:CatOther
@@ -1082,34 +1082,34 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
}
It '加密:名录里各 Slot 取或;条目级 :encrypt / :!encrypt 覆盖' {
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single') -CatalogPath $script:CatFile -MaxDepth 3).Encrypt | Should -BeFalse
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'encapp') -CatalogPath $script:CatFile -MaxDepth 3).Encrypt | Should -BeTrue
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'encapp :!encrypt') -CatalogPath $script:CatFile -MaxDepth 3).Encrypt | Should -BeFalse
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single :encrypt') -CatalogPath $script:CatFile -MaxDepth 3).Encrypt | Should -BeTrue
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line "single @ Encrypt='true'") -CatalogPath $script:CatFile -MaxDepth 3).Encrypt | Should -BeTrue
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single') -CatalogPath $script:CatFile).Encrypt | Should -BeFalse
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'encapp') -CatalogPath $script:CatFile).Encrypt | Should -BeTrue
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'encapp :!encrypt') -CatalogPath $script:CatFile).Encrypt | Should -BeFalse
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single :encrypt') -CatalogPath $script:CatFile).Encrypt | Should -BeTrue
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line "single @ Encrypt='true'") -CatalogPath $script:CatFile).Encrypt | Should -BeTrue
}
It '方向标记会传递到 Resolve-BakNRetBackupEntry.Direction' {
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line '+ single') -CatalogPath $script:CatFile -MaxDepth 3).Direction | Should -Be 'backup'
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line '- single') -CatalogPath $script:CatFile -MaxDepth 3).Direction | Should -Be 'restore'
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single') -CatalogPath $script:CatFile -MaxDepth 3).Direction | Should -Be 'both'
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line '+ single') -CatalogPath $script:CatFile).Direction | Should -Be 'backup'
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line '- single') -CatalogPath $script:CatFile).Direction | Should -Be 'restore'
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single') -CatalogPath $script:CatFile).Direction | Should -Be 'both'
}
It '归档内路径冲突(include 与 Slot 同名)-> Blocking' {
$entry = ConvertFrom-BackupListLine -Line "conflict :+ Data:$script:CatOther"
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
$resolved.Blocking | Should -Match '归档内路径冲突'
}
It '归档内路径冲突(父子关系)-> Blocking' {
$entry = ConvertFrom-BackupListLine -Line "conflict :+ Data\sub:$script:CatOther"
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
$resolved.Blocking | Should -Match '父子关系'
}
It '名录里没有该名字:Error 给出,Items 为空' {
$entry = ConvertFrom-BackupListLine -Line 'no-such-thing'
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
$resolved.Error | Should -Match 'no-such-thing'
@($resolved.Items).Count | Should -Be 0
}
+1 -2
View File
@@ -322,7 +322,7 @@ foreach ($name in $Entries) {
$entry = ConvertFrom-BackupListLine -Line $name
if (-not $entry) { continue }
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $catalogPath -MaxDepth $config.CatalogMaxDepth
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $catalogPath
if (-not $resolved.BaseName) {
$failures += "$name :解析不出归档名"
@@ -456,7 +456,6 @@ foreach ($name in $Entries) {
BackupDir = '$scratchBackupRoot'
LogDir = '$scratchLogDir'
SoftwareCatalog = '$scratchCatalog'
CatalogMaxDepth = $($config.CatalogMaxDepth)
VerifyArchive = `$true
}
"@, [System.Text.UTF8Encoding]::new($false))
+4 -6
View File
@@ -61,8 +61,7 @@ function New-E2EConfig {
param(
[Parameter(Mandatory = $true)][string]$Path,
[Parameter(Mandatory = $true)][string]$LogDir,
[string]$SoftwareCatalog,
[int]$CatalogMaxDepth = 5
[string]$SoftwareCatalog
)
$lines = @(
'@{'
@@ -72,7 +71,6 @@ function New-E2EConfig {
' MinFreeSpaceGB = 0'
)
if ($SoftwareCatalog) { $lines += " SoftwareCatalog = '$SoftwareCatalog'" }
$lines += " CatalogMaxDepth = $CatalogMaxDepth"
$lines += '}'
[System.IO.File]::WriteAllText($Path, ($lines -join "`r`n"), [System.Text.UTF8Encoding]::new($true))
}
@@ -84,13 +82,13 @@ function Get-NewestLog {
Sort-Object LastWriteTime | Select-Object -Last 1
}
function Get-ArchiveNames {
function Get-ArchiveName {
param([Parameter(Mandatory = $true)][string]$Dir)
return @(Get-ChildItem -LiteralPath $Dir -File -Filter *.7z -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty BaseName)
}
function Get-OrphanNames {
function Get-OrphanName {
<# .SYNOPSIS 从备份日志里解析出"孤儿归档"那一段点名的归档名。 #>
param([Parameter(Mandatory = $true)][string]$LogPath)
@@ -528,7 +526,7 @@ Test-Case '行首 - = 仅备份端跳过(日志点名),不产生归档' {
}
Test-Case '孤儿审计:`-` 条目的归档名算有主,真孤儿才被点名' {
$orphans = Get-OrphanNames -LogPath $dirLog.FullName
$orphans = Get-OrphanName -LogPath $dirLog.FullName
Assert-True ($orphans -contains 'zzz-orphan.7z') '真孤儿必须被点名'
Assert-False ($orphans -contains 'app-b.7z') '`-` 条目的归档不能被误报成孤儿'
}
+3 -1
View File
@@ -23,6 +23,8 @@
.EXAMPLE
.\tests\Run-RealSmoke.ps1
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '',
Justification = '误判:这些参数的值是在传给 Test-Case / It 的 scriptblock 里用的,静态分析看不到那层使用。')]
[CmdletBinding()]
param(
[string]$ModulePath,
@@ -130,7 +132,7 @@ Test-Case '真实清单里每个条目都能解析出方向,且软件名都能
if ($item.Direction -eq 'backup') { $backupOnly++ }
if ($item.Direction -eq 'restore') { $restoreOnly++ }
$resolved = Resolve-BakNRetBackupEntry -Entry $item -CatalogPath $catalogPath -MaxDepth $config.CatalogMaxDepth
$resolved = Resolve-BakNRetBackupEntry -Entry $item -CatalogPath $catalogPath
if ($resolved.Error -and $resolved.Error -like '*名录里没有*') { $catalogMiss += $resolved.Error }
}
+2
View File
@@ -66,6 +66,8 @@ function Assert-Null {
}
function Assert-FileExists {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '',
Justification = '误判:规则把结尾的 s 当复数,而这里的名词是 FileExists(Exists 不是复数)。')]
param([string]$Path, [string]$Because)
if (-not (Test-Path -LiteralPath $Path)) {
throw ("文件应当存在但不存在:{0}{1}" -f $Path, $(if ($Because) { "($Because)" } else { '' }))