-
-
Notifications
You must be signed in to change notification settings - Fork 21
/
Assert-SameFile.ps1
203 lines (167 loc) · 5.57 KB
/
Assert-SameFile.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
<#PSScriptInfo
.VERSION 1.2.1
.AUTHOR Roman Kuzmin
.COPYRIGHT (c) Roman Kuzmin
.TAGS Test
.GUID 1707aec3-6f77-41bd-8df4-953c7704f4a6
.LICENSEURI http://www.apache.org/licenses/LICENSE-2.0
.PROJECTURI https://github.com/nightroman/PowerShelf
#>
<#
.Synopsis
Compares the sample and result files or texts.
.Description
This script automates one typical test scenario, it compares the sample and
result files and performs copy and view operations if the sample is missing
(nor yet created) or the result is different (potentially valid but changed
so that the sample may have to be updated after review).
If the result is missing then the test fails. If the sample is missing then
a warning is written and the sample is created as a copy of the result. The
target directory is also created if it does not exist.
If files are different then the test either fails or, if View is specified
and Fail is not, invokes View, writes a warning, and then prompts to update
the sample file.
File comparison is done via MD5 hashes, it is fast and suitable for large
files. But there is a tiny chance that file differences are not detected.
.Parameter Sample
Specifies the sample file path. If it does not exist then it is
created as a copy of the result.
.Parameter Result
Specifies the result file path. The file must exist.
.Parameter View
Specifies a command invoked when the files are different. It is an
application name or a script block. The arguments are file paths.
.Parameter Fail
Tells to fail on differences even when View is specified.
.Parameter Text
Tells that the sample and result are strings to compare as text
ignoring line endings. If they differ and View is set then View
uses temp files Sample.txt and Result.txt with saved texts.
.Example
Assert-SameFile Sample.log Result.log Merge.exe
This command compares Sample.log and Result.log at the current location and
uses Merge.exe for viewing differences (Merge.exe and file paths are passed
in Start-Process).
.Example
Assert-SameFile Sample.log Result.log {git diff --no-index $args[0] $args[1]}
This command uses git in order to view changes. git requires more arguments
than Merge.exe above, so that the proper script block is used as a command.
.Link
https://github.com/nightroman/PowerShelf
#>
[CmdletBinding()]
param(
[string]$Sample
,
[string]$Result
,
[object]$View
,
[switch]$Fail
,
[switch]$Text
)
$ErrorActionPreference = 1
if ($View -and !($View -is [string] -or $View -is [scriptblock])) {
Write-Error "Invalid view command: '$View'."
}
function Start-View([string]$A, [string]$B) {
if ($View -is [string]) {
Start-Process $View ('"{0}" "{1}"' -f $A, $B)
}
else {
& $View $A $B
}
}
# compare text lines
if ($Text) {
# make and compare strings
$regex = [regex]'\r\n?'
$text1 = ($Sample.TrimEnd() -replace $regex, "`n") + "`n"
$text2 = ($Result.TrimEnd() -replace $regex, "`n") + "`n"
if ([string]::Equals($text1, $text2)) {
return
}
if (!$View) {
Write-Error "Different sample and result text."
}
# use cyclic suffix 0-9 to reduce collisions
$n = $env:AssertSameFile
$n = if ($n -match '^\d$') {([int]$n + 1) % 10} else {0}
$env:AssertSameFile = $n
# write temp files
$Sample = Join-Path $env:TEMP "Sample-$n.txt"
$Result = Join-Path $env:TEMP "Result-$n.txt"
[System.IO.File]::WriteAllText($Sample, $text1)
[System.IO.File]::WriteAllText($Result, $text2)
# show
Start-View $Sample $Result
if ($Fail) {
Write-Error "Different sample and result text."
}
Write-Warning "Different sample and result text."
return
}
# result must exist
$fileResult = [System.IO.FileInfo]$PSCmdlet.GetUnresolvedProviderPathFromPSPath($Result)
if (!$fileResult.Exists) {
Write-Error "Missing result file '$Result'."
}
# make missing sample
$fileSample = [System.IO.FileInfo]$PSCmdlet.GetUnresolvedProviderPathFromPSPath($Sample)
if (!$fileSample.Exists) {
$null = [System.IO.Directory]::CreateDirectory($fileSample.DirectoryName)
Copy-Item -LiteralPath $fileResult.FullName -Destination $fileSample.FullName -Force
Write-Warning "Created missing sample file '$Sample'."
return
}
# compare
$same = $fileResult.Length -eq $fileSample.Length
if ($same) {
$md5 = [System.Security.Cryptography.MD5]::Create()
$reader = $fileSample.OpenRead()
try {
$1 = [Guid]$md5.ComputeHash($reader)
$reader.Close()
$2 = [Guid]$md5.ComputeHash(($reader = $fileResult.OpenRead()))
$same = $1 -eq $2
}
finally {
$reader.Close()
}
}
# pass
if ($same) {
return
}
# fail
if (!$View) {
Write-Error "Different sample '$Sample' and result '$Result'."
}
# show
Start-View $fileSample.FullName $fileResult.FullName
if ($Fail) {
Write-Error "Different sample '$Sample' and result '$Result'."
}
Write-Warning "Different sample '$Sample' and result '$Result'."
# choice, cast is for v2.0
function Get-Choice($Caption, $Message, $Choices) {
$Host.UI.PromptForChoice($Caption, $Message, [System.Management.Automation.Host.ChoiceDescription[]]$Choices, 0)
}
function New-Choice {
New-Object System.Management.Automation.Host.ChoiceDescription $args
}
# prompt
switch(Get-Choice 'Different result' 'How would you like to proceed?' @(
New-Choice '&0. Ignore' 'Do nothing.'
New-Choice '&1. Update' 'Copy result to sample.'
New-Choice '&2. Abort' 'Write terminating error.'
))
{
1 {
Copy-Item -LiteralPath $fileResult.FullName -Destination $fileSample.FullName -Force
}
2 {
Write-Error "Different sample '$Sample' and result '$Result'."
}
}